From a3309b51a254f142c535022615be6f76eb23fa9b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 4 May 2024 20:30:03 +0100 Subject: [PATCH 0001/2393] shadow: fix small pixel gaps between border huge fix --- src/render/decorations/CHyprDropShadowDecoration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 4f7ff822..fba279cc 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -190,7 +190,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), ROUNDING * pMonitor->scale); + g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); alphaSwapFB.bind(); From 0b215c5f246d3fde6c023e78b3e3579f7498c172 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 4 May 2024 23:46:10 +0100 Subject: [PATCH 0002/2393] idle-inhibit: fix and cleanup visibility logic fixes #5878 --- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Popup.cpp | 35 ++++++++++++++++++---------- src/desktop/Popup.hpp | 4 +++- src/desktop/Subsurface.cpp | 11 +++++++++ src/desktop/Subsurface.hpp | 2 ++ src/desktop/WLSurface.cpp | 12 ++++++++++ src/desktop/WLSurface.hpp | 1 + src/managers/input/IdleInhibitor.cpp | 29 ++++++++++++++--------- src/managers/input/InputManager.hpp | 4 ++-- 9 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index dd2cfb7d..d472b906 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -90,7 +90,7 @@ PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { pLS->alpha.setValueAndWarp(0.f); - pLS->surface.assign(pWLRLS->surface); + pLS->surface.assign(pWLRLS->surface, pLS); return pLS; } diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 3cfebe1b..b4de8dda 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -71,8 +71,8 @@ void CPopup::initAllSignals() { if (!m_pWLR) { if (!m_pWindowOwner.expired()) hyprListener_newPopup.initCallback(&m_pWindowOwner.lock()->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); - else if (m_pLayerOwner) - hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); + else if (!m_pLayerOwner.expired()) + hyprListener_newPopup.initCallback(&m_pLayerOwner.lock()->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); else ASSERT(false); @@ -119,8 +119,8 @@ void CPopup::onMap() { unconstrain(); sendScale(); - if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); } void CPopup::onUnmap() { @@ -136,8 +136,8 @@ void CPopup::onUnmap() { g_pInputManager->simulateMouseMovement(); - if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); } void CPopup::onCommit(bool ignoreSiblings) { @@ -178,8 +178,8 @@ void CPopup::onCommit(bool ignoreSiblings) { m_bRequestedReposition = false; - if (m_pLayerOwner && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); } void CPopup::onReposition() { @@ -232,8 +232,8 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) { Vector2D CPopup::t1ParentCoords() { if (!m_pWindowOwner.expired()) return m_pWindowOwner.lock()->m_vRealPosition.value(); - if (m_pLayerOwner) - return m_pLayerOwner->realPosition.value(); + if (!m_pLayerOwner.expired()) + return m_pLayerOwner.lock()->realPosition.value(); ASSERT(false); return {}; @@ -262,8 +262,19 @@ Vector2D CPopup::size() { void CPopup::sendScale() { if (!m_pWindowOwner.expired()) g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner.lock()->m_pWLSurface.m_fLastScale); - else if (m_pLayerOwner) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale); + else if (!m_pLayerOwner.expired()) + g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner.lock()->surface.m_fLastScale); else UNREACHABLE(); } + +bool CPopup::visible() { + if (!m_pWindowOwner.expired()) + return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock()); + if (!m_pLayerOwner.expired()) + return true; + if (m_pParent) + return m_pParent->visible(); + + return false; +} diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 16f011eb..cadbf244 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -29,12 +29,14 @@ class CPopup { void recheckTree(); + bool visible(); + CWLSurface m_sWLSurface; private: // T1 owners, each popup has to have one of these PHLWINDOWREF m_pWindowOwner; - PHLLS m_pLayerOwner; + PHLLSREF m_pLayerOwner; // T2 owners CPopup* m_pParent = nullptr; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index b2c9f8bd..1809efe5 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -227,3 +227,14 @@ void CSubsurface::initExistingSubsurfaces(wlr_surface* pSurface) { Vector2D CSubsurface::size() { return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; } + +bool CSubsurface::visible() { + if (!m_pWindowParent.expired()) + return g_pHyprRenderer->shouldRenderWindow(m_pWindowParent.lock()); + if (m_pPopupParent) + return m_pPopupParent->visible(); + if (m_pParent) + return m_pParent->visible(); + + return false; +} diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index e5094041..f3a5ea4b 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -29,6 +29,8 @@ class CSubsurface { void onMap(); void onUnmap(); + bool visible(); + void recheckDamageForSubsurfaces(); private: diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 41c357e0..fd6c28b3 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -197,3 +197,15 @@ void CWLSurface::onCommit() { std::shared_ptr CWLSurface::constraint() { return m_pConstraint.lock(); } + +bool CWLSurface::visible() { + if (!m_pWindowOwner.expired()) + return g_pHyprRenderer->shouldRenderWindow(m_pWindowOwner.lock()); + if (!m_pLayerOwner.expired()) + return true; + if (m_pPopupOwner) + return m_pPopupOwner->visible(); + if (m_pSubsurfaceOwner) + return m_pSubsurfaceOwner->visible(); + return true; // non-desktop, we don't know much. +} diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 752f4d11..8fb69937 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -33,6 +33,7 @@ class CWLSurface { Vector2D getViewporterCorrectedSize() const; CRegion logicalDamage() const; void onCommit(); + bool visible(); // getters for owners. PHLWINDOW getWindow(); diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 40c8c637..dc7c61c3 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -14,26 +14,33 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { recheckIdleInhibitorStatus(); }); - const auto PWINDOW = g_pCompositor->getWindowFromSurface(PINHIBIT->inhibitor->surface); + auto WLSurface = CWLSurface::surfaceFromWlr(PINHIBIT->inhibitor->surface); + + if (!WLSurface) { + Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Ignoring."); + PINHIBIT->inert = true; + recheckIdleInhibitorStatus(); + return; + } + + PINHIBIT->surfaceDestroyListener = WLSurface->events.destroy.registerListener( + [this, PINHIBIT](std::any data) { std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; }); }); - if (PWINDOW) { - PINHIBIT->pWindow = PWINDOW; - PINHIBIT->windowDestroyListener = PWINDOW->events.destroy.registerListener([PINHIBIT](std::any data) { - Debug::log(WARN, "Inhibitor got its window destroyed before its inhibitor resource."); - PINHIBIT->pWindow.reset(); - }); - } else - Debug::log(WARN, "Inhibitor is for no window?"); recheckIdleInhibitorStatus(); } void CInputManager::recheckIdleInhibitorStatus() { for (auto& ii : m_vIdleInhibitors) { - if (ii->pWindow.expired()) + if (ii->inert) continue; - if (g_pHyprRenderer->shouldRenderWindow(ii->pWindow.lock())) { + auto WLSurface = CWLSurface::surfaceFromWlr(ii->inhibitor->surface); + + if (!WLSurface) + continue; + + if (WLSurface->visible()) { PROTO::idle->setInhibit(true); return; } diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 98032dd4..719e19c6 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -242,8 +242,8 @@ class CInputManager { // idle inhibitors struct SIdleInhibitor { std::shared_ptr inhibitor; - PHLWINDOWREF pWindow; - CHyprSignalListener windowDestroyListener; + bool inert = false; + CHyprSignalListener surfaceDestroyListener; }; std::vector> m_vIdleInhibitors; From 62eadad20fe10ffaf13d9c65ee68608996d93df0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 5 May 2024 01:07:46 +0100 Subject: [PATCH 0003/2393] kde-server-decoration: move to new impl --- CMakeLists.txt | 1 + protocols/kde-server-decoration.xml | 85 +++++++++++++++++++++++++++ protocols/meson.build | 1 + src/Compositor.cpp | 3 - src/Compositor.hpp | 45 +++++++------- src/includes.hpp | 1 - src/managers/ProtocolManager.cpp | 48 +++++++-------- src/protocols/ServerDecorationKDE.cpp | 53 +++++++++++++++++ src/protocols/ServerDecorationKDE.hpp | 40 +++++++++++++ 9 files changed, 227 insertions(+), 50 deletions(-) create mode 100644 protocols/kde-server-decoration.xml create mode 100644 src/protocols/ServerDecorationKDE.cpp create mode 100644 src/protocols/ServerDecorationKDE.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9775098b..a4e400d1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -265,6 +265,7 @@ protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unsta protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) +protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" 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/kde-server-decoration.xml b/protocols/kde-server-decoration.xml new file mode 100644 index 00000000..b70bec12 --- /dev/null +++ b/protocols/kde-server-decoration.xml @@ -0,0 +1,85 @@ + + + + + + This interface allows to coordinate whether the server should create + a server-side window decoration around a wl_surface representing a + shell surface (wl_shell_surface or similar). By announcing support + for this interface the server indicates that it supports server + side decorations. + + Use in conjunction with zxdg_decoration_manager_v1 is undefined. + + + + When a client creates a server-side decoration object it indicates + that it supports the protocol. The client is supposed to tell the + server whether it wants server-side decorations or will provide + client-side decorations. + + If the client does not create a server-side decoration object for + a surface the server interprets this as lack of support for this + protocol and considers it as client-side decorated. Nevertheless a + client-side decorated surface should use this protocol to indicate + to the server that it does not want a server-side deco. + + + + + + + + + + + + + This event is emitted directly after binding the interface. It contains + the default mode for the decoration. When a new server decoration object + is created this new object will be in the default mode until the first + request_mode is requested. + + The server may change the default mode at any time. + + + + + + + + + + + + + + + + + + + + + This event is emitted directly after the decoration is created and + represents the base decoration policy by the server. E.g. a server + which wants all surfaces to be client-side decorated will send Client, + a server which wants server-side decoration will send Server. + + The client can request a different mode through the decoration request. + The server will acknowledge this by another event with the same mode. So + even if a server prefers server-side decoration it's possible to force a + client-side decoration. + + The server may emit this event at any time. In this case the client can + again request a different mode. It's the responsibility of the server to + prevent a feedback loop. + + + + + diff --git a/protocols/meson.build b/protocols/meson.build index ce89e7f1..1c9013f0 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -42,6 +42,7 @@ new_protocols = [ ['virtual-keyboard-unstable-v1.xml'], ['wlr-virtual-pointer-unstable-v1.xml'], ['wlr-output-management-unstable-v1.xml'], + ['kde-server-decoration.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 9609cbd1..1f5a355c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -240,9 +240,6 @@ void CCompositor::initServer() { m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4); - m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay); - wlr_server_decoration_manager_set_default_mode(m_sWLRServerDecoMgr, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - 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"); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f252d131..8be1956c 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -40,29 +40,28 @@ class CCompositor { ~CCompositor(); // ------------------ WLR BASICS ------------------ // - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - wlr_backend* m_sWLRBackend; - wlr_session* m_sWLRSession; - wlr_renderer* m_sWLRRenderer; - wlr_allocator* m_sWLRAllocator; - wlr_compositor* m_sWLRCompositor; - wlr_subcompositor* m_sWLRSubCompositor; - wlr_data_device_manager* m_sWLRDataDevMgr; - wlr_drm* m_sWRLDRM; - wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_output_layout* m_sWLROutputLayout; - wlr_layer_shell_v1* m_sWLRLayerShell; - wlr_xdg_shell* m_sWLRXDGShell; - wlr_cursor* m_sWLRCursor; - wlr_presentation* m_sWLRPresentation; - wlr_egl* m_sWLREGL; - int m_iDRMFD; - wlr_server_decoration_manager* m_sWLRServerDecoMgr; - wlr_tablet_manager_v2* m_sWLRTabletManager; - wlr_xdg_foreign_registry* m_sWLRForeignRegistry; - wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; - wlr_backend* m_sWLRHeadlessBackend; + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + wlr_backend* m_sWLRBackend; + wlr_session* m_sWLRSession; + wlr_renderer* m_sWLRRenderer; + wlr_allocator* m_sWLRAllocator; + wlr_compositor* m_sWLRCompositor; + wlr_subcompositor* m_sWLRSubCompositor; + wlr_data_device_manager* m_sWLRDataDevMgr; + wlr_drm* m_sWRLDRM; + wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; + wlr_output_layout* m_sWLROutputLayout; + wlr_layer_shell_v1* m_sWLRLayerShell; + wlr_xdg_shell* m_sWLRXDGShell; + wlr_cursor* m_sWLRCursor; + wlr_presentation* m_sWLRPresentation; + wlr_egl* m_sWLREGL; + int m_iDRMFD; + wlr_tablet_manager_v2* m_sWLRTabletManager; + wlr_xdg_foreign_registry* m_sWLRForeignRegistry; + wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; + wlr_backend* m_sWLRHeadlessBackend; // ------------------------------------------------- // std::string m_szHyprTempDataRoot = ""; diff --git a/src/includes.hpp b/src/includes.hpp index 73611fb2..6df38267 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -60,7 +60,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 115e10f4..47372d01 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -23,32 +23,34 @@ #include "../protocols/VirtualKeyboard.hpp" #include "../protocols/VirtualPointer.hpp" #include "../protocols/OutputManagement.hpp" +#include "../protocols/ServerDecorationKDE.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::foreignToplevelWlr = std::make_unique(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); - PROTO::shortcutsInhibit = std::make_unique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); - PROTO::textInputV3 = std::make_unique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); - PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); - PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); - PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation"); - PROTO::idle = std::make_unique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); - PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); - PROTO::ime = std::make_unique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); - PROTO::virtualKeyboard = std::make_unique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); - PROTO::virtualPointer = std::make_unique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); - PROTO::outputManagement = std::make_unique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); + 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"); + PROTO::shortcutsInhibit = std::make_unique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); + PROTO::textInputV3 = std::make_unique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); + PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); + PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); + PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation"); + PROTO::idle = std::make_unique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); + PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); + PROTO::ime = std::make_unique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); + PROTO::virtualKeyboard = std::make_unique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); + PROTO::virtualPointer = std::make_unique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); + PROTO::outputManagement = std::make_unique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); + PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp new file mode 100644 index 00000000..8d0e423b --- /dev/null +++ b/src/protocols/ServerDecorationKDE.cpp @@ -0,0 +1,53 @@ +#include "ServerDecorationKDE.hpp" + +#define LOGM PROTO::serverDecorationKDE->protoLog + +CServerDecorationKDE::CServerDecorationKDE(SP resource_, wlr_surface* surf) : resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](COrgKdeKwinServerDecoration* pMgr) { PROTO::serverDecorationKDE->destroyResource(this); }); + resource->setOnDestroy([this](COrgKdeKwinServerDecoration* pMgr) { PROTO::serverDecorationKDE->destroyResource(this); }); + + // we send this and ignore request_mode. + resource->sendMode(ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER); +} + +bool CServerDecorationKDE::good() { + return resource->resource(); +} + +CServerDecorationKDEProtocol::CServerDecorationKDEProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CServerDecorationKDEProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](COrgKdeKwinServerDecorationManager* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setCreate([this](COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* pointer) { this->createDecoration(pMgr, id, pointer); }); + + // send default mode of SSD, as Hyprland will never ask for CSD. Screw Gnome and GTK. + RESOURCE->sendDefaultMode(ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER); +} + +void CServerDecorationKDEProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperlaaaand) { + std::erase_if(m_vDecos, [&](const auto& other) { return other.get() == hayperlaaaand; }); +} + +void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) { + const auto CLIENT = pMgr->client(); + const auto RESOURCE = + m_vDecos.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))) + .get(); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vDecos.pop_back(); + return; + } +} diff --git a/src/protocols/ServerDecorationKDE.hpp b/src/protocols/ServerDecorationKDE.hpp new file mode 100644 index 00000000..ec7a852f --- /dev/null +++ b/src/protocols/ServerDecorationKDE.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "kde-server-decoration.hpp" + +class CServerDecorationKDE { + public: + CServerDecorationKDE(SP resource_, wlr_surface* surf); + + bool good(); + + private: + SP resource; +}; + +class CServerDecorationKDEProtocol : public IWaylandProtocol { + public: + CServerDecorationKDEProtocol(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); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CServerDecorationKDE* deco); + + void createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf); + + // + std::vector> m_vManagers; + std::vector> m_vDecos; + + friend class CServerDecorationKDE; +}; + +namespace PROTO { + inline UP serverDecorationKDE; +}; From aaf35b9f1f0ce49080f2a0b1e7943336b1ba6057 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sat, 4 May 2024 19:14:35 -0700 Subject: [PATCH 0004/2393] protocols: add hyprland_focus_grab_v1 implementation (#5850) * protocols: add hyprland_focus_grab_v1 implementation * protocols/focus_grab: fix keyboard focus staying on unlisted windows When creating a focus grab with layershell surfaces, the last active toplevel kept keyboard focus. * protocols/focus_grab: fix formatting * protocols/focus_grab: try to pick surface for keyboard focus * focus_grab: update keyboard focus to match spec * Revert "protocols/focus_grab: try to pick surface for keyboard focus" This reverts commit 090358d0d19cc65208641eaefa0a905e99145730. * protocols/focus_grab: fix issues and match new spec * kde-server-decoration: move to new impl * protocols/focus_grab: review fixup * Update hyprland-protocols --------- Co-authored-by: Vaxry --- CMakeLists.txt | 1 + flake.lock | 6 +- protocols/meson.build | 1 + src/managers/ProtocolManager.cpp | 2 + src/protocols/FocusGrab.cpp | 325 +++++++++++++++++++++++++++++++ src/protocols/FocusGrab.hpp | 77 ++++++++ subprojects/hyprland-protocols | 2 +- 7 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 src/protocols/FocusGrab.cpp create mode 100644 src/protocols/FocusGrab.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a4e400d1..cdf72fe0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,6 +266,7 @@ protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) +protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-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/flake.lock b/flake.lock index 2e8ccf87..4dc48dc9 100644 --- a/flake.lock +++ b/flake.lock @@ -36,11 +36,11 @@ ] }, "locked": { - "lastModified": 1691753796, - "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", + "lastModified": 1714869498, + "narHash": "sha256-vbLVOWvQqo4n1yvkg/Q70VTlPbMmTiCQfNTgcWDCfJM=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", + "rev": "e06482e0e611130cd1929f75e8c1cf679e57d161", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index 1c9013f0..f6c54d4d 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -43,6 +43,7 @@ new_protocols = [ ['wlr-virtual-pointer-unstable-v1.xml'], ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], + [hl_protocol_dir, 'protocols/hyprland-focus-grab-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/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 47372d01..ee27d35d 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -24,6 +24,7 @@ #include "../protocols/VirtualPointer.hpp" #include "../protocols/OutputManagement.hpp" #include "../protocols/ServerDecorationKDE.hpp" +#include "../protocols/FocusGrab.hpp" CProtocolManager::CProtocolManager() { @@ -51,6 +52,7 @@ CProtocolManager::CProtocolManager() { PROTO::virtualPointer = std::make_unique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); PROTO::outputManagement = std::make_unique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); + PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp new file mode 100644 index 00000000..61c17573 --- /dev/null +++ b/src/protocols/FocusGrab.cpp @@ -0,0 +1,325 @@ +#include "FocusGrab.hpp" +#include "Compositor.hpp" +#include +#include +#include +#include +#include + +static void focus_grab_pointer_enter(wlr_seat_pointer_grab* grab, wlr_surface* surface, double sx, double sy) { + if (static_cast(grab->data)->isSurfaceComitted(surface)) + wlr_seat_pointer_enter(grab->seat, surface, sx, sy); + else + wlr_seat_pointer_clear_focus(grab->seat); +} + +static void focus_grab_pointer_clear_focus(wlr_seat_pointer_grab* grab) { + wlr_seat_pointer_clear_focus(grab->seat); +} + +static void focus_grab_pointer_motion(wlr_seat_pointer_grab* grab, uint32_t time, double sx, double sy) { + wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +} + +static uint32_t focus_grab_pointer_button(wlr_seat_pointer_grab* grab, uint32_t time, uint32_t button, wl_pointer_button_state state) { + uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state); + + if (serial) + return serial; + else { + static_cast(grab->data)->finish(true); + return 0; + } +} + +static void focus_grab_pointer_axis(wlr_seat_pointer_grab* grab, uint32_t time, enum wl_pointer_axis orientation, double value, int32_t value_discrete, + enum wl_pointer_axis_source source, enum wl_pointer_axis_relative_direction relative_direction) { + wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, value_discrete, source, relative_direction); +} + +static void focus_grab_pointer_frame(wlr_seat_pointer_grab* grab) { + wlr_seat_pointer_send_frame(grab->seat); +} + +static void focus_grab_pointer_cancel(wlr_seat_pointer_grab* grab) { + static_cast(grab->data)->finish(true); +} + +static const wlr_pointer_grab_interface focus_grab_pointer_impl = { + .enter = focus_grab_pointer_enter, + .clear_focus = focus_grab_pointer_clear_focus, + .motion = focus_grab_pointer_motion, + .button = focus_grab_pointer_button, + .axis = focus_grab_pointer_axis, + .frame = focus_grab_pointer_frame, + .cancel = focus_grab_pointer_cancel, +}; + +static void focus_grab_keyboard_enter(wlr_seat_keyboard_grab* grab, wlr_surface* surface, const uint32_t keycodes[], size_t num_keycodes, const wlr_keyboard_modifiers* modifiers) { + if (static_cast(grab->data)->isSurfaceComitted(surface)) + wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers); + + // otherwise the last grabbed window should retain keyboard focus. +} + +static void focus_grab_keyboard_clear_focus(wlr_seat_keyboard_grab* grab) { + static_cast(grab->data)->finish(true); +} + +static void focus_grab_keyboard_key(wlr_seat_keyboard_grab* grab, uint32_t time, uint32_t key, uint32_t state) { + wlr_seat_keyboard_send_key(grab->seat, time, key, state); +} + +static void focus_grab_keyboard_modifiers(wlr_seat_keyboard_grab* grab, const wlr_keyboard_modifiers* modifiers) { + wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); +} + +static void focus_grab_keyboard_cancel(wlr_seat_keyboard_grab* grab) { + static_cast(grab->data)->finish(true); +} + +static const wlr_keyboard_grab_interface focus_grab_keyboard_impl = { + .enter = focus_grab_keyboard_enter, + .clear_focus = focus_grab_keyboard_clear_focus, + .key = focus_grab_keyboard_key, + .modifiers = focus_grab_keyboard_modifiers, + .cancel = focus_grab_keyboard_cancel, +}; + +static uint32_t focus_grab_touch_down(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { + if (!static_cast(grab->data)->isSurfaceComitted(point->surface)) + return 0; + + return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); +} + +static void focus_grab_touch_up(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { + wlr_seat_touch_send_up(grab->seat, time, point->touch_id); +} + +static void focus_grab_touch_motion(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { + wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, point->sy); +} + +static void focus_grab_touch_enter(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {} + +static void focus_grab_touch_frame(wlr_seat_touch_grab* grab) { + wlr_seat_touch_send_frame(grab->seat); +} + +static void focus_grab_touch_cancel(wlr_seat_touch_grab* grab) { + static_cast(grab->data)->finish(true); +} + +static const wlr_touch_grab_interface focus_grab_touch_impl = { + .down = focus_grab_touch_down, + .up = focus_grab_touch_up, + .motion = focus_grab_touch_motion, + .enter = focus_grab_touch_enter, + .frame = focus_grab_touch_frame, + .cancel = focus_grab_touch_cancel, +}; + +CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) { + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab"); +} + +CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { + hyprListener_surfaceDestroy.removeCallback(); +} + +CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) { + if (!resource->resource()) + return; + + m_sPointerGrab.interface = &focus_grab_pointer_impl; + m_sPointerGrab.data = this; + + m_sKeyboardGrab.interface = &focus_grab_keyboard_impl; + m_sKeyboardGrab.data = this; + + m_sTouchGrab.interface = &focus_grab_touch_impl; + m_sTouchGrab.data = this; + + resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); + resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); + resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); }); + resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); }); + resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); }); +} + +CFocusGrab::~CFocusGrab() { + finish(false); +} + +bool CFocusGrab::good() { + return resource->resource(); +} + +bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) { + auto iter = m_mSurfaces.find(surface); + if (iter == m_mSurfaces.end()) + return false; + + return iter->second->state == CFocusGrabSurfaceState::Comitted; +} + +void CFocusGrab::start() { + if (!m_bGrabActive) { + wlr_seat_pointer_start_grab(g_pCompositor->m_sSeat.seat, &m_sPointerGrab); + wlr_seat_keyboard_start_grab(g_pCompositor->m_sSeat.seat, &m_sKeyboardGrab); + wlr_seat_touch_start_grab(g_pCompositor->m_sSeat.seat, &m_sTouchGrab); + m_bGrabActive = true; + + // Ensure the grab ends if another grab begins, including from xdg_popup::grab. + + hyprListener_pointerGrabStarted.initCallback( + &g_pCompositor->m_sSeat.seat->events.pointer_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + + hyprListener_keyboardGrabStarted.initCallback( + &g_pCompositor->m_sSeat.seat->events.keyboard_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + + hyprListener_touchGrabStarted.initCallback( + &g_pCompositor->m_sSeat.seat->events.touch_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + } + + // Ensure new surfaces are focused if under the mouse when comitted. + g_pInputManager->simulateMouseMovement(); + refocusKeyboard(); +} + +void CFocusGrab::finish(bool sendCleared) { + if (m_bGrabActive) { + m_bGrabActive = false; + hyprListener_pointerGrabStarted.removeCallback(); + hyprListener_keyboardGrabStarted.removeCallback(); + hyprListener_touchGrabStarted.removeCallback(); + + // Only clear grabs that belong to this focus grab. When superseded by another grab + // or xdg_popup grab we might not own the current grab. + + bool hadGrab = false; + if (g_pCompositor->m_sSeat.seat->pointer_state.grab == &m_sPointerGrab) { + wlr_seat_pointer_end_grab(g_pCompositor->m_sSeat.seat); + hadGrab = true; + } + + if (g_pCompositor->m_sSeat.seat->keyboard_state.grab == &m_sKeyboardGrab) { + wlr_seat_keyboard_end_grab(g_pCompositor->m_sSeat.seat); + hadGrab = true; + } + + if (g_pCompositor->m_sSeat.seat->touch_state.grab == &m_sTouchGrab) { + wlr_seat_touch_end_grab(g_pCompositor->m_sSeat.seat); + hadGrab = true; + } + + m_mSurfaces.clear(); + + if (sendCleared) + resource->sendCleared(); + + // Ensure surfaces under the mouse when the grab ends get focus. + if (hadGrab) + g_pInputManager->refocus(); + } +} + +void CFocusGrab::addSurface(wlr_surface* surface) { + auto iter = m_mSurfaces.find(surface); + if (iter == m_mSurfaces.end()) + m_mSurfaces.emplace(surface, std::make_unique(this, surface)); +} + +void CFocusGrab::removeSurface(wlr_surface* surface) { + auto iter = m_mSurfaces.find(surface); + if (iter != m_mSurfaces.end()) { + if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) + m_mSurfaces.erase(iter); + else + iter->second->state = CFocusGrabSurfaceState::PendingRemoval; + } +} + +void CFocusGrab::eraseSurface(wlr_surface* surface) { + removeSurface(surface); + commit(); +} + +void CFocusGrab::refocusKeyboard() { + auto keyboardSurface = g_pCompositor->m_sSeat.seat->keyboard_state.focused_surface; + if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface)) + return; + + wlr_surface* surface = nullptr; + for (auto& [surf, state] : m_mSurfaces) { + if (state->state == CFocusGrabSurfaceState::Comitted) { + surface = surf; + break; + } + } + + if (surface) + g_pCompositor->focusSurface(surface); + else + Debug::log(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen."); +} + +void CFocusGrab::commit() { + auto surfacesChanged = false; + auto anyComitted = false; + for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) { + switch (iter->second->state) { + case CFocusGrabSurfaceState::PendingRemoval: + iter = m_mSurfaces.erase(iter); + surfacesChanged = true; + continue; + case CFocusGrabSurfaceState::PendingAddition: + iter->second->state = CFocusGrabSurfaceState::Comitted; + surfacesChanged = true; + anyComitted = true; + break; + case CFocusGrabSurfaceState::Comitted: anyComitted = true; break; + } + + iter++; + } + + if (surfacesChanged) { + if (anyComitted) + start(); + else + finish(true); + } +} + +CFocusGrabProtocol::CFocusGrabProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CFocusGrabProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); }); + RESOURCE->setCreateGrab([this](CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) { onCreateGrab(pMgr, id); }); +} + +void CFocusGrabProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CFocusGrabProtocol::destroyGrab(CFocusGrab* grab) { + std::erase_if(m_vGrabs, [&](const auto& other) { return other.get() == grab; }); +} + +void CFocusGrabProtocol::onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) { + m_vGrabs.push_back(std::make_unique(std::make_shared(pMgr->client(), pMgr->version(), id))); + const auto RESOURCE = m_vGrabs.back().get(); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vGrabs.pop_back(); + } +} diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp new file mode 100644 index 00000000..11c26774 --- /dev/null +++ b/src/protocols/FocusGrab.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include "WaylandProtocol.hpp" +#include "hyprland-focus-grab-v1.hpp" +#include "macros.hpp" +#include +#include +#include + +class CFocusGrab; + +class CFocusGrabSurfaceState { + public: + CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface); + ~CFocusGrabSurfaceState(); + + enum State { + PendingAddition, + PendingRemoval, + Comitted, + } state = PendingAddition; + + private: + DYNLISTENER(surfaceDestroy); +}; + +class CFocusGrab { + public: + CFocusGrab(SP resource_); + ~CFocusGrab(); + + bool good(); + bool isSurfaceComitted(wlr_surface* surface); + + void start(); + void finish(bool sendCleared); + + private: + void addSurface(wlr_surface* surface); + void removeSurface(wlr_surface* surface); + void eraseSurface(wlr_surface* surface); + void refocusKeyboard(); + void commit(); + + SP resource; + std::unordered_map> m_mSurfaces; + wlr_seat_pointer_grab m_sPointerGrab; + wlr_seat_keyboard_grab m_sKeyboardGrab; + wlr_seat_touch_grab m_sTouchGrab; + bool m_bGrabActive = false; + + DYNLISTENER(pointerGrabStarted); + DYNLISTENER(keyboardGrabStarted); + DYNLISTENER(touchGrabStarted); + friend class CFocusGrabSurfaceState; +}; + +class CFocusGrabProtocol : public IWaylandProtocol { + public: + CFocusGrabProtocol(const wl_interface* iface, const int& var, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyGrab(CFocusGrab* grab); + void onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id); + + std::vector> m_vManagers; + std::vector> m_vGrabs; + + friend class CFocusGrab; +}; + +namespace PROTO { + inline UP focusGrab; +} diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 0c2ce706..e06482e0 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 0c2ce70625cb30aef199cb388f99e19a61a6ce03 +Subproject commit e06482e0e611130cd1929f75e8c1cf679e57d161 From 03ebad3cbff0999af885c03e83a506a9d9cb5919 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Sun, 5 May 2024 22:04:40 +0900 Subject: [PATCH 0005/2393] idle-inhibit: enable idle inhibitor if no hl surface is associated (#5882) --- src/managers/input/IdleInhibitor.cpp | 10 ++++++---- src/managers/input/InputManager.hpp | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index dc7c61c3..468ea58b 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -17,8 +17,8 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { auto WLSurface = CWLSurface::surfaceFromWlr(PINHIBIT->inhibitor->surface); if (!WLSurface) { - Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Ignoring."); - PINHIBIT->inert = true; + Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Assuming it's visible."); + PINHIBIT->nonDesktop = true; recheckIdleInhibitorStatus(); return; } @@ -32,8 +32,10 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { void CInputManager::recheckIdleInhibitorStatus() { for (auto& ii : m_vIdleInhibitors) { - if (ii->inert) - continue; + if (ii->nonDesktop) { + PROTO::idle->setInhibit(true); + return; + } auto WLSurface = CWLSurface::surfaceFromWlr(ii->inhibitor->surface); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 719e19c6..329748b2 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -242,7 +242,7 @@ class CInputManager { // idle inhibitors struct SIdleInhibitor { std::shared_ptr inhibitor; - bool inert = false; + bool nonDesktop = false; CHyprSignalListener surfaceDestroyListener; }; std::vector> m_vIdleInhibitors; From 99aa34db6e3529717961cf31ad08ab000d66cd77 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Apr 2024 19:56:46 +0300 Subject: [PATCH 0006/2393] CMake: install files (instead of Makefile) --- CMakeLists.txt | 71 +++++++++++++++++++++++++++++++++++++++--- Makefile | 63 ++++++------------------------------- hyprctl/CMakeLists.txt | 15 ++++++++- hyprland.pc.in | 6 ++-- hyprpm/CMakeLists.txt | 13 ++++++++ 5 files changed, 105 insertions(+), 63 deletions(-) mode change 100755 => 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index cdf72fe0..72dae457 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.27) + include(CheckIncludeFile) +include(ExternalProject) +include(GNUInstallDirs) # Get version file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS) @@ -12,6 +15,7 @@ project(Hyprland set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) +set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) configure_file(hyprland.pc.in hyprland.pc @ONLY) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") @@ -23,8 +27,6 @@ message(STATUS "Gathering git info") execute_process( COMMAND ./scripts/generateVersion.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -# -# # udis add_subdirectory("subprojects/udis86") @@ -32,8 +34,6 @@ add_subdirectory("subprojects/udis86") # wlroots message(STATUS "Setting up wlroots") -include(ExternalProject) - if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) if(BUILDTYPE_LOWER STREQUAL "release") @@ -112,7 +112,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprwayland-scanner>=0.3.4 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) -file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") +file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") if(USE_TRACY) @@ -287,3 +287,64 @@ protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock # tools add_subdirectory(hyprctl) add_subdirectory(hyprpm) + +# binary and symlink +install(TARGETS Hyprland) + +install(CODE "execute_process( \ + COMMAND ${CMAKE_COMMAND} -E create_symlink \ + ${CMAKE_INSTALL_BINDIR}/Hyprland \ + ${CMAKE_INSTALL_BINDIR}/hyprland + )" +) + +# session file +install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop + DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions) + +# wallpapers +file(GLOB_RECURSE WALLPAPERS "assets/wall*") +install(FILES ${WALLPAPERS} + DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) + +# default config +install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf + DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) + +# portal config +install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf + DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal) + +# man pages +file(GLOB_RECURSE MANPAGES "docs/*.1") +install(FILES ${MANPAGES} + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + + +# pkgconfig entry +install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) + +# wlroots headers +set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr") +install(DIRECTORY ${HEADERS_WLR} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING PATTERN "*.h") + +# config.h and version.h +set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr") +install(DIRECTORY ${HEADERS_WLR_ROOT}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr + FILES_MATCHING PATTERN "*.h") + +# protocol headers +set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") +install(DIRECTORY ${HEADERS_PROTO} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING PATTERN "*.h*") + +# hyprland headers +set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") +install(DIRECTORY ${HEADERS_SRC} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING PATTERN "*.h*") diff --git a/Makefile b/Makefile index 07731993..53ac0fdf 100644 --- a/Makefile +++ b/Makefile @@ -2,27 +2,27 @@ PREFIX = /usr/local legacyrenderer: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Release --target all chmod -R 777 ./build legacyrendererdebug: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Release --target all chmod -R 777 ./build release: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Release --target all chmod -R 777 ./build debug: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Debug --target all chmod -R 777 ./build nopch: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Release --target all clear: rm -rf build @@ -30,58 +30,14 @@ clear: rm -rf ./subprojects/wlroots-hyprland/build all: - @if [[ "$EUID" = 0 ]]; then echo -en "Avoid running $(MAKE) all as sudo.\n"; fi $(MAKE) clear $(MAKE) release install: - @if [ ! -f ./build/Hyprland ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi - @echo -en "!NOTE: Please note make install does not compile Hyprland and only installs the already built files." - - mkdir -p ${PREFIX}/share/wayland-sessions - mkdir -p ${PREFIX}/bin - mkdir -p ${PREFIX}/share/hyprland - mkdir -p ${PREFIX}/share/bash-completion/completions - mkdir -p ${PREFIX}/share/fish/vendor_completions.d - mkdir -p ${PREFIX}/share/zsh/site-functions - cp -f ./build/Hyprland ${PREFIX}/bin - cp -f ./build/hyprctl/hyprctl ${PREFIX}/bin - cp -f ./build/hyprpm/hyprpm ${PREFIX}/bin - cp -f ./hyprctl/hyprctl.bash ${PREFIX}/share/bash-completion/completions/hyprctl - cp -f ./hyprctl/hyprctl.fish ${PREFIX}/share/fish/vendor_completions.d/hyprctl.fish - cp -f ./hyprctl/hyprctl.zsh ${PREFIX}/share/zsh/site-functions/_hyprctl - cp -f ./hyprpm/hyprpm.bash ${PREFIX}/share/bash-completion/completions/hyprpm - cp -f ./hyprpm/hyprpm.fish ${PREFIX}/share/fish/vendor_completions.d/hyprpm.fish - cp -f ./hyprpm/hyprpm.zsh ${PREFIX}/share/zsh/site-functions/_hyprpm - chmod 755 ${PREFIX}/bin/Hyprland - chmod 755 ${PREFIX}/bin/hyprctl - chmod 755 ${PREFIX}/bin/hyprpm - cd ${PREFIX}/bin && ln -sf Hyprland hyprland - if [ ! -f ${PREFIX}/share/wayland-sessions/hyprland.desktop ]; then cp ./example/hyprland.desktop ${PREFIX}/share/wayland-sessions; fi - cp ./assets/wall* ${PREFIX}/share/hyprland - mkdir -p ${PREFIX}/share/xdg-desktop-portal - cp ./assets/hyprland-portals.conf ${PREFIX}/share/xdg-desktop-portal - - mkdir -p ${PREFIX}/share/man/man1 - install -m644 ./docs/*.1 ${PREFIX}/share/man/man1 - - $(MAKE) installheaders + cmake --install ./build uninstall: - rm -f ${PREFIX}/share/wayland-sessions/hyprland.desktop - rm -f ${PREFIX}/bin/Hyprland - rm -f ${PREFIX}/bin/hyprland - rm -f ${PREFIX}/bin/hyprctl - rm -f ${PREFIX}/bin/hyprpm - rm -rf ${PREFIX}/share/hyprland - rm -f ${PREFIX}/share/man/man1/Hyprland.1 - rm -f ${PREFIX}/share/man/man1/hyprctl.1 - rm -f ${PREFIX}/share/bash-completion/completions/hyprctl - rm -f ${PREFIX}/share/fish/vendor_completions.d/hyprctl.fish - rm -f ${PREFIX}/share/zsh/site-functions/_hyprctl - rm -f ${PREFIX}/share/bash-completion/completions/hyprpm - rm -f ${PREFIX}/share/fish/vendor_completions.d/hyprpm.fish - rm -f ${PREFIX}/share/zsh/site-functions/_hyprpm + xargs rm < ./build/install_manifest.txt pluginenv: @echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n" @@ -95,7 +51,7 @@ installheaders: mkdir -p ${PREFIX}/include/hyprland/protocols mkdir -p ${PREFIX}/include/hyprland/wlroots-hyprland mkdir -p ${PREFIX}/share/pkgconfig - + find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland cd subprojects/wlroots-hyprland/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../.. cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../../.. @@ -143,8 +99,7 @@ asan: patch -p1 < ./scripts/hyprlandStaticAsan.diff cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja - cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Debug --target all @echo "Hyprland done" ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf - diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt index 99964b50..6f70ace8 100644 --- a/hyprctl/CMakeLists.txt +++ b/hyprctl/CMakeLists.txt @@ -5,4 +5,17 @@ project( DESCRIPTION "Control utility for Hyprland" ) -add_executable(hyprctl "main.cpp") \ No newline at end of file +add_executable(hyprctl "main.cpp") + +# binary +install(TARGETS hyprctl) + +# shell completions +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprctl.bash + DESTINATION ${CMAKE_INSTALL_DATADIR}/bash-completion/completions + RENAME hyprctl) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprctl.fish + DESTINATION ${CMAKE_INSTALL_DATADIR}/fish/vendor_completions.d) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprctl.zsh + DESTINATION ${CMAKE_INSTALL_DATADIR}/zsh/site-functions + RENAME _hyprctl) diff --git a/hyprland.pc.in b/hyprland.pc.in index c93e8f42..45e9c604 100644 --- a/hyprland.pc.in +++ b/hyprland.pc.in @@ -1,8 +1,8 @@ -prefix="@PREFIX@" -includedir="${prefix}/include" +prefix=@PREFIX@ +includedir=@INCLUDEDIR@ Name: Hyprland URL: https://github.com/hyprwm/Hyprland Description: Hyprland header files Version: @HYPRLAND_VERSION@ -Cflags: -I"${includedir}/hyprland/protocols" -I"${includedir}/hyprland/wlroots-hyprland" -I"${includedir}" +Cflags: -I${includedir} -I${includedir}/hyprland/protocols -I${includedir}/hyprland diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index a6bd1eca..8b6a8320 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -14,3 +14,16 @@ pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus) add_executable(hyprpm ${SRCFILES}) target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus) + +# binary +install(TARGETS hyprpm) + +# shell completions +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprpm.bash + DESTINATION ${CMAKE_INSTALL_DATADIR}/bash-completion/completions + RENAME hyprpm) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprpm.fish + DESTINATION ${CMAKE_INSTALL_DATADIR}/fish/vendor_completions.d) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprpm.zsh + DESTINATION ${CMAKE_INSTALL_DATADIR}/zsh/site-functions + RENAME _hyprpm) From f15513309b24790099d42974274eb23f66f7c985 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Apr 2024 19:58:54 +0300 Subject: [PATCH 0007/2393] Nix: use CMake for builds instead of Meson Build using submodules instead of patching the build process and using Nix derivations of the subprojects. From this commit on, you'll have to change the Hyprland flake url to `git+https://github.com/hyprwm/Hyprland?submodules=1` --- flake.lock | 25 ++------------ flake.nix | 25 ++------------ nix/default.nix | 62 +++++++++++++++++------------------ nix/overlays.nix | 30 ++++++++--------- nix/patches/meson-build.patch | 61 ---------------------------------- nix/udis86.nix | 32 ------------------ nix/wlroots.nix | 16 --------- 7 files changed, 49 insertions(+), 202 deletions(-) delete mode 100644 nix/patches/meson-build.patch delete mode 100644 nix/udis86.nix delete mode 100644 nix/wlroots.nix diff --git a/flake.lock b/flake.lock index 4dc48dc9..976553d3 100644 --- a/flake.lock +++ b/flake.lock @@ -29,9 +29,11 @@ "hyprland-protocols": { "inputs": { "nixpkgs": [ + "xdph", "nixpkgs" ], "systems": [ + "xdph", "systems" ] }, @@ -114,12 +116,10 @@ "root": { "inputs": { "hyprcursor": "hyprcursor", - "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems", - "wlroots": "wlroots", "xdph": "xdph" } }, @@ -138,28 +138,9 @@ "type": "github" } }, - "wlroots": { - "flake": false, - "locked": { - "lastModified": 1713731601, - "narHash": "sha256-bdcKdtLkusvv85DNuJsajZLFeq7bXp+x5AGP1Sd4wD8=", - "owner": "hyprwm", - "repo": "wlroots-hyprland", - "rev": "5c1d51c5a2793480f5b6c4341ad0797052aec2ea", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "wlroots-hyprland", - "rev": "5c1d51c5a2793480f5b6c4341ad0797052aec2ea", - "type": "github" - } - }, "xdph": { "inputs": { - "hyprland-protocols": [ - "hyprland-protocols" - ], + "hyprland-protocols": "hyprland-protocols", "hyprlang": [ "hyprlang" ], diff --git a/flake.nix b/flake.nix index 69d1dfed..eff2b3cd 100644 --- a/flake.nix +++ b/flake.nix @@ -7,14 +7,6 @@ # systems.url = "github:nix-systems/default-linux"; - wlroots = { - type = "github"; - owner = "hyprwm"; - repo = "wlroots-hyprland"; - rev = "5c1d51c5a2793480f5b6c4341ad0797052aec2ea"; - flake = false; - }; - hyprcursor = { url = "github:hyprwm/hyprcursor"; inputs.nixpkgs.follows = "nixpkgs"; @@ -22,12 +14,6 @@ inputs.hyprlang.follows = "hyprlang"; }; - hyprland-protocols = { - url = "github:hyprwm/hyprland-protocols"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.systems.follows = "systems"; - }; - hyprlang = { url = "github:hyprwm/hyprlang"; inputs.nixpkgs.follows = "nixpkgs"; @@ -44,7 +30,6 @@ url = "github:hyprwm/xdg-desktop-portal-hyprland"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; - inputs.hyprland-protocols.follows = "hyprland-protocols"; inputs.hyprlang.follows = "hyprlang"; }; }; @@ -92,8 +77,6 @@ # dependencies hyprland-protocols - wlroots-hyprland - udis86 ; }); @@ -103,13 +86,9 @@ stdenv = pkgsFor.${system}.gcc13Stdenv; } { name = "hyprland-shell"; - nativeBuildInputs = with pkgsFor.${system}; [cmake python3 expat libxml2]; - buildInputs = [self.packages.${system}.wlroots-hyprland]; + nativeBuildInputs = with pkgsFor.${system}; [expat libxml2]; hardeningDisable = ["fortify"]; - inputsFrom = [ - self.packages.${system}.wlroots-hyprland - self.packages.${system}.hyprland - ]; + inputsFrom = [pkgsFor.${system}.hyprland]; }; }); diff --git a/nix/default.nix b/nix/default.nix index 216e69a5..e9d81fd7 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -4,10 +4,12 @@ pkg-config, pkgconf, makeWrapper, + cmake, meson, ninja, binutils, cairo, + expat, git, hyprcursor, hyprland-protocols, @@ -19,19 +21,19 @@ libexecinfo, libinput, libuuid, - libxcb, libxkbcommon, mesa, pango, pciutils, + python3, systemd, tomlplusplus, udis86, wayland, wayland-protocols, wayland-scanner, - wlroots-hyprland, - xcbutilwm, + wlroots, + xorg, xwayland, debug ? false, enableXWayland ? true, @@ -48,9 +50,7 @@ }: assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; -assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; let - wlr = wlroots-hyprland.override {inherit enableXWayland;}; -in +assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; stdenv.mkDerivation { pname = "hyprland${lib.optionalString debug "-debug"}"; inherit version; @@ -63,11 +63,6 @@ in src = lib.cleanSource ../.; }; - patches = [ - # make meson use the provided wlroots instead of the git submodule - ./patches/meson-build.patch - ]; - postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp @@ -91,9 +86,11 @@ in hyprwayland-scanner jq makeWrapper + cmake meson ninja pkg-config + python3 wayland-scanner ]; @@ -103,10 +100,12 @@ in "dev" ]; - buildInputs = - wlr.buildInputs - ++ [ + buildInputs = lib.concatLists [ + wlroots.buildInputs + udis86.buildInputs + [ cairo + expat git hyprcursor.dev hyprland-protocols @@ -120,31 +119,32 @@ in pango pciutils tomlplusplus - udis86 wayland wayland-protocols - wlr ] - ++ lib.optionals stdenv.hostPlatform.isMusl [libexecinfo] - ++ lib.optionals enableXWayland [libxcb xcbutilwm xwayland] - ++ lib.optionals withSystemd [systemd]; + (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) + (lib.optionals enableXWayland [ + xorg.libxcb + xorg.libXdmcp + xorg.xcbutil + xorg.xcbutilwm + xwayland + ]) + (lib.optionals withSystemd [systemd]) + ]; - mesonBuildType = + cmakeBuildType = if debug - then "debug" - else "release"; + then "Debug" + else "RelWithDebInfo"; - mesonAutoFeatures = "disabled"; - - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) - (lib.mesonEnable "legacy_renderer" legacyRenderer) - (lib.mesonEnable "systemd" withSystemd) + cmakeFlags = [ + (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) + (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) + (lib.cmakeBool "NO_SYSTEMD" (!withSystemd)) ]; postInstall = '' - ln -s ${wlr}/include/wlr $dev/include/hyprland/wlroots - ${lib.optionalString wrapRuntimeDeps '' wrapProgram $out/bin/Hyprland \ --suffix PATH : ${lib.makeBinPath [ @@ -161,7 +161,7 @@ in homepage = "https://github.com/hyprwm/Hyprland"; description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; license = licenses.bsd3; - platforms = wlr.meta.platforms; + platforms = wlroots.meta.platforms; mainProgram = "Hyprland"; }; } diff --git a/nix/overlays.nix b/nix/overlays.nix index 3a7dca52..50d9f9d9 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -22,12 +22,11 @@ in { hyprland-packages = lib.composeManyExtensions [ # Dependencies inputs.hyprcursor.overlays.default - inputs.hyprland-protocols.overlays.default inputs.hyprlang.overlays.default inputs.hyprwayland-scanner.overlays.default - self.overlays.wlroots-hyprland - self.overlays.udis86 self.overlays.wayland-protocols + self.overlays.xwayland + # Hyprland packages themselves (final: prev: let date = mkDate (self.lastModifiedDate or "19700101"); @@ -36,19 +35,20 @@ in { stdenv = final.gcc13Stdenv; version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; - udis86 = final.udis86-hyprland; # explicit override until decided on breaking change of the name - inherit (final) wlroots-hyprland; # explicit override until decided on breaking change of the name inherit date; }; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; hyprland-debug = final.hyprland.override {debug = true;}; hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;}; + + # deprecated packages hyprland-nvidia = builtins.trace '' hyprland-nvidia was removed. Please use the hyprland package. Nvidia patches are no longer needed. '' final.hyprland; + hyprland-hidpi = builtins.trace '' hyprland-hidpi was removed. Please use the hyprland package. @@ -64,18 +64,14 @@ in { inputs.xdph.overlays.xdg-desktop-portal-hyprland ]; - udis86 = final: prev: { - udis86-hyprland = final.callPackage ./udis86.nix {}; - }; - - # Patched version of wlroots for Hyprland. - # It is under a new package name so as to not conflict with - # the standard version in nixpkgs. - wlroots-hyprland = final: prev: { - wlroots-hyprland = final.callPackage ./wlroots.nix { - version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}"; - src = inputs.wlroots; - }; + # Patches XWayland's pkgconfig file to not include Cflags or includedir + # The above two variables trip up CMake and the build fails + xwayland = final: prev: { + xwayland = prev.xwayland.overrideAttrs (old: { + postInstall = '' + sed -i '/includedir/d' $out/lib/pkgconfig/xwayland.pc + ''; + }); }; wayland-protocols = final: prev: { diff --git a/nix/patches/meson-build.patch b/nix/patches/meson-build.patch deleted file mode 100644 index eb1d3f9a..00000000 --- a/nix/patches/meson-build.patch +++ /dev/null @@ -1,61 +0,0 @@ -diff --git a/meson.build b/meson.build -index 40883073..d8f2e536 100644 ---- a/meson.build -+++ b/meson.build -@@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h') - add_project_arguments('-DHAS_EXECINFO', language: 'cpp') - endif - --wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2']) --have_xwlr = wlroots.get_variable('features').get('xwayland') --xcb_dep = dependency('xcb', required: get_option('xwayland')) -- --cmake = import('cmake') --udis = cmake.subproject('udis86') --udis86 = udis.dependency('libudis86') -- --if get_option('xwayland').enabled() and not have_xwlr -- error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support') --endif --have_xwayland = xcb_dep.found() and have_xwlr -- --if not have_xwayland -+if get_option('xwayland').disabled() - add_project_arguments('-DNO_XWAYLAND', language: 'cpp') - endif - -@@ -65,8 +52,6 @@ if get_option('buildtype') == 'debug' - add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') - endif - --version_h = run_command('sh', '-c', 'scripts/generateVersion.sh') -- - globber = run_command('find', 'src', '-name', '*.h*', check: true) - headers = globber.stdout().strip().split('\n') - foreach file : headers -diff --git a/src/meson.build b/src/meson.build -index 15c69552..327aa4fb 100644 ---- a/src/meson.build -+++ b/src/meson.build -@@ -9,7 +9,7 @@ executable('Hyprland', src, - server_protos, - dependency('wayland-server'), - dependency('wayland-client'), -- wlroots.get_variable('wlroots'), -+ dependency('wlroots'), - dependency('cairo'), - dependency('hyprcursor'), - dependency('hyprlang', version: '>= 0.3.2'), -@@ -17,10 +17,10 @@ executable('Hyprland', src, - dependency('egl'), - dependency('xkbcommon'), - dependency('libinput'), -- xcb_dep, -+ dependency('xcb', required: get_option('xwayland')), - backtrace_dep, - epoll_dep, -- udis86, -+ dependency('udis86'), - - dependency('pixman-1'), - dependency('gl', 'opengl'), diff --git a/nix/udis86.nix b/nix/udis86.nix deleted file mode 100644 index d5e92afc..00000000 --- a/nix/udis86.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - lib, - stdenv, - fetchFromGitHub, - autoreconfHook, - python3, -}: -stdenv.mkDerivation { - pname = "udis86"; - version = "unstable-2022-10-13"; - - src = fetchFromGitHub { - owner = "canihavesomecoffee"; - repo = "udis86"; - rev = "5336633af70f3917760a6d441ff02d93477b0c86"; - hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g="; - }; - - nativeBuildInputs = [autoreconfHook python3]; - - configureFlags = ["--enable-shared"]; - - outputs = ["bin" "out" "dev" "lib"]; - - meta = with lib; { - homepage = "https://udis86.sourceforge.net"; - license = licenses.bsd2; - mainProgram = "udcli"; - description = "Easy-to-use, minimalistic x86 disassembler library (libudis86)"; - platforms = platforms.all; - }; -} diff --git a/nix/wlroots.nix b/nix/wlroots.nix deleted file mode 100644 index b0dccb00..00000000 --- a/nix/wlroots.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - version, - src, - git, - wlroots, - enableXWayland ? true, -}: -wlroots.overrideAttrs (old: { - inherit version src enableXWayland; - - pname = "${old.pname}-hyprland"; - - patches = [ ]; # don't inherit old.patches - - nativeBuildInputs = old.nativeBuildInputs ++ [ git ]; -}) From 589f758d947cb4e8b888d2da00076a9fb0a6d521 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Apr 2024 20:13:59 +0300 Subject: [PATCH 0008/2393] CI/Nix: build with submodules - Clone repo recursively - Update Nix install action - Remove wlroots update --- .github/workflows/nix-build.yml | 5 +++-- .github/workflows/nix-ci.yml | 7 +++---- .github/workflows/nix-update-inputs.yml | 11 ++++------ .github/workflows/nix-update-wlroots.yml | 26 ------------------------ 4 files changed, 10 insertions(+), 39 deletions(-) delete mode 100644 .github/workflows/nix-update-wlroots.yml diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 45db0b5e..33ee5cac 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -18,12 +18,13 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.ref }} + submodules: recursive - - uses: cachix/install-nix-action@v25 + - uses: cachix/install-nix-action@v26 - uses: DeterminateSystems/magic-nix-cache-action@main - uses: cachix/cachix-action@v12 with: name: hyprland authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - run: nix build .#${{ matrix.package }} --extra-substituters "https://hyprland.cachix.org" -L + - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index f0de7f5c..3b017576 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -3,13 +3,12 @@ name: Nix on: [push, pull_request, workflow_dispatch] jobs: - wlroots: - if: github.event_name != 'pull_request' - uses: ./.github/workflows/nix-update-wlroots.yml + update-inputs: + uses: ./.github/workflows/nix-update-inputs.yml secrets: inherit build: if: always() && !cancelled() && !contains(needs.*.result, 'failure') - needs: wlroots + needs: update-inputs uses: ./.github/workflows/nix-build.yml secrets: inherit diff --git a/.github/workflows/nix-update-inputs.yml b/.github/workflows/nix-update-inputs.yml index f5df3f4f..000900d9 100644 --- a/.github/workflows/nix-update-inputs.yml +++ b/.github/workflows/nix-update-inputs.yml @@ -1,8 +1,10 @@ name: Nix on: - schedule: - - cron: '0 0 * * *' # check daily + workflow_call: + secrets: + PAT: + required: true jobs: update: @@ -22,8 +24,3 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "[gha] Nix: update inputs" - - update-build: - needs: update - uses: ./.github/workflows/nix-build.yml - secrets: inherit diff --git a/.github/workflows/nix-update-wlroots.yml b/.github/workflows/nix-update-wlroots.yml deleted file mode 100644 index a0db9ef5..00000000 --- a/.github/workflows/nix-update-wlroots.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Nix - -on: - workflow_call: - secrets: - PAT: - required: true - -jobs: - update: - name: wlroots - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - with: - token: ${{ secrets.PAT }} - - - uses: DeterminateSystems/nix-installer-action@main - - name: Update lockfile - run: nix/update-wlroots.sh - - - name: Commit - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: "[gha] Nix: update wlroots" From 1ed1ce9506e65f76fe5236194516f23d662bba0b Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 5 May 2024 17:16:00 +0100 Subject: [PATCH 0009/2393] internal: new shared_ptr and weak_ptr implementation (#5883) moves std::shared_ptrs to a new implementation Advantages: - you can dereference a weak_ptr directly. This will obviously segfault on a nullptr deref if it's expired. - this is useful to avoid the .lock() hell where we are 100% sure the pointer _should_ be valid. (and if it isn't, it should throw.) - weak_ptrs are still valid while the SP is being destroyed. - reasoning: while an object (e.g. CWindow) is being destroyed, its `weak_ptr self` should be accessible (the sp is still alive, and so is CWindow), but it's not because by stl it's already expired (to prevent resurrection) - this impl solves it differently. w_p is expired, but can still be dereferenced and used. Creating `s_p`s is not possible anymore, though. - this is useful in destructors and callbacks. --- CMakeLists.txt | 2 + src/Compositor.cpp | 10 +- src/debug/HyprCtl.cpp | 6 +- src/debug/HyprCtl.hpp | 14 +- src/defines.hpp | 14 +- src/desktop/DesktopTypes.hpp | 20 +- src/desktop/LayerSurface.cpp | 12 +- src/desktop/Popup.cpp | 26 +- src/desktop/Subsurface.cpp | 12 +- src/desktop/WLSurface.cpp | 8 +- src/desktop/WLSurface.hpp | 14 +- src/desktop/Window.cpp | 4 +- src/desktop/Window.hpp | 4 +- src/desktop/Workspace.cpp | 4 +- src/desktop/Workspace.hpp | 8 +- src/devices/VirtualKeyboard.cpp | 4 +- src/devices/VirtualPointer.cpp | 2 +- src/events/Monitors.cpp | 8 +- src/events/Windows.cpp | 4 +- src/helpers/AnimatedVariable.hpp | 2 +- src/helpers/Monitor.cpp | 12 +- src/helpers/memory/SharedPtr.hpp | 300 ++++++++++++++++++ src/helpers/memory/WeakPtr.hpp | 188 +++++++++++ src/helpers/signal/Listener.hpp | 3 +- src/helpers/signal/Signal.cpp | 4 +- src/helpers/signal/Signal.hpp | 2 +- src/layout/DwindleLayout.cpp | 24 +- src/layout/IHyprLayout.cpp | 18 +- src/layout/MasterLayout.cpp | 24 +- src/macros.hpp | 4 +- src/managers/AnimationManager.cpp | 4 +- src/managers/AnimationManager.hpp | 2 +- src/managers/HookSystemManager.cpp | 12 +- src/managers/HookSystemManager.hpp | 10 +- src/managers/KeybindManager.cpp | 28 +- src/managers/SessionLockManager.cpp | 8 +- src/managers/TokenManager.cpp | 6 +- src/managers/TokenManager.hpp | 13 +- src/managers/eventLoop/EventLoopManager.cpp | 4 +- src/managers/eventLoop/EventLoopManager.hpp | 9 +- src/managers/eventLoop/EventLoopTimer.cpp | 8 +- src/managers/eventLoop/EventLoopTimer.hpp | 14 +- src/managers/input/IdleInhibitor.cpp | 4 +- src/managers/input/InputManager.cpp | 21 +- src/managers/input/InputManager.hpp | 8 +- src/managers/input/InputMethodPopup.cpp | 4 +- src/managers/input/InputMethodRelay.cpp | 6 +- src/managers/input/TextInput.cpp | 14 +- src/managers/input/TextInput.hpp | 14 +- src/managers/input/Touch.cpp | 19 +- src/plugins/PluginAPI.cpp | 10 +- src/plugins/PluginAPI.hpp | 12 +- src/plugins/PluginSystem.hpp | 24 +- src/protocols/AlphaModifier.cpp | 5 +- src/protocols/CursorShape.cpp | 2 +- src/protocols/FocusGrab.cpp | 2 +- src/protocols/ForeignToplevel.cpp | 6 +- src/protocols/ForeignToplevelWlr.cpp | 8 +- src/protocols/FractionalScale.cpp | 4 +- src/protocols/GammaControl.cpp | 2 +- src/protocols/IdleInhibit.cpp | 4 +- src/protocols/IdleNotify.cpp | 9 +- src/protocols/IdleNotify.hpp | 10 +- src/protocols/InputMethodV2.cpp | 12 +- src/protocols/OutputManagement.cpp | 17 +- src/protocols/OutputPower.cpp | 2 +- src/protocols/PointerConstraints.cpp | 4 +- src/protocols/PointerGestures.cpp | 6 +- src/protocols/RelativePointer.cpp | 2 +- src/protocols/Screencopy.hpp | 22 +- src/protocols/ServerDecorationKDE.cpp | 3 +- src/protocols/SessionLock.cpp | 6 +- src/protocols/ShortcutsInhibit.cpp | 2 +- src/protocols/TearingControl.cpp | 4 +- src/protocols/TextInputV3.cpp | 4 +- src/protocols/ToplevelExport.cpp | 8 +- src/protocols/VirtualKeyboard.cpp | 2 +- src/protocols/VirtualPointer.cpp | 2 +- src/protocols/XDGActivation.cpp | 2 +- src/protocols/XDGDecoration.cpp | 3 +- src/protocols/XDGOutput.cpp | 2 +- src/render/OpenGL.cpp | 8 +- src/render/OpenGL.hpp | 8 +- src/render/Renderer.cpp | 6 +- .../decorations/CHyprBorderDecoration.cpp | 43 ++- .../decorations/CHyprGroupBarDecoration.cpp | 50 +-- .../decorations/DecorationPositioner.cpp | 15 +- .../decorations/DecorationPositioner.hpp | 17 +- 88 files changed, 899 insertions(+), 414 deletions(-) create mode 100644 src/helpers/memory/SharedPtr.hpp create mode 100644 src/helpers/memory/WeakPtr.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 72dae457..ef077d8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Enabling ASan") target_link_libraries(Hyprland asan) + pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) + target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) target_compile_options(Hyprland PUBLIC -fsanitize=address) endif() diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 1f5a355c..96831751 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1183,7 +1183,7 @@ void CCompositor::sanityCheckWorkspaces() { const auto& WORKSPACE = *it; // If ref == 1, only the compositor holds a ref, which means it's inactive and has no mapped windows. - if (!WORKSPACE->m_bPersistent && WORKSPACE.use_count() == 1) { + if (!WORKSPACE->m_bPersistent && WORKSPACE.strongRef() == 1) { it = m_vWorkspaces.erase(it); continue; } @@ -1823,7 +1823,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { setBorderColor(*RENDERDATA.borderGradient); else { const bool GROUPLOCKED = pWindow->m_sGroupData.pNextWindow.lock() ? pWindow->getGroupHead()->m_sGroupData.locked : false; - if (pWindow == m_pLastWindow.lock()) { + if (pWindow == m_pLastWindow) { const auto* const ACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL); setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR : @@ -1848,7 +1848,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() * *PFULLSCREENALPHA) : *PFULLSCREENALPHA; } else { - if (pWindow == m_pLastWindow.lock()) + if (pWindow == m_pLastWindow) pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() : pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA; else @@ -1867,7 +1867,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // shadow if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) { - if (pWindow == m_pLastWindow.lock()) { + if (pWindow == m_pLastWindow) { pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); } else { pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); @@ -2346,7 +2346,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { const bool FLOAT = regexp.starts_with("floating"); for (auto& w : m_vWindows) { - if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow.lock()->m_pWorkspace || w->isHidden()) + if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) continue; return w; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 7f034570..6382e899 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1588,11 +1588,11 @@ CHyprCtl::CHyprCtl() { startHyprCtlSocket(); } -std::shared_ptr CHyprCtl::registerCommand(SHyprCtlCommand cmd) { - return m_vCommands.emplace_back(std::make_shared(cmd)); +SP CHyprCtl::registerCommand(SHyprCtlCommand cmd) { + return m_vCommands.emplace_back(makeShared(cmd)); } -void CHyprCtl::unregisterCommand(const std::shared_ptr& cmd) { +void CHyprCtl::unregisterCommand(const SP& cmd) { std::erase(m_vCommands, cmd); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index cad57447..ebcb87cf 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -9,21 +9,21 @@ class CHyprCtl { public: CHyprCtl(); - std::string makeDynamicCall(const std::string& input); - std::shared_ptr registerCommand(SHyprCtlCommand cmd); - void unregisterCommand(const std::shared_ptr& cmd); - std::string getReply(std::string); + std::string makeDynamicCall(const std::string& input); + SP registerCommand(SHyprCtlCommand cmd); + void unregisterCommand(const SP& cmd); + std::string getReply(std::string); - int m_iSocketFD = -1; + int m_iSocketFD = -1; struct { bool all = false; } m_sCurrentRequestParams; private: - void startHyprCtlSocket(); + void startHyprCtlSocket(); - std::vector> m_vCommands; + std::vector> m_vCommands; }; inline std::unique_ptr g_pHyprCtl; \ No newline at end of file diff --git a/src/defines.hpp b/src/defines.hpp index a563bc36..0b2c0e0c 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -3,16 +3,4 @@ #include "helpers/WLListener.hpp" #include "helpers/Color.hpp" #include "macros.hpp" - -class CWindow; -class CLayerSurface; - -/* Shared pointer to a window */ -typedef SP PHLWINDOW; -/* Weak pointer to a window */ -typedef WP PHLWINDOWREF; - -/* Shared pointer to a layer surface */ -typedef SP PHLLS; -/* Weak pointer to a layer surface */ -typedef WP PHLLSREF; +#include "desktop/DesktopTypes.hpp" diff --git a/src/desktop/DesktopTypes.hpp b/src/desktop/DesktopTypes.hpp index 1548f694..4e40c4e0 100644 --- a/src/desktop/DesktopTypes.hpp +++ b/src/desktop/DesktopTypes.hpp @@ -1,6 +1,20 @@ #pragma once -#include - +#include "../macros.hpp" class CWorkspace; +class CWindow; +class CLayerSurface; -typedef std::shared_ptr PHLWORKSPACE; \ No newline at end of file +/* Shared pointer to a workspace */ +typedef SP PHLWORKSPACE; +/* Weak pointer to a workspace */ +typedef WP PHLWORKSPACEREF; + +/* Shared pointer to a window */ +typedef SP PHLWINDOW; +/* Weak pointer to a window */ +typedef WP PHLWINDOWREF; + +/* Shared pointer to a layer surface */ +typedef SP PHLLS; +/* Weak pointer to a layer surface */ +typedef WP PHLLSREF; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index d472b906..aeaf1aa8 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -58,7 +58,7 @@ static void onDestroy(void* owner, void* data) { // IMPL PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { - PHLLS pLS = std::shared_ptr(new CLayerSurface); + PHLLS pLS = SP(new CLayerSurface); auto PMONITOR = g_pCompositor->getMonitorFromOutput(pWLRLS->output); @@ -176,7 +176,7 @@ void CLayerSurface::onMap() { if ((uint64_t)monitorID != PMONITOR->ID) { const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self.lock()) { + if (*it == self) { PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); POLDMON->m_aLayerSurfaceLayers[layer].erase(it); break; @@ -235,7 +235,7 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0].lock()->layerSurface->surface); + g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface); if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -284,7 +284,7 @@ void CLayerSurface::onUnmap() { foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow.lock()->m_pWorkspace)) { + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { // if there isn't any, focus the last window const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); g_pCompositor->focusWindow(nullptr); @@ -325,7 +325,7 @@ void CLayerSurface::onCommit() { const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self.lock()) { + if (*it == self) { PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); POLDMON->m_aLayerSurfaceLayers[layer].erase(it); break; @@ -341,7 +341,7 @@ void CLayerSurface::onCommit() { if (layer != layerSurface->current.layer) { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self.lock()) { + if (*it == self) { PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(std::move(*it)); PMONITOR->m_aLayerSurfaceLayers[layer].erase(it); break; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index b4de8dda..73a29560 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -70,9 +70,9 @@ void CPopup::initAllSignals() { if (!m_pWLR) { if (!m_pWindowOwner.expired()) - hyprListener_newPopup.initCallback(&m_pWindowOwner.lock()->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); + hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); else if (!m_pLayerOwner.expired()) - hyprListener_newPopup.initCallback(&m_pLayerOwner.lock()->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); + hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); else ASSERT(false); @@ -119,8 +119,8 @@ void CPopup::onMap() { unconstrain(); sendScale(); - if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); } void CPopup::onUnmap() { @@ -136,8 +136,8 @@ void CPopup::onUnmap() { g_pInputManager->simulateMouseMovement(); - if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); } void CPopup::onCommit(bool ignoreSiblings) { @@ -146,7 +146,7 @@ void CPopup::onCommit(bool ignoreSiblings) { return; } - if (!m_pWindowOwner.expired() && (!m_pWindowOwner.lock()->m_bIsMapped || !m_pWindowOwner.lock()->m_pWorkspace->m_bVisible)) { + if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) { m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height}; static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -178,8 +178,8 @@ void CPopup::onCommit(bool ignoreSiblings) { m_bRequestedReposition = false; - if (!m_pLayerOwner.expired() && m_pLayerOwner.lock()->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) - g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner.lock()->layer)); + if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) + g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); } void CPopup::onReposition() { @@ -231,9 +231,9 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) { Vector2D CPopup::t1ParentCoords() { if (!m_pWindowOwner.expired()) - return m_pWindowOwner.lock()->m_vRealPosition.value(); + return m_pWindowOwner->m_vRealPosition.value(); if (!m_pLayerOwner.expired()) - return m_pLayerOwner.lock()->realPosition.value(); + return m_pLayerOwner->realPosition.value(); ASSERT(false); return {}; @@ -261,9 +261,9 @@ Vector2D CPopup::size() { void CPopup::sendScale() { if (!m_pWindowOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner.lock()->m_pWLSurface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale); else if (!m_pLayerOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner.lock()->surface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale); else UNREACHABLE(); } diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 1809efe5..21482ff7 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -74,7 +74,7 @@ void CSubsurface::initSignals() { hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface"); } else { if (!m_pWindowParent.expired()) - hyprListener_newSubsurface.initCallback(&m_pWindowParent.lock()->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); + hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); else if (m_pPopupParent) hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); else @@ -86,7 +86,7 @@ void CSubsurface::checkSiblingDamage() { if (!m_pParent) return; // ?????????? - const double SCALE = m_pWindowParent.lock() && m_pWindowParent.lock()->m_bIsX11 ? 1.0 / m_pWindowParent.lock()->m_fX11SurfaceScaledBy : 1.0; + const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; for (auto& n : m_pParent->m_vChildren) { if (n.get() == this) @@ -106,7 +106,7 @@ void CSubsurface::recheckDamageForSubsurfaces() { void CSubsurface::onCommit() { // no damaging if it's not visible - if (!m_pWindowParent.expired() && (!m_pWindowParent.lock()->m_bIsMapped || !m_pWindowParent.lock()->m_pWorkspace->m_bVisible)) { + if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) { m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -122,7 +122,7 @@ void CSubsurface::onCommit() { if (m_pPopupParent) m_pPopupParent->recheckTree(); if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this - m_pWindowParent.lock()->m_pPopupHead->recheckTree(); + m_pWindowParent->m_pPopupHead->recheckTree(); // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) checkSiblingDamage(); @@ -170,7 +170,7 @@ void CSubsurface::onMap() { g_pHyprRenderer->damageBox(&box); if (!m_pWindowParent.expired()) - m_pWindowParent.lock()->updateSurfaceScaleTransformDetails(); + m_pWindowParent->updateSurfaceScaleTransformDetails(); } void CSubsurface::onUnmap() { @@ -207,7 +207,7 @@ Vector2D CSubsurface::coordsGlobal() { Vector2D coords = coordsRelativeToParent(); if (!m_pWindowParent.expired()) - coords += m_pWindowParent.lock()->m_vRealPosition.value(); + coords += m_pWindowParent->m_vRealPosition.value(); else if (m_pPopupParent) coords += m_pPopupParent->coordsGlobal(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index fd6c28b3..9396bbdd 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -175,9 +175,9 @@ std::optional CWLSurface::getSurfaceBoxGlobal() { return {}; if (!m_pWindowOwner.expired()) - return m_pWindowOwner.lock()->getWindowMainSurfaceBox(); + return m_pWindowOwner->getWindowMainSurfaceBox(); if (!m_pLayerOwner.expired()) - return m_pLayerOwner.lock()->geometry; + return m_pLayerOwner->geometry; if (m_pPopupOwner) return CBox{m_pPopupOwner->coordsGlobal(), m_pPopupOwner->size()}; if (m_pSubsurfaceOwner) @@ -186,7 +186,7 @@ std::optional CWLSurface::getSurfaceBoxGlobal() { return {}; } -void CWLSurface::appendConstraint(std::weak_ptr constraint) { +void CWLSurface::appendConstraint(WP constraint) { m_pConstraint = constraint; } @@ -194,7 +194,7 @@ void CWLSurface::onCommit() { ; } -std::shared_ptr CWLSurface::constraint() { +SP CWLSurface::constraint() { return m_pConstraint.lock(); } diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 8fb69937..03e81b45 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -42,9 +42,9 @@ class CWLSurface { CSubsurface* getSubsurface(); // desktop components misc utils - std::optional getSurfaceBoxGlobal(); - void appendConstraint(std::weak_ptr constraint); - std::shared_ptr constraint(); + std::optional getSurfaceBoxGlobal(); + void appendConstraint(WP constraint); + SP constraint(); // allow stretching. Useful for plugins. bool m_bFillIgnoreSmall = false; @@ -99,11 +99,11 @@ class CWLSurface { CSubsurface* m_pSubsurfaceOwner = nullptr; // - std::weak_ptr m_pConstraint; + WP m_pConstraint; - void destroy(); - void init(); - bool desktopComponent(); + void destroy(); + void init(); + bool desktopComponent(); DYNLISTENER(destroy); DYNLISTENER(commit); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 78403afe..b92a3d9d 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -8,7 +8,7 @@ #include "../managers/TokenManager.hpp" PHLWINDOW CWindow::create() { - PHLWINDOW pWindow = std::shared_ptr(new CWindow); + PHLWINDOW pWindow = SP(new CWindow); pWindow->m_pSelf = pWindow; @@ -894,7 +894,7 @@ PHLWINDOW CWindow::getGroupHead() { PHLWINDOW CWindow::getGroupTail() { PHLWINDOW curr = m_pSelf.lock(); - while (!curr->m_sGroupData.pNextWindow.lock()->m_sGroupData.head) + while (!curr->m_sGroupData.pNextWindow->m_sGroupData.head) curr = curr->m_sGroupData.pNextWindow.lock(); return curr; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d6b962e7..dd361c30 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -467,7 +467,7 @@ inline bool valid(PHLWINDOW w) { } inline bool valid(PHLWINDOWREF w) { - return w.lock().get(); + return !w.expired(); } inline bool validMapped(PHLWINDOW w) { @@ -479,7 +479,7 @@ inline bool validMapped(PHLWINDOW w) { inline bool validMapped(PHLWINDOWREF w) { if (!valid(w)) return false; - return w.lock()->m_bIsMapped; + return w->m_bIsMapped; } /** diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index cc43d221..b730c9ab 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -3,7 +3,7 @@ #include "../config/ConfigValue.hpp" PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special) { - PHLWORKSPACE workspace = std::make_shared(id, monitorID, name, special); + PHLWORKSPACE workspace = makeShared(id, monitorID, name, special); workspace->init(workspace); return workspace; } @@ -183,7 +183,7 @@ void CWorkspace::moveToMonitor(const int& id) { } PHLWINDOW CWorkspace::getLastFocusedWindow() { - if (!validMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow.lock()->workspaceID() != m_iID) + if (!validMapped(m_pLastFocusedWindow) || m_pLastFocusedWindow->workspaceID() != m_iID) return nullptr; return m_pLastFocusedWindow.lock(); diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 8789fab4..3fae3dfc 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -78,11 +78,11 @@ class CWorkspace { void markInert(); private: - void init(PHLWORKSPACE self); + void init(PHLWORKSPACE self); - std::shared_ptr m_pFocusedWindowHook; - bool m_bInert = true; - std::weak_ptr m_pSelf; + SP m_pFocusedWindowHook; + bool m_bInert = true; + WP m_pSelf; }; inline bool valid(const PHLWORKSPACE& ref) { diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp index dfe3c6df..e2be0078 100644 --- a/src/devices/VirtualKeyboard.cpp +++ b/src/devices/VirtualKeyboard.cpp @@ -57,7 +57,7 @@ bool CVirtualKeyboard::isVirtual() { wlr_keyboard* CVirtualKeyboard::wlr() { if (keyboard.expired()) return nullptr; - return keyboard.lock()->wlr(); + return keyboard->wlr(); } void CVirtualKeyboard::disconnectCallbacks() { @@ -71,5 +71,5 @@ void CVirtualKeyboard::disconnectCallbacks() { wl_client* CVirtualKeyboard::getClient() { if (keyboard.expired()) return nullptr; - return keyboard.lock()->client(); + return keyboard->client(); } diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 2b46ff28..4ebf8865 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -168,5 +168,5 @@ void CVirtualPointer::disconnectCallbacks() { wlr_pointer* CVirtualPointer::wlr() { if (pointer.expired()) return nullptr; - return pointer.lock()->wlr(); + return pointer->wlr(); } diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 69cc912d..982dc941 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -16,7 +16,7 @@ // // // --------------------------------------------------------- // -static void checkDefaultCursorWarp(std::shared_ptr* PNEWMONITORWRAP, std::string monitorName) { +static void checkDefaultCursorWarp(SP* PNEWMONITORWRAP, std::string monitorName) { const auto PNEWMONITOR = PNEWMONITORWRAP->get(); static auto PCURSORMONITOR = CConfigValue("general:default_cursor_monitor"); @@ -61,9 +61,9 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { } // add it to real - std::shared_ptr* PNEWMONITORWRAP = nullptr; + SP* PNEWMONITORWRAP = nullptr; - PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(std::make_shared()); + PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); if (std::string("HEADLESS-1") == OUTPUT->name) g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get(); @@ -196,7 +196,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) { Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName); - std::erase_if(g_pCompositor->m_vRealMonitors, [&](std::shared_ptr& el) { return el.get() == pMonitor; }); + std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == pMonitor; }); } void Events::listener_monitorStateRequest(void* owner, void* data) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e3d06691..db4e0985 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -729,7 +729,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { // swallowing if (valid(PWINDOW->m_pSwallowed)) { - PWINDOW->m_pSwallowed.lock()->setHidden(false); + PWINDOW->m_pSwallowed->setHidden(false); g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); PWINDOW->m_pSwallowed.reset(); } @@ -1024,7 +1024,7 @@ void Events::listener_activateX11(void* owner, void* data) { Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW); - if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->getPID() != PWINDOW->getPID()) + if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID()) return; if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland)) diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index be54392a..5c63032e 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -146,7 +146,7 @@ class CBaseAnimatedVariable { protected: PHLWINDOWREF m_pWindow; - std::weak_ptr m_pWorkspace; + PHLWORKSPACEREF m_pWorkspace; PHLLSREF m_pLayer; SAnimationPropertyConfig* m_pConfig = nullptr; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 1369244d..3c489d4b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -123,7 +123,7 @@ void CMonitor::onConnect(bool noRule) { m_bRenderingInitPassed = true; } - std::shared_ptr* thisWrapper = nullptr; + SP* thisWrapper = nullptr; // find the wrap for (auto& m : g_pCompositor->m_vRealMonitors) { @@ -337,7 +337,7 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } - std::erase_if(g_pCompositor->m_vMonitors, [&](std::shared_ptr& el) { return el.get() == this; }); + std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); } void CMonitor::addDamage(const pixman_region32_t* rg) { @@ -464,7 +464,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // push to mvmonitors - std::shared_ptr* thisWrapper = nullptr; + SP* thisWrapper = nullptr; // find the wrap for (auto& m : g_pCompositor->m_vRealMonitors) { @@ -578,7 +578,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo } if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && - !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bPinned && g_pCompositor->m_pLastWindow.lock()->m_iMonitorID == ID)) { + !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); auto pWindow = pWorkspace->getLastFocusedWindow(); @@ -636,7 +636,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); - if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bPinned && g_pCompositor->m_pLastWindow.lock()->m_iMonitorID == ID)) { + if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST) g_pCompositor->focusWindow(PLAST); else @@ -704,7 +704,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); - if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bPinned && g_pCompositor->m_pLastWindow.lock()->m_iMonitorID == ID)) { + if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST) g_pCompositor->focusWindow(PLAST); else diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp new file mode 100644 index 00000000..ff9b4a45 --- /dev/null +++ b/src/helpers/memory/SharedPtr.hpp @@ -0,0 +1,300 @@ +#pragma once + +#include +#include +#include +#include +#include + +#define SP CSharedPointer + +/* + This is a custom impl of std::shared_ptr. + It is not thread-safe like the STL one, + but Hyprland is single-threaded anyways. + + It differs a bit from how the STL one works, + namely in the fact that it keeps the T* inside the + control block, and that you can still make a CWeakPtr + or deref an existing one inside the destructor. +*/ +namespace CSharedPointer_ { + + class impl_base { + public: + virtual ~impl_base(){}; + + virtual void inc() noexcept = 0; + virtual void dec() noexcept = 0; + virtual void incWeak() noexcept = 0; + virtual void decWeak() noexcept = 0; + virtual unsigned int ref() noexcept = 0; + virtual unsigned int wref() noexcept = 0; + virtual void destroy() noexcept = 0; + virtual bool destroying() noexcept = 0; + virtual bool dataNonNull() noexcept = 0; + }; + + template + class impl : public impl_base { + public: + impl(T* data) noexcept : _data(data) { + ; + } + + /* strong refcount */ + unsigned int _ref = 0; + /* weak refcount */ + unsigned int _weak = 0; + + T* _data = nullptr; + + friend void swap(impl*& a, impl*& b) { + impl* tmp = a; + a = b; + b = tmp; + } + + /* if the destructor was called, + creating shared_ptrs is no longer valid */ + bool _destroying = false; + + void _destroy() { + if (!_data) + return; + + // first, we destroy the data, but keep the pointer. + // this way, weak pointers will still be able to + // reference and use, but no longer create shared ones. + _destroying = true; + __deleter(_data); + // now, we can reset the data and call it a day. + _data = nullptr; + _destroying = false; + } + + std::default_delete __deleter{}; + + // + virtual void inc() noexcept { + _ref++; + } + + virtual void dec() noexcept { + _ref--; + } + + virtual void incWeak() noexcept { + _weak++; + } + + virtual void decWeak() noexcept { + _weak--; + } + + virtual unsigned int ref() noexcept { + return _ref; + } + + virtual unsigned int wref() noexcept { + return _weak; + } + + virtual void destroy() noexcept { + _destroy(); + } + + virtual bool destroying() noexcept { + return _destroying; + } + + virtual bool dataNonNull() noexcept { + return _data; + } + + virtual ~impl() { + destroy(); + } + }; +}; + +template +class CSharedPointer { + public: + template + using validHierarchy = typename std::enable_if::value>; + + /* creates a new shared pointer managing a resource + avoid calling. Could duplicate ownership. Prefer makeShared */ + explicit CSharedPointer(T* object) noexcept { + impl_ = new CSharedPointer_::impl(object); + increment(); + } + + /* creates a shared pointer from a reference */ + template > + CSharedPointer(const CSharedPointer& ref) noexcept { + impl_ = ref.impl_; + increment(); + } + + CSharedPointer(const CSharedPointer& ref) noexcept { + impl_ = ref.impl_; + increment(); + } + + template > + CSharedPointer(CSharedPointer&& ref) noexcept { + std::swap(impl_, ref.impl_); + } + + CSharedPointer(CSharedPointer&& ref) noexcept { + std::swap(impl_, ref.impl_); + } + + /* allows weakPointer to create from an impl */ + CSharedPointer(CSharedPointer_::impl_base* implementation) noexcept { + impl_ = implementation; + increment(); + } + + /* creates an empty shared pointer with no implementation */ + CSharedPointer() noexcept { + ; // empty + } + + /* creates an empty shared pointer with no implementation */ + CSharedPointer(std::nullptr_t) noexcept { + ; // empty + } + + ~CSharedPointer() { + // we do not decrement here, + // because we want to preserve the pointer + // in case this is the last owner. + if (impl_ && impl_->ref() == 1) + destroyImpl(); + else + decrement(); + } + + template > + CSharedPointer& operator=(const CSharedPointer& rhs) { + if (impl_ == rhs.impl_) + return *this; + + decrement(); + impl_ = rhs.impl_; + increment(); + return *this; + } + + CSharedPointer& operator=(const CSharedPointer& rhs) { + if (impl_ == rhs.impl_) + return *this; + + decrement(); + impl_ = rhs.impl_; + increment(); + return *this; + } + + template > + CSharedPointer& operator=(CSharedPointer&& rhs) { + std::swap(impl_, rhs.impl_); + return *this; + } + + CSharedPointer& operator=(CSharedPointer&& rhs) { + std::swap(impl_, rhs.impl_); + return *this; + } + + operator bool() const { + return impl_ && impl_->dataNonNull(); + } + + bool operator==(const CSharedPointer& rhs) const { + return impl_ == rhs.impl_; + } + + bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const { + return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; + } + + bool operator<(const CSharedPointer& rhs) const { + return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; + } + + T* operator->() const { + return get(); + } + + T& operator*() const { + return *get(); + } + + void reset() { + decrement(); + impl_ = nullptr; + } + + T* get() const { + return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); + } + + unsigned int strongRef() const { + return impl_ ? impl_->ref() : 0; + } + + CSharedPointer_::impl_base* impl_ = nullptr; + + private: + /* + no-op if there is no impl_ + may delete the stored object if ref == 0 + may delete and reset impl_ if ref == 0 and weak == 0 + */ + void decrement() { + if (!impl_) + return; + + impl_->dec(); + + // if ref == 0, we can destroy impl + if (impl_->ref() == 0) + destroyImpl(); + } + /* no-op if there is no impl_ */ + void increment() { + if (!impl_) + return; + + impl_->inc(); + } + + /* destroy the pointed-to object + if able, will also destroy impl */ + void destroyImpl() { + // destroy the impl contents + impl_->destroy(); + + // check for weak refs, if zero, we can also delete impl_ + if (impl_->wref() == 0) { + delete impl_; + impl_ = nullptr; + } + } +}; + +template +static CSharedPointer makeShared(Args&&... args) { + return CSharedPointer(new U(std::forward(args)...)); +} + +template +struct std::hash> { + std::size_t operator()(const CSharedPointer& p) const noexcept { + return std::hash{}(p->impl_); + } +}; diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp new file mode 100644 index 00000000..677fddf4 --- /dev/null +++ b/src/helpers/memory/WeakPtr.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include "SharedPtr.hpp" + +#define WP CWeakPointer + +/* + This is a Hyprland implementation of std::weak_ptr. + + See SharedPtr.hpp for more info on how it's different. +*/ + +template +class CWeakPointer { + public: + template + using validHierarchy = typename std::enable_if::value>; + + /* create a weak ptr from a reference */ + template > + CWeakPointer(const CSharedPointer& ref) noexcept { + if (!ref.impl_) + return; + + impl_ = ref.impl_; + incrementWeak(); + } + + /* create a weak ptr from another weak ptr */ + template > + CWeakPointer(const CWeakPointer& ref) noexcept { + if (!ref.impl_) + return; + + impl_ = ref.impl_; + incrementWeak(); + } + + CWeakPointer(const CWeakPointer& ref) noexcept { + if (!ref.impl_) + return; + + impl_ = ref.impl_; + incrementWeak(); + } + + template > + CWeakPointer(CWeakPointer&& ref) noexcept { + std::swap(impl_, ref.impl_); + } + + CWeakPointer(CWeakPointer&& ref) noexcept { + std::swap(impl_, ref.impl_); + } + + /* create a weak ptr from another weak ptr with assignment */ + template > + CWeakPointer& operator=(const CWeakPointer& rhs) { + if (impl_ == rhs.impl_) + return *this; + + decrementWeak(); + impl_ = rhs.impl_; + incrementWeak(); + return *this; + } + + CWeakPointer& operator=(const CWeakPointer& rhs) { + if (impl_ == rhs.impl_) + return *this; + + decrementWeak(); + impl_ = rhs.impl_; + incrementWeak(); + return *this; + } + + /* create a weak ptr from a shared ptr with assignment */ + template > + CWeakPointer& operator=(const CSharedPointer& rhs) { + if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) + return *this; + + decrementWeak(); + impl_ = rhs.impl_; + incrementWeak(); + return *this; + } + + /* create an empty weak ptr */ + CWeakPointer() { + ; + } + + ~CWeakPointer() { + decrementWeak(); + } + + /* expired MAY return true even if the pointer is still stored. + the situation would be e.g. self-weak pointer in a destructor. + for pointer validity, use valid() */ + bool expired() const { + return !impl_ || !impl_->dataNonNull() || impl_->destroying(); + } + + /* this means the pointed-to object is not yet deleted and can still be + referenced, but it might be in the process of being deleted. + check !expired() if you want to check whether it's valid and + assignable to a SP. */ + bool valid() const { + return impl_ && impl_->dataNonNull(); + } + + void reset() { + decrementWeak(); + impl_ = nullptr; + } + + CSharedPointer lock() const { + if (!impl_ || !impl_->dataNonNull() || impl_->destroying()) + return {}; + + return CSharedPointer(impl_); + } + + /* this returns valid() */ + operator bool() const { + return valid(); + } + + bool operator==(const CWeakPointer& rhs) const { + return impl_ == rhs.impl_; + } + + bool operator==(const CSharedPointer& rhs) const { + return impl_ == rhs.impl_; + } + + bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const { + return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; + } + + bool operator<(const CWeakPointer& rhs) const { + return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; + } + + T* get() const { + return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); + } + + T* operator->() const { + return get(); + } + + CSharedPointer_::impl_base* impl_ = nullptr; + + private: + /* no-op if there is no impl_ */ + void decrementWeak() { + if (!impl_) + return; + + impl_->decWeak(); + + // we need to check for ->destroying, + // because otherwise we could destroy here + // and have a shared_ptr destroy the same thing + // later (in situations where we have a weak_ptr to self) + if (impl_->wref() == 0 && impl_->ref() == 0 && !impl_->destroying()) { + delete impl_; + impl_ = nullptr; + } + } + /* no-op if there is no impl_ */ + void incrementWeak() { + if (!impl_) + return; + + impl_->incWeak(); + } +}; + +template +struct std::hash> { + std::size_t operator()(const CWeakPointer& p) const noexcept { + return std::hash{}(p->impl_); + } +}; diff --git a/src/helpers/signal/Listener.hpp b/src/helpers/signal/Listener.hpp index 7ca96e87..e6aa8d73 100644 --- a/src/helpers/signal/Listener.hpp +++ b/src/helpers/signal/Listener.hpp @@ -3,6 +3,7 @@ #include #include #include +#include "../../macros.hpp" class CSignal; @@ -21,7 +22,7 @@ class CSignalListener { std::function m_fHandler; }; -typedef std::shared_ptr CHyprSignalListener; +typedef SP CHyprSignalListener; class CStaticSignalListener { public: diff --git a/src/helpers/signal/Signal.cpp b/src/helpers/signal/Signal.cpp index d105eb78..fdd2cc23 100644 --- a/src/helpers/signal/Signal.cpp +++ b/src/helpers/signal/Signal.cpp @@ -20,8 +20,8 @@ void CSignal::emit(std::any data) { } CHyprSignalListener CSignal::registerListener(std::function handler) { - CHyprSignalListener listener = std::make_shared(handler); - m_vListeners.emplace_back(std::weak_ptr(listener)); + CHyprSignalListener listener = makeShared(handler); + m_vListeners.emplace_back(WP(listener)); return listener; } diff --git a/src/helpers/signal/Signal.hpp b/src/helpers/signal/Signal.hpp index 8938a70c..3d04f7de 100644 --- a/src/helpers/signal/Signal.hpp +++ b/src/helpers/signal/Signal.hpp @@ -19,6 +19,6 @@ class CSignal { void registerStaticListener(std::function handler, void* owner); private: - std::vector> m_vListeners; + std::vector> m_vListeners; std::vector> m_vStaticListeners; }; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index e6ebe998..172a157b 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -282,8 +282,8 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir OPENINGON = getClosestNodeOnWorkspace(PNODE->workspaceID, MOUSECOORDS); } else if (*PUSEACTIVE) { - if (g_pCompositor->m_pLastWindow.lock() && !g_pCompositor->m_pLastWindow.lock()->m_bIsFloating && g_pCompositor->m_pLastWindow.lock() != pWindow && - g_pCompositor->m_pLastWindow.lock()->m_pWorkspace == pWindow->m_pWorkspace && g_pCompositor->m_pLastWindow.lock()->m_bIsMapped) { + if (g_pCompositor->m_pLastWindow.lock() && !g_pCompositor->m_pLastWindow->m_bIsFloating && g_pCompositor->m_pLastWindow.lock() != pWindow && + g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace && g_pCompositor->m_pLastWindow->m_bIsMapped) { OPENINGON = getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()); } else { OPENINGON = getNodeFromWindow(g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS)); @@ -334,19 +334,19 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir } if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) { - if (OPENINGON->pWindow.lock()->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) + if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) return; } // if it's a group, add the window - if (OPENINGON->pWindow.lock()->m_sGroupData.pNextWindow.lock() // target is group + if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window m_lDwindleNodesData.remove(*PNODE); static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow.lock()->getGroupTail())->insertWindowToGroup(pWindow); + (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - OPENINGON->pWindow.lock()->setGroupCurrent(pWindow); + OPENINGON->pWindow->setGroupCurrent(pWindow); pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); @@ -984,15 +984,15 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { getMasterNodeOnWorkspace(PNODE2->workspaceID)->recalcSizePosRecursive(); if (ACTIVE1) { - ACTIVE1->box = PNODE->box; - ACTIVE1->pWindow.lock()->m_vPosition = ACTIVE1->box.pos(); - ACTIVE1->pWindow.lock()->m_vSize = ACTIVE1->box.size(); + ACTIVE1->box = PNODE->box; + ACTIVE1->pWindow->m_vPosition = ACTIVE1->box.pos(); + ACTIVE1->pWindow->m_vSize = ACTIVE1->box.size(); } if (ACTIVE2) { - ACTIVE2->box = PNODE2->box; - ACTIVE2->pWindow.lock()->m_vPosition = ACTIVE2->box.pos(); - ACTIVE2->pWindow.lock()->m_vSize = ACTIVE2->box.size(); + ACTIVE2->box = PNODE2->box; + ACTIVE2->pWindow->m_vPosition = ACTIVE2->box.pos(); + ACTIVE2->pWindow->m_vSize = ACTIVE2->box.size(); } g_pHyprRenderer->damageWindow(pWindow); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index dcaab25b..6f7252d2 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -45,11 +45,11 @@ void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { pWindow->m_sGroupData.pNextWindow.reset(); if (pWindow->m_sGroupData.head) { - std::swap(PWINDOWPREV->m_sGroupData.pNextWindow.lock()->m_sGroupData.head, pWindow->m_sGroupData.head); - std::swap(PWINDOWPREV->m_sGroupData.pNextWindow.lock()->m_sGroupData.locked, pWindow->m_sGroupData.locked); + std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.head, pWindow->m_sGroupData.head); + std::swap(PWINDOWPREV->m_sGroupData.pNextWindow->m_sGroupData.locked, pWindow->m_sGroupData.locked); } - if (pWindow == m_pLastTiledWindow.lock()) + if (pWindow == m_pLastTiledWindow) m_pLastTiledWindow.reset(); pWindow->setHidden(false); @@ -68,7 +68,7 @@ void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { onWindowRemovedTiling(pWindow); } - if (pWindow == m_pLastTiledWindow.lock()) + if (pWindow == m_pLastTiledWindow) m_pLastTiledWindow.reset(); } @@ -508,7 +508,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { // fix pseudo leaving artifacts g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); - if (pWindow == g_pCompositor->m_pLastWindow.lock()) + if (pWindow == g_pCompositor->m_pLastWindow) m_pLastTiledWindow = pWindow; } else { onWindowRemovedTiling(pWindow); @@ -533,7 +533,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->updateSpecialRenderData(); - if (pWindow == m_pLastTiledWindow.lock()) + if (pWindow == m_pLastTiledWindow) m_pLastTiledWindow.reset(); } @@ -589,7 +589,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { } // let's try the last tiled window. - if (m_pLastTiledWindow.lock() && m_pLastTiledWindow.lock()->m_pWorkspace == pWindow->m_pWorkspace) + if (m_pLastTiledWindow.lock() && m_pLastTiledWindow->m_pWorkspace == pWindow->m_pWorkspace) return m_pLastTiledWindow.lock(); // if we don't, let's try to find any window that is in the middle @@ -625,14 +625,14 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { } bool IHyprLayout::isWindowReachable(PHLWINDOW pWindow) { - return pWindow && (!pWindow->isHidden() || pWindow->m_sGroupData.pNextWindow.lock()); + return pWindow && (!pWindow->isHidden() || pWindow->m_sGroupData.pNextWindow); } void IHyprLayout::bringWindowToTop(PHLWINDOW pWindow) { if (pWindow == nullptr) return; - if (pWindow->isHidden() && pWindow->m_sGroupData.pNextWindow.lock()) { + if (pWindow->isHidden() && pWindow->m_sGroupData.pNextWindow) { // grouped, change the current to this window pWindow->setGroupCurrent(pWindow); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 1d902bde..af0182e1 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -91,27 +91,27 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire static auto PMFACT = CConfigValue("master:mfact"); float lastSplitPercent = *PMFACT; - auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow.lock()) && g_pCompositor->m_pLastWindow.lock()->m_pWorkspace == pWindow->m_pWorkspace ? + auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow.lock()) && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()) : getMasterNodeOnWorkspace(pWindow->workspaceID()); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) { - if (OPENINGON->pWindow.lock()->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) + if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) return; } // if it's a group, add the window - if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow.lock()->m_sGroupData.pNextWindow.lock() // target is group + if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) { m_lMasterNodesData.remove(*PNODE); static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow.lock()->getGroupTail())->insertWindowToGroup(pWindow); + (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - OPENINGON->pWindow.lock()->setGroupCurrent(pWindow); + OPENINGON->pWindow->setGroupCurrent(pWindow); pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); @@ -135,17 +135,17 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire for (auto it = m_lMasterNodesData.begin(); it != m_lMasterNodesData.end(); ++it) { if (it->workspaceID != pWindow->workspaceID()) continue; - const CBox box = it->pWindow.lock()->getWindowIdealBoundingBoxIgnoreReserved(); + const CBox box = it->pWindow->getWindowIdealBoundingBoxIgnoreReserved(); if (box.containsPoint(MOUSECOORDS)) { switch (orientation) { case ORIENTATION_LEFT: case ORIENTATION_RIGHT: - if (MOUSECOORDS.y > it->pWindow.lock()->middle().y) + if (MOUSECOORDS.y > it->pWindow->middle().y) ++it; break; case ORIENTATION_TOP: case ORIENTATION_BOTTOM: - if (MOUSECOORDS.x > it->pWindow.lock()->middle().x) + if (MOUSECOORDS.x > it->pWindow->middle().x) ++it; break; case ORIENTATION_CENTER: break; @@ -163,19 +163,19 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire switch (orientation) { case ORIENTATION_LEFT: case ORIENTATION_CENTER: - if (MOUSECOORDS.x < nd.pWindow.lock()->middle().x) + if (MOUSECOORDS.x < nd.pWindow->middle().x) forceDropAsMaster = true; break; case ORIENTATION_RIGHT: - if (MOUSECOORDS.x > nd.pWindow.lock()->middle().x) + if (MOUSECOORDS.x > nd.pWindow->middle().x) forceDropAsMaster = true; break; case ORIENTATION_TOP: - if (MOUSECOORDS.y < nd.pWindow.lock()->middle().y) + if (MOUSECOORDS.y < nd.pWindow->middle().y) forceDropAsMaster = true; break; case ORIENTATION_BOTTOM: - if (MOUSECOORDS.y > nd.pWindow.lock()->middle().y) + if (MOUSECOORDS.y > nd.pWindow->middle().y) forceDropAsMaster = true; break; default: UNREACHABLE(); diff --git a/src/macros.hpp b/src/macros.hpp index e319051f..b57d9737 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -4,9 +4,9 @@ #include #include -#define SP std::shared_ptr +#include "helpers/memory/WeakPtr.hpp" + #define UP std::unique_ptr -#define WP std::weak_ptr #ifndef NDEBUG #ifdef HYPRLAND_DEBUG diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index c39df580..21c1055f 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -7,7 +7,7 @@ #include "../desktop/LayerSurface.hpp" #include "eventLoop/EventLoopManager.hpp" -int wlTick(std::shared_ptr self, void* data) { +int wlTick(SP self, void* data) { if (g_pAnimationManager) g_pAnimationManager->onTicked(); @@ -27,7 +27,7 @@ CAnimationManager::CAnimationManager() { std::vector points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)}; m_mBezierCurves["default"].setup(&points); - m_pAnimationTimer = std::make_unique(std::chrono::microseconds(500), wlTick, nullptr); + m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); g_pEventLoopManager->addTimer(m_pAnimationTimer); } diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 5d4d0e1c..601a38b3 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -33,7 +33,7 @@ class CAnimationManager { std::vector m_vAnimatedVariables; std::vector m_vActiveAnimatedVariables; - std::shared_ptr m_pAnimationTimer; + SP m_pAnimationTimer; float m_fLastTickTime; // in ms diff --git a/src/managers/HookSystemManager.cpp b/src/managers/HookSystemManager.cpp index 11007f1a..a1920863 100644 --- a/src/managers/HookSystemManager.cpp +++ b/src/managers/HookSystemManager.cpp @@ -7,16 +7,16 @@ CHookSystemManager::CHookSystemManager() { } // returns the pointer to the function -std::shared_ptr CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) { - std::shared_ptr hookFN = std::make_shared(fn); +SP CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) { + SP hookFN = makeShared(fn); m_mRegisteredHooks[event].emplace_back(SCallbackFNPtr{.fn = hookFN, .handle = handle}); return hookFN; } -void CHookSystemManager::unhook(std::shared_ptr fn) { +void CHookSystemManager::unhook(SP fn) { for (auto& [k, v] : m_mRegisteredHooks) { std::erase_if(v, [&](const auto& other) { - std::shared_ptr fn_ = other.fn.lock(); + SP fn_ = other.fn.lock(); return fn_.get() == fn.get(); }); @@ -37,7 +37,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal if (!cb.handle) { // we don't guard hl hooks - if (std::shared_ptr fn = cb.fn.lock()) + if (SP fn = cb.fn.lock()) (*fn)(fn.get(), info, data); else needsDeadCleanup = true; @@ -51,7 +51,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal try { if (!setjmp(m_jbHookFaultJumpBuf)) { - if (std::shared_ptr fn = cb.fn.lock()) + if (SP fn = cb.fn.lock()) (*fn)(fn.get(), info, data); else needsDeadCleanup = true; diff --git a/src/managers/HookSystemManager.hpp b/src/managers/HookSystemManager.hpp index 4b27fadf..75377aaa 100644 --- a/src/managers/HookSystemManager.hpp +++ b/src/managers/HookSystemManager.hpp @@ -16,8 +16,8 @@ typedef std::function HOOK_CALLBACK_FN; struct SCallbackFNPtr { - std::weak_ptr fn; - HANDLE handle = nullptr; + WP fn; + HANDLE handle = nullptr; }; #define EMIT_HOOK_EVENT(name, param) \ @@ -43,9 +43,9 @@ class CHookSystemManager { // returns the pointer to the function. // losing this pointer (letting it get destroyed) // will equal to unregistering the callback. - [[nodiscard("Losing this pointer instantly unregisters the callback")]] std::shared_ptr hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, - HANDLE handle = nullptr); - void unhook(std::shared_ptr fn); + [[nodiscard("Losing this pointer instantly unregisters the callback")]] SP hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, + HANDLE handle = nullptr); + void unhook(SP fn); void emit(std::vector* const callbacks, SCallbackInfo& info, std::any data = 0); std::vector* getVecForEvent(const std::string& event); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7708a77a..16b631c8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -532,7 +532,7 @@ int repeatKeyHandler(void* data) { Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); DISPATCHER->second((*ppActiveKeybind)->arg); - wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pCompositor->m_sSeat.keyboard.lock()->repeatRate); + wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pCompositor->m_sSeat.keyboard->repeatRate); return 0; } @@ -1162,7 +1162,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } - if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { + if (PWINDOW == g_pCompositor->m_pLastWindow) { if (const auto PATCOORDS = g_pCompositor->vectorToWindowUnified(OLDMIDDLE, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, PWINDOW); PATCOORDS) g_pCompositor->focusWindow(PATCOORDS); else @@ -1910,7 +1910,7 @@ void CKeybindManager::pass(std::string regexp) { return; } - const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bIsX11; + const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; const auto SL = Vector2D(g_pCompositor->m_sSeat.seat->pointer_state.sx, g_pCompositor->m_sSeat.seat->pointer_state.sy); uint32_t keycodes[32] = {0}; @@ -2026,9 +2026,9 @@ void CKeybindManager::swapnext(std::string arg) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - const auto PLASTCYCLED = validMapped(g_pCompositor->m_pLastWindow.lock()->m_pLastCycledWindow) && - g_pCompositor->m_pLastWindow.lock()->m_pLastCycledWindow.lock()->m_pWorkspace == PLASTWINDOW->m_pWorkspace ? - g_pCompositor->m_pLastWindow.lock()->m_pLastCycledWindow.lock() : + const auto PLASTCYCLED = + validMapped(g_pCompositor->m_pLastWindow->m_pLastCycledWindow) && g_pCompositor->m_pLastWindow->m_pLastCycledWindow->m_pWorkspace == PLASTWINDOW->m_pWorkspace ? + g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() : nullptr; if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") @@ -2151,7 +2151,7 @@ void CKeybindManager::mouse(std::string args) { } void CKeybindManager::bringActiveToTop(std::string args) { - if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bIsFloating) + if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true); } @@ -2160,7 +2160,7 @@ void CKeybindManager::alterZOrder(std::string args) { const auto POSITION = args.substr(0, args.find_first_of(',')); auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX); - if (!PWINDOW && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bIsFloating) + if (!PWINDOW && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) { @@ -2183,8 +2183,8 @@ void CKeybindManager::alterZOrder(std::string args) { void CKeybindManager::fakeFullscreenActive(std::string args) { if (!g_pCompositor->m_pLastWindow.expired()) { // will also set the flag - g_pCompositor->m_pLastWindow.lock()->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow.lock()->m_bFakeFullscreenState; - g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow.lock(), g_pCompositor->m_pLastWindow.lock()->shouldSendFullscreenState()); + g_pCompositor->m_pLastWindow->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow->m_bFakeFullscreenState; + g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow.lock(), g_pCompositor->m_pLastWindow->shouldSendFullscreenState()); } } @@ -2349,7 +2349,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW; // note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating - if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow.lock()) { // target is group + if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); g_pCompositor->warpCursorTo(PWINDOW->middle()); @@ -2416,9 +2416,9 @@ void CKeybindManager::moveGroupWindow(std::string args) { if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock()) return; - if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow.lock()->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { - std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow.lock()->m_sGroupData.head); - std::swap(PLASTWINDOW->m_sGroupData.locked, PLASTWINDOW->m_sGroupData.pNextWindow.lock()->m_sGroupData.locked); + if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { + std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); + std::swap(PLASTWINDOW->m_sGroupData.locked, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.locked); } else PLASTWINDOW->switchWithWindowInGroup(BACK ? PLASTWINDOW->getGroupPrevious() : PLASTWINDOW->m_sGroupData.pNextWindow.lock()); diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index d1c609d3..6dd096bb 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -5,12 +5,12 @@ #include "../protocols/SessionLock.hpp" SSessionLockSurface::SSessionLockSurface(SP surface_) : surface(surface_) { - pWlrSurface = surface.lock()->surface(); + pWlrSurface = surface->surface(); listeners.map = surface_->events.map.registerListener([this](std::any data) { mapped = true; - g_pCompositor->focusSurface(surface.lock()->surface()); + g_pCompositor->focusSurface(surface->surface()); const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); @@ -124,7 +124,7 @@ bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) { return false; for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { - if (sls->surface.lock()->surface() == pSurface) + if (sls->surface->surface() == pSurface) return true; } @@ -144,7 +144,7 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { if (!sls->mapped) continue; - g_pCompositor->focusSurface(sls->surface.lock()->surface()); + g_pCompositor->focusSurface(sls->surface->surface()); break; } } diff --git a/src/managers/TokenManager.cpp b/src/managers/TokenManager.cpp index 89db3256..451baac1 100644 --- a/src/managers/TokenManager.cpp +++ b/src/managers/TokenManager.cpp @@ -26,11 +26,11 @@ std::string CTokenManager::getRandomUUID() { std::string CTokenManager::registerNewToken(std::any data, std::chrono::system_clock::duration expires) { std::string uuid = getRandomUUID(); - m_mTokens[uuid] = std::make_shared(uuid, data, expires); + m_mTokens[uuid] = makeShared(uuid, data, expires); return uuid; } -std::shared_ptr CTokenManager::getToken(const std::string& uuid) { +SP CTokenManager::getToken(const std::string& uuid) { // cleanup expired tokens const auto NOW = std::chrono::system_clock::now(); @@ -42,7 +42,7 @@ std::shared_ptr CTokenManager::getToken(const std::string& uuid) { return m_mTokens.at(uuid); } -void CTokenManager::removeToken(std::shared_ptr token) { +void CTokenManager::removeToken(SP token) { if (!token) return; m_mTokens.erase(token->uuid); diff --git a/src/managers/TokenManager.hpp b/src/managers/TokenManager.hpp index ead02275..afe8c55b 100644 --- a/src/managers/TokenManager.hpp +++ b/src/managers/TokenManager.hpp @@ -1,11 +1,12 @@ #pragma once -#include #include #include #include #include +#include "../helpers/memory/SharedPtr.hpp" + class CUUIDToken { public: CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::system_clock::duration expires); @@ -24,14 +25,14 @@ class CUUIDToken { class CTokenManager { public: - std::string registerNewToken(std::any data, std::chrono::system_clock::duration expires); - std::string getRandomUUID(); + std::string registerNewToken(std::any data, std::chrono::system_clock::duration expires); + std::string getRandomUUID(); - std::shared_ptr getToken(const std::string& uuid); - void removeToken(std::shared_ptr token); + SP getToken(const std::string& uuid); + void removeToken(SP token); private: - std::unordered_map> m_mTokens; + std::unordered_map> m_mTokens; }; inline std::unique_ptr g_pTokenManager; \ No newline at end of file diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 20de570c..c78bc551 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -38,12 +38,12 @@ void CEventLoopManager::onTimerFire() { nudgeTimers(); } -void CEventLoopManager::addTimer(std::shared_ptr timer) { +void CEventLoopManager::addTimer(SP timer) { m_sTimers.timers.push_back(timer); nudgeTimers(); } -void CEventLoopManager::removeTimer(std::shared_ptr timer) { +void CEventLoopManager::removeTimer(SP timer) { std::erase_if(m_sTimers.timers, [timer](const auto& t) { return timer == t; }); nudgeTimers(); } diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index ccd70123..13d74571 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -13,8 +12,8 @@ class CEventLoopManager { CEventLoopManager(); void enterLoop(wl_display* display, wl_event_loop* wlEventLoop); - void addTimer(std::shared_ptr timer); - void removeTimer(std::shared_ptr timer); + void addTimer(SP timer); + void removeTimer(SP timer); void onTimerFire(); @@ -28,8 +27,8 @@ class CEventLoopManager { } m_sWayland; struct { - std::vector> timers; - int timerfd = -1; + std::vector> timers; + int timerfd = -1; } m_sTimers; }; diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp index 5ece1cac..dbb405e5 100644 --- a/src/managers/eventLoop/EventLoopTimer.cpp +++ b/src/managers/eventLoop/EventLoopTimer.cpp @@ -2,10 +2,8 @@ #include #include "EventLoopManager.hpp" -CEventLoopTimer::CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, - void* data_) : - cb(cb_), - data(data_) { +CEventLoopTimer::CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_) : + cb(cb_), data(data_) { if (!timeout.has_value()) expires.reset(); @@ -40,7 +38,7 @@ bool CEventLoopTimer::cancelled() { return wasCancelled; } -void CEventLoopTimer::call(std::shared_ptr self) { +void CEventLoopTimer::call(SP self) { expires.reset(); cb(self, data); } diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index 8865d29f..fc0b2522 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -4,9 +4,11 @@ #include #include +#include "../../helpers/memory/SharedPtr.hpp" + class CEventLoopTimer { public: - CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_); + CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_); // if not specified, disarms. // if specified, arms. @@ -19,11 +21,11 @@ class CEventLoopTimer { bool cancelled(); // resets expires - void call(std::shared_ptr self); + void call(SP self); private: - std::function self, void* data)> cb; - void* data = nullptr; - std::optional expires; - bool wasCancelled = false; + std::function self, void* data)> cb; + void* data = nullptr; + std::optional expires; + bool wasCancelled = false; }; diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 468ea58b..a71059e4 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -5,11 +5,11 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique()).get(); - PINHIBIT->inhibitor = std::any_cast>(inhibitor); + PINHIBIT->inhibitor = std::any_cast>(inhibitor); Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface); - PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource.lock()->events.destroy.registerListener([this, PINHIBIT](std::any data) { + PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) { std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; }); recheckIdleInhibitorStatus(); }); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 81ceae79..6d493e5b 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -250,7 +250,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!PSLS) return; - foundSurface = PSLS->surface.lock()->surface(); + foundSurface = PSLS->surface->surface(); surfacePos = PMONITOR->vecPosition; } @@ -408,7 +408,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_pFoundSurfaceToFocus = foundSurface; } - if (currentlyDraggedWindow.lock() && pFoundWindow != currentlyDraggedWindow.lock()) { + if (currentlyDraggedWindow.lock() && pFoundWindow != currentlyDraggedWindow) { wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); return; @@ -434,8 +434,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (FOLLOWMOUSE != 1 && !refocus) { if (pFoundWindow != g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock() && - ((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || - (g_pCompositor->m_pLastWindow.lock()->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) { + ((pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR == 2) || (g_pCompositor->m_pLastWindow->m_bIsFloating != pFoundWindow->m_bIsFloating && *PFLOATBEHAVIOR != 0))) { // enter if change floating style if (FOLLOWMOUSE != 3 && allowKeyboardRefocus) g_pCompositor->focusWindow(pFoundWindow, foundSurface); @@ -446,12 +445,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); } - if (pFoundWindow == g_pCompositor->m_pLastWindow.lock()) { + if (pFoundWindow == g_pCompositor->m_pLastWindow) { m_pLastMouseSurface = foundSurface; wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); } - if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow.lock()) + if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow) wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); m_bLastFocusOnLS = false; @@ -671,7 +670,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { } // if clicked on a floating window make it top - if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow.lock()->m_bIsFloating) + if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true); break; @@ -1172,9 +1171,9 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { - g_pCompositor->m_sSeat.keyboard = m_vKeyboards.back(); - g_pCompositor->m_sSeat.keyboard.lock()->active = true; - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, g_pCompositor->m_sSeat.keyboard.lock()->wlr()); + g_pCompositor->m_sSeat.keyboard = m_vKeyboards.back(); + g_pCompositor->m_sSeat.keyboard->active = true; + wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, g_pCompositor->m_sSeat.keyboard->wlr()); } else { g_pCompositor->m_sSeat.keyboard.reset(); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, nullptr); @@ -1278,7 +1277,7 @@ bool CInputManager::shouldIgnoreVirtualKeyboard(SP pKeyboard) { CVirtualKeyboard* vk = (CVirtualKeyboard*)pKeyboard.get(); - return !pKeyboard || (!m_sIMERelay.m_pIME.expired() && m_sIMERelay.m_pIME.lock()->grabClient() == vk->getClient()); + return !pKeyboard || (!m_sIMERelay.m_pIME.expired() && m_sIMERelay.m_pIME->grabClient() == vk->getClient()); } void CInputManager::refocus() { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 329748b2..7d78c133 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -144,7 +144,7 @@ class CInputManager { std::deque m_dExclusiveLSes; // constraints - std::vector> m_vConstraints; + std::vector> m_vConstraints; // void newTabletTool(wlr_input_device*); @@ -241,9 +241,9 @@ class CInputManager { // idle inhibitors struct SIdleInhibitor { - std::shared_ptr inhibitor; - bool nonDesktop = false; - CHyprSignalListener surfaceDestroyListener; + SP inhibitor; + bool nonDesktop = false; + CHyprSignalListener surfaceDestroyListener; }; std::vector> m_vIdleInhibitors; diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index f2d49ae8..9ff584e6 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -73,7 +73,7 @@ void CInputPopup::damageSurface() { } void CInputPopup::updateBox() { - if (!popup.lock()->mapped) + if (!popup->mapped) return; const auto OWNER = queryOwner(); @@ -114,7 +114,7 @@ void CInputPopup::updateBox() { popupOffset.x -= popupOverflow; CBox cursorBoxLocal({-popupOffset.x, -popupOffset.y}, cursorBoxParent.size()); - popup.lock()->sendInputRectangle(cursorBoxLocal); + popup->sendInputRectangle(cursorBoxLocal); CBox popupBoxParent(cursorBoxParent.pos() + popupOffset, currentPopupSize); if (popupBoxParent != lastBoxLocal) { diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 778f3086..abf18fba 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -85,7 +85,7 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() { } void CInputMethodRelay::onNewTextInput(std::any tiv3) { - m_vTextInputs.emplace_back(std::make_unique(std::any_cast>(tiv3))); + m_vTextInputs.emplace_back(std::make_unique(std::any_cast>(tiv3))); } void CInputMethodRelay::onNewTextInput(STextInputV1* pTIV1) { @@ -106,7 +106,7 @@ void CInputMethodRelay::activateIME(CTextInput* pInput) { if (m_pIME.expired()) return; - m_pIME.lock()->activate(); + m_pIME->activate(); commitIMEState(pInput); } @@ -114,7 +114,7 @@ void CInputMethodRelay::deactivateIME(CTextInput* pInput) { if (m_pIME.expired()) return; - m_pIME.lock()->deactivate(); + m_pIME->deactivate(); commitIMEState(pInput); } diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 77718174..b3f0b0cb 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -11,7 +11,7 @@ CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) { initCallbacks(); } -CTextInput::CTextInput(std::weak_ptr ti) : pV3Input(ti) { +CTextInput::CTextInput(WP ti) : pV3Input(ti) { initCallbacks(); } @@ -109,7 +109,7 @@ void CTextInput::onCommit() { return; } - if (!(isV3() ? pV3Input.lock()->current.enabled : pV1Input->active)) { + if (!(isV3() ? pV3Input->current.enabled : pV1Input->active)) { Debug::log(WARN, "Disabled TextInput commit?"); return; } @@ -180,7 +180,7 @@ void CTextInput::enter(wlr_surface* pSurface) { } if (isV3()) - pV3Input.lock()->enter(pSurface); + pV3Input->enter(pSurface); else { zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->resource); pV1Input->active = true; @@ -200,7 +200,7 @@ void CTextInput::leave() { } if (isV3() && focusedSurface()) - pV3Input.lock()->leave(focusedSurface()); + pV3Input->leave(focusedSurface()); else if (focusedSurface() && pV1Input) { zwp_text_input_v1_send_leave(pV1Input->resourceImpl); pV1Input->active = false; @@ -216,7 +216,7 @@ wlr_surface* CTextInput::focusedSurface() { } wl_client* CTextInput::client() { - return isV3() ? pV3Input.lock()->client() : pV1Input->client; + return isV3() ? pV3Input->client() : pV1Input->client; } void CTextInput::commitStateToIME(SP ime) { @@ -284,9 +284,9 @@ void CTextInput::updateIMEState(SP ime) { } bool CTextInput::hasCursorRectangle() { - return !isV3() || pV3Input.lock()->current.box.updated; + return !isV3() || pV3Input->current.box.updated; } CBox CTextInput::cursorBox() { - return CBox{isV3() ? pV3Input.lock()->current.box.cursorBox : pV1Input->cursorRectangle}; + return CBox{isV3() ? pV3Input->current.box.cursorBox : pV1Input->cursorRectangle}; } \ No newline at end of file diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 481d60c1..ff21da95 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -15,7 +15,7 @@ class CInputMethodV2; class CTextInput { public: - CTextInput(std::weak_ptr ti); + CTextInput(WP ti); CTextInput(STextInputV1* ti); ~CTextInput(); @@ -37,13 +37,13 @@ class CTextInput { wlr_surface* focusedSurface(); private: - void setFocusedSurface(wlr_surface* pSurface); - void initCallbacks(); + void setFocusedSurface(wlr_surface* pSurface); + void initCallbacks(); - wlr_surface* pFocusedSurface = nullptr; - int enterLocks = 0; - std::weak_ptr pV3Input; - STextInputV1* pV1Input = nullptr; + wlr_surface* pFocusedSurface = nullptr; + int enterLocks = 0; + WP pV3Input; + STextInputV1* pV1Input = nullptr; DYNLISTENER(textInputEnable); DYNLISTENER(textInputDisable); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 8f6e2226..7b0d6190 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -38,7 +38,7 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { if (m_sActiveSwipe.pWorkspaceBegin) { return; // TODO: Don't swipe if you touched a floating window. - } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus.lock()->layer <= ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)) { + } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); @@ -67,16 +67,15 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { Vector2D local; if (!m_sTouchData.touchFocusWindow.expired()) { - if (m_sTouchData.touchFocusWindow.lock()->m_bIsX11) { - local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow.lock()->m_vRealPosition.goal()) * - m_sTouchData.touchFocusWindow.lock()->m_fX11SurfaceScaledBy; - m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow.lock()->m_vRealPosition.goal(); + if (m_sTouchData.touchFocusWindow->m_bIsX11) { + local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; + m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition.goal(); } else { g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow.lock(), local); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; } } else if (!m_sTouchData.touchFocusLS.expired()) { - local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusLS.lock()->geometry.pos(); + local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusLS->geometry.pos(); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; } else { @@ -130,18 +129,18 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) { return; } if (validMapped(m_sTouchData.touchFocusWindow)) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow.lock()->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; - if (m_sTouchData.touchFocusWindow.lock()->m_bIsX11) - local = local * m_sTouchData.touchFocusWindow.lock()->m_fX11SurfaceScaledBy; + if (m_sTouchData.touchFocusWindow->m_bIsX11) + local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); } else if (!m_sTouchData.touchFocusLS.expired()) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS.lock()->monitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 3266579b..6e09ba2c 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -13,18 +13,18 @@ APICALL const char* __hyprland_api_get_hash() { return GIT_COMMIT_HASH; } -APICALL std::shared_ptr HyprlandAPI::registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn) { +APICALL SP HyprlandAPI::registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) return nullptr; auto PFN = g_pHookSystem->hookDynamic(event, fn, handle); - PLUGIN->registeredCallbacks.emplace_back(std::make_pair<>(event, std::weak_ptr(PFN))); + PLUGIN->registeredCallbacks.emplace_back(std::make_pair<>(event, WP(PFN))); return PFN; } -APICALL bool HyprlandAPI::unregisterCallback(HANDLE handle, std::shared_ptr fn) { +APICALL bool HyprlandAPI::unregisterCallback(HANDLE handle, SP fn) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) @@ -355,7 +355,7 @@ APICALL SVersionInfo HyprlandAPI::getHyprlandVersion(HANDLE handle) { return {GIT_COMMIT_HASH, GIT_TAG, GIT_DIRTY != std::string(""), GIT_BRANCH, GIT_COMMIT_MESSAGE, GIT_COMMITS}; } -APICALL std::shared_ptr HyprlandAPI::registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd) { +APICALL SP HyprlandAPI::registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) @@ -366,7 +366,7 @@ APICALL std::shared_ptr HyprlandAPI::registerHyprCtlCommand(HAN return PTR; } -APICALL bool HyprlandAPI::unregisterHyprCtlCommand(HANDLE handle, std::shared_ptr cmd) { +APICALL bool HyprlandAPI::unregisterHyprCtlCommand(HANDLE handle, SP cmd) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index df04efbe..83db5f85 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -23,6 +23,7 @@ Feel like the API is missing something you'd like to use in your plugin? Open an #include "../helpers/Color.hpp" #include "HookSystem.hpp" #include "../SharedDefs.hpp" +#include "../defines.hpp" #include "../version.h" #include @@ -63,9 +64,6 @@ class IHyprWindowDecoration; struct SConfigValue; class CWindow; -typedef std::shared_ptr PHLWINDOW; -typedef std::weak_ptr PHLWINDOWREF; - /* These methods are for the plugin to implement Methods marked with REQUIRED are required. @@ -144,7 +142,7 @@ namespace HyprlandAPI { WARNING: Losing this pointer will unregister the callback! */ - APICALL [[nodiscard]] std::shared_ptr registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn); + APICALL [[nodiscard]] SP registerCallbackDynamic(HANDLE handle, const std::string& event, HOOK_CALLBACK_FN fn); /* Unregisters a callback. If the callback was dynamic, frees the memory. @@ -153,7 +151,7 @@ namespace HyprlandAPI { Deprecated: just reset the pointer you received with registerCallbackDynamic */ - APICALL [[deprecated]] bool unregisterCallback(HANDLE handle, std::shared_ptr fn); + APICALL [[deprecated]] bool unregisterCallback(HANDLE handle, SP fn); /* Calls a hyprctl command. @@ -281,14 +279,14 @@ namespace HyprlandAPI { returns: Pointer. Nullptr on fail. */ - APICALL std::shared_ptr registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd); + APICALL SP registerHyprCtlCommand(HANDLE handle, SHyprCtlCommand cmd); /* Unregisters a hyprctl command returns: true on success. False otherwise. */ - APICALL bool unregisterHyprCtlCommand(HANDLE handle, std::shared_ptr cmd); + APICALL bool unregisterHyprCtlCommand(HANDLE handle, SP cmd); }; /* diff --git a/src/plugins/PluginSystem.hpp b/src/plugins/PluginSystem.hpp index a442c31c..333b49e5 100644 --- a/src/plugins/PluginSystem.hpp +++ b/src/plugins/PluginSystem.hpp @@ -8,22 +8,22 @@ class IHyprWindowDecoration; class CPlugin { public: - std::string name = ""; - std::string description = ""; - std::string author = ""; - std::string version = ""; + std::string name = ""; + std::string description = ""; + std::string author = ""; + std::string version = ""; - std::string path = ""; + std::string path = ""; - bool m_bLoadedWithConfig = false; + bool m_bLoadedWithConfig = false; - HANDLE m_pHandle = nullptr; + HANDLE m_pHandle = nullptr; - std::vector registeredLayouts; - std::vector registeredDecorations; - std::vector>> registeredCallbacks; - std::vector registeredDispatchers; - std::vector> registeredHyprctlCommands; + std::vector registeredLayouts; + std::vector registeredDecorations; + std::vector>> registeredCallbacks; + std::vector registeredDispatchers; + std::vector> registeredHyprctlCommands; }; class CPluginSystem { diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index 195e4b38..b9b99f69 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -111,9 +111,8 @@ void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, return; } - const auto RESOURCE = - m_mAlphaModifiers.emplace(surface, std::make_unique(std::make_shared(pMgr->client(), pMgr->version(), id), surface)) - .first->second.get(); + const auto RESOURCE = m_mAlphaModifiers.emplace(surface, std::make_unique(makeShared(pMgr->client(), pMgr->version(), id), surface)) + .first->second.get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 73c03ef3..2f25b22b 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -74,7 +74,7 @@ void CCursorShapeProtocol::onGetTabletToolV2(CWpCursorShapeManagerV1* pMgr, uint void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr, uint32_t id, wl_resource* resource) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vDevices.emplace_back(std::make_shared(CLIENT, pMgr->version(), id)); + const auto RESOURCE = m_vDevices.emplace_back(makeShared(CLIENT, pMgr->version(), id)); RESOURCE->setOnDestroy([this](CWpCursorShapeDeviceV1* p) { this->onDeviceResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpCursorShapeDeviceV1* p) { this->onDeviceResourceDestroy(p->resource()); }); diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 61c17573..1ab4d4a6 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -315,7 +315,7 @@ void CFocusGrabProtocol::destroyGrab(CFocusGrab* grab) { } void CFocusGrabProtocol::onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) { - m_vGrabs.push_back(std::make_unique(std::make_shared(pMgr->client(), pMgr->version(), id))); + m_vGrabs.push_back(std::make_unique(makeShared(pMgr->client(), pMgr->version(), id))); const auto RESOURCE = m_vGrabs.back().get(); if (!RESOURCE->good()) { diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 970b3747..0d2a7e57 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -45,7 +45,7 @@ void CForeignToplevelList::onMap(PHLWINDOW pWindow) { return; const auto NEWHANDLE = PROTO::foreignToplevel->m_vHandles.emplace_back( - std::make_shared(std::make_shared(resource->client(), resource->version(), 0), pWindow)); + makeShared(makeShared(resource->client(), resource->version(), 0), pWindow)); if (!NEWHANDLE->good()) { LOGM(ERR, "Couldn't create a foreign handle"); @@ -68,7 +68,7 @@ void CForeignToplevelList::onMap(PHLWINDOW pWindow) { SP CForeignToplevelList::handleForWindow(PHLWINDOW pWindow) { std::erase_if(handles, [](const auto& wp) { return wp.expired(); }); - const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h.lock()->window() == pWindow; }); + const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h->window() == pWindow; }); return IT == handles.end() ? SP{} : IT->lock(); } @@ -131,7 +131,7 @@ CForeignToplevelProtocol::CForeignToplevelProtocol(const wl_interface* iface, co } void CForeignToplevelProtocol::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(); + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); if (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 35d7b01c..25c4579f 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -139,7 +139,7 @@ void CForeignToplevelHandleWlr::sendState() { wl_array state; wl_array_init(&state); - if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { + 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; } @@ -185,7 +185,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { return; const auto NEWHANDLE = PROTO::foreignToplevelWlr->m_vHandles.emplace_back( - std::make_shared(std::make_shared(resource->client(), resource->version(), 0), pWindow)); + makeShared(makeShared(resource->client(), resource->version(), 0), pWindow)); if (!NEWHANDLE->good()) { LOGM(ERR, "Couldn't create a foreign handle"); @@ -208,7 +208,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { SP CForeignToplevelWlrManager::handleForWindow(PHLWINDOW pWindow) { std::erase_if(handles, [](const auto& wp) { return wp.expired(); }); - const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h.lock()->window() == pWindow; }); + const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h->window() == pWindow; }); return IT == handles.end() ? SP{} : IT->lock(); } @@ -346,7 +346,7 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa } 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(); + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); if (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index f478e622..691ab697 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -36,8 +36,8 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* return; } - const auto PADDON = m_mAddons.emplace(surface, std::make_unique(std::make_shared(pMgr->client(), pMgr->version(), id), surface)) - .first->second.get(); + const auto PADDON = + m_mAddons.emplace(surface, std::make_unique(makeShared(pMgr->client(), pMgr->version(), id), surface)).first->second.get(); if (!PADDON->good()) { m_mAddons.erase(surface); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 356fd88d..c8db7100 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -157,7 +157,7 @@ void CGammaControlProtocol::destroyGammaControl(CGammaControl* gamma) { void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vGammaControllers.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), output)).get(); + const auto RESOURCE = m_vGammaControllers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), output)).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/IdleInhibit.cpp b/src/protocols/IdleInhibit.cpp index 9960c00f..0ff11a56 100644 --- a/src/protocols/IdleInhibit.cpp +++ b/src/protocols/IdleInhibit.cpp @@ -48,8 +48,8 @@ void CIdleInhibitProtocol::removeInhibitor(CIdleInhibitorResource* resource) { void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vInhibitors.emplace_back(std::make_shared(std::make_shared(CLIENT, pMgr->version(), id), surface)); + const auto RESOURCE = m_vInhibitors.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), surface)); - RESOURCE->inhibitor = std::make_shared(RESOURCE, surface); + RESOURCE->inhibitor = makeShared(RESOURCE, surface); events.newIdleInhibitor.emit(RESOURCE->inhibitor); } \ No newline at end of file diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 63d01e60..2ec7d2a1 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -3,7 +3,7 @@ #define LOGM PROTO::idle->protoLog -static int onTimer(std::shared_ptr self, void* data) { +static int onTimer(SP self, void* data) { const auto NOTIF = (CExtIdleNotification*)data; @@ -19,7 +19,7 @@ CExtIdleNotification::CExtIdleNotification(SP resource_, resource->setDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); }); resource->setOnDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); }); - timer = std::make_shared(std::nullopt, onTimer, this); + timer = makeShared(std::nullopt, onTimer, this); g_pEventLoopManager->addTimer(timer); updateTimer(); @@ -77,9 +77,8 @@ void CIdleNotifyProtocol::destroyNotification(CExtIdleNotification* notif) { } void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { - const auto CLIENT = pMgr->client(); - const auto RESOURCE = - m_vNotifications.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), timeout)).get(); + const auto CLIENT = pMgr->client(); + const auto RESOURCE = m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout)).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/IdleNotify.hpp b/src/protocols/IdleNotify.hpp index c1c7b62d..d0b40775 100644 --- a/src/protocols/IdleNotify.hpp +++ b/src/protocols/IdleNotify.hpp @@ -18,13 +18,13 @@ class CExtIdleNotification { void onActivity(); private: - SP resource; - uint32_t timeoutMs = 0; - std::shared_ptr timer; + SP resource; + uint32_t timeoutMs = 0; + SP timer; - bool idled = false; + bool idled = false; - void updateTimer(); + void updateTimer(); }; class CIdleNotifyProtocol : public IWaylandProtocol { diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 86601747..d84f6772 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -23,7 +23,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SPgrabs, [](const auto& g) { return g.expired(); }); + std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); }); } void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { @@ -131,7 +131,7 @@ CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, CInputMethodPopupV2::~CInputMethodPopupV2() { if (!owner.expired()) - std::erase_if(owner.lock()->popups, [](const auto& p) { return p.expired(); }); + std::erase_if(owner->popups, [](const auto& p) { return p.expired(); }); events.destroy.emit(); } @@ -193,7 +193,7 @@ CInputMethodV2::CInputMethodV2(SP resource_) : resource(resou resource->setGetInputPopupSurface([this](CZwpInputMethodV2* r, uint32_t id, wl_resource* surface) { const auto RESOURCE = PROTO::ime->m_vPopups.emplace_back( - std::make_shared(std::make_shared(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surface))); + makeShared(makeShared(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surface))); if (!RESOURCE->good()) { r->noMemory(); @@ -209,8 +209,8 @@ CInputMethodV2::CInputMethodV2(SP resource_) : resource(resou }); resource->setGrabKeyboard([this](CZwpInputMethodV2* r, uint32_t id) { - const auto RESOURCE = PROTO::ime->m_vGrabs.emplace_back( - std::make_shared(std::make_shared(r->client(), r->version(), id), self.lock())); + const auto RESOURCE = + PROTO::ime->m_vGrabs.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); if (!RESOURCE->good()) { r->noMemory(); @@ -364,7 +364,7 @@ void CInputMethodV2Protocol::destroyResource(CInputMethodV2* ime) { } void CInputMethodV2Protocol::onGetIME(CZwpInputMethodManagerV2* mgr, wl_resource* seat, uint32_t id) { - const auto RESOURCE = m_vIMEs.emplace_back(std::make_shared(std::make_shared(mgr->client(), mgr->version(), id))); + const auto RESOURCE = m_vIMEs.emplace_back(makeShared(makeShared(mgr->client(), mgr->version(), id))); if (!RESOURCE->good()) { mgr->noMemory(); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 18be636d..9ebcba07 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -18,7 +18,7 @@ COutputManager::COutputManager(SP resource_) : resource(re LOGM(LOG, "Creating new configuration"); const auto RESOURCE = PROTO::outputManagement->m_vConfigurations.emplace_back( - std::make_shared(std::make_shared(resource->client(), resource->version(), id), self.lock())); + makeShared(makeShared(resource->client(), resource->version(), id), self.lock())); if (!RESOURCE->good()) { resource->noMemory(); @@ -49,7 +49,7 @@ void COutputManager::makeAndSendNewHead(CMonitor* pMonitor) { return; const auto RESOURCE = - PROTO::outputManagement->m_vHeads.emplace_back(std::make_shared(std::make_shared(resource->client(), resource->version(), 0), pMonitor)); + PROTO::outputManagement->m_vHeads.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), pMonitor)); if (!RESOURCE->good()) { resource->noMemory(); @@ -205,8 +205,7 @@ void COutputHead::updateMode() { } void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) { - const auto RESOURCE = - PROTO::outputManagement->m_vModes.emplace_back(std::make_shared(std::make_shared(resource->client(), resource->version(), 0), mode)); + const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), mode)); if (!RESOURCE->good()) { resource->noMemory(); @@ -275,7 +274,7 @@ COutputConfiguration::COutputConfiguration(SP resour } const auto RESOURCE = PROTO::outputManagement->m_vConfigurationHeads.emplace_back( - std::make_shared(std::make_shared(resource->client(), resource->version(), id), PMONITOR)); + makeShared(makeShared(resource->client(), resource->version(), id), PMONITOR)); if (!RESOURCE->good()) { resource->noMemory(); @@ -326,7 +325,7 @@ COutputConfiguration::COutputConfiguration(SP resour else resource->sendFailed(); - owner.lock()->sendDone(); + owner->sendDone(); }); } @@ -359,8 +358,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { newRule.name = PMONITOR->szName; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = {head->state.mode.lock()->getMode()->width, head->state.mode.lock()->getMode()->height}; - newRule.refreshRate = head->state.mode.lock()->getMode()->refresh / 1000.F; + newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; + newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F; } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { newRule.resolution = head->state.customMode.size; newRule.refreshRate = head->state.customMode.refresh / 1000.F; @@ -539,7 +538,7 @@ COutputManagementProtocol::COutputManagementProtocol(const wl_interface* iface, } void COutputManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_shared(std::make_shared(client, ver, id))); + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); if (!RESOURCE->good()) { wl_client_post_no_memory(client); diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index fae1a131..db241048 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -69,7 +69,7 @@ void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uin } const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), PMONITOR)).get(); + const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), PMONITOR)).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index bcc515eb..95356430 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -246,7 +246,7 @@ void CPointerConstraintsProtocol::onLockPointer(CZwpPointerConstraintsV1* pMgr, zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - std::make_shared(std::make_shared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } @@ -255,7 +255,7 @@ void CPointerConstraintsProtocol::onConfinePointer(CZwpPointerConstraintsV1* pMg zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - std::make_shared(std::make_shared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index b3840093..5b5d1c52 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -71,7 +71,7 @@ void CPointerGesturesProtocol::onGestureDestroy(CPointerGestureHold* gesture) { void CPointerGesturesProtocol::onGetPinchGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vPinches.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vPinches.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -82,7 +82,7 @@ void CPointerGesturesProtocol::onGetPinchGesture(CZwpPointerGesturesV1* pMgr, ui void CPointerGesturesProtocol::onGetSwipeGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vSwipes.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vSwipes.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -93,7 +93,7 @@ void CPointerGesturesProtocol::onGetSwipeGesture(CZwpPointerGesturesV1* pMgr, ui void CPointerGesturesProtocol::onGetHoldGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vHolds.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vHolds.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index 0e50641e..c64687ee 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -47,7 +47,7 @@ void CRelativePointerProtocol::destroyRelativePointer(CRelativePointer* pointer) void CRelativePointerProtocol::onGetRelativePointer(CZwpRelativePointerManagerV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vRelativePointers.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vRelativePointers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 0acb4423..c39152d8 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -20,21 +20,21 @@ class CScreencopyClient { CScreencopyClient(); ~CScreencopyClient(); - int ref = 0; - wl_resource* resource = nullptr; + int ref = 0; + wl_resource* resource = nullptr; - eClientOwners clientOwner = CLIENT_SCREENCOPY; + eClientOwners clientOwner = CLIENT_SCREENCOPY; - int frameCounter = 0; - int framesInLastHalfSecond = 0; - CTimer lastMeasure; - CTimer lastFrame; - bool sentScreencast = false; + int frameCounter = 0; + int framesInLastHalfSecond = 0; + CTimer lastMeasure; + CTimer lastFrame; + bool sentScreencast = false; - void onTick(); - std::shared_ptr tickCallback; + void onTick(); + SP tickCallback; - bool operator==(const CScreencopyClient& other) const { + bool operator==(const CScreencopyClient& other) const { return resource == other.resource; } }; diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index 8d0e423b..d47467b3 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -42,8 +42,7 @@ void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperl void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vDecos.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))) - .get(); + m_vDecos.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 7ed66c97..19582be4 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -161,7 +161,7 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { LOGM(LOG, "New sessionLock with id {}", id); const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vLocks.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))); + const auto RESOURCE = m_vLocks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id))); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -195,8 +195,8 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id } } - const auto RESOURCE = m_vLockSurfaces.emplace_back( - std::make_unique(std::make_shared(lock->client(), lock->version(), id), PSURFACE, PMONITOR, sessionLock)); + const auto RESOURCE = + m_vLockSurfaces.emplace_back(makeShared(makeShared(lock->client(), lock->version(), id), PSURFACE, PMONITOR, sessionLock)); if (!RESOURCE->good()) { lock->noMemory(); diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index ffc74b53..af9724b5 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -58,7 +58,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa } const auto RESOURCE = - m_vInhibitors.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), surf)).get(); + m_vInhibitors.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), surf)).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index e0534735..df3126fe 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -22,7 +22,7 @@ void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { } void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf) { - const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique(std::make_shared(client, pMgr->version(), id), surf)).get(); + const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique(makeShared(client, pMgr->version(), id), surf)).get(); if (!CONTROLLER->good()) { pMgr->noMemory(); @@ -67,7 +67,7 @@ void CTearingControl::updateWindow() { if (pWindow.expired()) return; - pWindow.lock()->m_bTearingHint = hint == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; + pWindow->m_bTearingHint = hint == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; } bool CTearingControl::good() { diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index fbd4a745..233f5209 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -116,7 +116,7 @@ void CTextInputV3Protocol::destroyTextInput(CTextInputV3* input) { void CTextInputV3Protocol::onGetTextInput(CZwpTextInputManagerV3* pMgr, uint32_t id, wl_resource* seat) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vTextInputs.emplace_back(std::make_shared(std::make_shared(CLIENT, pMgr->version(), id))); + const auto RESOURCE = m_vTextInputs.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id))); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -125,5 +125,5 @@ void CTextInputV3Protocol::onGetTextInput(CZwpTextInputManagerV3* pMgr, uint32_t return; } - events.newTextInput.emit(std::weak_ptr(RESOURCE)); + events.newTextInput.emit(WP(RESOURCE)); } \ No newline at end of file diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index b708ad09..70f00fa1 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -369,7 +369,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times return false; // render the client - const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow.lock()->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10}; g_pHyprRenderer->makeEGLCurrent(); @@ -393,7 +393,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow.lock()->m_vRealPosition.value()); + g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); if (!PFORMAT) { @@ -426,7 +426,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times } bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow.lock()->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; @@ -440,7 +440,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow.lock()->m_vRealPosition.value()); + g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 1cc76447..3d67bd06 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -122,7 +122,7 @@ void CVirtualKeyboardProtocol::destroyResource(CVirtualKeyboardV1Resource* keeb) void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, wl_resource* seat, uint32_t id) { - const auto RESOURCE = m_vKeyboards.emplace_back(std::make_shared(std::make_shared(pMgr->client(), pMgr->version(), id))); + const auto RESOURCE = m_vKeyboards.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index cad8af67..1fb83888 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -151,7 +151,7 @@ void CVirtualPointerProtocol::destroyResource(CVirtualPointerV1Resource* pointer void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { - const auto RESOURCE = m_vPointers.emplace_back(std::make_shared(std::make_shared(pMgr->client(), pMgr->version(), id))); + const auto RESOURCE = m_vPointers.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 2e85c0a2..a4745cba 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -92,7 +92,7 @@ void CXDGActivationProtocol::destroyToken(CXDGActivationToken* token) { void CXDGActivationProtocol::onGetToken(CXdgActivationV1* pMgr, uint32_t id) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vTokens.emplace_back(std::make_unique(std::make_shared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vTokens.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index f4d19432..5a4cf68d 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -64,8 +64,7 @@ void CXDGDecorationProtocol::onGetDecoration(CZxdgDecorationManagerV1* pMgr, uin const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_mDecorations.emplace(xdgToplevel, std::make_unique(std::make_shared(CLIENT, pMgr->version(), id), xdgToplevel)) - .first->second.get(); + m_mDecorations.emplace(xdgToplevel, std::make_unique(makeShared(CLIENT, pMgr->version(), id), xdgToplevel)).first->second.get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 37ed990d..9d3e2ac9 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -53,7 +53,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 const auto CLIENT = mgr->client(); - CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(std::make_shared(CLIENT, mgr->version(), id), PMONITOR)).get(); + CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); #ifndef NO_XWAYLAND if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == CLIENT) pXDGOutput->isXWayland = true; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 31625b3b..cea49818 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -874,7 +874,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* } } - if (m_pCurrentWindow.lock() && m_pCurrentWindow.lock()->m_sAdditionalConfigData.forceRGBX) + if (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX) shader = &m_RenderData.pCurrentMonData->m_shRGBX; glActiveTexture(GL_TEXTURE0); @@ -943,7 +943,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* if (allowDim && m_pCurrentWindow.lock() && *PDIMINACTIVE) { glUniform1i(shader->applyTint, 1); - const auto DIM = m_pCurrentWindow.lock()->m_fDimPercent.value(); + const auto DIM = m_pCurrentWindow->m_fDimPercent.value(); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); } else { glUniform1i(shader->applyTint, 0); @@ -1494,7 +1494,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo m_RenderData.renderModif.applyToRegion(texDamage); if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || - (m_pCurrentWindow.lock() && (m_pCurrentWindow.lock()->m_sAdditionalConfigData.forceNoBlur || m_pCurrentWindow.lock()->m_sAdditionalConfigData.forceRGBX))) { + (m_pCurrentWindow.lock() && (m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur || m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX))) { renderTexture(tex, pBox, a, round, false, true); return; } @@ -1591,7 +1591,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in TRACY_GPU_ZONE("RenderBorder"); - if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow.lock()->m_sAdditionalConfigData.forceNoBorder)) + if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBorder)) return; CBox newBox = *box; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index f13d506b..bebf82bc 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -196,10 +196,10 @@ class CHyprOpenGLImpl { PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window PHLLS m_pCurrentLayer; // hack to get the current rendered layer - std::map> m_mWindowFramebuffers; - std::map> m_mLayerFramebuffers; - std::unordered_map m_mMonitorRenderResources; - std::unordered_map m_mMonitorBGFBs; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; + std::unordered_map m_mMonitorRenderResources; + std::unordered_map m_mMonitorBGFBs; struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7053adf7..7bd24de7 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -417,7 +417,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor continue; // render active window after all others of this pass - if (w == g_pCompositor->m_pLastWindow.lock()) { + if (w == g_pCompositor->m_pLastWindow) { lastWindow = w; continue; } @@ -740,12 +740,12 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon SRenderData renderdata = {pMonitor, time, pMonitor->vecPosition.x, pMonitor->vecPosition.y}; renderdata.blur = false; - renderdata.surface = pSurface->surface.lock()->surface(); + renderdata.surface = pSurface->surface->surface(); renderdata.decorate = false; renderdata.w = pMonitor->vecSize.x; renderdata.h = pMonitor->vecSize.y; - wlr_surface_for_each_surface(pSurface->surface.lock()->surface(), renderSurface, &renderdata); + wlr_surface_for_each_surface(pSurface->surface->surface(), renderSurface, &renderdata); } void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index c171a2b6..7d9a0401 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -11,7 +11,7 @@ CHyprBorderDecoration::~CHyprBorderDecoration() { } SDecorationPositioningInfo CHyprBorderDecoration::getPositioningInfo() { - const auto BORDERSIZE = m_pWindow.lock()->getRealBorderSize(); + const auto BORDERSIZE = m_pWindow->getRealBorderSize(); m_seExtents = {{BORDERSIZE, BORDERSIZE}, {BORDERSIZE, BORDERSIZE}}; if (doesntWantBorders()) @@ -36,12 +36,12 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { CBox box = m_bAssignedGeometry; box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_BOTTOM | DECORATION_EDGE_LEFT | DECORATION_EDGE_RIGHT | DECORATION_EDGE_TOP, m_pWindow.lock())); - const auto PWORKSPACE = m_pWindow.lock()->m_pWorkspace; + const auto PWORKSPACE = m_pWindow->m_pWorkspace; if (!PWORKSPACE) return box; - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow.lock()->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); + const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); return box.translate(WORKSPACEOFFSET); } @@ -52,29 +52,28 @@ void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a) { if (m_bAssignedGeometry.width < m_seExtents.topLeft.x + 1 || m_bAssignedGeometry.height < m_seExtents.topLeft.y + 1) return; - CBox windowBox = - assignedBoxGlobal().translate(-pMonitor->vecPosition + m_pWindow.lock()->m_vFloatingOffset).expand(-m_pWindow.lock()->getRealBorderSize()).scale(pMonitor->scale).round(); + CBox windowBox = assignedBoxGlobal().translate(-pMonitor->vecPosition + m_pWindow->m_vFloatingOffset).expand(-m_pWindow->getRealBorderSize()).scale(pMonitor->scale).round(); if (windowBox.width < 1 || windowBox.height < 1) return; - auto grad = m_pWindow.lock()->m_cRealBorderColor; - const bool ANIMATED = m_pWindow.lock()->m_fBorderFadeAnimationProgress.isBeingAnimated(); - float a1 = a * (ANIMATED ? m_pWindow.lock()->m_fBorderFadeAnimationProgress.value() : 1.f); + auto grad = m_pWindow->m_cRealBorderColor; + const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated(); + float a1 = a * (ANIMATED ? m_pWindow->m_fBorderFadeAnimationProgress.value() : 1.f); - if (m_pWindow.lock()->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) { - grad.m_fAngle += m_pWindow.lock()->m_fBorderAngleAnimationProgress.value() * M_PI * 2; + if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) { + grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.value() * M_PI * 2; grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); } - int borderSize = m_pWindow.lock()->getRealBorderSize(); - const auto ROUNDING = m_pWindow.lock()->rounding() * pMonitor->scale; + int borderSize = m_pWindow->getRealBorderSize(); + const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a1); if (ANIMATED) { - float a2 = a * (1.f - m_pWindow.lock()->m_fBorderFadeAnimationProgress.value()); - g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow.lock()->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2); + float a2 = a * (1.f - m_pWindow->m_fBorderFadeAnimationProgress.value()); + g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2); } } @@ -83,7 +82,7 @@ eDecorationType CHyprBorderDecoration::getDecorationType() { } void CHyprBorderDecoration::updateWindow(PHLWINDOW) { - if (m_pWindow.lock()->getRealBorderSize() != m_seExtents.topLeft.x) + if (m_pWindow->getRealBorderSize() != m_seExtents.topLeft.x) g_pDecorationPositioner->repositionDeco(this); } @@ -91,15 +90,15 @@ void CHyprBorderDecoration::damageEntire() { if (!validMapped(m_pWindow)) return; - auto surfaceBox = m_pWindow.lock()->getWindowMainSurfaceBox(); - const auto ROUNDING = m_pWindow.lock()->rounding(); + auto surfaceBox = m_pWindow->getWindowMainSurfaceBox(); + const auto ROUNDING = m_pWindow->rounding(); const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 2; - const auto BORDERSIZE = m_pWindow.lock()->getRealBorderSize() + 1; + const auto BORDERSIZE = m_pWindow->getRealBorderSize() + 1; - const auto PWINDOWWORKSPACE = m_pWindow.lock()->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow.lock()->m_bPinned) + const auto PWINDOWWORKSPACE = m_pWindow->m_pWorkspace; + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); - surfaceBox.translate(m_pWindow.lock()->m_vFloatingOffset); + surfaceBox.translate(m_pWindow->m_vFloatingOffset); CBox surfaceBoxExpandedBorder = surfaceBox; surfaceBoxExpandedBorder.expand(BORDERSIZE); @@ -134,5 +133,5 @@ std::string CHyprBorderDecoration::getDisplayName() { } bool CHyprBorderDecoration::doesntWantBorders() { - return !m_pWindow.lock()->m_sSpecialRenderData.border || m_pWindow.lock()->m_bX11DoesntWantBorders || m_pWindow.lock()->getRealBorderSize() == 0; + return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders || m_pWindow->getRealBorderSize() == 0; } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index ee1e713a..e854d63a 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -39,7 +39,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { info.priority = *PPRIORITY; info.reserved = true; - if (*PENABLED && m_pWindow.lock()->m_sSpecialRenderData.decorate) + if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate) info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; else info.desiredExtents = {{0, 0}, {0, 0}}; @@ -58,8 +58,8 @@ eDecorationType CHyprGroupBarDecoration::getDecorationType() { // void CHyprGroupBarDecoration::updateWindow(PHLWINDOW pWindow) { - if (m_pWindow.lock()->m_sGroupData.pNextWindow.expired()) { - m_pWindow.lock()->removeWindowDeco(this); + if (m_pWindow->m_sGroupData.pNextWindow.expired()) { + m_pWindow->removeWindowDeco(this); return; } @@ -76,14 +76,14 @@ void CHyprGroupBarDecoration::updateWindow(PHLWINDOW pWindow) { damageEntire(); if (m_dwGroupMembers.size() == 0) { - m_pWindow.lock()->removeWindowDeco(this); + m_pWindow->removeWindowDeco(this); return; } } void CHyprGroupBarDecoration::damageEntire() { auto box = assignedBoxGlobal(); - box.translate(m_pWindow.lock()->m_vFloatingOffset); + box.translate(m_pWindow->m_vFloatingOffset); g_pHyprRenderer->damageBox(&box); } @@ -97,7 +97,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { static auto PHEIGHT = CConfigValue("group:groupbar:height"); static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); - if (!*PENABLED || !m_pWindow.lock()->m_sSpecialRenderData.decorate) + if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate) return; const auto ASSIGNEDBOX = assignedBoxGlobal(); @@ -111,8 +111,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { int xoff = 0; for (int i = 0; i < barsToDraw; ++i) { - CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow.lock()->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow.lock()->m_vFloatingOffset.y, m_fBarWidth, + CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) @@ -129,7 +129,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - const bool GROUPLOCKED = m_pWindow.lock()->getGroupHead()->m_sGroupData.locked; + const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked; const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; @@ -137,8 +137,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); - rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow.lock()->m_vFloatingOffset.x, - ASSIGNEDBOX.y - pMonitor->vecPosition.y + m_pWindow.lock()->m_vFloatingOffset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, + rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2}; rect.scale(pMonitor->scale); @@ -150,7 +150,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { } if (*PRENDERTITLES) { - CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i].lock()->m_szTitle); + CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); if (!pTitleTex) pTitleTex = m_sTitleTexs.titleTexs @@ -335,7 +335,7 @@ void refreshGroupBarGradients() { } bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { - if (m_pWindow.lock() == m_pWindow.lock()->m_sGroupData.pNextWindow.lock()) + if (m_pWindow.lock() == m_pWindow->m_sGroupData.pNextWindow.lock()) return false; const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; @@ -344,7 +344,7 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) return false; - PHLWINDOW pWindow = m_pWindow.lock()->getGroupWindowByIndex(WINDOWINDEX); + PHLWINDOW pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); // hack g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); @@ -370,7 +370,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND const float BARRELATIVEX = pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); - PHLWINDOW pWindowInsertAfter = m_pWindow.lock()->getGroupWindowByIndex(WINDOWINDEX); + PHLWINDOW pWindowInsertAfter = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); PHLWINDOW pWindowInsertEnd = pWindowInsertAfter->m_sGroupData.pNextWindow.lock(); PHLWINDOW pDraggedHead = pDraggedWindow->m_sGroupData.pNextWindow.lock() ? pDraggedWindow->getGroupHead() : pDraggedWindow; @@ -411,7 +411,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND if (WINDOWINDEX == -1) std::swap(pDraggedHead->m_sGroupData.head, pWindowInsertEnd->m_sGroupData.head); - m_pWindow.lock()->setGroupCurrent(pDraggedWindow); + m_pWindow->setGroupCurrent(pDraggedWindow); pDraggedWindow->applyGroupRules(); pDraggedWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); @@ -423,7 +423,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND } bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) { - if (m_pWindow.lock()->m_bIsFullscreen && m_pWindow.lock()->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) + if (m_pWindow->m_bIsFullscreen && m_pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) return true; const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; @@ -437,7 +437,7 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) pressedCursorPos = pos; else if (e->state == WL_POINTER_BUTTON_STATE_RELEASED && pressedCursorPos == pos) - g_pXWaylandManager->sendCloseWindow(m_pWindow.lock()->getGroupWindowByIndex(WINDOWINDEX)); + g_pXWaylandManager->sendCloseWindow(m_pWindow->getGroupWindowByIndex(WINDOWINDEX)); return true; } @@ -452,9 +452,9 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point return true; } - PHLWINDOW pWindow = m_pWindow.lock()->getGroupWindowByIndex(WINDOWINDEX); + PHLWINDOW pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); - if (pWindow != m_pWindow.lock()) + if (pWindow != m_pWindow) pWindow->setGroupCurrent(pWindow); if (!g_pCompositor->isWindowActive(pWindow) && *PFOLLOWMOUSE != 3) @@ -469,13 +469,13 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, wlr_pointer_axis_event* e) { static auto PGROUPBARSCROLLING = CConfigValue("group:groupbar:scrolling"); - if (!*PGROUPBARSCROLLING || m_pWindow.lock()->m_sGroupData.pNextWindow.expired()) + if (!*PGROUPBARSCROLLING || m_pWindow->m_sGroupData.pNextWindow.expired()) return false; if (e->delta > 0) - m_pWindow.lock()->setGroupCurrent(m_pWindow.lock()->m_sGroupData.pNextWindow.lock()); + m_pWindow->setGroupCurrent(m_pWindow->m_sGroupData.pNextWindow.lock()); else - m_pWindow.lock()->setGroupCurrent(m_pWindow.lock()->getGroupPrevious()); + m_pWindow->setGroupCurrent(m_pWindow->getGroupPrevious()); return true; } @@ -506,9 +506,9 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() { CBox box = m_bAssignedBox; box.translate(g_pDecorationPositioner->getEdgeDefinedPoint(DECORATION_EDGE_TOP, m_pWindow.lock())); - const auto PWORKSPACE = m_pWindow.lock()->m_pWorkspace; + const auto PWORKSPACE = m_pWindow->m_pWorkspace; - if (PWORKSPACE && !m_pWindow.lock()->m_bPinned) + if (PWORKSPACE && !m_pWindow->m_bPinned) box.translate(PWORKSPACE->m_vRenderOffset.value()); return box; diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 39aacd81..d46af035 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -85,12 +85,17 @@ CDecorationPositioner::SWindowPositioningData* CDecorationPositioner::getDataFor } void CDecorationPositioner::sanitizeDatas() { - std::erase_if(m_mWindowDatas, [](const auto& other) { return !valid(other.first); }); + std::erase_if(m_mWindowDatas, [](const auto& other) { + if (!valid(other.first)) + return true; + + return false; + }); std::erase_if(m_vWindowPositioningDatas, [](const auto& other) { if (!validMapped(other->pWindow)) return true; - if (std::find_if(other->pWindow.lock()->m_dWindowDecorations.begin(), other->pWindow.lock()->m_dWindowDecorations.end(), - [&](const auto& el) { return el.get() == other->pDecoration; }) == other->pWindow.lock()->m_dWindowDecorations.end()) + if (std::find_if(other->pWindow->m_dWindowDecorations.begin(), other->pWindow->m_dWindowDecorations.end(), + [&](const auto& el) { return el.get() == other->pDecoration; }) == other->pWindow->m_dWindowDecorations.end()) return true; return false; }); @@ -302,7 +307,7 @@ SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(PHLWI CBox decoBox; if (data->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { - decoBox = data->pWindow.lock()->getWindowMainSurfaceBox(); + decoBox = data->pWindow->getWindowMainSurfaceBox(); decoBox.addExtents(data->positioningInfo.desiredExtents); } else { decoBox = data->lastReply.assignedGeometry; @@ -340,7 +345,7 @@ CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { CBox decoBox; if (data->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { - decoBox = data->pWindow.lock()->getWindowMainSurfaceBox(); + decoBox = data->pWindow->getWindowMainSurfaceBox(); decoBox.addExtents(data->positioningInfo.desiredExtents); } else { decoBox = data->lastReply.assignedGeometry; diff --git a/src/render/decorations/DecorationPositioner.hpp b/src/render/decorations/DecorationPositioner.hpp index b99891b6..880dc3f8 100644 --- a/src/render/decorations/DecorationPositioner.hpp +++ b/src/render/decorations/DecorationPositioner.hpp @@ -1,17 +1,14 @@ #pragma once #include -#include #include #include #include "../../helpers/Box.hpp" +#include "../../desktop/DesktopTypes.hpp" class CWindow; class IHyprWindowDecoration; -typedef std::shared_ptr PHLWINDOW; -typedef std::weak_ptr PHLWINDOWREF; - enum eDecorationPositioningPolicy { DECORATION_POSITION_ABSOLUTE = 0, /* Decoration wants absolute positioning */ DECORATION_POSITION_STICKY, /* Decoration is stuck to some edge of a window */ @@ -90,13 +87,13 @@ class CDecorationPositioner { bool needsRecalc = false; }; - std::map> m_mWindowDatas; - std::vector> m_vWindowPositioningDatas; + std::map m_mWindowDatas; + std::vector> m_vWindowPositioningDatas; - SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow); - void onWindowUnmap(PHLWINDOW pWindow); - void onWindowMap(PHLWINDOW pWindow); - void sanitizeDatas(); + SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow); + void onWindowUnmap(PHLWINDOW pWindow); + void onWindowMap(PHLWINDOW pWindow); + void sanitizeDatas(); }; inline std::unique_ptr g_pDecorationPositioner; \ No newline at end of file From c7fbc30bfd64b2104006fef291f4c4bff537beb2 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 5 May 2024 20:34:13 +0300 Subject: [PATCH 0010/2393] Nix: add missing deps CMake used to warn about these deps so I've added them. Also propagates wlroots' nativeBuildInputs. --- nix/default.nix | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index e9d81fd7..4ab9c19d 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -10,6 +10,7 @@ binutils, cairo, expat, + fribidi, git, hyprcursor, hyprland-protocols, @@ -17,14 +18,19 @@ hyprwayland-scanner, jq, libGL, + libdatrie, libdrm, libexecinfo, libinput, + libselinux, + libsepol, + libthai, libuuid, libxkbcommon, mesa, pango, pciutils, + pcre2, python3, systemd, tomlplusplus, @@ -70,28 +76,31 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov # Generate version.h cp src/version.h.in src/version.h substituteInPlace src/version.h \ - --replace "@HASH@" '${commit}' \ - --replace "@BRANCH@" "" \ - --replace "@MESSAGE@" "" \ - --replace "@DATE@" "${date}" \ - --replace "@TAG@" "" \ - --replace "@DIRTY@" '${ + --replace-warn "@HASH@" '${commit}' \ + --replace-warn "@BRANCH@" "" \ + --replace-warn "@MESSAGE@" "" \ + --replace-warn "@DATE@" "${date}" \ + --replace-warn "@TAG@" "" \ + --replace-warn "@DIRTY@" '${ if commit == "" then "dirty" else "" }' ''; - nativeBuildInputs = [ - hyprwayland-scanner - jq - makeWrapper - cmake - meson - ninja - pkg-config - python3 - wayland-scanner + nativeBuildInputs = lib.concatLists [ + [ + hyprwayland-scanner + jq + makeWrapper + cmake + ninja + pkg-config + python3 + wayland-scanner + ] + # introduce this later so that cmake takes precedence + wlroots.nativeBuildInputs ]; outputs = [ @@ -106,18 +115,24 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov [ cairo expat + fribidi git hyprcursor.dev hyprland-protocols hyprlang - libdrm libGL + libdrm + libdatrie libinput + libselinux + libsepol + libthai libuuid libxkbcommon mesa pango pciutils + pcre2 tomlplusplus wayland wayland-protocols From cddeec47a1fc0e70d8598fd10c29cd0e9489999f Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sun, 5 May 2024 13:28:14 -0500 Subject: [PATCH 0011/2393] keybinds: make the keybind manager check for session lock (#5894) --- src/managers/KeybindManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 16b631c8..6eadfd99 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -557,6 +557,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi const bool IGNORECONDITIONS = SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. + if (!k.locked && g_pSessionLockManager->isSessionLocked()) + continue; + if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) continue; From a8a04c746b07fe80bb852bb42473d58868d3b294 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 6 May 2024 02:24:11 +0100 Subject: [PATCH 0012/2393] renderer: deny solitary during a session lock closes #5906 fixes #5899 --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7bd24de7..ee874589 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2488,7 +2488,7 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient.reset(); // reset it, if we find one it will be set. - if (g_pHyprNotificationOverlay->hasAny()) + if (g_pHyprNotificationOverlay->hasAny() || g_pSessionLockManager->isSessionLocked()) return; const auto PWORKSPACE = pMonitor->activeWorkspace; From 05e4a3f1a89ec2defb1d77a223a9ce94e75fc76e Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Mon, 6 May 2024 07:32:01 -0700 Subject: [PATCH 0013/2393] windows: Revert "window: set config only when both props end anims" (#5904) This reverts commit 7617c03dfd0073654ca8c4d9a6f5db278d14cd28, fixing a bug that caused the bottom right corner of windows to animate oddly. --- src/events/Windows.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index db4e0985..8643a539 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -36,10 +36,10 @@ void setAnimToMove(void* data) { CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data; - if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) { - animvar->setConfig(PANIMCFG); + animvar->setConfig(PANIMCFG); + + if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) animvar->getWindow()->m_bAnimatingIn = false; - } } void Events::listener_mapWindow(void* owner, void* data) { From fa69de8ab6cc17bb763a1586c55847c5d5a82a83 Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Mon, 6 May 2024 12:19:26 -0400 Subject: [PATCH 0014/2393] pointer-constraints: Remove unnecessary cursor warps (#5895) modified: src/protocols/PointerConstraints.cpp Co-authored-by: Agent_00Ming --- src/protocols/PointerConstraints.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 95356430..7b5729c0 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -110,9 +110,6 @@ void CPointerConstraint::deactivate() { active = false; - if (locked) - g_pCompositor->warpCursorTo(logicPositionHint(), true); - if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT) { dead = true; // remove from inputmgr @@ -134,9 +131,6 @@ void CPointerConstraint::activate() { wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, pHLSurface->wlr(), LOCAL.x, LOCAL.y); } - if (locked) - g_pCompositor->warpCursorTo(logicPositionHint(), true); - if (locked) resourceL->sendLocked(); else From 0c446ec5f4c39599ea97cb703dd3ac7718fb9169 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 6 May 2024 21:36:31 +0100 Subject: [PATCH 0015/2393] memory: fix SP/WP hierarchy templates --- src/helpers/memory/SharedPtr.hpp | 16 +++++++++------- src/helpers/memory/WeakPtr.hpp | 18 ++++++++++-------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp index ff9b4a45..77f5164a 100644 --- a/src/helpers/memory/SharedPtr.hpp +++ b/src/helpers/memory/SharedPtr.hpp @@ -122,7 +122,9 @@ template class CSharedPointer { public: template - using validHierarchy = typename std::enable_if::value>; + using validHierarchy = typename std::enable_if&, X>::value, CSharedPointer&>::type; + template + using isConstructible = typename std::enable_if::value>::type; /* creates a new shared pointer managing a resource avoid calling. Could duplicate ownership. Prefer makeShared */ @@ -132,7 +134,7 @@ class CSharedPointer { } /* creates a shared pointer from a reference */ - template > + template > CSharedPointer(const CSharedPointer& ref) noexcept { impl_ = ref.impl_; increment(); @@ -143,7 +145,7 @@ class CSharedPointer { increment(); } - template > + template > CSharedPointer(CSharedPointer&& ref) noexcept { std::swap(impl_, ref.impl_); } @@ -178,8 +180,8 @@ class CSharedPointer { decrement(); } - template > - CSharedPointer& operator=(const CSharedPointer& rhs) { + template + validHierarchy&> operator=(const CSharedPointer& rhs) { if (impl_ == rhs.impl_) return *this; @@ -199,8 +201,8 @@ class CSharedPointer { return *this; } - template > - CSharedPointer& operator=(CSharedPointer&& rhs) { + template + validHierarchy&> operator=(CSharedPointer&& rhs) { std::swap(impl_, rhs.impl_); return *this; } diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp index 677fddf4..f0e72146 100644 --- a/src/helpers/memory/WeakPtr.hpp +++ b/src/helpers/memory/WeakPtr.hpp @@ -14,10 +14,12 @@ template class CWeakPointer { public: template - using validHierarchy = typename std::enable_if::value>; + using validHierarchy = typename std::enable_if&, X>::value, CWeakPointer&>::type; + template + using isConstructible = typename std::enable_if::value>::type; /* create a weak ptr from a reference */ - template > + template > CWeakPointer(const CSharedPointer& ref) noexcept { if (!ref.impl_) return; @@ -27,7 +29,7 @@ class CWeakPointer { } /* create a weak ptr from another weak ptr */ - template > + template > CWeakPointer(const CWeakPointer& ref) noexcept { if (!ref.impl_) return; @@ -44,7 +46,7 @@ class CWeakPointer { incrementWeak(); } - template > + template > CWeakPointer(CWeakPointer&& ref) noexcept { std::swap(impl_, ref.impl_); } @@ -54,8 +56,8 @@ class CWeakPointer { } /* create a weak ptr from another weak ptr with assignment */ - template > - CWeakPointer& operator=(const CWeakPointer& rhs) { + template + validHierarchy&> operator=(const CWeakPointer& rhs) { if (impl_ == rhs.impl_) return *this; @@ -76,8 +78,8 @@ class CWeakPointer { } /* create a weak ptr from a shared ptr with assignment */ - template > - CWeakPointer& operator=(const CSharedPointer& rhs) { + template + validHierarchy&> operator=(const CSharedPointer& rhs) { if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) return *this; From 57e76f91d9a388a41223e5ac0f13863d4b663bcd Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 7 May 2024 01:20:06 -0500 Subject: [PATCH 0016/2393] keybinds: fix xkb keybind name to keysym comparison (#5917) --- src/managers/KeybindManager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 6eadfd99..ce518ea6 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -576,9 +576,10 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi } else { // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs - const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); + const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); - if (KBKEY == 0) { + if (KBKEY == 0 && KBKEYLOWER == 0) { // Keysym failed to resolve from the key name of the currently iterated bind. // This happens for names such as `switch:off:Lid Switch` as well as some keys // (such as yen and ro). @@ -589,9 +590,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi continue; } - const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - - if (key.keysym != KBKEY && key.keysym != KBKEYUPPER) + if (key.keysym != KBKEY && key.keysym != KBKEYLOWER) continue; } From 0acad88c3c837840b01e1b61069a1a7e95944607 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 11:48:02 +0100 Subject: [PATCH 0017/2393] foreign-toplevel-wlr: send current class and title on map fixes #5910 --- src/protocols/ForeignToplevelWlr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 25c4579f..38d7a38d 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -196,8 +196,8 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { LOGM(LOG, "Newly mapped window {:016x}", (uintptr_t)pWindow.get()); resource->sendToplevel(NEWHANDLE->resource.get()); - NEWHANDLE->resource->sendAppId(pWindow->m_szInitialClass.c_str()); - NEWHANDLE->resource->sendTitle(pWindow->m_szInitialTitle.c_str()); + NEWHANDLE->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); + NEWHANDLE->resource->sendTitle(pWindow->m_szTitle.c_str()); if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) NEWHANDLE->sendMonitor(PMONITOR); NEWHANDLE->sendState(); From 96365309de49b5641e61b0028199382dcc25f8b2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 11:53:29 +0100 Subject: [PATCH 0018/2393] deco-positioner: avoid infinite recalcs fixes #5908 --- src/render/decorations/DecorationPositioner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index d46af035..17f6d913 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -271,8 +271,10 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { } } - WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}; - g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); + if (WINDOWDATA->extents != SWindowDecorationExtents{{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}) { + WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}; + g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); + } } void CDecorationPositioner::onWindowUnmap(PHLWINDOW pWindow) { From 375e77e398b3d69ca90ed58420b929523576c6ef Mon Sep 17 00:00:00 2001 From: VPavliashvili Date: Tue, 7 May 2024 15:00:55 +0400 Subject: [PATCH 0019/2393] ipc: add togglegroup, moveintogroup and moveoutofgroup events (#5866) --- src/desktop/Window.cpp | 11 +++++++++++ src/managers/KeybindManager.cpp | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b92a3d9d..b4af12f1 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -836,6 +836,8 @@ void CWindow::createGroup() { g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)}); } } @@ -852,9 +854,12 @@ void CWindow::destroyGroup() { g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)}); return; } + std::string addresses; PHLWINDOW curr = m_pSelf.lock(); std::vector members; do { @@ -863,6 +868,8 @@ void CWindow::destroyGroup() { PLASTWIN->m_sGroupData.pNextWindow.reset(); curr->setHidden(false); members.push_back(curr); + + addresses += std::format("{:x},", (uintptr_t)curr.get()); } while (curr.get() != this); for (auto& w : members) { @@ -883,6 +890,10 @@ void CWindow::destroyGroup() { g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + if (!addresses.empty()) + addresses.pop_back(); + g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{}", addresses)}); } PHLWINDOW CWindow::getGroupHead() { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ce518ea6..c52fda17 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2237,6 +2237,8 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) pWindow->addWindowDeco(std::make_unique(pWindow)); + + g_pEventManager->postEvent(SHyprIPCEvent{"moveintogroup", std::format("{:x}", (uintptr_t)pWindow.get())}); } void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir) { @@ -2274,6 +2276,8 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& g_pCompositor->focusWindow(PWINDOWPREV); g_pCompositor->warpCursorTo(PWINDOWPREV->middle()); } + + g_pEventManager->postEvent(SHyprIPCEvent{"moveoutofgroup", std::format("{:x}", (uintptr_t)pWindow.get())}); } void CKeybindManager::moveIntoGroup(std::string args) { From 2bcc8d303f889432171c5113af5f2962858099a4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 13:30:31 +0100 Subject: [PATCH 0020/2393] eventloop: don't call lost timers --- src/managers/eventLoop/EventLoopManager.cpp | 4 +++- src/managers/eventLoop/EventLoopManager.hpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index c78bc551..5910e71a 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -31,7 +31,7 @@ void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoo void CEventLoopManager::onTimerFire() { for (auto& t : m_sTimers.timers) { - if (t->passed() && !t->cancelled()) + if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled()) t->call(t); } @@ -62,6 +62,8 @@ static void timespecAddNs(timespec* pTimespec, int64_t delta) { } void CEventLoopManager::nudgeTimers() { + // remove timers that have gone missing + std::erase_if(m_sTimers.timers, [](const auto& t) { return t.strongRef() <= 1; }); long nextTimerUs = 10 * 1000 * 1000; // 10s diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 13d74571..f2ba61a4 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -12,6 +12,8 @@ class CEventLoopManager { CEventLoopManager(); void enterLoop(wl_display* display, wl_event_loop* wlEventLoop); + + // Note: will remove the timer if the ptr is lost. void addTimer(SP timer); void removeTimer(SP timer); From ec092bd601d9d351ff6ca34bd97f12055b2a4dd9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 14:26:26 +0100 Subject: [PATCH 0021/2393] core: chase hyprwayland-scanner --- flake.lock | 6 +++--- src/protocols/OutputManagement.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/flake.lock b/flake.lock index 976553d3..4dc7da82 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1714755542, - "narHash": "sha256-D0pg+ZRwrt4lavZ97Ca8clsgbPA3duLj8iEM7riaIFY=", + "lastModified": 1715088365, + "narHash": "sha256-cVH43+fiiCXqr6F2vUA8KmNI9ytWIQoZGnVz0IpBbZw=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "1270ebaa539e56d61b708c24b072b09cbbd3a828", + "rev": "6119dc2a965fd30ffa45c50a8398d5da3150df4c", "type": "github" }, "original": { diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 9ebcba07..e7779726 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -166,7 +166,7 @@ void COutputHead::sendAllData() { LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); - resource->sendCurrentMode(m->resource->resource()); + resource->sendCurrentMode(m->resource.get()); break; } } @@ -197,7 +197,7 @@ void COutputHead::updateMode() { LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); - resource->sendCurrentMode(m->resource->resource()); + resource->sendCurrentMode(m->resource.get()); break; } } From 6ccc22194ca2d16bd7dc4b7263f897a547c50e6b Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 7 May 2024 10:07:50 -0500 Subject: [PATCH 0022/2393] xkb: check value correctly with xkb_state_layout_index_is_active() (#5925) --- src/debug/HyprCtl.cpp | 2 +- src/devices/IKeyboard.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6382e899..d6e8608f 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1084,7 +1084,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap); xkb_layout_index_t activeLayout = 0; while (activeLayout < LAYOUTS) { - if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE)) + if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) break; activeLayout++; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 61b078fb..61c78f5b 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -36,7 +36,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { - if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) { + if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from an active index {}", (uintptr_t)this, i); CVarList keyboardLayouts(currentRules.layout, 0, ','); @@ -103,7 +103,7 @@ std::string IKeyboard::getActiveLayout() { const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { - if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE)) { + if (xkb_state_layout_index_is_active(STATE, i, XKB_STATE_LAYOUT_EFFECTIVE) == 1) { const auto LAYOUTNAME = xkb_keymap_layout_get_name(KEYMAP, i); if (LAYOUTNAME) From 598bbd186b1e6e70a01ba7f98c89404531008f15 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 16:50:30 +0100 Subject: [PATCH 0023/2393] window: avoid uaf on updateWindow decos TODO, make these pointers SP to avoid this in the future. fixes #5909 --- src/desktop/Window.cpp | 2 ++ src/desktop/Window.hpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b4af12f1..00066b27 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -211,6 +211,8 @@ void CWindow::updateWindowDecos() { } for (auto& wd : decos) { + if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end()) + continue; wd->updateWindow(m_pSelf.lock()); } } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index dd361c30..40e5db49 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -332,6 +332,7 @@ class CWindow { PHLWINDOWREF m_pLastCycledWindow; // Window decorations + // TODO: make this a SP. std::deque> m_dWindowDecorations; std::vector m_vDecosToRemove; From 22a86fd7a287e16522bef80d4a89f399ce654cc3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 18:42:55 +0100 Subject: [PATCH 0024/2393] session-lock: don't allow events from rejected locks fixes #5913 --- src/managers/SessionLockManager.cpp | 1 + src/protocols/SessionLock.cpp | 12 +++++++++++- src/protocols/SessionLock.hpp | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 6dd096bb..fd4841f4 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -43,6 +43,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { if (PROTO::sessionLock->isLocked() && !*PALLOWRELOCK) { Debug::log(LOG, "Cannot re-lock, misc:allow_session_lock_restore is disabled"); + pLock->sendDenied(); return; } diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 19582be4..db3404be 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -113,6 +113,11 @@ CSessionLock::CSessionLock(SP resource_) : resource(resource_ }); resource->setUnlockAndDestroy([this](CExtSessionLockV1* r) { + if (inert) { + PROTO::sessionLock->destroyResource(this); + return; + } + events.unlockAndDestroy.emit(); inert = true; PROTO::sessionLock->locked = false; @@ -132,6 +137,11 @@ bool CSessionLock::good() { return resource->resource(); } +void CSessionLock::sendDenied() { + inert = true; + resource->sendFinished(); +} + CSessionLockProtocol::CSessionLockProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -171,8 +181,8 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { if (m_vLocks.size() > 1) { LOGM(ERR, "Tried to lock a locked session"); - RESOURCE->resource->sendFinished(); RESOURCE->inert = true; + RESOURCE->resource->sendFinished(); return; } diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp index b5d7aed5..6b0c4e08 100644 --- a/src/protocols/SessionLock.hpp +++ b/src/protocols/SessionLock.hpp @@ -52,6 +52,7 @@ class CSessionLock { bool good(); void sendLocked(); + void sendDenied(); struct { CSignal newLockSurface; // SP From 601210878dc5d05f195753dccf0cafa3187c6ad6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 7 May 2024 19:53:15 +0100 Subject: [PATCH 0025/2393] cmake: bump hw-s required ver to 0.3.5 --- CMakeLists.txt | 2 +- flake.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef077d8b..f491e100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.4 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.5 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") diff --git a/flake.lock b/flake.lock index 4dc7da82..39d7fbdd 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715088365, - "narHash": "sha256-cVH43+fiiCXqr6F2vUA8KmNI9ytWIQoZGnVz0IpBbZw=", + "lastModified": 1715090986, + "narHash": "sha256-FXpQvmS9R7alwZ47XK5UIcAbC9YKSxc0+GOVYqwa0jM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "6119dc2a965fd30ffa45c50a8398d5da3150df4c", + "rev": "94e32ec37e7215b16d5c1b41b1773ff6742e704b", "type": "github" }, "original": { From 57a12476deef1b3e9967896cd8b3676131193865 Mon Sep 17 00:00:00 2001 From: Username404-59 <53659497+Username404-59@users.noreply.github.com> Date: Wed, 8 May 2024 00:13:58 +0200 Subject: [PATCH 0026/2393] internal: Add missing errno.h include to SdDaemon.cpp (#5938) Fixes clang --- src/helpers/SdDaemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 0835637a..d5df3121 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include From 5e7925eaeba474cfc283e26b7aa3426ec97424f7 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 8 May 2024 01:31:16 +0100 Subject: [PATCH 0027/2393] foreign-toplevel: bypass no activate focus checks ref #5939 those are used by focus switchers so they should bypass stuff like focus_on_activate = false --- src/desktop/Window.cpp | 4 ++-- src/desktop/Window.hpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 00066b27..e9e50a56 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1274,7 +1274,7 @@ std::unordered_map CWindow::getEnv() { return results; } -void CWindow::activate() { +void CWindow::activate(bool force) { static auto PFOCUSONACTIVATE = CConfigValue("misc:focus_on_activate"); g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)this)}); @@ -1282,7 +1282,7 @@ void CWindow::activate() { m_bIsUrgent = true; - if (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE)) + if (!force && (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) return; if (m_bIsFloating) diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 40e5db49..ed79c896 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -422,7 +422,7 @@ class CWindow { bool visibleOnMonitor(CMonitor* pMonitor); int workspaceID(); bool onSpecialWorkspace(); - void activate(); + void activate(bool force = false); int getRealBorderSize(); void updateSpecialRenderData(); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 38d7a38d..1762ad2a 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -17,10 +17,9 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPm_eSuppressedEvents & SUPPRESS_ACTIVATE) - return; - - PWINDOW->activate(); + // these requests bypass the config'd stuff cuz it's usually like + // window switchers and shit + PWINDOW->activate(true); }); resource->setSetFullscreen([this](CZwlrForeignToplevelHandleV1* p, wl_resource* output) { From 70b5e6df70a7eac180e2c8e9c2bce70ff43b45ad Mon Sep 17 00:00:00 2001 From: giskard Date: Wed, 8 May 2024 11:57:47 +0800 Subject: [PATCH 0028/2393] meson: require hyprwayland-scanner >= 0.3.5 --- protocols/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/meson.build b/protocols/meson.build index f6c54d4d..4c315797 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -17,7 +17,7 @@ wayland_scanner = find_program( wayland_scanner_dep.get_variable('wayland_scanner'), native: true, ) -hyprwayland_scanner_dep = dependency('hyprwayland-scanner', native: true) +hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.5', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, From 36d32973ddc1bd1d4096ec36f3b8cb507009eba4 Mon Sep 17 00:00:00 2001 From: William Gray Date: Wed, 8 May 2024 07:30:20 -0500 Subject: [PATCH 0029/2393] keybinds: add empty on monitor and next empty flags (#5936) * empty on monitor * add flag for next empty * clang-format changes * next also uses m_pLastMonitor --- src/helpers/MiscFunctions.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index f9bb5b46..4855553a 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -282,10 +282,18 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { } outName = WORKSPACENAME; } else if (in.starts_with("empty")) { - int id = 0; + const bool same_mon = in.substr(5).contains("m"); + const bool next = in.substr(5).contains("n"); + if (same_mon || next) { + if (!g_pCompositor->m_pLastMonitor) { + Debug::log(ERR, "Empty monitor workspace on monitor null!"); + return WORKSPACE_INVALID; + } + } + int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; while (++id < INT_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); - if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0)) + if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0 && (!same_mon || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID))) return id; } } else if (in.starts_with("prev")) { From d1ad490cdaaa97d5df83d28e86f02c96107ba142 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 8 May 2024 15:24:02 +0100 Subject: [PATCH 0030/2393] cmake: fix .pc file inputs (#5946) --- hyprland.pc.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hyprland.pc.in b/hyprland.pc.in index 45e9c604..6484b95f 100644 --- a/hyprland.pc.in +++ b/hyprland.pc.in @@ -1,8 +1,7 @@ -prefix=@PREFIX@ -includedir=@INCLUDEDIR@ +prefix=@PREFIX@/@INCLUDEDIR@ Name: Hyprland URL: https://github.com/hyprwm/Hyprland Description: Hyprland header files Version: @HYPRLAND_VERSION@ -Cflags: -I${includedir} -I${includedir}/hyprland/protocols -I${includedir}/hyprland +Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlroots-hyprland From 6a988d9276691957f1d9138f93c2209b580cad13 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 8 May 2024 12:11:08 -0500 Subject: [PATCH 0031/2393] core: cleanup environment on exit (#5941) --- src/Compositor.cpp | 24 ++++++++++++++++++++++++ src/Compositor.hpp | 1 + src/managers/XWaylandManager.cpp | 6 +++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 96831751..11834043 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -341,6 +341,28 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_sessionActive); } +void CCompositor::cleanEnvironment() { + // in compositor constructor + unsetenv("WAYLAND_DISPLAY"); + // in startCompositor + unsetenv("HYPRLAND_INSTANCE_SIGNATURE"); + + // in main + unsetenv("HYPRLAND_CMD"); + unsetenv("XDG_BACKEND"); + unsetenv("XDG_CURRENT_DESKTOP"); + + if (m_sWLRSession) { + const auto CMD = +#ifdef USES_SYSTEMD + "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash " + "dbus-update-activation-environment 2>/dev/null && " +#endif + "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME"; + g_pKeybindManager->spawn(CMD); + } +} + void CCompositor::cleanup() { if (!m_sWLDisplay || m_bIsShuttingDown) return; @@ -358,6 +380,8 @@ void CCompositor::cleanup() { Systemd::SdNotify(0, "STOPPING=1"); #endif + cleanEnvironment(); + // unload all remaining plugins while the compositor is // still in a normal working state. g_pPluginSystem->unloadAllPlugins(); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 8be1956c..0ef006be 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -191,6 +191,7 @@ class CCompositor { private: void initAllSignals(); void removeAllSignals(); + void cleanEnvironment(); void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index cbfc43d8..423c45ca 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -27,7 +27,11 @@ CHyprXWaylandManager::CHyprXWaylandManager() { #endif } -CHyprXWaylandManager::~CHyprXWaylandManager() {} +CHyprXWaylandManager::~CHyprXWaylandManager() { +#ifndef NO_XWAYLAND + unsetenv("DISPLAY"); +#endif +} wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { if (pWindow->m_bIsX11) From e4e84064f2d07810e0c150bce1369a0a00503e9a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 8 May 2024 22:17:10 +0100 Subject: [PATCH 0032/2393] xdg-activation: keep tokens after the resource is dead fixes #5957 --- src/protocols/XDGActivation.cpp | 29 +++++++++++++++++++---------- src/protocols/XDGActivation.hpp | 6 ++++++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index a4745cba..1d9814ac 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -31,6 +31,21 @@ CXDGActivationToken::CXDGActivationToken(SP resource_) : LOGM(LOG, "assigned new xdg-activation token {}", token); resource->sendDone(token.c_str()); + + PROTO::activation->m_vSentTokens.push_back({token, resource->client()}); + + auto count = std::count_if(PROTO::activation->m_vSentTokens.begin(), PROTO::activation->m_vSentTokens.end(), + [this](const auto& other) { return other.client == resource->client(); }); + + if (count > 10) { + // remove first token. Too many, dear app. + for (auto i = PROTO::activation->m_vSentTokens.begin(); i != PROTO::activation->m_vSentTokens.end(); ++i) { + if (i->client == resource->client()) { + PROTO::activation->m_vSentTokens.erase(i); + break; + } + } + } }); } @@ -54,21 +69,15 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t RESOURCE->setDestroy([this](CXdgActivationV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setGetActivationToken([this](CXdgActivationV1* pMgr, uint32_t id) { this->onGetToken(pMgr, id); }); RESOURCE->setActivate([this](CXdgActivationV1* pMgr, const char* token, wl_resource* surface) { - const auto TOKEN = std::find_if(m_vTokens.begin(), m_vTokens.end(), [token](const auto& t) { return t->committed && t->token == token; }); + auto TOKEN = std::find_if(m_vSentTokens.begin(), m_vSentTokens.end(), [token](const auto& t) { return t.token == token; }); - if (TOKEN == m_vTokens.end()) { + if (TOKEN == m_vSentTokens.end()) { LOGM(WARN, "activate event for non-existent token {}??", token); return; } - auto xdgToken = TOKEN->get(); - - if (xdgToken->used) { - LOGM(WARN, "activate event for already used token {}, ignoring", token); - return; - } - - xdgToken->used = true; + // remove token. It's been now spent. + m_vSentTokens.erase(TOKEN); wlr_surface* surf = wlr_surface_from_resource(surface); const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); diff --git a/src/protocols/XDGActivation.hpp b/src/protocols/XDGActivation.hpp index 626c6e78..80af988d 100644 --- a/src/protocols/XDGActivation.hpp +++ b/src/protocols/XDGActivation.hpp @@ -37,6 +37,12 @@ class CXDGActivationProtocol : public IWaylandProtocol { void destroyToken(CXDGActivationToken* pointer); void onGetToken(CXdgActivationV1* pMgr, uint32_t id); + struct SSentToken { + std::string token; + wl_client* client = nullptr; // READ-ONLY: can be dead + }; + std::vector m_vSentTokens; + // std::vector> m_vManagers; std::vector> m_vTokens; From ed411f53bdcf8d455f9e6ca769693aa84dc8372f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 5 May 2024 22:18:10 +0100 Subject: [PATCH 0033/2393] cursor: move to a hyprland impl This moves wlr_cursor to a completely new impl mostly under CPointerManager Also adds beginSimple to OpenGL for simple render passes (e.g. cursor) --- src/Compositor.cpp | 98 ++-- src/Compositor.hpp | 4 +- src/config/ConfigManager.cpp | 3 + src/debug/HyprCtl.cpp | 4 +- src/debug/HyprDebugOverlay.cpp | 2 +- src/desktop/WLSurface.cpp | 2 +- src/desktop/Window.cpp | 2 +- src/devices/IHID.cpp | 5 + src/devices/IHID.hpp | 11 + src/devices/IKeyboard.cpp | 4 + src/devices/IKeyboard.hpp | 1 + src/devices/IPointer.cpp | 4 + src/devices/IPointer.hpp | 2 + src/devices/ITouch.cpp | 6 +- src/devices/ITouch.hpp | 8 +- src/devices/Mouse.cpp | 5 + src/devices/TouchDevice.cpp | 1 + src/devices/VirtualPointer.cpp | 5 + src/events/Devices.cpp | 80 --- src/events/Events.hpp | 27 - src/events/Monitors.cpp | 23 +- src/events/Windows.cpp | 6 +- src/helpers/Box.cpp | 20 +- src/helpers/Box.hpp | 5 +- src/helpers/Monitor.cpp | 36 +- src/helpers/Monitor.hpp | 4 + src/helpers/Region.cpp | 5 +- src/helpers/Vector2D.cpp | 8 +- src/helpers/Vector2D.hpp | 1 + src/hyprerror/HyprError.cpp | 2 +- src/includes.hpp | 2 - src/managers/CursorManager.cpp | 75 ++- src/managers/CursorManager.hpp | 13 +- src/managers/KeybindManager.cpp | 45 +- src/managers/KeybindManager.hpp | 7 +- src/managers/PointerManager.cpp | 864 ++++++++++++++++++++++++++++ src/managers/PointerManager.hpp | 158 +++++ src/managers/input/InputManager.cpp | 90 +-- src/managers/input/InputManager.hpp | 28 +- src/managers/input/Swipe.cpp | 14 +- src/managers/input/Tablets.cpp | 24 +- src/managers/input/Touch.cpp | 52 +- src/protocols/Screencopy.cpp | 22 +- src/protocols/Screencopy.hpp | 5 +- src/protocols/ToplevelExport.cpp | 19 +- src/render/OpenGL.cpp | 90 ++- src/render/OpenGL.hpp | 47 +- src/render/Renderbuffer.cpp | 8 +- src/render/Renderbuffer.hpp | 2 + src/render/Renderer.cpp | 72 +-- src/render/Renderer.hpp | 25 +- 51 files changed, 1550 insertions(+), 496 deletions(-) create mode 100644 src/devices/IHID.cpp create mode 100644 src/managers/PointerManager.cpp create mode 100644 src/managers/PointerManager.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 11834043..caf042bc 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3,6 +3,7 @@ #include "config/ConfigValue.hpp" #include "managers/CursorManager.hpp" #include "managers/TokenManager.hpp" +#include "managers/PointerManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -227,13 +228,8 @@ void CCompositor::initServer() { wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); wlr_viewporter_create(m_sWLDisplay); - m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay); - m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6); - m_sWLRCursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout); - m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0"); m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); @@ -246,7 +242,7 @@ void CCompositor::initServer() { Debug::log(INFO, "VR will not be available"); } - m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); + // m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); @@ -270,23 +266,6 @@ void CCompositor::initServer() { void CCompositor::initAllSignals() { addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell"); - addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.axis, &Events::listen_mouseAxis, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.frame, &Events::listen_mouseFrame, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_begin, &Events::listen_swipeBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_update, &Events::listen_swipeUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.swipe_end, &Events::listen_swipeEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_begin, &Events::listen_pinchBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_update, &Events::listen_pinchUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.pinch_end, &Events::listen_pinchEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_down, &Events::listen_touchBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_up, &Events::listen_touchEnd, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_motion, &Events::listen_touchUpdate, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.touch_frame, &Events::listen_touchFrame, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.hold_begin, &Events::listen_holdBegin, m_sWLRCursor, "WLRCursor"); - addWLSignal(&m_sWLRCursor->events.hold_end, &Events::listen_holdEnd, m_sWLRCursor, "WLRCursor"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); @@ -307,23 +286,6 @@ void CCompositor::initAllSignals() { void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newOutput); removeWLSignal(&Events::listen_newXDGToplevel); - removeWLSignal(&Events::listen_mouseMove); - removeWLSignal(&Events::listen_mouseMoveAbsolute); - removeWLSignal(&Events::listen_mouseButton); - removeWLSignal(&Events::listen_mouseAxis); - removeWLSignal(&Events::listen_mouseFrame); - removeWLSignal(&Events::listen_swipeBegin); - removeWLSignal(&Events::listen_swipeUpdate); - removeWLSignal(&Events::listen_swipeEnd); - removeWLSignal(&Events::listen_pinchBegin); - removeWLSignal(&Events::listen_pinchUpdate); - removeWLSignal(&Events::listen_pinchEnd); - removeWLSignal(&Events::listen_touchBegin); - removeWLSignal(&Events::listen_touchEnd); - removeWLSignal(&Events::listen_touchUpdate); - removeWLSignal(&Events::listen_touchFrame); - removeWLSignal(&Events::listen_holdBegin); - removeWLSignal(&Events::listen_holdEnd); removeWLSignal(&Events::listen_newInput); removeWLSignal(&Events::listen_requestMouse); removeWLSignal(&Events::listen_requestSetSel); @@ -434,9 +396,6 @@ void CCompositor::cleanup() { g_pWatchdog.reset(); g_pXWaylandManager.reset(); - if (m_sWLRCursor) - wlr_cursor_destroy(m_sWLRCursor); - if (m_sSeat.seat) wlr_seat_destroy(m_sSeat.seat); @@ -485,6 +444,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pConfigManager->init(); g_pWatchdog = std::make_unique(); // requires config + + Debug::log(LOG, "Creating the PointerManager!"); + g_pPointerManager = std::make_unique(); } break; case STAGE_LATE: { Debug::log(LOG, "Creating the ThreadManager!"); @@ -668,24 +630,28 @@ CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { } CMonitor* CCompositor::getMonitorFromCursor() { - const auto COORDS = Vector2D(m_sWLRCursor->x, m_sWLRCursor->y); - - return getMonitorFromVector(COORDS); + return getMonitorFromVector(g_pPointerManager->position()); } CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { - const auto OUTPUT = wlr_output_layout_output_at(m_sWLROutputLayout, point.x, point.y); + SP mon; + for (auto& m : m_vMonitors) { + if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { + mon = m; + break; + } + } - if (!OUTPUT) { - float bestDistance = 0.f; - CMonitor* pBestMon = nullptr; + if (!mon) { + float bestDistance = 0.f; + SP pBestMon; for (auto& m : m_vMonitors) { float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); if (dist < bestDistance || !pBestMon) { bestDistance = dist; - pBestMon = m.get(); + pBestMon = m; } } @@ -694,10 +660,10 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { return m_vMonitors.front().get(); } - return pBestMon; + return pBestMon.get(); } - return getMonitorFromOutput(OUTPUT); + return mon.get(); } void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { @@ -732,7 +698,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper const auto BB = w->getWindowBoxUnified(properties); CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { - if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) + if (box.containsPoint(g_pPointerManager->position())) return w; if (!w->m_bIsX11) { @@ -766,7 +732,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) continue; - if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) { + if (box.containsPoint(g_pPointerManager->position())) { if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) { // Override Redirect @@ -1719,7 +1685,7 @@ void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) { } CMonitor* CCompositor::getMonitorInDirection(const char& dir) { - return this->getMonitorInDirection(m_pLastMonitor, dir); + return this->getMonitorInDirection(m_pLastMonitor.get(), dir); } CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) { @@ -1733,7 +1699,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha CMonitor* longestIntersectMonitor = nullptr; for (auto& m : m_vMonitors) { - if (m.get() == m_pLastMonitor) + if (m == m_pLastMonitor) continue; const auto POSB = m->vecPosition; @@ -2011,7 +1977,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) CMonitor* CCompositor::getMonitorFromString(const std::string& name) { if (name == "current") - return g_pCompositor->m_pLastMonitor; + return g_pCompositor->m_pLastMonitor.get(); else if (isDirection(name)) return getMonitorInDirection(name[0]); else if (name[0] == '+' || name[0] == '-') { @@ -2032,7 +1998,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { int currentPlace = 0; for (int i = 0; i < (int)m_vMonitors.size(); i++) { - if (m_vMonitors[i].get() == m_pLastMonitor) { + if (m_vMonitors[i] == m_pLastMonitor) { currentPlace = i; break; } @@ -2158,7 +2124,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon } } - if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't. + if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor.get()) { // if it was active, preserve its' status. If it wasn't, don't. Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID); if (valid(pMonitor->activeWorkspace)) { @@ -2174,7 +2140,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon pWorkspace->m_bVisible = true; if (!noWarpCursor) - wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2); + g_pPointerManager->warpTo(pMonitor->vecPosition + pMonitor->vecTransformedSize / 2.F); g_pInputManager->sendMotionEventsToFocused(); } @@ -2439,10 +2405,10 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { if (*PNOWARPS && !force) return; - wlr_cursor_warp(m_sWLRCursor, nullptr, pos.x, pos.y); + g_pPointerManager->warpTo(pos); const auto PMONITORNEW = getMonitorFromVector(pos); - if (PMONITORNEW != m_pLastMonitor) + if (PMONITORNEW != m_pLastMonitor.get()) setActiveMonitor(PMONITORNEW); } @@ -2587,11 +2553,11 @@ void CCompositor::renameWorkspace(const int& id, const std::string& name) { } void CCompositor::setActiveMonitor(CMonitor* pMonitor) { - if (m_pLastMonitor == pMonitor) + if (m_pLastMonitor.get() == pMonitor) return; if (!pMonitor) { - m_pLastMonitor = nullptr; + m_pLastMonitor.reset(); return; } @@ -2599,7 +2565,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) { g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")}); EMIT_HOOK_EVENT("focusedMon", pMonitor); - m_pLastMonitor = pMonitor; + m_pLastMonitor = pMonitor->self; } bool CCompositor::isWorkspaceSpecial(const int& id) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 0ef006be..d017949b 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -51,10 +51,8 @@ class CCompositor { wlr_data_device_manager* m_sWLRDataDevMgr; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_output_layout* m_sWLROutputLayout; wlr_layer_shell_v1* m_sWLRLayerShell; wlr_xdg_shell* m_sWLRXDGShell; - wlr_cursor* m_sWLRCursor; wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; int m_iDRMFD; @@ -88,7 +86,7 @@ class CCompositor { wlr_surface* m_pLastFocus = nullptr; PHLWINDOWREF m_pLastWindow; - CMonitor* m_pLastMonitor = nullptr; + WP m_pLastMonitor; std::vector m_vWindowFocusHistory; // first element is the most recently focused. diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c6c0ceaf..135a6a94 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -516,6 +516,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:col.active_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffffff"}); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d6e8608f..c0dc8d8e 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -115,7 +115,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, - (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"), + (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); } @@ -137,7 +137,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); } } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index b5f7e1f2..37ccc67a 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -33,7 +33,7 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { m_pMonitor = pMonitor; // anim data too - const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor; + const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get(); if (PMONITORFORTICKS) { if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) m_dLastAnimationTicks.pop_front(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 9396bbdd..c09d8fda 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -122,7 +122,7 @@ void CWLSurface::destroy() { g_pCompositor->m_pLastFocus = nullptr; if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface) g_pInputManager->m_pLastMouseSurface = nullptr; - if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface) + if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this) g_pHyprRenderer->m_sLastCursorData.surf.reset(); m_pWLRSurface = nullptr; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e9e50a56..2b95ad4c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1169,7 +1169,7 @@ void CWindow::setSuspended(bool suspend) { bool CWindow::visibleOnMonitor(CMonitor* pMonitor) { CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; - return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr()); + return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); } void CWindow::setAnimationsToMove() { diff --git a/src/devices/IHID.cpp b/src/devices/IHID.cpp new file mode 100644 index 00000000..2b7466dc --- /dev/null +++ b/src/devices/IHID.cpp @@ -0,0 +1,5 @@ +#include "IHID.hpp" + +eHIDType IHID::getType() { + return HID_TYPE_UNKNOWN; +} diff --git a/src/devices/IHID.hpp b/src/devices/IHID.hpp index c2b397c7..2830864b 100644 --- a/src/devices/IHID.hpp +++ b/src/devices/IHID.hpp @@ -10,13 +10,24 @@ enum eHIDCapabilityType : uint32_t { HID_INPUT_CAPABILITY_TOUCH = (1 << 2), }; +enum eHIDType { + HID_TYPE_UNKNOWN = 0, + HID_TYPE_POINTER, + HID_TYPE_KEYBOARD, + HID_TYPE_TOUCH, + HID_TYPE_TABLET, +}; + /* Base class for a HID device. This could be a keyboard, a mouse, or a touchscreen. */ class IHID { public: + virtual ~IHID() {} + virtual uint32_t getCapabilities() = 0; + virtual eHIDType getType(); struct { CSignal destroy; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 61c78f5b..3bd42eac 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -7,6 +7,10 @@ uint32_t IKeyboard::getCapabilities() { return HID_INPUT_CAPABILITY_KEYBOARD; } +eHIDType IKeyboard::getType() { + return HID_TYPE_KEYBOARD; +} + IKeyboard::~IKeyboard() { events.destroy.emit(); diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 35ccd8cb..d90550da 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -13,6 +13,7 @@ class IKeyboard : public IHID { public: virtual ~IKeyboard(); virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_keyboard* wlr() = 0; diff --git a/src/devices/IPointer.cpp b/src/devices/IPointer.cpp index 9eb507b2..c2ac78c5 100644 --- a/src/devices/IPointer.cpp +++ b/src/devices/IPointer.cpp @@ -3,3 +3,7 @@ uint32_t IPointer::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER; } + +eHIDType IPointer::getType() { + return HID_TYPE_POINTER; +} diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index eda7da2c..e2347c95 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -13,6 +13,7 @@ struct wlr_pointer; class IPointer : public IHID { public: virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_pointer* wlr() = 0; @@ -24,6 +25,7 @@ class IPointer : public IHID { struct SMotionAbsoluteEvent { uint32_t timeMs = 0; Vector2D absolute; // 0.0 - 1.0 + SP device; }; struct SButtonEvent { diff --git a/src/devices/ITouch.cpp b/src/devices/ITouch.cpp index 3fa347fd..72a9ade6 100644 --- a/src/devices/ITouch.cpp +++ b/src/devices/ITouch.cpp @@ -2,4 +2,8 @@ uint32_t ITouch::getCapabilities() { return HID_INPUT_CAPABILITY_TOUCH; -} \ No newline at end of file +} + +eHIDType ITouch::getType() { + return HID_TYPE_TOUCH; +} diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index 7a109bec..5929be02 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -10,13 +10,15 @@ struct wlr_touch; class ITouch : public IHID { public: virtual uint32_t getCapabilities(); + virtual eHIDType getType(); virtual bool isVirtual() = 0; virtual wlr_touch* wlr() = 0; struct SDownEvent { - uint32_t timeMs = 0; - int32_t touchID = 0; - Vector2D pos; + uint32_t timeMs = 0; + int32_t touchID = 0; + Vector2D pos; + SP device; }; struct SUpEvent { diff --git a/src/devices/Mouse.cpp b/src/devices/Mouse.cpp index e2a6f4ed..b860298c 100644 --- a/src/devices/Mouse.cpp +++ b/src/devices/Mouse.cpp @@ -36,6 +36,7 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ .timeMs = E->time_msec, .absolute = {E->x, E->y}, + .device = self.lock(), }); }, this, "CMouse"); @@ -62,6 +63,10 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { }); }, this, "CMouse"); + hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { + pointerEvents.frame.emit(); + }, this, "CMouse"); + hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { auto E = (wlr_pointer_swipe_begin_event*)data; diff --git a/src/devices/TouchDevice.cpp b/src/devices/TouchDevice.cpp index e8e52dc2..64c521a2 100644 --- a/src/devices/TouchDevice.cpp +++ b/src/devices/TouchDevice.cpp @@ -27,6 +27,7 @@ CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { .timeMs = E->time_msec, .touchID = E->touch_id, .pos = {E->x, E->y}, + .device = self.lock(), }); }, this, "CTouchDevice"); diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 4ebf8865..c8ee3332 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -37,6 +37,7 @@ CVirtualPointer::CVirtualPointer(SP resource) : point pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ .timeMs = E->time_msec, .absolute = {E->x, E->y}, + .device = self.lock(), }); }, this, "CVirtualPointer"); @@ -63,6 +64,10 @@ CVirtualPointer::CVirtualPointer(SP resource) : point }); }, this, "CVirtualPointer"); + hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { + pointerEvents.frame.emit(); + }, this, "CVirtualPointer"); + hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { auto E = (wlr_pointer_swipe_begin_event*)data; diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 1de1b768..f36a95de 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -4,7 +4,6 @@ #include "../helpers/WLClasses.hpp" #include "../managers/input/InputManager.hpp" #include "../render/Renderer.hpp" -#include "../protocols/PointerGestures.hpp" // ---------------------------------------------------- // // _____ ________ _______ _____ ______ _____ // @@ -16,26 +15,6 @@ // // // ---------------------------------------------------- // -void Events::listener_mouseFrame(wl_listener* listener, void* data) { - wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); -} - -void Events::listener_mouseMove(wl_listener* listener, void* data) { - g_pInputManager->onMouseMoved((wlr_pointer_motion_event*)data); -} - -void Events::listener_mouseMoveAbsolute(wl_listener* listener, void* data) { - g_pInputManager->onMouseWarp((wlr_pointer_motion_absolute_event*)data); -} - -void Events::listener_mouseButton(wl_listener* listener, void* data) { - g_pInputManager->onMouseButton((wlr_pointer_button_event*)data); -} - -void Events::listener_mouseAxis(wl_listener* listener, void* data) { - g_pInputManager->onMouseWheel((wlr_pointer_axis_event*)data); -} - void Events::listener_requestMouse(wl_listener* listener, void* data) { const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; @@ -75,62 +54,3 @@ void Events::listener_newInput(wl_listener* listener, void* data) { g_pInputManager->updateCapabilities(); } - -void Events::listener_swipeBegin(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_begin_event*)data; - - g_pInputManager->onSwipeBegin(EVENT); -} - -void Events::listener_swipeUpdate(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_update_event*)data; - - g_pInputManager->onSwipeUpdate(EVENT); -} - -void Events::listener_swipeEnd(wl_listener* listener, void* data) { - const auto EVENT = (wlr_pointer_swipe_end_event*)data; - - g_pInputManager->onSwipeEnd(EVENT); -} - -void Events::listener_pinchBegin(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_begin_event*)data; - PROTO::pointerGestures->pinchBegin(EV->time_msec, EV->fingers); -} - -void Events::listener_pinchUpdate(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_update_event*)data; - PROTO::pointerGestures->pinchUpdate(EV->time_msec, {EV->dx, EV->dy}, EV->scale, EV->rotation); -} - -void Events::listener_pinchEnd(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_pinch_end_event*)data; - PROTO::pointerGestures->pinchEnd(EV->time_msec, EV->cancelled); -} - -void Events::listener_touchBegin(wl_listener* listener, void* data) { - g_pInputManager->onTouchDown((wlr_touch_down_event*)data); -} - -void Events::listener_touchEnd(wl_listener* listener, void* data) { - g_pInputManager->onTouchUp((wlr_touch_up_event*)data); -} - -void Events::listener_touchUpdate(wl_listener* listener, void* data) { - g_pInputManager->onTouchMove((wlr_touch_motion_event*)data); -} - -void Events::listener_touchFrame(wl_listener* listener, void* data) { - wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat); -} - -void Events::listener_holdBegin(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_hold_begin_event*)data; - PROTO::pointerGestures->holdBegin(EV->time_msec, EV->fingers); -} - -void Events::listener_holdEnd(wl_listener* listener, void* data) { - const auto EV = (wlr_pointer_hold_end_event*)data; - PROTO::pointerGestures->holdEnd(EV->time_msec, EV->cancelled); -} \ No newline at end of file diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 830ca8d1..69da2d09 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -40,16 +40,6 @@ namespace Events { DYNLISTENFUNC(dissociateX11); DYNLISTENFUNC(ackConfigure); - // Window subsurfaces - // LISTENER(newSubsurfaceWindow); - - // Input events - LISTENER(mouseMove); - LISTENER(mouseMoveAbsolute); - LISTENER(mouseButton); - LISTENER(mouseAxis); - LISTENER(mouseFrame); - LISTENER(newInput); // Virt Ptr @@ -89,23 +79,6 @@ namespace Events { // session LISTENER(sessionActive); - // Touchpad shit - LISTENER(swipeBegin); - LISTENER(swipeEnd); - LISTENER(swipeUpdate); - LISTENER(pinchBegin); - LISTENER(pinchUpdate); - LISTENER(pinchEnd); - - // Touch - LISTENER(touchBegin); - LISTENER(touchEnd); - LISTENER(touchUpdate); - LISTENER(touchFrame); - - LISTENER(holdBegin); - LISTENER(holdEnd); - // Session Lock LISTENER(newSessionLock); }; diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 982dc941..ab8fc7b0 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -16,8 +16,7 @@ // // // --------------------------------------------------------- // -static void checkDefaultCursorWarp(SP* PNEWMONITORWRAP, std::string monitorName) { - const auto PNEWMONITOR = PNEWMONITORWRAP->get(); +static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { static auto PCURSORMONITOR = CConfigValue("general:default_cursor_monitor"); static auto firstMonitorAdded = std::chrono::system_clock::now(); @@ -61,18 +60,18 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { } // add it to real - SP* PNEWMONITORWRAP = nullptr; - - PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); if (std::string("HEADLESS-1") == OUTPUT->name) - g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get(); + g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); - (*PNEWMONITORWRAP)->output = OUTPUT; + PNEWMONITOR->output = OUTPUT; + PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false; - (*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); - const auto PNEWMONITOR = PNEWMONITORWRAP->get(); + PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); PNEWMONITOR->isUnsafeFallback = FALLBACK; + EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); + if (!FALLBACK) PNEWMONITOR->onConnect(false); @@ -82,14 +81,14 @@ void Events::listener_newOutput(wl_listener* listener, void* data) { // ready to process if we have a real monitor if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) - g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR; + g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); g_pCompositor->m_bReadyToProcess = true; g_pConfigManager->m_bWantsMonitorReload = true; - g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR); + g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get()); - checkDefaultCursorWarp(PNEWMONITORWRAP, OUTPUT->name); + checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name); for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 8643a539..221348ff 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -54,10 +54,10 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); - auto PMONITOR = g_pCompositor->m_pLastMonitor; + auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!g_pCompositor->m_pLastMonitor) { g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); - PMONITOR = g_pCompositor->m_pLastMonitor; + PMONITOR = g_pCompositor->m_pLastMonitor.get(); } auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -330,7 +330,7 @@ void Events::listener_mapWindow(void* owner, void* data) { else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); - PMONITOR = g_pCompositor->m_pLastMonitor; + PMONITOR = g_pCompositor->m_pLastMonitor.get(); } } else workspaceSilent = false; diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index 8470b509..77406ecf 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -121,7 +121,7 @@ CBox& CBox::noNegativeSize() { return *this; } -CBox CBox::intersection(const CBox other) const { +CBox CBox::intersection(const CBox& other) const { const float newX = std::max(x, other.x); const float newY = std::max(y, other.y); const float newBottom = std::min(y + h, other.y + other.h); @@ -137,6 +137,14 @@ CBox CBox::intersection(const CBox other) const { return {newX, newY, newW, newH}; } +bool CBox::overlaps(const CBox& other) const { + return (other.x + other.w >= x) && (x + w >= other.x) && (other.y + other.h >= y) && (y + h >= other.y); +} + +bool CBox::inside(const CBox& bound) const { + return bound.x < x && bound.y < y && x + w < bound.x + bound.w && y + h < bound.y + bound.h; +} + CBox CBox::roundInternal() { float newW = x + w - std::floor(x); float newH = y + h - std::floor(y); @@ -156,6 +164,16 @@ Vector2D CBox::size() const { return {w, h}; } +Vector2D CBox::closestPoint(const Vector2D& vec) const { + if (containsPoint(vec)) + return vec; + + Vector2D nv = vec; + nv.x = std::clamp(nv.x, x, x + w); + nv.y = std::clamp(nv.y, y, y + h); + return nv; +} + SWindowDecorationExtents CBox::extentsFrom(const CBox& small) { return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}}; } diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp index 98ba8d47..57df2154 100644 --- a/src/helpers/Box.hpp +++ b/src/helpers/Box.hpp @@ -54,13 +54,16 @@ class CBox { CBox& noNegativeSize(); CBox copy() const; - CBox intersection(const CBox other) const; + CBox intersection(const CBox& other) const; + bool overlaps(const CBox& other) const; + bool inside(const CBox& bound) const; SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box Vector2D middle() const; Vector2D pos() const; Vector2D size() const; + Vector2D closestPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const; bool empty() const; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 3c489d4b..d0e777ed 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -149,14 +149,14 @@ void CMonitor::onConnect(bool noRule) { for (const auto& PTOUCHDEV : g_pInputManager->m_vTouches) { if (matchesStaticSelector(PTOUCHDEV->boundOutput)) { Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output); } } for (const auto& PTABLET : g_pInputManager->m_lTablets) { if (matchesStaticSelector(PTABLET.boundOutput)) { Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output); } } @@ -203,7 +203,7 @@ void CMonitor::onConnect(bool noRule) { // verify last mon valid bool found = false; for (auto& m : g_pCompositor->m_vMonitors) { - if (m.get() == g_pCompositor->m_pLastMonitor) { + if (m == g_pCompositor->m_pLastMonitor) { found = true; break; } @@ -219,6 +219,7 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); + updateGlobal(); } void CMonitor::onDisconnect(bool destroy) { @@ -285,10 +286,11 @@ void CMonitor::onDisconnect(bool destroy) { m_bEnabled = false; m_bRenderingInitPassed = false; + updateGlobal(); + if (BACKUPMON) { // snap cursor - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f, - BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f); + g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true); // move workspaces std::deque wspToMove; @@ -306,22 +308,19 @@ void CMonitor::onDisconnect(bool destroy) { } else { g_pCompositor->m_pLastFocus = nullptr; g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastMonitor = nullptr; + g_pCompositor->m_pLastMonitor.reset(); } if (activeWorkspace) activeWorkspace->m_bVisible = false; activeWorkspace.reset(); - if (!destroy) - wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); - wlr_output_state_set_enabled(state.wlr(), false); if (!state.commit()) Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); - if (g_pCompositor->m_pLastMonitor == this) + if (g_pCompositor->m_pLastMonitor.get() == this) g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); if (g_pHyprRenderer->m_pMostHzMonitor == this) { @@ -508,8 +507,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) { activeWorkspace.reset(); - wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output); - vecPosition = PMIRRORMON->vecPosition; pMirrorOf = PMIRRORMON; @@ -728,9 +725,6 @@ void CMonitor::setSpecialWorkspace(const int& id) { void CMonitor::moveTo(const Vector2D& pos) { vecPosition = pos; - - if (!isMirror()) - wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y); } Vector2D CMonitor::middle() { @@ -749,10 +743,22 @@ void CMonitor::updateMatrix() { int64_t CMonitor::activeWorkspaceID() { return activeWorkspace ? activeWorkspace->m_iID : 0; } + int64_t CMonitor::activeSpecialWorkspaceID() { return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0; } +CBox CMonitor::logicalBox() { + return {vecPosition, vecSize}; +} + +void CMonitor::updateGlobal() { + if (output->width > 0 && output->height > 0 && m_bEnabled) + wlr_output_create_global(output, g_pCompositor->m_sWLDisplay); + else + wlr_output_destroy_global(output); +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; wlr_output_state_init(&m_state); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index a93d23af..2d49aeb3 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -114,6 +114,8 @@ class CMonitor { SMonitorRule activeMonitorRule; + WP self; + // mirroring CMonitor* pMirrorOf = nullptr; std::vector mirrors; @@ -167,6 +169,8 @@ class CMonitor { void updateMatrix(); int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); + CBox logicalBox(); + void updateGlobal(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index bcbf672d..20eaf452 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -142,6 +142,9 @@ bool CRegion::empty() const { } Vector2D CRegion::closestPoint(const Vector2D& vec) const { + if (containsPoint(vec)) + return vec; + double bestDist = __FLT_MAX__; Vector2D leader = vec; @@ -162,7 +165,7 @@ Vector2D CRegion::closestPoint(const Vector2D& vec) const { else y = vec.y; - double distance = sqrt(pow(x, 2) + pow(y, 2)); + double distance = pow(x, 2) + pow(y, 2); if (distance < bestDist) { bestDist = distance; leader = {x, y}; diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp index c74da0b1..6f96d686 100644 --- a/src/helpers/Vector2D.cpp +++ b/src/helpers/Vector2D.cpp @@ -42,9 +42,11 @@ Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const { } double Vector2D::distance(const Vector2D& other) const { - double dx = x - other.x; - double dy = y - other.y; - return std::sqrt(dx * dx + dy * dy); + return std::sqrt(distanceSq(other)); +} + +double Vector2D::distanceSq(const Vector2D& other) const { + return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y); } double Vector2D::size() const { diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp index 309ed3bc..0f1440c3 100644 --- a/src/helpers/Vector2D.hpp +++ b/src/helpers/Vector2D.hpp @@ -89,6 +89,7 @@ class Vector2D { } double distance(const Vector2D& other) const; + double distanceSq(const Vector2D& other) const; double size() const; Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 7a9e9e87..4c7b6731 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -10,7 +10,7 @@ CHyprError::CHyprError() { if (!m_bIsCreated) return; - g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor); + g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get()); m_bMonitorChanged = true; }); diff --git a/src/includes.hpp b/src/includes.hpp index 6df38267..57ea5d54 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -39,7 +39,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -52,7 +51,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 3fcecfe4..4ee3adfc 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -1,6 +1,7 @@ #include "CursorManager.hpp" #include "Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "PointerManager.hpp" extern "C" { #include @@ -73,8 +74,8 @@ static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t fla if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) return false; - *data = cairo_image_surface_get_data(buffer->surface); - *stride = cairo_image_surface_get_stride(buffer->surface); + *data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface); + *stride = buffer->stride; *format = DRM_FORMAT_ARGB8888; return true; } @@ -94,6 +95,14 @@ CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector wlrBuffer.surface = surf; wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); wlrBuffer.parent = this; + wlrBuffer.stride = cairo_image_surface_get_stride(surf); +} + +CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) { + wlrBuffer.pixelData = pixelData; + wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); + wlrBuffer.parent = this; + wlrBuffer.stride = 4 * size_.x; } CCursorManager::CCursorBuffer::~CCursorBuffer() { @@ -104,18 +113,53 @@ wlr_buffer* CCursorManager::getCursorBuffer() { return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; } -void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) { - wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y); +void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { + if (!surf || !surf->wlr()) + g_pPointerManager->resetCursorImage(); + else + g_pPointerManager->setCursorSurface(surf, hotspot); m_bOurBufferConnected = false; } +void CCursorManager::setXCursor(const std::string& name) { + if (!m_pWLRXCursorMgr) { + g_pPointerManager->resetCursorImage(); + return; + } + + float scale = std::ceil(m_fCursorScale); + wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale); + + auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale); + if (!xcursor) { + Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name); + xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale); + } + + if (!xcursor || !xcursor->images[0]) { + Debug::log(ERR, "XCursor is broken. F this garbage."); + g_pPointerManager->resetCursorImage(); + return; + } + + auto image = xcursor->images[0]; + + m_vCursorBuffers.emplace_back(std::make_unique(image->buffer, Vector2D{image->width, image->height}, Vector2D{image->hotspot_x, image->hotspot_y})); + + g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{image->hotspot_x, image->hotspot_y} / scale, scale); + if (m_vCursorBuffers.size() > 1) + wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + + m_bOurBufferConnected = true; +} + void CCursorManager::setCursorFromName(const std::string& name) { static auto PUSEHYPRCURSOR = CConfigValue("misc:enable_hyprcursor"); if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { - wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str()); + setXCursor(name); return; } @@ -142,7 +186,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { if (m_sCurrentCursorShapeData.images.size() < 1) { Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); - wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str()); + setXCursor(name); return; } } @@ -151,12 +195,10 @@ void CCursorManager::setCursorFromName(const std::string& name) { Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); - if (g_pCompositor->m_sWLRCursor) { - wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX / m_fCursorScale, - m_sCurrentCursorShapeData.images[0].hotspotY / m_fCursorScale, m_fCursorScale); - if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); - } + g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, + m_fCursorScale); + if (m_vCursorBuffers.size() > 1) + wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); m_bOurBufferConnected = true; @@ -183,9 +225,10 @@ void CCursorManager::tickAnimatedCursor() { Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); - if (g_pCompositor->m_sWLRCursor) - wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX / m_fCursorScale, - m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY / m_fCursorScale, m_fCursorScale); + g_pPointerManager->setCursorBuffer( + getCursorBuffer(), + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, + m_fCursorScale); wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); } @@ -223,8 +266,6 @@ void CCursorManager::updateTheme() { highestScale = m->scale; } - highestScale = std::ceil(highestScale); - if (std::round(highestScale * m_iSize) == m_sCurrentStyleInfo.size) return; diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 629f29e1..b4c5232a 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -9,6 +9,7 @@ struct wlr_buffer; struct wlr_xcursor_manager; struct wlr_xwayland; +class CWLSurface; class CCursorManager { public: @@ -18,7 +19,8 @@ class CCursorManager { wlr_buffer* getCursorBuffer(); void setCursorFromName(const std::string& name); - void setCursorSurface(wlr_surface* surf, const Vector2D& hotspot); + void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot); + void setXCursor(const std::string& name); void changeTheme(const std::string& name, const int size); void updateTheme(); @@ -30,13 +32,16 @@ class CCursorManager { class CCursorBuffer { public: CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); + CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); ~CCursorBuffer(); struct SCursorWlrBuffer { wlr_buffer base; - cairo_surface_t* surface = nullptr; - bool dropped = false; - CCursorBuffer* parent = nullptr; + cairo_surface_t* surface = nullptr; + bool dropped = false; + CCursorBuffer* parent = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; } wlrBuffer; private: diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c52fda17..62265e00 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -256,7 +256,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { if (!monitor) return false; - const auto LASTMONITOR = g_pCompositor->m_pLastMonitor; + const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); if (LASTMONITOR == monitor) { Debug::log(LOG, "Tried to move to active monitor"); return false; @@ -407,7 +407,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { return !suppressEvent && !mouseBindWasActive; } -bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { +bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); static auto PDELAY = CConfigValue("binds:scroll_event_delay"); @@ -426,13 +426,13 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { } bool found = false; - if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL) { - if (e->delta < 0) + if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + if (e.delta < 0) found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true); else found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true); - } else if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - if (e->delta < 0) + } else if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + if (e.delta < 0) found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true); else found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true); @@ -444,18 +444,18 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { return !found; } -bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { +bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); bool suppressEvent = false; - m_uLastMouseCode = e->button; + m_uLastMouseCode = e.button; m_uLastCode = 0; - m_uTimeLastMs = e->time_msec; + m_uTimeLastMs = e.timeMs; bool mouseBindWasActive = ensureMouseBindState(); - const auto KEY_NAME = "mouse:" + std::to_string(e->button); + const auto KEY_NAME = "mouse:" + std::to_string(e.button); const auto KEY = SPressedKeyWithMods{ .keyName = KEY_NAME, @@ -468,7 +468,7 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { m_pActiveKeybind = nullptr; } - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_dPressedKeys.push_back(KEY); suppressEvent = handleKeybinds(MODS, KEY, true); @@ -501,12 +501,11 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { return !suppressEvent && !mouseBindWasActive; } -void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) { - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { +void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) { + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) mouse("1resizewindow"); - } else { + else mouse("0resizewindow"); - } } void CKeybindManager::onSwitchEvent(const std::string& switchName) { @@ -965,7 +964,7 @@ void CKeybindManager::changeworkspace(std::string args) { static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); static auto PWORKSPACECENTERON = CConfigValue("binds:workspace_center_on"); - const auto PMONITOR = g_pCompositor->m_pLastMonitor; + const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PMONITOR) return; @@ -1445,20 +1444,20 @@ void CKeybindManager::moveCursorToCorner(std::string arg) { switch (CORNER) { case 0: // bottom left - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, true); break; case 1: // bottom right - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, - PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, + true); break; case 2: // top right - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; case 3: // top left - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; } } @@ -1488,7 +1487,7 @@ void CKeybindManager::moveCursor(std::string args) { x = std::stoi(x_str); y = std::stoi(y_str); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, x, y); + g_pCompositor->warpCursorTo({x, y}, true); } void CKeybindManager::workspaceOpt(std::string args) { @@ -1624,7 +1623,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { return; } - const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor; + const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PCURRMONITOR) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index c382f3eb..da98a749 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -5,6 +5,7 @@ #include "../Compositor.hpp" #include #include +#include "../devices/IPointer.hpp" class CInputManager; class CConfigManager; @@ -62,9 +63,9 @@ class CKeybindManager { ~CKeybindManager(); bool onKeyEvent(std::any, SP); - bool onAxisEvent(wlr_pointer_axis_event*); - bool onMouseEvent(wlr_pointer_button_event*); - void resizeWithBorder(wlr_pointer_button_event*); + bool onAxisEvent(const IPointer::SAxisEvent&); + bool onMouseEvent(const IPointer::SButtonEvent&); + void resizeWithBorder(const IPointer::SButtonEvent&); void onSwitchEvent(const std::string&); void onSwitchOnEvent(const std::string&); void onSwitchOffEvent(const std::string&); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp new file mode 100644 index 00000000..caff8d22 --- /dev/null +++ b/src/managers/PointerManager.cpp @@ -0,0 +1,864 @@ +#include "PointerManager.hpp" +#include "../Compositor.hpp" +#include "../config/ConfigValue.hpp" +#include "../protocols/PointerGestures.hpp" +#include "../protocols/FractionalScale.hpp" +#include +#include +#include + +// TODO: make nicer +// this will come with the eventual rewrite of wlr_drm, etc... +static bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) { + ASSERT(a->format == b->format); + + size_t capacity = a->len < b->len ? a->len : b->len; + uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity); + if (!modifiers) + return false; + + struct wlr_drm_format fmt = { + .format = a->format, + .len = 0, + .capacity = capacity, + .modifiers = modifiers, + }; + + for (size_t i = 0; i < a->len; i++) { + for (size_t j = 0; j < b->len; j++) { + if (a->modifiers[i] == b->modifiers[j]) { + ASSERT(fmt.len < fmt.capacity); + fmt.modifiers[fmt.len++] = a->modifiers[i]; + break; + } + } + } + + wlr_drm_format_finish(dst); + *dst = fmt; + return true; +} + +static bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) { + ASSERT(src->len <= src->capacity); + + uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len); + if (!modifiers) + return false; + + memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len); + + wlr_drm_format_finish(dst); + dst->capacity = src->len; + dst->len = src->len; + dst->format = src->format; + dst->modifiers = modifiers; + return true; +} + +static const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) { + if (!r->impl->get_render_formats) + return nullptr; + + return r->impl->get_render_formats(r); +} + +static bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) { + + const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer); + if (render_formats == NULL) { + wlr_log(WLR_ERROR, "Failed to get render formats"); + return false; + } + + const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt); + if (render_format == NULL) { + wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt); + return false; + } + + if (display_formats != NULL) { + const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt); + if (display_format == NULL) { + wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt); + return false; + } + if (!wlr_drm_format_intersect(format, display_format, render_format)) { + wlr_log(WLR_DEBUG, + "Failed to intersect display and render " + "modifiers for format 0x%" PRIX32 " on output %s", + fmt, output->name); + return false; + } + } else { + // The output can display any format + if (!wlr_drm_format_copy(format, render_format)) + return false; + } + + if (format->len == 0) { + wlr_drm_format_finish(format); + wlr_log(WLR_DEBUG, "Failed to pick output format"); + return false; + } + + return true; +} + +static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) { + struct wlr_allocator* allocator = output->allocator; + ASSERT(allocator != NULL); + + const struct wlr_drm_format_set* display_formats = NULL; + if (output->impl->get_cursor_formats) { + display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps); + if (display_formats == NULL) { + wlr_log(WLR_DEBUG, "Failed to get cursor display formats"); + return false; + } + } + + return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888); +} + +CPointerManager::CPointerManager() { + hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { + auto PMONITOR = std::any_cast>(data); + + onMonitorLayoutChange(); + + PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); + PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); + PMONITOR->events.destroy.registerStaticListener( + [this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr); + }); +} + +void CPointerManager::lockSoftwareForMonitor(SP mon) { + auto state = stateFor(mon); + state->softwareLocks++; + + if (state->softwareLocks == 1) + updateCursorBackend(); +} + +void CPointerManager::unlockSoftwareForMonitor(SP mon) { + auto state = stateFor(mon); + state->softwareLocks--; + if (state->softwareLocks < 0) + state->softwareLocks = 0; + + if (state->softwareLocks == 0) + updateCursorBackend(); +} + +Vector2D CPointerManager::position() { + return pointerPos; +} + +bool CPointerManager::hasCursor() { + return currentCursorImage.pBuffer || currentCursorImage.surface; +} + +SP CPointerManager::stateFor(SP mon) { + auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; }); + if (it == monitorStates.end()) + return monitorStates.emplace_back(makeShared(mon)); + return *it; +} + +void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { + if (buf == currentCursorImage.pBuffer) { + if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { + currentCursorImage.hotspot = hotspot; + currentCursorImage.scale = scale; + updateCursorBackend(); + } + + return; + } + + resetCursorImage(false); + + if (buf) { + currentCursorImage.size = {buf->width, buf->height}; + currentCursorImage.pBuffer = wlr_buffer_lock(buf); + + currentCursorImage.hyprListener_destroyBuffer.initCallback( + &buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager"); + } + + currentCursorImage.hotspot = hotspot; + currentCursorImage.scale = scale; + + updateCursorBackend(); +} + +void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { + if (surf == currentCursorImage.surface) { + if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) { + currentCursorImage.hotspot = hotspot; + currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F; + updateCursorBackend(); + } + + return; + } + + resetCursorImage(false); + + if (surf) { + currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height}; + currentCursorImage.surface = surf; + currentCursorImage.scale = surf->wlr()->current.scale; + + currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); + currentCursorImage.hyprListener_commitSurface.initCallback( + &surf->wlr()->events.commit, + [this](void* owner, void* data) { + currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height}; + currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F; + recheckEnteredOutputs(); + updateCursorBackend(); + }, + nullptr, "CPointerManager"); + + if (surf->wlr()->current.buffer) { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_surface_send_frame_done(surf->wlr(), &now); + } + } + + currentCursorImage.hotspot = hotspot; + + recheckEnteredOutputs(); + updateCursorBackend(); +} + +void CPointerManager::recheckEnteredOutputs() { + if (!hasCursor()) + return; + + auto box = getCursorBoxGlobal(); + + for (auto& s : monitorStates) { + if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) + continue; + + const bool overlaps = box.overlaps(s->monitor->logicalBox()); + + if (!s->entered && overlaps) { + s->entered = true; + + if (!currentCursorImage.surface) + continue; + + wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output); + PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale); + g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale); + } else if (s->entered && !overlaps) { + s->entered = false; + + // if we are using hw cursors, prevent + // the cursor from being stuck at the last point. + // if we are leaving it, move it to narnia. + if (!s->hardwareFailed && s->monitor->output->impl->move_cursor) + s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420); + + if (!currentCursorImage.surface) + continue; + + wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output); + } + } +} + +void CPointerManager::resetCursorImage(bool apply) { + if (currentCursorImage.surface) { + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output); + } + + currentCursorImage.destroySurface.reset(); + currentCursorImage.hyprListener_commitSurface.removeCallback(); + currentCursorImage.surface = nullptr; + } else if (currentCursorImage.pBuffer) { + wlr_buffer_unlock(currentCursorImage.pBuffer); + currentCursorImage.hyprListener_destroyBuffer.removeCallback(); + currentCursorImage.pBuffer = nullptr; + } + + if (currentCursorImage.pBufferTexture) { + wlr_texture_destroy(currentCursorImage.pBufferTexture); + currentCursorImage.pBufferTexture = nullptr; + } + + currentCursorImage.scale = 1.F; + currentCursorImage.hotspot = {0, 0}; + + if (!apply) + return; + + for (auto& ms : monitorStates) { + if (ms->cursorFrontBuffer) { + if (ms->monitor->output->impl->set_cursor) + ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0); + wlr_buffer_unlock(ms->cursorFrontBuffer); + ms->cursorFrontBuffer = nullptr; + } + } +} + +void CPointerManager::updateCursorBackend() { + static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + + for (auto& m : g_pCompositor->m_vMonitors) { + auto state = stateFor(m); + + if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { + Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); + state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + state->hardwareFailed = true; + + if (state->hwApplied) + setHWCursorBuffer(state, nullptr); + + state->hwApplied = false; + continue; + } + + state->hardwareFailed = false; + } +} + +void CPointerManager::onCursorMoved() { + if (!hasCursor()) + return; + + for (auto& m : g_pCompositor->m_vMonitors) { + auto state = stateFor(m); + + state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + + if (state->hardwareFailed || !state->entered) + continue; + + const auto CURSORPOS = getCursorPosForMonitor(m); + m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y); + } +} + +bool CPointerManager::attemptHardwareCursor(SP state) { + auto output = state->monitor->output; + + if (!output->impl->set_cursor) + return false; + + const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); + state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y); + + auto texture = getCurrentCursorTexture(); + + if (!texture) { + Debug::log(TRACE, "[pointer] no texture for hw cursor -> hiding"); + setHWCursorBuffer(state, nullptr); + return true; + } + + auto buffer = renderHWCursorBuffer(state, texture); + + if (!buffer) { + Debug::log(TRACE, "[pointer] hw cursor failed rendering"); + setHWCursorBuffer(state, nullptr); + return false; + } + + bool success = setHWCursorBuffer(state, buffer); + + if (!success) { + Debug::log(TRACE, "[pointer] hw cursor failed applying, hiding"); + setHWCursorBuffer(state, nullptr); + return false; + } else + state->hwApplied = true; + + return success; +} + +bool CPointerManager::setHWCursorBuffer(SP state, wlr_buffer* buf) { + if (!state->monitor->output->impl->set_cursor) + return false; + + const auto HOTSPOT = transformedHotspot(state->monitor.lock()); + + Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT); + + if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x, HOTSPOT.y)) + return false; + + wlr_buffer_unlock(state->cursorFrontBuffer); + state->cursorFrontBuffer = buf; + + g_pCompositor->scheduleFrameForMonitor(state->monitor.get()); + + if (buf) + wlr_buffer_lock(buf); + + return true; +} + +wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, wlr_texture* texture) { + auto output = state->monitor->output; + + int w = currentCursorImage.size.x, h = currentCursorImage.size.y; + if (output->impl->get_cursor_size) { + output->impl->get_cursor_size(output, &w, &h); + + if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) { + Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h); + return nullptr; + } + } + + if (w <= 0 || h <= 0) { + Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h); + return nullptr; + } + + if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) { + wlr_drm_format fmt = {0}; + if (!output_pick_cursor_format(output, &fmt)) { + Debug::log(TRACE, "Failed to pick cursor format"); + return nullptr; + } + + wlr_swapchain_destroy(output->cursor_swapchain); + output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt); + wlr_drm_format_finish(&fmt); + + if (!output->cursor_swapchain) { + Debug::log(TRACE, "Failed to create cursor swapchain"); + return nullptr; + } + } + + wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr); + if (!buf) { + Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); + return nullptr; + } + + CRegion damage = {0, 0, INT16_MAX, INT16_MAX}; + + g_pHyprRenderer->makeEGLCurrent(); + g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs + + const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888); + RBO->bind(); + + g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); + g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); + + CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; + Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, Vector2D{w, h}, + currentCursorImage.scale, state->monitor->scale, xbox.size()); + + g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); + + g_pHyprOpenGL->end(); + glFlush(); + g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + + g_pHyprRenderer->onRenderbufferDestroy(RBO); + + wlr_buffer_unlock(buf); + + return buf; +} + +void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage, std::optional overridePos) { + if (!hasCursor()) + return; + + auto state = stateFor(pMonitor); + + if ((!state->hardwareFailed && state->softwareLocks == 0)) { + if (currentCursorImage.surface) + wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + return; + } + + auto box = state->box.copy(); + if (overridePos.has_value()) { + box.x = overridePos->x; + box.y = overridePos->y; + } + + if (box.intersection(CBox{{}, {pMonitor->vecSize}}).empty()) + return; + + auto texture = getCurrentCursorTexture(); + if (!texture) + return; + + box.scale(pMonitor->scale); + + g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); + + if (currentCursorImage.surface) + wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); +} + +Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { + return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} + //.transform(pMonitor->transform, pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale) + .pos() * + pMonitor->scale; +} + +Vector2D CPointerManager::transformedHotspot(SP pMonitor) { + return CBox{currentCursorImage.hotspot, {0, 0}} + .transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) + .pos(); +} + +CBox CPointerManager::getCursorBoxLogicalForMonitor(SP pMonitor) { + return getCursorBoxGlobal().translate(-pMonitor->vecPosition); +} + +CBox CPointerManager::getCursorBoxGlobal() { + return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot / currentCursorImage.scale); +} + +Vector2D CPointerManager::closestValid(const Vector2D& pos) { + static auto PADDING = CConfigValue("cursor:hotspot_padding"); + + auto CURSOR_PADDING = std::clamp((int)*PADDING, 1, 100); // 1px + CBox hotBox = {{pos.x - CURSOR_PADDING, pos.y - CURSOR_PADDING}, {2 * CURSOR_PADDING, 2 * CURSOR_PADDING}}; + + // + static auto INSIDE_LAYOUT = [this](const CBox& box) -> bool { + for (auto& b : currentMonitorLayout.monitorBoxes) { + if (box.inside(b)) + return true; + } + return false; + }; + + static auto INSIDE_LAYOUT_COORD = [this](const Vector2D& vec) -> bool { + for (auto& b : currentMonitorLayout.monitorBoxes) { + if (b.containsPoint(vec)) + return true; + } + return false; + }; + + static auto NEAREST_LAYOUT = [this](const Vector2D& vec) -> Vector2D { + Vector2D leader; + float distanceSq = __FLT_MAX__; + + for (auto& b : currentMonitorLayout.monitorBoxes) { + auto p = b.closestPoint(vec); + auto distSq = p.distanceSq(vec); + + if (distSq < distanceSq) { + leader = p; + distanceSq = distSq; + } + } + + if (distanceSq > 1337.69420e+20F) + return {0, 0}; // ??? + + return leader; + }; + + if (INSIDE_LAYOUT(hotBox)) + return pos; + + Vector2D leader = NEAREST_LAYOUT(pos); + + hotBox.x = leader.x - CURSOR_PADDING; + hotBox.y = leader.y - CURSOR_PADDING; + + // push the hotbox around so that it fits in the layout + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING}); + hotBox.translate(delta); + } + + if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING})) { + auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING}); + hotBox.translate(delta); + } + + return hotBox.middle(); +} + +void CPointerManager::damageIfSoftware() { + auto b = getCursorBoxGlobal(); + + static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + + for (auto& mw : monitorStates) { + if (mw->monitor.expired()) + continue; + + if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { + g_pHyprRenderer->damageBox(&b); + break; + } + } +} + +void CPointerManager::warpTo(const Vector2D& logical) { + damageIfSoftware(); + + pointerPos = closestValid(logical); + recheckEnteredOutputs(); + onCursorMoved(); + + damageIfSoftware(); +} + +void CPointerManager::move(const Vector2D& deltaLogical) { + const auto oldPos = pointerPos; + auto newPos = oldPos + deltaLogical; + + warpTo(newPos); +} + +void CPointerManager::warpAbsolute(const Vector2D& abs, SP dev) { + + SP currentMonitor = g_pCompositor->m_pLastMonitor.lock(); + + switch (dev->getType()) { + case HID_TYPE_TABLET: + //TODO: + break; + case HID_TYPE_TOUCH: { + auto TOUCH = SP(dev); + if (!TOUCH->boundOutput.empty()) { + const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); + if (PMONITOR) + currentMonitor = PMONITOR->self.lock(); + } + break; + } + default: break; + } + + if (!currentMonitor) + return; + + damageIfSoftware(); + + pointerPos = currentMonitor->vecPosition + currentMonitor->vecSize * abs; + onCursorMoved(); + recheckEnteredOutputs(); + + damageIfSoftware(); +} + +void CPointerManager::onMonitorLayoutChange() { + currentMonitorLayout.monitorBoxes.clear(); + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->isMirror() || !m->m_bEnabled) + continue; + + currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize}); + } + + damageIfSoftware(); + + pointerPos = closestValid(pointerPos); + updateCursorBackend(); + recheckEnteredOutputs(); + + damageIfSoftware(); +} + +wlr_texture* CPointerManager::getCurrentCursorTexture() { + if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr()))) + return nullptr; + + if (currentCursorImage.pBuffer) { + if (!currentCursorImage.pBufferTexture) + currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); + return currentCursorImage.pBufferTexture; + } + + return wlr_surface_get_texture(currentCursorImage.surface->wlr()); +} + +void CPointerManager::attachPointer(SP pointer) { + if (!pointer) + return; + + auto listener = pointerListeners.emplace_back(makeShared()); + + listener->pointer = pointer; + + // clang-format off + listener->destroy = pointer->events.destroy.registerListener([this] (std::any d) { + detachPointer(nullptr); + }); + + listener->motion = pointer->pointerEvents.motion.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseMoved(E); + }); + + listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseWarp(E); + }); + + listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseButton(E); + }); + + listener->axis = pointer->pointerEvents.axis.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onMouseWheel(E); + }); + + listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { + wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); + }); + + listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeBegin(E); + }); + + listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeEnd(E); + }); + + listener->swipeUpdate = pointer->pointerEvents.swipeUpdate.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onSwipeUpdate(E); + }); + + listener->pinchBegin = pointer->pointerEvents.pinchBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); + }); + + listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchEnd(E.timeMs, E.cancelled); + }); + + listener->pinchUpdate = pointer->pointerEvents.pinchUpdate.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->pinchUpdate(E.timeMs, E.delta, E.scale, E.rotation); + }); + + listener->holdBegin = pointer->pointerEvents.holdBegin.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->holdBegin(E.timeMs, E.fingers); + }); + + listener->holdEnd = pointer->pointerEvents.holdEnd.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + PROTO::pointerGestures->holdEnd(E.timeMs, E.cancelled); + }); + // clang-format on + + Debug::log(LOG, "Attached pointer {} to global", pointer->hlName); +} + +void CPointerManager::attachTouch(SP touch) { + if (!touch) + return; + + auto listener = touchListeners.emplace_back(makeShared()); + + listener->touch = touch; + + // clang-format off + listener->destroy = touch->events.destroy.registerListener([this] (std::any d) { + detachTouch(nullptr); + }); + + listener->down = touch->touchEvents.down.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchDown(E); + }); + + listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchUp(E); + }); + + listener->motion = touch->touchEvents.motion.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTouchMove(E); + }); + + listener->cancel = touch->touchEvents.cancel.registerListener([this] (std::any e) { + // + }); + + listener->frame = touch->touchEvents.frame.registerListener([this] (std::any e) { + wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat); + }); + // clang-format on + + Debug::log(LOG, "Attached touch {} to global", touch->hlName); +} + +void CPointerManager::detachPointer(SP pointer) { + std::erase_if(pointerListeners, [pointer](const auto& e) { return e->pointer.expired() || e->pointer == pointer; }); +} + +void CPointerManager::detachTouch(SP touch) { + std::erase_if(touchListeners, [touch](const auto& e) { return e->touch.expired() || e->touch == touch; }); +} + +void CPointerManager::damageCursor(SP pMonitor) { + for (auto& mw : monitorStates) { + if (mw->monitor != pMonitor) + continue; + + auto b = getCursorBoxGlobal().intersection(pMonitor->logicalBox()); + + if (b.empty()) + return; + + g_pHyprRenderer->damageBox(&b); + + return; + } +} diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp new file mode 100644 index 00000000..2446cde7 --- /dev/null +++ b/src/managers/PointerManager.hpp @@ -0,0 +1,158 @@ +#pragma once + +#include "../devices/IPointer.hpp" +#include "../devices/ITouch.hpp" +#include "../helpers/Box.hpp" +#include "../helpers/Region.hpp" +#include "../desktop/WLSurface.hpp" +#include + +class CMonitor; +struct wlr_input_device; +class IHID; + +/* + The naming here is a bit confusing. + CPointerManager manages the _position_ and _displaying_ of the cursor, + but the CCursorManager _only_ manages the actual image (texture) and size + of the cursor. +*/ + +class CPointerManager { + public: + CPointerManager(); + + // pointers will move the cursor on their respective events + void attachPointer(SP pointer); + // touch inputs won't move the cursor, it needs to be done manually + void attachTouch(SP touch); + + void detachPointer(SP pointer); + void detachTouch(SP touch); + + // only clamps to the layout. + void warpTo(const Vector2D& logical); + void move(const Vector2D& deltaLogical); + void warpAbsolute(const Vector2D& abs, SP dev); + + void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); + void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot); + void resetCursorImage(bool apply = true); + + void lockSoftwareForMonitor(SP pMonitor); + void unlockSoftwareForMonitor(SP pMonitor); + + void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); + + // this is needed e.g. during screensharing where + // the software cursors aren't locked during the cursor move, but they + // are rendered later. + void damageCursor(SP pMonitor); + + // + Vector2D position(); + + private: + void recheckPointerPosition(); + void onMonitorLayoutChange(); + void onMonitorDisconnect(); + void updateCursorBackend(); + void onCursorMoved(); + bool hasCursor(); + void damageIfSoftware(); + void recheckEnteredOutputs(); + + // closest valid point to a given one + Vector2D closestValid(const Vector2D& pos); + + // returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot. + Vector2D getCursorPosForMonitor(SP pMonitor); + // returns the thing in logical coordinates of the monitor + CBox getCursorBoxLogicalForMonitor(SP pMonitor); + // returns the thing in global coords + CBox getCursorBoxGlobal(); + + Vector2D transformedHotspot(SP pMonitor); + + wlr_texture* getCurrentCursorTexture(); + + struct SPointerListener { + CHyprSignalListener destroy; + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; + + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; + + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; + + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + + WP pointer; + }; + std::vector> pointerListeners; + + struct STouchListener { + CHyprSignalListener destroy; + CHyprSignalListener down; + CHyprSignalListener up; + CHyprSignalListener motion; + CHyprSignalListener cancel; + CHyprSignalListener frame; + + WP touch; + }; + std::vector> touchListeners; + + struct { + std::vector monitorBoxes; + } currentMonitorLayout; + + struct { + wlr_buffer* pBuffer = nullptr; + CWLSurface* surface = nullptr; + wlr_texture* pBufferTexture = nullptr; + + Vector2D hotspot; + Vector2D size; + float scale = 1.F; + + CHyprSignalListener destroySurface; + DYNLISTENER(commitSurface); + DYNLISTENER(destroyBuffer); + } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors + + Vector2D pointerPos = {0, 0}; + + struct SMonitorPointerState { + SMonitorPointerState(SP m) : monitor(m) {} + WP monitor; + + int softwareLocks = 0; + bool hardwareFailed = false; + CBox box; // logical + bool entered = false; + bool hwApplied = false; + + wlr_buffer* cursorFrontBuffer = nullptr; + }; + + std::vector> monitorStates; + SP stateFor(SP mon); + bool attemptHardwareCursor(SP state); + wlr_buffer* renderHWCursorBuffer(SP state, wlr_texture* texture); + bool setHWCursorBuffer(SP state, wlr_buffer* buf); + + struct { + SP monitorAdded; + } hooks; +}; + +inline UP g_pPointerManager; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6d493e5b..22fc24d4 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -20,6 +20,8 @@ #include "../../devices/VirtualKeyboard.hpp" #include "../../devices/TouchDevice.hpp" +#include "../../managers/PointerManager.hpp" + CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { if (!cursorImageUnlocked()) @@ -63,31 +65,31 @@ CInputManager::~CInputManager() { m_lSwitches.clear(); } -void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) { +void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { static auto PSENS = CConfigValue("general:sensitivity"); static auto PNOACCEL = CConfigValue("input:force_no_accel"); static auto PSENSTORAW = CConfigValue("general:apply_sens_to_raw"); - const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y); + const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; if (*PSENSTORAW == 1) - PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA * *PSENS, Vector2D{e->unaccel_dx, e->unaccel_dy} * *PSENS); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS); else - PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA, Vector2D{e->unaccel_dx, e->unaccel_dy}); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); - wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS); + g_pPointerManager->move(DELTA * *PSENS); - mouseMoveUnified(e->time_msec); + mouseMoveUnified(e.timeMs); m_tmrLastCursorMovement.reset(); m_bLastInputTouch = false; } -void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) { - wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y); +void CInputManager::onMouseWarp(IPointer::SMotionAbsoluteEvent e) { + g_pPointerManager->warpAbsolute(e.absolute, e.device); - mouseMoveUnified(e->time_msec); + mouseMoveUnified(e.timeMs); m_tmrLastCursorMovement.reset(); @@ -194,14 +196,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (SURF && CONSTRAINT) { if (CONSTRAINT->isLocked()) { const auto HINT = CONSTRAINT->logicPositionHint(); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, HINT.x, HINT.y); + g_pCompositor->warpCursorTo(HINT, true); } else { const auto RG = CONSTRAINT->logicConstraintRegion(); const auto CLOSEST = RG.closestPoint(mouseCoords); const auto BOX = SURF->getSurfaceBoxGlobal(); const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (SURF->getWindow() ? SURF->getWindow()->m_fX11SurfaceScaledBy : 1.0); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y); + g_pCompositor->warpCursorTo(CLOSEST, true); wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y); PROTO::relativePointer->sendRelativeMotion((uint64_t)time * 1000, {}, {}); } @@ -241,7 +243,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); - if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) + if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) g_pCompositor->setActiveMonitor(PMONITOR); if (g_pSessionLockManager->isSessionLocked()) { @@ -350,7 +352,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); if (!foundSurface) { if (!m_bEmptyFocusCursorSet) { @@ -491,19 +493,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); } -void CInputManager::onMouseButton(wlr_pointer_button_event* e) { +void CInputManager::onMouseButton(IPointer::SButtonEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e); PROTO::idle->onActivity(); m_tmrLastCursorMovement.reset(); - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) { - m_lCurrentlyHeldButtons.push_back(e->button); + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { + m_lCurrentlyHeldButtons.push_back(e.button); } else { - if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e->button; }) == m_lCurrentlyHeldButtons.end()) + if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e.button; }) == m_lCurrentlyHeldButtons.end()) return; - std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e->button; }); + std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e.button; }); } switch (m_ecbClickBehavior) { @@ -512,7 +514,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) { default: break; } - if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e->state == WL_POINTER_BUTTON_STATE_RELEASED) { + if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e.state == WL_POINTER_BUTTON_STATE_RELEASED) { if (m_bRefocusHeldByButtons) refocus(); else @@ -549,7 +551,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even m_sCursorSurfaceInfo.name = ""; m_sCursorSurfaceInfo.inUse = true; - g_pHyprRenderer->setCursorSurface(e->surface, e->hotspot_x, e->hotspot_y); + g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e->hotspot_x, e->hotspot_y); } } @@ -564,7 +566,7 @@ void CInputManager::restoreCursorIconToApp() { if (m_sCursorSurfaceInfo.name.empty()) { if (m_sCursorSurfaceInfo.wlSurface.exists()) - g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface.wlr(), m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); + g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); } else { g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name); } @@ -617,7 +619,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) { } } -void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { +void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // notify the keybind manager static auto PPASSMOUSE = CConfigValue("binds:pass_mouse_when_bound"); @@ -639,7 +641,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { // clicking on border triggers resize // TODO detect click on LS properly - if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) { if (w && !w->m_bIsFullscreen) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; @@ -651,7 +653,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { } } - switch (e->state) { + switch (e.state) { case WL_POINTER_BUTTON_STATE_PRESSED: if (*PFOLLOWMOUSE == 3) // don't refocus on full loose break; @@ -679,14 +681,14 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) { // notify app if we didnt handle it if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus)) - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e->time_msec, e->button, e->state); + wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e.timeMs, e.button, e.state); - if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor && PMON) + if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON) g_pCompositor->setActiveMonitor(PMON); } -void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { - switch (e->state) { +void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) { + switch (e.state) { case WL_POINTER_BUTTON_STATE_PRESSED: { const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); @@ -707,12 +709,12 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) { m_ecbClickBehavior = CLICKMODE_DEFAULT; } -void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { +void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { static auto POFFWINDOWAXIS = CConfigValue("input:off_window_axis_events"); static auto PINPUTSCROLLFACTOR = CConfigValue("input:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue("input:touchpad:scroll_factor"); - auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e->source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); + auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); const auto EMAP = std::unordered_map{{"event", e}}; EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP); @@ -742,20 +744,20 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) { const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1); if (*POFFWINDOWAXIS == 3) - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, TEMPCURX, TEMPCURY); + g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, TEMPCURX - BOX.x, TEMPCURY - BOX.y); + wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, TEMPCURX - BOX.x, TEMPCURY - BOX.y); wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); } } } - wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source, + wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { - return Vector2D(g_pCompositor->m_sWLRCursor->x, g_pCompositor->m_sWLRCursor->y); + return g_pPointerManager->position(); } void CInputManager::newKeyboard(wlr_input_device* keyboard) { @@ -989,7 +991,7 @@ void CInputManager::setupMouse(SP mauz) { (int)libinput_device_config_accel_get_default_profile(LIBINPUTDEV)); } - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &mauz->wlr()->base); + g_pPointerManager->attachPointer(mauz); mauz->connected = true; @@ -1020,10 +1022,10 @@ void CInputManager::setPointerConfigs() { if (HASCONFIG) { const auto ENABLED = g_pConfigManager->getDeviceInt(devname, "enabled"); if (ENABLED && !m->connected) { - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base); + g_pPointerManager->attachPointer(m); m->connected = true; } else if (!ENABLED && m->connected) { - wlr_cursor_detach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base); + g_pPointerManager->detachPointer(m); m->connected = false; } } @@ -1386,7 +1388,7 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) { } setTouchDeviceConfigs(PNEWDEV); - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); + g_pPointerManager->attachTouch(PNEWDEV); PNEWDEV->events.destroy.registerStaticListener( [this](void* owner, std::any data) { @@ -1431,7 +1433,7 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr; if (PMONITOR) { Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, PMONITOR->szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output); } else if (bound) Debug::log(ERR, "Failed to bind touch device {} to output '{}': monitor not found", PTOUCHDEV->hlName, output); } @@ -1468,17 +1470,17 @@ void CInputManager::setTabletConfigs() { const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT); if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) { Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName); - wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); - wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); + // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); + // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); t.boundOutput = OUTPUT; } else if (!PMONITOR) Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT); const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position"); const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size"); - auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; - if (!regionBox.empty()) - wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); + //auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; + // if (!regionBox.empty()) + // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position"); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 7d78c133..a2caed46 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -7,15 +7,15 @@ #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" #include "../../helpers/signal/Listener.hpp" +#include "../../devices/IPointer.hpp" +#include "../../devices/ITouch.hpp" class CPointerConstraint; class CWindow; class CIdleInhibitor; class CVirtualKeyboardV1Resource; class CVirtualPointerV1Resource; -class IPointer; class IKeyboard; -class ITouch; enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, @@ -74,10 +74,10 @@ class CInputManager { CInputManager(); ~CInputManager(); - void onMouseMoved(wlr_pointer_motion_event*); - void onMouseWarp(wlr_pointer_motion_absolute_event*); - void onMouseButton(wlr_pointer_button_event*); - void onMouseWheel(wlr_pointer_axis_event*); + void onMouseMoved(IPointer::SMotionEvent); + void onMouseWarp(IPointer::SMotionAbsoluteEvent); + void onMouseButton(IPointer::SButtonEvent); + void onMouseWheel(IPointer::SAxisEvent); void onKeyboardKey(std::any, SP); void onKeyboardMod(SP); @@ -112,9 +112,9 @@ class CInputManager { eClickBehaviorMode getClickMode(); void processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e); - void onTouchDown(wlr_touch_down_event*); - void onTouchUp(wlr_touch_up_event*); - void onTouchMove(wlr_touch_motion_event*); + void onTouchDown(ITouch::SDownEvent); + void onTouchUp(ITouch::SUpEvent); + void onTouchMove(ITouch::SMotionEvent); STouchData m_sTouchData; @@ -153,9 +153,9 @@ class CInputManager { void newIdleInhibitor(std::any); void recheckIdleInhibitorStatus(); - void onSwipeBegin(wlr_pointer_swipe_begin_event*); - void onSwipeEnd(wlr_pointer_swipe_end_event*); - void onSwipeUpdate(wlr_pointer_swipe_update_event*); + void onSwipeBegin(IPointer::SSwipeBeginEvent); + void onSwipeEnd(IPointer::SSwipeEndEvent); + void onSwipeUpdate(IPointer::SSwipeUpdateEvent); SSwipeGesture m_sActiveSwipe; @@ -212,8 +212,8 @@ class CInputManager { void setupKeyboard(SP keeb); void setupMouse(SP mauz); - void processMouseDownNormal(wlr_pointer_button_event* e); - void processMouseDownKill(wlr_pointer_button_event* e); + void processMouseDownNormal(const IPointer::SButtonEvent& e); + void processMouseDownKill(const IPointer::SButtonEvent& e); bool cursorImageUnlocked(); diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 8c489af5..63adc8ca 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -2,14 +2,14 @@ #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" -void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) { +void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { static auto PSWIPE = CConfigValue("gestures:workspace_swipe"); static auto PSWIPEFINGERS = CConfigValue("gestures:workspace_swipe_fingers"); static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e); - if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) + if (e.fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) return; int onMonitor = 0; @@ -32,7 +32,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin = PWORKSPACE; m_sActiveSwipe.delta = 0; - m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor; + m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor.get(); m_sActiveSwipe.avgSpeed = 0; m_sActiveSwipe.speedPoints = 0; @@ -43,7 +43,7 @@ void CInputManager::beginWorkspaceSwipe() { } } -void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) { +void CInputManager::onSwipeEnd(IPointer::SSwipeEndEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e); if (!m_sActiveSwipe.pWorkspaceBegin) @@ -198,7 +198,7 @@ void CInputManager::endWorkspaceSwipe() { } } -void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { +void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e); if (!m_sActiveSwipe.pWorkspaceBegin) @@ -207,7 +207,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) { const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx)); + const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x)); updateWorkspaceSwipe(delta); } @@ -348,7 +348,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { if (*PSWIPEFOREVER) { if (abs(m_sActiveSwipe.delta) >= SWIPEDISTANCE) { - onSwipeEnd(nullptr); + onSwipeEnd({}); beginWorkspaceSwipe(); } } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 979eb1a7..a0bd81ce 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -18,7 +18,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { Debug::log(LOG, "Attaching tablet to cursor!"); - wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); + // wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); PNEWTABLET->hyprListener_Destroy.initCallback( &pDevice->events.destroy, @@ -39,7 +39,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { switch (EVENT->tool->type) { case WLR_TABLET_TOOL_TYPE_MOUSE: - wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); + // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); g_pInputManager->simulateMouseMovement(); g_pInputManager->focusTablet(PTAB, EVENT->tool, true); g_pInputManager->m_tmrLastCursorMovement.reset(); @@ -50,16 +50,16 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) { double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN; double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN; - if (PTAB->relativeInput) - wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); - else { - // Calculate transformations if active area is set - if (!PTAB->activeArea.empty()) { - x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); - y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); - } - wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); - } + // if (PTAB->relativeInput) + // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); + // else { + // Calculate transformations if active area is set + // if (!PTAB->activeArea.empty()) { + // x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); + // y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); + // } + // wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); + // } g_pInputManager->simulateMouseMovement(); g_pInputManager->focusTablet(PTAB, EVENT->tool, true); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7b0d6190..60d85aa6 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -4,7 +4,7 @@ #include "../../protocols/IdleNotify.hpp" #include "../../devices/ITouch.hpp" -void CInputManager::onTouchDown(wlr_touch_down_event* e) { +void CInputManager::onTouchDown(ITouch::SDownEvent e) { static auto PSWIPETOUCH = CConfigValue("gestures:workspace_swipe_touch"); static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); @@ -14,23 +14,18 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e); - auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : ""); + auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : ""); - const auto PDEVIT = std::find_if(m_vTouches.begin(), m_vTouches.end(), [&](const auto& other) { return other->wlr() == e->touch; }); + PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.get(); - if (PDEVIT != m_vTouches.end() && !(*PDEVIT)->boundOutput.empty()) - PMONITOR = g_pCompositor->getMonitorFromName((*PDEVIT)->boundOutput); - - PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor; - - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); refocus(); if (m_ecbClickBehavior == CLICKMODE_KILL) { - wlr_pointer_button_event e; + IPointer::SButtonEvent e; e.state = WL_POINTER_BUTTON_STATE_PRESSED; - g_pInputManager->processMouseDownKill(&e); + g_pInputManager->processMouseDownKill(e); return; } @@ -45,10 +40,10 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { // TODO: support no_gaps_when_only? const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); - const double POSITION = (VERTANIMS ? e->y : e->x); + const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); if (POSITION < TARGETLEFT || POSITION > TARGETRIGHT) { beginWorkspaceSwipe(); - m_sActiveSwipe.touch_id = e->touch_id; + m_sActiveSwipe.touch_id = e.touchID; // Set the initial direction based on which edge you started from if (POSITION > 0.5) m_sActiveSwipe.initialDirection = *PSWIPEINVR ? -1 : 1; @@ -78,34 +73,33 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) { local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusLS->geometry.pos(); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; - } else { + } else return; // oops, nothing found. - } - wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local.x, local.y); PROTO::idle->onActivity(); } -void CInputManager::onTouchUp(wlr_touch_up_event* e) { +void CInputManager::onTouchUp(ITouch::SUpEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e); if (m_sActiveSwipe.pWorkspaceBegin) { // If there was a swipe from this finger, end it. - if (e->touch_id == m_sActiveSwipe.touch_id) + if (e.touchID == m_sActiveSwipe.touch_id) endWorkspaceSwipe(); return; } if (m_sTouchData.touchFocusSurface) { - wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id); + wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID); } } -void CInputManager::onTouchMove(wlr_touch_motion_event* e) { +void CInputManager::onTouchMove(ITouch::SMotionEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e); if (m_sActiveSwipe.pWorkspaceBegin) { // Do nothing if this is using a different finger. - if (e->touch_id != m_sActiveSwipe.touch_id) + if (e.touchID != m_sActiveSwipe.touch_id) return; const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); @@ -116,37 +110,37 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) { if (m_sActiveSwipe.initialDirection == -1) { if (*PSWIPEINVR) // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e->y : e->x) - 1)); + updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e.pos.y : e.pos.x) - 1)); else // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e->y : e->x))); + updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e.pos.y : e.pos.x))); } else if (*PSWIPEINVR) // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e->y : e->x)); + updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e.pos.y : e.pos.x)); else // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e->y : e->x))); + updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x))); return; } if (validMapped(m_sTouchData.touchFocusWindow)) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; if (m_sTouchData.touchFocusWindow->m_bIsX11) local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); } else if (!m_sTouchData.touchFocusLS.expired()) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); - wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y); + wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); } } diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 476df0b8..a4d62506 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -1,5 +1,6 @@ #include "Screencopy.hpp" #include "../Compositor.hpp" +#include "../managers/PointerManager.hpp" #include @@ -183,6 +184,11 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force if (!frame) return; + if (frame->lockedSWCursors) { + g_pPointerManager->unlockSoftwareForMonitor(frame->pMonitor->self.lock()); + g_pPointerManager->damageCursor(frame->pMonitor->self.lock()); + } + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); @@ -352,8 +358,11 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou m_vFramesAwaitingWrite.emplace_back(PFRAME); g_pHyprRenderer->m_bDirectScanoutBlocked = true; - if (PFRAME->overlayCursor) - g_pHyprRenderer->m_bSoftwareCursorsLocked = true; + if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) { + PFRAME->lockedSWCursors = true; + g_pPointerManager->lockSoftwareForMonitor(PFRAME->pMonitor->self.lock()); + g_pPointerManager->damageCursor(PFRAME->pMonitor->self.lock()); + } if (!PFRAME->withDamage) g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); @@ -393,17 +402,8 @@ void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { removeFrame(f); } - g_pHyprRenderer->m_bSoftwareCursorsLocked = false; - if (m_vFramesAwaitingWrite.empty()) { g_pHyprRenderer->m_bDirectScanoutBlocked = false; - } else { - for (auto& f : m_vFramesAwaitingWrite) { - if (f->overlayCursor) { - g_pHyprRenderer->m_bSoftwareCursorsLocked = true; - break; - } - } } } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index c39152d8..7b9a5770 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -48,8 +48,9 @@ struct SScreencopyFrame { CBox box = {}; int shmStride = 0; - bool overlayCursor = false; - bool withDamage = false; + bool overlayCursor = false; + bool withDamage = false; + bool lockedSWCursors = false; wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 70f00fa1..d3b71a9e 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -1,6 +1,7 @@ #include "ToplevelExport.hpp" #include "../Compositor.hpp" #include "ForeignToplevelWlr.hpp" +#include "../managers/PointerManager.hpp" #include @@ -313,7 +314,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; - if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr())) + if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) continue; shareFrame(f); @@ -382,8 +383,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times return false; } - if (frame->overlayCursor) - wlr_output_lock_software_cursors(PMONITOR->output, true); + if (frame->overlayCursor) { + g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); @@ -393,7 +396,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); if (!PFORMAT) { @@ -419,8 +422,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times wlr_buffer_end_data_ptr_access(frame->buffer); - if (frame->overlayCursor) - wlr_output_lock_software_cursors(PMONITOR->output, false); + if (frame->overlayCursor) { + g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } return true; } @@ -440,7 +445,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (frame->overlayCursor) - g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index cea49818..5cbac942 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -246,13 +246,10 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return false; } -void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { +void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; - static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); - #ifndef GLES2 - const GLenum RESETSTATUS = glGetGraphicsResetStatus(); if (RESETSTATUS != GL_NO_ERROR) { std::string errStr = ""; @@ -265,7 +262,62 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr); return; } +#endif + TRACY_GPU_ZONE("RenderBeginSimple"); + + const auto FBO = rb ? rb->getFB() : fb; + + glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + + matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + + wlr_matrix_identity(m_RenderData.monitorProjection.data()); + if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { + const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; + wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); + wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform); + wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); + } + + m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; + + if (!m_RenderData.pCurrentMonData->m_bShadersInitialized) + initShaders(); + + m_RenderData.damage.set(damage); + m_RenderData.finalDamage.set(damage); + + m_bFakeFrame = true; + + m_RenderData.currentFB = FBO; + FBO->bind(); + m_bOffloadedFramebuffer = false; + + m_RenderData.mainFB = m_RenderData.currentFB; + m_RenderData.outFB = FBO; + + m_RenderData.simplePass = true; +} + +void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { + m_RenderData.pMonitor = pMonitor; + + static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); + +#ifndef GLES2 + const GLenum RESETSTATUS = glGetGraphicsResetStatus(); + if (RESETSTATUS != GL_NO_ERROR) { + std::string errStr = ""; + switch (RESETSTATUS) { + case GL_GUILTY_CONTEXT_RESET: errStr = "GL_GUILTY_CONTEXT_RESET"; break; + case GL_INNOCENT_CONTEXT_RESET: errStr = "GL_INNOCENT_CONTEXT_RESET"; break; + case GL_UNKNOWN_CONTEXT_RESET: errStr = "GL_UNKNOWN_CONTEXT_RESET"; break; + default: errStr = "UNKNOWN??"; break; + } + RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr); + return; + } #endif TRACY_GPU_ZONE("RenderBegin"); @@ -274,6 +326,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.monitorProjection = pMonitor->projMatrix; + if (m_mMonitorRenderResources.contains(pMonitor) && m_mMonitorRenderResources.at(pMonitor).offloadFB.m_vSize != pMonitor->vecPixelSize) destroyMonitorResources(pMonitor); @@ -753,7 +807,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -814,6 +868,12 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, i renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); } +void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) { + RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); + + renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV); +} + void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); @@ -822,6 +882,14 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha scissor((CBox*)nullptr); } +void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { + RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); + + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); + + scissor((CBox*)nullptr); +} + void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); @@ -843,7 +911,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1006,7 +1074,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1060,7 +1128,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame // get transform const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1119,7 +1187,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform); float matrix[9]; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data()); + wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1615,7 +1683,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1921,7 +1989,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const float matrix[9]; wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index bebf82bc..ca9eecc6 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -95,33 +95,35 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - CMonitor* pMonitor = nullptr; - PHLWORKSPACE pWorkspace = nullptr; - float projection[9]; - float savedProjection[9]; + CMonitor* pMonitor = nullptr; + PHLWORKSPACE pWorkspace = nullptr; + float projection[9]; + float savedProjection[9]; + std::array monitorProjection; - SMonitorRenderData* pCurrentMonData = nullptr; - CFramebuffer* currentFB = nullptr; // current rendering to - CFramebuffer* mainFB = nullptr; // main to render to - CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) + SMonitorRenderData* pCurrentMonData = nullptr; + CFramebuffer* currentFB = nullptr; // current rendering to + CFramebuffer* mainFB = nullptr; // main to render to + CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) - CRegion damage; - CRegion finalDamage; // damage used for funal off -> main + CRegion damage; + CRegion finalDamage; // damage used for funal off -> main - SRenderModifData renderModif; - float mouseZoomFactor = 1.f; - bool mouseZoomUseMouse = true; // true by default - bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() - bool blockScreenShader = false; + SRenderModifData renderModif; + float mouseZoomFactor = 1.f; + bool mouseZoomUseMouse = true; // true by default + bool useNearestNeighbor = false; + bool forceIntrospection = false; // cleaned in ::end() + bool blockScreenShader = false; + bool simplePass = false; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); + Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); - CBox clipBox = {}; // scaled coordinates + CBox clipBox = {}; // scaled coordinates - uint32_t discardMode = DISCARD_OPAQUE; - float discardOpacity = 0.f; + uint32_t discardMode = DISCARD_OPAQUE; + float discardOpacity = 0.f; }; class CGradientValueData; @@ -131,13 +133,16 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); void end(); void renderRect(CBox*, const CColor&, int round = 0); void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); + void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false); void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 9434c3f0..5003f600 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -8,16 +8,16 @@ CRenderbuffer::~CRenderbuffer() { if (!g_pCompositor) return; - if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)); + g_pHyprRenderer->makeEGLCurrent(); + unbind(); m_sFramebuffer.release(); glDeleteRenderbuffers(1, &m_iRBO); g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage); } -CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer) { +CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) { // EVIL, but we can't include a hidden header because nixos is fucking special static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*); @@ -58,7 +58,7 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); hyprListener_destroyBuffer.initCallback( - &buffer->events.destroy, [](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy((CRenderbuffer*)owner); }, this, "CRenderbuffer"); + &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } void CRenderbuffer::bind() { diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index d8df8ca5..2a8bf250 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -13,6 +13,7 @@ class CRenderbuffer { void bindFB(); void unbind(); CFramebuffer* getFB(); + uint32_t getFormat(); wlr_buffer* m_pWlrBuffer = nullptr; @@ -22,4 +23,5 @@ class CRenderbuffer { EGLImageKHR m_iImage = 0; GLuint m_iRBO = 0; CFramebuffer m_sFramebuffer; + uint32_t m_uDrmFormat = 0; }; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ee874589..a671bd40 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -5,6 +5,7 @@ #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" +#include "../managers/PointerManager.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" @@ -95,8 +96,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) TRACY_GPU_ZONE("RenderSurface"); - double outputX = 0, outputY = 0; - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->pMonitor->output, &outputX, &outputY); + double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); @@ -217,9 +217,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) } bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { - CBox geometry = pWindow->getFullWindowBoundingBox(); - - if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr())) + if (!pWindow->visibleOnMonitor(pMonitor)) return false; if (!pWindow->m_pWorkspace && !pWindow->m_bFadingOut) @@ -1209,10 +1207,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { EMIT_HOOK_EVENT("render", RENDER_PRE); - const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked; - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, true); - pMonitor->renderingActive = true; // we need to cleanup fading out when rendering the appropriate context @@ -1238,12 +1232,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); - - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - pMonitor->state.clear(); - return; } @@ -1300,7 +1289,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { renderLockscreen(pMonitor, &now, renderBox); - if (pMonitor == g_pCompositor->m_pLastMonitor) { + if (pMonitor == g_pCompositor->m_pLastMonitor.get()) { g_pHyprNotificationOverlay->draw(pMonitor); g_pHyprError->draw(); } @@ -1338,11 +1327,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; if (lockSoftware) { - wlr_output_lock_software_cursors(pMonitor->output, true); - g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage); - wlr_output_lock_software_cursors(pMonitor->output, false); + g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); + g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); + g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); } else - g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage); + g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); } EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT); @@ -1373,21 +1362,13 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->state.wlr()->tearing_page_flip = shouldTear; if (!pMonitor->state.commit()) { - - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - wlr_damage_ring_add_whole(&pMonitor->damage); - return; } if (shouldTear) pMonitor->tearingState.busy = true; - if (UNLOCK_SC) - wlr_output_lock_software_cursors(pMonitor->output, false); - if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame) g_pCompositor->scheduleFrameForMonitor(pMonitor); @@ -1843,6 +1824,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->onDisconnect(); pMonitor->events.modeChanged.emit(); + pMonitor->updateGlobal(); return true; } @@ -2248,11 +2230,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); pMonitor->events.modeChanged.emit(); + pMonitor->updateGlobal(); return true; } -void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force) { +void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; if (surf == m_sLastCursorData.surf && hotspotX == m_sLastCursorData.hotspotX && hotspotY == m_sLastCursorData.hotspotY && !force) @@ -2266,7 +2249,7 @@ void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspo if (m_bCursorHidden && !force) return; - wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspotX, hotspotY); + g_pCursorManager->setCursorSurface(surf, {hotspotX, hotspotY}); } void CHyprRenderer::setCursorFromName(const std::string& name, bool force) { @@ -2338,7 +2321,7 @@ void CHyprRenderer::setCursorHidden(bool hide) { m_bCursorHidden = hide; if (hide) { - wlr_cursor_unset_image(g_pCompositor->m_sWLRCursor); + g_pPointerManager->resetCursorImage(); return; } @@ -2544,23 +2527,6 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient = PCANDIDATE; } -void CHyprRenderer::renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional overridePos) { - const auto CURSORPOS = overridePos.value_or(g_pInputManager->getMouseCoordsInternal() - pMonitor->vecPosition) * pMonitor->scale; - wlr_output_cursor* cursor; - wl_list_for_each(cursor, &pMonitor->output->cursors, link) { - if (!cursor->enabled || !cursor->visible || pMonitor->output->hardware_cursor == cursor) - continue; - - if (!cursor->texture) - continue; - - CBox cursorBox = CBox{CURSORPOS.x, CURSORPOS.y, cursor->width, cursor->height}.translate({-cursor->hotspot_x, -cursor->hotspot_y}); - - // TODO: NVIDIA doesn't like if we use renderTexturePrimitive here. Why? - g_pHyprOpenGL->renderTexture(cursor->texture, &cursorBox, 1.0); - } -} - CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) { auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; }); @@ -2582,7 +2548,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2593,7 +2559,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode if (mode == RENDER_MODE_FULL_FAKE) { RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!"); fb->bind(); - g_pHyprOpenGL->begin(pMonitor, damage, fb); + if (simple) + g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb); + else + g_pHyprOpenGL->begin(pMonitor, damage, fb); return true; } @@ -2623,7 +2592,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode wlr_damage_ring_rotate_buffer(&pMonitor->damage, m_pCurrentWlrBuffer, damage.pixman()); m_pCurrentRenderbuffer->bind(); - g_pHyprOpenGL->begin(pMonitor, damage); + if (simple) + g_pHyprOpenGL->beginSimple(pMonitor, damage, m_pCurrentRenderbuffer); + else + g_pHyprOpenGL->begin(pMonitor, damage); return true; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b93af0b0..748a055f 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -64,9 +64,8 @@ class CHyprRenderer { void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods bool canSkipBackBufferClear(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor); - void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force = false); + void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); - void renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional overridePos = {}); void onRenderbufferDestroy(CRenderbuffer* rb); CRenderbuffer* getCurrentRBO(); bool isNvidia(); @@ -75,15 +74,14 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr); - void endRender(); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; PHLWINDOWREF m_pLastScanout; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; - bool m_bSoftwareCursorsLocked = false; + CMonitor* m_pMostHzMonitor = nullptr; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); @@ -100,10 +98,10 @@ class CHyprRenderer { CTimer m_tRenderTimer; struct { - int hotspotX; - int hotspotY; - std::optional surf = nullptr; - std::string name; + int hotspotX; + int hotspotY; + std::optional surf = nullptr; + std::string name; } m_sLastCursorData; private: @@ -139,6 +137,7 @@ class CHyprRenderer { friend class CHyprOpenGLImpl; friend class CToplevelExportProtocolManager; friend class CInputManager; + friend class CPointerManager; }; inline std::unique_ptr g_pHyprRenderer; From 84e8d1810d57b65a0bc3b5ac2998bc023df880f4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 6 May 2024 02:15:26 +0100 Subject: [PATCH 0034/2393] Tablet: move to new impl Ring and strip are not implemented. Will I implement this? God fucking knows. Nobody seems to have that anyways. --- CMakeLists.txt | 2 +- protocols/meson.build | 2 +- protocols/tablet-unstable-v2.xml | 1178 --------------------------- src/Compositor.cpp | 2 - src/Compositor.hpp | 1 - src/debug/HyprCtl.cpp | 25 +- src/devices/IHID.hpp | 3 + src/devices/Tablet.cpp | 326 ++++++++ src/devices/Tablet.hpp | 228 ++++++ src/events/Devices.cpp | 4 +- src/helpers/Monitor.cpp | 14 - src/helpers/WLClasses.hpp | 66 -- src/includes.hpp | 1 - src/managers/PointerManager.cpp | 96 ++- src/managers/PointerManager.hpp | 18 +- src/managers/ProtocolManager.cpp | 2 + src/managers/input/InputManager.cpp | 127 ++- src/managers/input/InputManager.hpp | 44 +- src/managers/input/Tablets.cpp | 501 ++++++------ src/protocols/Tablet.cpp | 656 +++++++++++++++ src/protocols/Tablet.hpp | 236 ++++++ 21 files changed, 1926 insertions(+), 1606 deletions(-) delete mode 100644 protocols/tablet-unstable-v2.xml create mode 100644 src/devices/Tablet.cpp create mode 100644 src/devices/Tablet.hpp create mode 100644 src/protocols/Tablet.cpp create mode 100644 src/protocols/Tablet.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f491e100..513f06bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -251,7 +251,6 @@ target_link_libraries(Hyprland uuid ) -protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true) protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) @@ -285,6 +284,7 @@ protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" " protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) +protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 4c315797..345b47ee 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -29,7 +29,6 @@ protocols = [ [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], - ['tablet-unstable-v2.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] ] @@ -60,6 +59,7 @@ new_protocols = [ [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], + [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], ] wl_protos_src = [] diff --git a/protocols/tablet-unstable-v2.xml b/protocols/tablet-unstable-v2.xml deleted file mode 100644 index b286d964..00000000 --- a/protocols/tablet-unstable-v2.xml +++ /dev/null @@ -1,1178 +0,0 @@ - - - - - Copyright 2014 © Stephen "Lyude" Chandler Paul - Copyright 2015-2016 © Red Hat, Inc. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice (including the - next paragraph) shall be included in all copies or substantial - portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - - - This description provides a high-level overview of the interplay between - the interfaces defined this protocol. For details, see the protocol - specification. - - More than one tablet may exist, and device-specifics matter. Tablets are - not represented by a single virtual device like wl_pointer. A client - binds to the tablet manager object which is just a proxy object. From - that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat) - and that returns the actual interface that has all the tablets. With - this indirection, we can avoid merging wp_tablet into the actual Wayland - protocol, a long-term benefit. - - The wp_tablet_seat sends a "tablet added" event for each tablet - connected. That event is followed by descriptive events about the - hardware; currently that includes events for name, vid/pid and - a wp_tablet.path event that describes a local path. This path can be - used to uniquely identify a tablet or get more information through - libwacom. Emulated or nested tablets can skip any of those, e.g. a - virtual tablet may not have a vid/pid. The sequence of descriptive - events is terminated by a wp_tablet.done event to signal that a client - may now finalize any initialization for that tablet. - - Events from tablets require a tool in proximity. Tools are also managed - by the tablet seat; a "tool added" event is sent whenever a tool is new - to the compositor. That event is followed by a number of descriptive - events about the hardware; currently that includes capabilities, - hardware id and serial number, and tool type. Similar to the tablet - interface, a wp_tablet_tool.done event is sent to terminate that initial - sequence. - - Any event from a tool happens on the wp_tablet_tool interface. When the - tool gets into proximity of the tablet, a proximity_in event is sent on - the wp_tablet_tool interface, listing the tablet and the surface. That - event is followed by a motion event with the coordinates. After that, - it's the usual motion, axis, button, etc. events. The protocol's - serialisation means events are grouped by wp_tablet_tool.frame events. - - Two special events (that don't exist in X) are down and up. They signal - "tip touching the surface". For tablets without real proximity - detection, the sequence is: proximity_in, motion, down, frame. - - When the tool leaves proximity, a proximity_out event is sent. If any - button is still down, a button release event is sent before this - proximity event. These button events are sent in the same frame as the - proximity event to signal to the client that the buttons were held when - the tool left proximity. - - If the tool moves out of the surface but stays in proximity (i.e. - between windows), compositor-specific grab policies apply. This usually - means that the proximity-out is delayed until all buttons are released. - - Moving a tool physically from one tablet to the other has no real effect - on the protocol, since we already have the tool object from the "tool - added" event. All the information is already there and the proximity - events on both tablets are all a client needs to reconstruct what - happened. - - Some extra axes are normalized, i.e. the client knows the range as - specified in the protocol (e.g. [0, 65535]), the granularity however is - unknown. The current normalized axes are pressure, distance, and slider. - - Other extra axes are in physical units as specified in the protocol. - The current extra axes with physical units are tilt, rotation and - wheel rotation. - - Since tablets work independently of the pointer controlled by the mouse, - the focus handling is independent too and controlled by proximity. - The wp_tablet_tool.set_cursor request sets a tool-specific cursor. - This cursor surface may be the same as the mouse cursor, and it may be - the same across tools but it is possible to be more fine-grained. For - example, a client may set different cursors for the pen and eraser. - - Tools are generally independent of tablets and it is - compositor-specific policy when a tool can be removed. Common approaches - will likely include some form of removing a tool when all tablets the - tool was used on are removed. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible changes - may be added together with the corresponding interface version bump. - Backward incompatible changes are done by bumping the version number in - the protocol and interface names and resetting the interface version. - Once the protocol is to be declared stable, the 'z' prefix and the - version number in the protocol and interface names are removed and the - interface version number is reset. - - - - - An object that provides access to the graphics tablets available on this - system. All tablets are associated with a seat, to get access to the - actual tablets, use wp_tablet_manager.get_tablet_seat. - - - - - Get the wp_tablet_seat object for the given seat. This object - provides access to all graphics tablets in this seat. - - - - - - - - Destroy the wp_tablet_manager object. Objects created from this - object are unaffected and should be destroyed separately. - - - - - - - An object that provides access to the graphics tablets available on this - seat. After binding to this interface, the compositor sends a set of - wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events. - - - - - Destroy the wp_tablet_seat object. Objects created from this - object are unaffected and should be destroyed separately. - - - - - - This event is sent whenever a new tablet becomes available on this - seat. This event only provides the object id of the tablet, any - static information about the tablet (device name, vid/pid, etc.) is - sent through the wp_tablet interface. - - - - - - - This event is sent whenever a tool that has not previously been used - with a tablet comes into use. This event only provides the object id - of the tool; any static information about the tool (capabilities, - type, etc.) is sent through the wp_tablet_tool interface. - - - - - - - This event is sent whenever a new pad is known to the system. Typically, - pads are physically attached to tablets and a pad_added event is - sent immediately after the wp_tablet_seat.tablet_added. - However, some standalone pad devices logically attach to tablets at - runtime, and the client must wait for wp_tablet_pad.enter to know - the tablet a pad is attached to. - - This event only provides the object id of the pad. All further - features (buttons, strips, rings) are sent through the wp_tablet_pad - interface. - - - - - - - - An object that represents a physical tool that has been, or is - currently in use with a tablet in this seat. Each wp_tablet_tool - object stays valid until the client destroys it; the compositor - reuses the wp_tablet_tool object to indicate that the object's - respective physical tool has come into proximity of a tablet again. - - A wp_tablet_tool object's relation to a physical tool depends on the - tablet's ability to report serial numbers. If the tablet supports - this capability, then the object represents a specific physical tool - and can be identified even when used on multiple tablets. - - A tablet tool has a number of static characteristics, e.g. tool type, - hardware_serial and capabilities. These capabilities are sent in an - event sequence after the wp_tablet_seat.tool_added event before any - actual events from this tool. This initial event sequence is - terminated by a wp_tablet_tool.done event. - - Tablet tool events are grouped by wp_tablet_tool.frame events. - Any events received before a wp_tablet_tool.frame event should be - considered part of the same hardware state change. - - - - - Sets the surface of the cursor used for this tool on the given - tablet. This request only takes effect if the tool is in proximity - of one of the requesting client's surfaces or the surface parameter - is the current pointer surface. If there was a previous surface set - with this request it is replaced. If surface is NULL, the cursor - image is hidden. - - The parameters hotspot_x and hotspot_y define the position of the - pointer surface relative to the pointer location. Its top-left corner - is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the - coordinates of the pointer location, in surface-local coordinates. - - On surface.attach requests to the pointer surface, hotspot_x and - hotspot_y are decremented by the x and y parameters passed to the - request. Attach must be confirmed by wl_surface.commit as usual. - - The hotspot can also be updated by passing the currently set pointer - surface to this request with new values for hotspot_x and hotspot_y. - - The current and pending input regions of the wl_surface are cleared, - and wl_surface.set_input_region is ignored until the wl_surface is no - longer used as the cursor. When the use as a cursor ends, the current - and pending input regions become undefined, and the wl_surface is - unmapped. - - This request gives the surface the role of a wp_tablet_tool cursor. A - surface may only ever be used as the cursor surface for one - wp_tablet_tool. If the surface already has another role or has - previously been used as cursor surface for a different tool, a - protocol error is raised. - - - - - - - - - - This destroys the client's resource for this tool object. - - - - - - Describes the physical type of a tool. The physical type of a tool - generally defines its base usage. - - The mouse tool represents a mouse-shaped tool that is not a relative - device but bound to the tablet's surface, providing absolute - coordinates. - - The lens tool is a mouse-shaped tool with an attached lens to - provide precision focus. - - - - - - - - - - - - - - The tool type is the high-level type of the tool and usually decides - the interaction expected from this tool. - - This event is sent in the initial burst of events before the - wp_tablet_tool.done event. - - - - - - - If the physical tool can be identified by a unique 64-bit serial - number, this event notifies the client of this serial number. - - If multiple tablets are available in the same seat and the tool is - uniquely identifiable by the serial number, that tool may move - between tablets. - - Otherwise, if the tool has no serial number and this event is - missing, the tool is tied to the tablet it first comes into - proximity with. Even if the physical tool is used on multiple - tablets, separate wp_tablet_tool objects will be created, one per - tablet. - - This event is sent in the initial burst of events before the - wp_tablet_tool.done event. - - - - - - - - This event notifies the client of a hardware id available on this tool. - - The hardware id is a device-specific 64-bit id that provides extra - information about the tool in use, beyond the wl_tool.type - enumeration. The format of the id is specific to tablets made by - Wacom Inc. For example, the hardware id of a Wacom Grip - Pen (a stylus) is 0x802. - - This event is sent in the initial burst of events before the - wp_tablet_tool.done event. - - - - - - - - Describes extra capabilities on a tablet. - - Any tool must provide x and y values, extra axes are - device-specific. - - - - - - - - - - - - This event notifies the client of any capabilities of this tool, - beyond the main set of x/y axes and tip up/down detection. - - One event is sent for each extra capability available on this tool. - - This event is sent in the initial burst of events before the - wp_tablet_tool.done event. - - - - - - - This event signals the end of the initial burst of descriptive - events. A client may consider the static description of the tool to - be complete and finalize initialization of the tool. - - - - - - This event is sent when the tool is removed from the system and will - send no further events. Should the physical tool come back into - proximity later, a new wp_tablet_tool object will be created. - - It is compositor-dependent when a tool is removed. A compositor may - remove a tool on proximity out, tablet removal or any other reason. - A compositor may also keep a tool alive until shutdown. - - If the tool is currently in proximity, a proximity_out event will be - sent before the removed event. See wp_tablet_tool.proximity_out for - the handling of any buttons logically down. - - When this event is received, the client must wp_tablet_tool.destroy - the object. - - - - - - Notification that this tool is focused on a certain surface. - - This event can be received when the tool has moved from one surface to - another, or when the tool has come back into proximity above the - surface. - - If any button is logically down when the tool comes into proximity, - the respective button event is sent after the proximity_in event but - within the same frame as the proximity_in event. - - - - - - - - - Notification that this tool has either left proximity, or is no - longer focused on a certain surface. - - When the tablet tool leaves proximity of the tablet, button release - events are sent for each button that was held down at the time of - leaving proximity. These events are sent before the proximity_out - event but within the same wp_tablet.frame. - - If the tool stays within proximity of the tablet, but the focus - changes from one surface to another, a button release event may not - be sent until the button is actually released or the tool leaves the - proximity of the tablet. - - - - - - Sent whenever the tablet tool comes in contact with the surface of the - tablet. - - If the tool is already in contact with the tablet when entering the - input region, the client owning said region will receive a - wp_tablet.proximity_in event, followed by a wp_tablet.down - event and a wp_tablet.frame event. - - Note that this event describes logical contact, not physical - contact. On some devices, a compositor may not consider a tool in - logical contact until a minimum physical pressure threshold is - exceeded. - - - - - - - Sent whenever the tablet tool stops making contact with the surface of - the tablet, or when the tablet tool moves out of the input region - and the compositor grab (if any) is dismissed. - - If the tablet tool moves out of the input region while in contact - with the surface of the tablet and the compositor does not have an - ongoing grab on the surface, the client owning said region will - receive a wp_tablet.up event, followed by a wp_tablet.proximity_out - event and a wp_tablet.frame event. If the compositor has an ongoing - grab on this device, this event sequence is sent whenever the grab - is dismissed in the future. - - Note that this event describes logical contact, not physical - contact. On some devices, a compositor may not consider a tool out - of logical contact until physical pressure falls below a specific - threshold. - - - - - - Sent whenever a tablet tool moves. - - - - - - - - Sent whenever the pressure axis on a tool changes. The value of this - event is normalized to a value between 0 and 65535. - - Note that pressure may be nonzero even when a tool is not in logical - contact. See the down and up events for more details. - - - - - - - Sent whenever the distance axis on a tool changes. The value of this - event is normalized to a value between 0 and 65535. - - Note that distance may be nonzero even when a tool is not in logical - contact. See the down and up events for more details. - - - - - - - Sent whenever one or both of the tilt axes on a tool change. Each tilt - value is in degrees, relative to the z-axis of the tablet. - The angle is positive when the top of a tool tilts along the - positive x or y axis. - - - - - - - - Sent whenever the z-rotation axis on the tool changes. The - rotation value is in degrees clockwise from the tool's - logical neutral position. - - - - - - - Sent whenever the slider position on the tool changes. The - value is normalized between -65535 and 65535, with 0 as the logical - neutral position of the slider. - - The slider is available on e.g. the Wacom Airbrush tool. - - - - - - - Sent whenever the wheel on the tool emits an event. This event - contains two values for the same axis change. The degrees value is - in the same orientation as the wl_pointer.vertical_scroll axis. The - clicks value is in discrete logical clicks of the mouse wheel. This - value may be zero if the movement of the wheel was less - than one logical click. - - Clients should choose either value and avoid mixing degrees and - clicks. The compositor may accumulate values smaller than a logical - click and emulate click events when a certain threshold is met. - Thus, wl_tablet_tool.wheel events with non-zero clicks values may - have different degrees values. - - - - - - - - Describes the physical state of a button that produced the button event. - - - - - - - - Sent whenever a button on the tool is pressed or released. - - If a button is held down when the tool moves in or out of proximity, - button events are generated by the compositor. See - wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for - details. - - - - - - - - - Marks the end of a series of axis and/or button updates from the - tablet. The Wayland protocol requires axis updates to be sent - sequentially, however all events within a frame should be considered - one hardware event. - - - - - - - - - - - - The wp_tablet interface represents one graphics tablet device. The - tablet interface itself does not generate events; all events are - generated by wp_tablet_tool objects when in proximity above a tablet. - - A tablet has a number of static characteristics, e.g. device name and - pid/vid. These capabilities are sent in an event sequence after the - wp_tablet_seat.tablet_added event. This initial event sequence is - terminated by a wp_tablet.done event. - - - - - This destroys the client's resource for this tablet object. - - - - - - This event is sent in the initial burst of events before the - wp_tablet.done event. - - - - - - - This event is sent in the initial burst of events before the - wp_tablet.done event. - - - - - - - - A system-specific device path that indicates which device is behind - this wp_tablet. This information may be used to gather additional - information about the device, e.g. through libwacom. - - A device may have more than one device path. If so, multiple - wp_tablet.path events are sent. A device may be emulated and not - have a device path, and in that case this event will not be sent. - - The format of the path is unspecified, it may be a device node, a - sysfs path, or some other identifier. It is up to the client to - identify the string provided. - - This event is sent in the initial burst of events before the - wp_tablet.done event. - - - - - - - This event is sent immediately to signal the end of the initial - burst of descriptive events. A client may consider the static - description of the tablet to be complete and finalize initialization - of the tablet. - - - - - - Sent when the tablet has been removed from the system. When a tablet - is removed, some tools may be removed. - - When this event is received, the client must wp_tablet.destroy - the object. - - - - - - - A circular interaction area, such as the touch ring on the Wacom Intuos - Pro series tablets. - - Events on a ring are logically grouped by the wl_tablet_pad_ring.frame - event. - - - - - Request that the compositor use the provided feedback string - associated with this ring. This request should be issued immediately - after a wp_tablet_pad_group.mode_switch event from the corresponding - group is received, or whenever the ring is mapped to a different - action. See wp_tablet_pad_group.mode_switch for more details. - - Clients are encouraged to provide context-aware descriptions for - the actions associated with the ring; compositors may use this - information to offer visual feedback about the button layout - (eg. on-screen displays). - - The provided string 'description' is a UTF-8 encoded string to be - associated with this ring, and is considered user-visible; general - internationalization rules apply. - - The serial argument will be that of the last - wp_tablet_pad_group.mode_switch event received for the group of this - ring. Requests providing other serials than the most recent one will be - ignored. - - - - - - - - This destroys the client's resource for this ring object. - - - - - - Describes the source types for ring events. This indicates to the - client how a ring event was physically generated; a client may - adjust the user interface accordingly. For example, events - from a "finger" source may trigger kinetic scrolling. - - - - - - - Source information for ring events. - - This event does not occur on its own. It is sent before a - wp_tablet_pad_ring.frame event and carries the source information - for all events within that frame. - - The source specifies how this event was generated. If the source is - wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event - will be sent when the user lifts the finger off the device. - - This event is optional. If the source is unknown for an interaction, - no event is sent. - - - - - - - Sent whenever the angle on a ring changes. - - The angle is provided in degrees clockwise from the logical - north of the ring in the pad's current rotation. - - - - - - - Stop notification for ring events. - - For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop - event is sent to notify a client that the interaction with the ring - has terminated. This enables the client to implement kinetic scrolling. - See the wp_tablet_pad_ring.source documentation for information on - when this event may be generated. - - Any wp_tablet_pad_ring.angle events with the same source after this - event should be considered as the start of a new interaction. - - - - - - Indicates the end of a set of ring events that logically belong - together. A client is expected to accumulate the data in all events - within the frame before proceeding. - - All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong - logically together. For example, on termination of a finger interaction - on a ring the compositor will send a wp_tablet_pad_ring.source event, - a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event. - - A wp_tablet_pad_ring.frame event is sent for every logical event - group, even if the group only contains a single wp_tablet_pad_ring - event. Specifically, a client may get a sequence: angle, frame, - angle, frame, etc. - - - - - - - - A linear interaction area, such as the strips found in Wacom Cintiq - models. - - Events on a strip are logically grouped by the wl_tablet_pad_strip.frame - event. - - - - - Requests the compositor to use the provided feedback string - associated with this strip. This request should be issued immediately - after a wp_tablet_pad_group.mode_switch event from the corresponding - group is received, or whenever the strip is mapped to a different - action. See wp_tablet_pad_group.mode_switch for more details. - - Clients are encouraged to provide context-aware descriptions for - the actions associated with the strip, and compositors may use this - information to offer visual feedback about the button layout - (eg. on-screen displays). - - The provided string 'description' is a UTF-8 encoded string to be - associated with this ring, and is considered user-visible; general - internationalization rules apply. - - The serial argument will be that of the last - wp_tablet_pad_group.mode_switch event received for the group of this - strip. Requests providing other serials than the most recent one will be - ignored. - - - - - - - - This destroys the client's resource for this strip object. - - - - - - Describes the source types for strip events. This indicates to the - client how a strip event was physically generated; a client may - adjust the user interface accordingly. For example, events - from a "finger" source may trigger kinetic scrolling. - - - - - - - Source information for strip events. - - This event does not occur on its own. It is sent before a - wp_tablet_pad_strip.frame event and carries the source information - for all events within that frame. - - The source specifies how this event was generated. If the source is - wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event - will be sent when the user lifts their finger off the device. - - This event is optional. If the source is unknown for an interaction, - no event is sent. - - - - - - - Sent whenever the position on a strip changes. - - The position is normalized to a range of [0, 65535], the 0-value - represents the top-most and/or left-most position of the strip in - the pad's current rotation. - - - - - - - Stop notification for strip events. - - For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop - event is sent to notify a client that the interaction with the strip - has terminated. This enables the client to implement kinetic - scrolling. See the wp_tablet_pad_strip.source documentation for - information on when this event may be generated. - - Any wp_tablet_pad_strip.position events with the same source after this - event should be considered as the start of a new interaction. - - - - - - Indicates the end of a set of events that represent one logical - hardware strip event. A client is expected to accumulate the data - in all events within the frame before proceeding. - - All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong - logically together. For example, on termination of a finger interaction - on a strip the compositor will send a wp_tablet_pad_strip.source event, - a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame - event. - - A wp_tablet_pad_strip.frame event is sent for every logical event - group, even if the group only contains a single wp_tablet_pad_strip - event. Specifically, a client may get a sequence: position, frame, - position, frame, etc. - - - - - - - - A pad group describes a distinct (sub)set of buttons, rings and strips - present in the tablet. The criteria of this grouping is usually positional, - eg. if a tablet has buttons on the left and right side, 2 groups will be - presented. The physical arrangement of groups is undisclosed and may - change on the fly. - - Pad groups will announce their features during pad initialization. Between - the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the - pad group will announce the buttons, rings and strips contained in it, - plus the number of supported modes. - - Modes are a mechanism to allow multiple groups of actions for every element - in the pad group. The number of groups and available modes in each is - persistent across device plugs. The current mode is user-switchable, it - will be announced through the wp_tablet_pad_group.mode_switch event both - whenever it is switched, and after wp_tablet_pad.enter. - - The current mode logically applies to all elements in the pad group, - although it is at clients' discretion whether to actually perform different - actions, and/or issue the respective .set_feedback requests to notify the - compositor. See the wp_tablet_pad_group.mode_switch event for more details. - - - - - Destroy the wp_tablet_pad_group object. Objects created from this object - are unaffected and should be destroyed separately. - - - - - - Sent on wp_tablet_pad_group initialization to announce the available - buttons in the group. Button indices start at 0, a button may only be - in one group at a time. - - This event is first sent in the initial burst of events before the - wp_tablet_pad_group.done event. - - Some buttons are reserved by the compositor. These buttons may not be - assigned to any wp_tablet_pad_group. Compositors may broadcast this - event in the case of changes to the mapping of these reserved buttons. - If the compositor happens to reserve all buttons in a group, this event - will be sent with an empty array. - - - - - - - Sent on wp_tablet_pad_group initialization to announce available rings. - One event is sent for each ring available on this pad group. - - This event is sent in the initial burst of events before the - wp_tablet_pad_group.done event. - - - - - - - Sent on wp_tablet_pad initialization to announce available strips. - One event is sent for each strip available on this pad group. - - This event is sent in the initial burst of events before the - wp_tablet_pad_group.done event. - - - - - - - Sent on wp_tablet_pad_group initialization to announce that the pad - group may switch between modes. A client may use a mode to store a - specific configuration for buttons, rings and strips and use the - wl_tablet_pad_group.mode_switch event to toggle between these - configurations. Mode indices start at 0. - - Switching modes is compositor-dependent. See the - wp_tablet_pad_group.mode_switch event for more details. - - This event is sent in the initial burst of events before the - wp_tablet_pad_group.done event. This event is only sent when more than - more than one mode is available. - - - - - - - This event is sent immediately to signal the end of the initial - burst of descriptive events. A client may consider the static - description of the tablet to be complete and finalize initialization - of the tablet group. - - - - - - Notification that the mode was switched. - - A mode applies to all buttons, rings and strips in a group - simultaneously, but a client is not required to assign different actions - for each mode. For example, a client may have mode-specific button - mappings but map the ring to vertical scrolling in all modes. Mode - indices start at 0. - - Switching modes is compositor-dependent. The compositor may provide - visual cues to the client about the mode, e.g. by toggling LEDs on - the tablet device. Mode-switching may be software-controlled or - controlled by one or more physical buttons. For example, on a Wacom - Intuos Pro, the button inside the ring may be assigned to switch - between modes. - - The compositor will also send this event after wp_tablet_pad.enter on - each group in order to notify of the current mode. Groups that only - feature one mode will use mode=0 when emitting this event. - - If a button action in the new mode differs from the action in the - previous mode, the client should immediately issue a - wp_tablet_pad.set_feedback request for each changed button. - - If a ring or strip action in the new mode differs from the action - in the previous mode, the client should immediately issue a - wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request - for each changed ring or strip. - - - - - - - - - - A pad device is a set of buttons, rings and strips - usually physically present on the tablet device itself. Some - exceptions exist where the pad device is physically detached, e.g. the - Wacom ExpressKey Remote. - - Pad devices have no axes that control the cursor and are generally - auxiliary devices to the tool devices used on the tablet surface. - - A pad device has a number of static characteristics, e.g. the number - of rings. These capabilities are sent in an event sequence after the - wp_tablet_seat.pad_added event before any actual events from this pad. - This initial event sequence is terminated by a wp_tablet_pad.done - event. - - All pad features (buttons, rings and strips) are logically divided into - groups and all pads have at least one group. The available groups are - notified through the wp_tablet_pad.group event; the compositor will - emit one event per group before emitting wp_tablet_pad.done. - - Groups may have multiple modes. Modes allow clients to map multiple - actions to a single pad feature. Only one mode can be active per group, - although different groups may have different active modes. - - - - - Requests the compositor to use the provided feedback string - associated with this button. This request should be issued immediately - after a wp_tablet_pad_group.mode_switch event from the corresponding - group is received, or whenever a button is mapped to a different - action. See wp_tablet_pad_group.mode_switch for more details. - - Clients are encouraged to provide context-aware descriptions for - the actions associated with each button, and compositors may use - this information to offer visual feedback on the button layout - (e.g. on-screen displays). - - Button indices start at 0. Setting the feedback string on a button - that is reserved by the compositor (i.e. not belonging to any - wp_tablet_pad_group) does not generate an error but the compositor - is free to ignore the request. - - The provided string 'description' is a UTF-8 encoded string to be - associated with this ring, and is considered user-visible; general - internationalization rules apply. - - The serial argument will be that of the last - wp_tablet_pad_group.mode_switch event received for the group of this - button. Requests providing other serials than the most recent one will - be ignored. - - - - - - - - - Destroy the wp_tablet_pad object. Objects created from this object - are unaffected and should be destroyed separately. - - - - - - Sent on wp_tablet_pad initialization to announce available groups. - One event is sent for each pad group available. - - This event is sent in the initial burst of events before the - wp_tablet_pad.done event. At least one group will be announced. - - - - - - - A system-specific device path that indicates which device is behind - this wp_tablet_pad. This information may be used to gather additional - information about the device, e.g. through libwacom. - - The format of the path is unspecified, it may be a device node, a - sysfs path, or some other identifier. It is up to the client to - identify the string provided. - - This event is sent in the initial burst of events before the - wp_tablet_pad.done event. - - - - - - - Sent on wp_tablet_pad initialization to announce the available - buttons. - - This event is sent in the initial burst of events before the - wp_tablet_pad.done event. This event is only sent when at least one - button is available. - - - - - - - This event signals the end of the initial burst of descriptive - events. A client may consider the static description of the pad to - be complete and finalize initialization of the pad. - - - - - - Describes the physical state of a button that caused the button - event. - - - - - - - - Sent whenever the physical state of a button changes. - - - - - - - - - Notification that this pad is focused on the specified surface. - - - - - - - - - Notification that this pad is no longer focused on the specified - surface. - - - - - - - - Sent when the pad has been removed from the system. When a tablet - is removed its pad(s) will be removed too. - - When this event is received, the client must destroy all rings, strips - and groups that were offered by this pad, and issue wp_tablet_pad.destroy - the pad itself. - - - - diff --git a/src/Compositor.cpp b/src/Compositor.cpp index caf042bc..a31b1a57 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -242,8 +242,6 @@ void CCompositor::initServer() { Debug::log(INFO, "VR will not be available"); } - // m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay); - m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); wlr_xdg_foreign_v1_create(m_sWLDisplay, m_sWLRForeignRegistry); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index d017949b..96557b8d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -56,7 +56,6 @@ class CCompositor { wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; int m_iDRMFD; - wlr_tablet_manager_v2* m_sWLRTabletManager; wlr_xdg_foreign_registry* m_sWLRForeignRegistry; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; wlr_backend* m_sWLRHeadlessBackend; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index c0dc8d8e..56b7bd2b 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -22,6 +22,7 @@ #include "../devices/IPointer.hpp" #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" +#include "../devices/Tablet.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -557,7 +558,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"tablets\": [\n"; - for (auto& d : g_pInputManager->m_lTabletPads) { + for (auto& d : g_pInputManager->m_vTabletPads) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -567,26 +568,26 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "name": "{}" }} }},)#", - (uintptr_t)&d, (uintptr_t)d.pTabletParent, escapeJSONStrings(d.pTabletParent ? d.pTabletParent->name : "")); + (uintptr_t)d.get(), (uintptr_t)d->parent.get(), escapeJSONStrings(d->parent ? d->parent->hlName : "")); } - for (auto& d : g_pInputManager->m_lTablets) { + for (auto& d : g_pInputManager->m_vTablets) { result += std::format( R"#( {{ "address": "0x{:x}", "name": "{}" }},)#", - (uintptr_t)&d, escapeJSONStrings(d.name)); + (uintptr_t)d.get(), escapeJSONStrings(d->hlName)); } - for (auto& d : g_pInputManager->m_lTabletTools) { + for (auto& d : g_pInputManager->m_vTabletTools) { result += std::format( R"#( {{ "address": "0x{:x}", "type": "tabletTool", "belongsTo": "0x{:x}" }},)#", - (uintptr_t)&d, d.wlrTabletTool ? (uintptr_t)d.wlrTabletTool->data : 0); + (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); } trimTrailingComma(result); @@ -643,16 +644,16 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n\nTablets:\n"; - for (auto& d : g_pInputManager->m_lTabletPads) { - result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)&d, (uintptr_t)d.pTabletParent, d.pTabletParent ? d.pTabletParent->name : ""); + for (auto& d : g_pInputManager->m_vTabletPads) { + result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->parent.get(), d->parent ? d->parent->hlName : ""); } - for (auto& d : g_pInputManager->m_lTablets) { - result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)&d, d.name, d.wlrTablet->width_mm, d.wlrTablet->height_mm); + for (auto& d : g_pInputManager->m_vTablets) { + result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm); } - for (auto& d : g_pInputManager->m_lTabletTools) { - result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)&d, d.wlrTabletTool ? (uintptr_t)d.wlrTabletTool->data : 0); + for (auto& d : g_pInputManager->m_vTabletTools) { + result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); } result += "\n\nTouch:\n"; diff --git a/src/devices/IHID.hpp b/src/devices/IHID.hpp index 2830864b..cac25112 100644 --- a/src/devices/IHID.hpp +++ b/src/devices/IHID.hpp @@ -8,6 +8,7 @@ enum eHIDCapabilityType : uint32_t { HID_INPUT_CAPABILITY_KEYBOARD = (1 << 0), HID_INPUT_CAPABILITY_POINTER = (1 << 1), HID_INPUT_CAPABILITY_TOUCH = (1 << 2), + HID_INPUT_CAPABILITY_TABLET = (1 << 3), }; enum eHIDType { @@ -16,6 +17,8 @@ enum eHIDType { HID_TYPE_KEYBOARD, HID_TYPE_TOUCH, HID_TYPE_TABLET, + HID_TYPE_TABLET_TOOL, + HID_TYPE_TABLET_PAD, }; /* diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp new file mode 100644 index 00000000..f5b610a9 --- /dev/null +++ b/src/devices/Tablet.cpp @@ -0,0 +1,326 @@ +#include "Tablet.hpp" +#include "../defines.hpp" +#include "../protocols/Tablet.hpp" + +SP CTablet::create(wlr_tablet* tablet) { + SP pTab = SP(new CTablet(tablet)); + + pTab->self = pTab; + + PROTO::tablet->registerDevice(pTab); + + return pTab; +} + +SP CTabletTool::create(wlr_tablet_tool* tablet) { + SP pTab = SP(new CTabletTool(tablet)); + + pTab->self = pTab; + + PROTO::tablet->registerDevice(pTab); + + return pTab; +} + +SP CTabletPad::create(wlr_tablet_pad* tablet) { + SP pTab = SP(new CTabletPad(tablet)); + + pTab->self = pTab; + + PROTO::tablet->registerDevice(pTab); + + return pTab; +} + +SP CTabletTool::fromWlr(wlr_tablet_tool* tool) { + return ((CTabletTool*)tool->data)->self.lock(); +} + +SP CTablet::fromWlr(wlr_tablet* tablet) { + return ((CTablet*)tablet->data)->self.lock(); +} + +static uint32_t wlrUpdateToHl(uint32_t wlr) { + uint32_t result = 0; + if (wlr & WLR_TABLET_TOOL_AXIS_X) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X; + if (wlr & WLR_TABLET_TOOL_AXIS_Y) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y; + if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE; + if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE; + if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X; + if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y; + if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION; + if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER; + if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL) + result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL; + return result; +} + +uint32_t CTablet::getCapabilities() { + return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; +} + +wlr_tablet* CTablet::wlr() { + return tablet; +} + +CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) { + if (!tablet) + return; + + tablet->data = this; + + // clang-format off + hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) { + tablet = nullptr; + disconnectCallbacks(); + events.destroy.emit(); + }, this, "CTablet"); + + hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) { + auto E = (wlr_tablet_tool_axis_event*)data; + + tabletEvents.axis.emit(SAxisEvent{ + .tool = E->tool, + .tablet = self.lock(), + .timeMs = E->time_msec, + .updatedAxes = wlrUpdateToHl(E->updated_axes), + .axis = {E->x, E->y}, + .axisDelta = {E->dx, E->dy}, + .tilt = {E->tilt_x, E->tilt_y}, + .pressure = E->pressure, + .distance = E->distance, + .rotation = E->rotation, + .slider = E->slider, + .wheelDelta = E->wheel_delta, + }); + }, this, "CTablet"); + + hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) { + auto E = (wlr_tablet_tool_proximity_event*)data; + + tabletEvents.proximity.emit(SProximityEvent{ + .tool = E->tool, + .tablet = self.lock(), + .timeMs = E->time_msec, + .proximity = {E->x, E->y}, + .in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN, + }); + }, this, "CTablet"); + + hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) { + auto E = (wlr_tablet_tool_tip_event*)data; + + tabletEvents.tip.emit(STipEvent{ + .tool = E->tool, + .tablet = self.lock(), + .timeMs = E->time_msec, + .tip = {E->x, E->y}, + .in = E->state == WLR_TABLET_TOOL_TIP_DOWN, + }); + }, this, "CTablet"); + + hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) { + auto E = (wlr_tablet_tool_button_event*)data; + + tabletEvents.button.emit(SButtonEvent{ + .tool = E->tool, + .tablet = self.lock(), + .timeMs = E->time_msec, + .button = E->button, + .down = E->state == WLR_BUTTON_PRESSED, + }); + }, this, "CTablet"); + // clang-format on + + deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN"; +} + +CTablet::~CTablet() { + if (tablet) + tablet->data = nullptr; + + PROTO::tablet->recheckRegisteredDevices(); +} + +void CTablet::disconnectCallbacks() { + hyprListener_axis.removeCallback(); + hyprListener_button.removeCallback(); + hyprListener_destroy.removeCallback(); + hyprListener_proximity.removeCallback(); + hyprListener_tip.removeCallback(); +} + +eHIDType CTablet::getType() { + return HID_TYPE_TABLET; +} + +uint32_t CTabletPad::getCapabilities() { + return HID_INPUT_CAPABILITY_TABLET; +} + +wlr_tablet_pad* CTabletPad::wlr() { + return pad; +} + +eHIDType CTabletPad::getType() { + return HID_TYPE_TABLET_PAD; +} + +CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) { + if (!pad) + return; + + // clang-format off + hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) { + pad = nullptr; + disconnectCallbacks(); + events.destroy.emit(); + }, this, "CTabletPad"); + + hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) { + auto E = (wlr_tablet_pad_button_event*)data; + + padEvents.button.emit(SButtonEvent{ + .timeMs = E->time_msec, + .button = E->button, + .down = E->state == WLR_BUTTON_PRESSED, + .mode = E->mode, + .group = E->group, + }); + }, this, "CTabletPad"); + + hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) { + auto E = (wlr_tablet_pad_ring_event*)data; + + padEvents.ring.emit(SRingEvent{ + .timeMs = E->time_msec, + .finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, + .ring = E->ring, + .position = E->position, + .mode = E->mode, + }); + }, this, "CTabletPad"); + + hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) { + auto E = (wlr_tablet_pad_strip_event*)data; + + padEvents.strip.emit(SStripEvent{ + .timeMs = E->time_msec, + .finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, + .strip = E->strip, + .position = E->position, + .mode = E->mode, + }); + }, this, "CTabletPad"); + + hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) { + if (!data) + return; + + padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data)); + }, this, "CTabletPad"); + // clang-format on + + deviceName = pad->base.name ? pad->base.name : "UNKNOWN"; +} + +CTabletPad::~CTabletPad() { + PROTO::tablet->recheckRegisteredDevices(); +} + +void CTabletPad::disconnectCallbacks() { + hyprListener_ring.removeCallback(); + hyprListener_button.removeCallback(); + hyprListener_destroy.removeCallback(); + hyprListener_strip.removeCallback(); + hyprListener_attach.removeCallback(); +} + +uint32_t CTabletTool::getCapabilities() { + return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; +} + +wlr_tablet_tool* CTabletTool::wlr() { + return tool; +} + +eHIDType CTabletTool::getType() { + return HID_TYPE_TABLET_TOOL; +} + +CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) { + if (!tool) + return; + + // clang-format off + hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) { + tool = nullptr; + disconnectCallbacks(); + events.destroy.emit(); + }, this, "CTabletTool"); + // clang-format on + + if (tool->tilt) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; + if (tool->pressure) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; + if (tool->distance) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; + if (tool->rotation) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; + if (tool->slider) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; + if (tool->wheel) + toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; + + tool->data = this; + + deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom); +} + +CTabletTool::~CTabletTool() { + if (tool) + tool->data = nullptr; + + PROTO::tablet->recheckRegisteredDevices(); +} + +void CTabletTool::disconnectCallbacks() { + hyprListener_destroy.removeCallback(); + hyprListener_destroySurface.removeCallback(); +} + +wlr_surface* CTabletTool::getSurface() { + return pSurface; +} + +void CTabletTool::setSurface(wlr_surface* surf) { + if (surf == pSurface) + return; + + if (pSurface) { + hyprListener_destroySurface.removeCallback(); + pSurface = nullptr; + } + + pSurface = surf; + + if (surf) { + hyprListener_destroySurface.initCallback( + &surf->events.destroy, + [this](void* owner, void* data) { + PROTO::tablet->proximityOut(self.lock()); + pSurface = nullptr; + hyprListener_destroySurface.removeCallback(); + }, + this, "CTabletTool"); + } +} diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp new file mode 100644 index 00000000..f2444972 --- /dev/null +++ b/src/devices/Tablet.hpp @@ -0,0 +1,228 @@ +#pragma once + +#include "IHID.hpp" +#include "../helpers/WLListener.hpp" +#include "../macros.hpp" +#include "../helpers/Vector2D.hpp" +#include "../helpers/Box.hpp" + +struct wlr_tablet; +struct wlr_tablet_tool; +struct wlr_tablet_pad; + +class CTabletTool; +class CTabletPad; + +/* + A tablet device + Tablets don't have an interface for now, + if there will be a need it's trivial to do. +*/ +class CTablet : public IHID { + public: + static SP create(wlr_tablet* tablet); + static SP fromWlr(wlr_tablet* tablet); + ~CTablet(); + + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + wlr_tablet* wlr(); + + enum eTabletToolAxes { + HID_TABLET_TOOL_AXIS_X = (1 << 0), + HID_TABLET_TOOL_AXIS_Y = (1 << 1), + HID_TABLET_TOOL_AXIS_TILT_X = (1 << 2), + HID_TABLET_TOOL_AXIS_TILT_Y = (1 << 3), + HID_TABLET_TOOL_AXIS_DISTANCE = (1 << 4), + HID_TABLET_TOOL_AXIS_PRESSURE = (1 << 5), + HID_TABLET_TOOL_AXIS_ROTATION = (1 << 6), + HID_TABLET_TOOL_AXIS_SLIDER = (1 << 7), + HID_TABLET_TOOL_AXIS_WHEEL = (1 << 8), + }; + + struct SAxisEvent { + wlr_tablet_tool* tool; + SP tablet; + + uint32_t timeMs = 0; + uint32_t updatedAxes = 0; // eTabletToolAxes + Vector2D axis; + Vector2D axisDelta; + Vector2D tilt; + double pressure = 0; + double distance = 0; + double rotation = 0; + double slider = 0; + double wheelDelta = 0; + }; + + struct SProximityEvent { + wlr_tablet_tool* tool; + SP tablet; + + uint32_t timeMs = 0; + Vector2D proximity; + bool in = false; + }; + + struct STipEvent { + wlr_tablet_tool* tool; + SP tablet; + + uint32_t timeMs = 0; + Vector2D tip; + bool in = false; + }; + + struct SButtonEvent { + wlr_tablet_tool* tool; + SP tablet; + + uint32_t timeMs = 0; + uint32_t button; + bool down = false; + }; + + struct { + CSignal axis; + CSignal proximity; + CSignal tip; + CSignal button; + } tabletEvents; + + WP self; + + bool relativeInput = false; + std::string hlName = ""; + std::string boundOutput = ""; + CBox activeArea; + CBox boundBox; // output-local + + private: + CTablet(wlr_tablet* tablet); + + void disconnectCallbacks(); + + wlr_tablet* tablet = nullptr; + + DYNLISTENER(destroy); + DYNLISTENER(axis); + DYNLISTENER(proximity); + DYNLISTENER(tip); + DYNLISTENER(button); +}; + +class CTabletPad : public IHID { + public: + static SP create(wlr_tablet_pad* pad); + ~CTabletPad(); + + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + wlr_tablet_pad* wlr(); + + struct SButtonEvent { + uint32_t timeMs = 0; + uint32_t button = 0; + bool down = false; + uint32_t mode = 0; + uint32_t group = 0; + }; + + struct SRingEvent { + uint32_t timeMs = 0; + bool finger = false; + uint32_t ring = 0; + double position = 0; + uint32_t mode = 0; + }; + + struct SStripEvent { + uint32_t timeMs = 0; + bool finger = false; + uint32_t strip = 0; + double position = 0; + uint32_t mode = 0; + }; + + struct { + CSignal button; + CSignal ring; + CSignal strip; + CSignal attach; + } padEvents; + + WP self; + WP parent; + + std::string hlName; + + private: + CTabletPad(wlr_tablet_pad* pad); + + void disconnectCallbacks(); + + wlr_tablet_pad* pad = nullptr; + + DYNLISTENER(destroy); + DYNLISTENER(ring); + DYNLISTENER(strip); + DYNLISTENER(button); + DYNLISTENER(attach); +}; + +class CTabletTool : public IHID { + public: + static SP create(wlr_tablet_tool* tool); + static SP fromWlr(wlr_tablet_tool* tool); + ~CTabletTool(); + + enum eTabletToolType { + HID_TABLET_TOOL_TYPE_PEN = 1, + HID_TABLET_TOOL_TYPE_ERASER, + HID_TABLET_TOOL_TYPE_BRUSH, + HID_TABLET_TOOL_TYPE_PENCIL, + HID_TABLET_TOOL_TYPE_AIRBRUSH, + HID_TABLET_TOOL_TYPE_MOUSE, + HID_TABLET_TOOL_TYPE_LENS, + HID_TABLET_TOOL_TYPE_TOTEM, + }; + + enum eTabletToolCapabilities { + HID_TABLET_TOOL_CAPABILITY_TILT = (1 << 0), + HID_TABLET_TOOL_CAPABILITY_PRESSURE = (1 << 1), + HID_TABLET_TOOL_CAPABILITY_DISTANCE = (1 << 2), + HID_TABLET_TOOL_CAPABILITY_ROTATION = (1 << 3), + HID_TABLET_TOOL_CAPABILITY_SLIDER = (1 << 4), + HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), + }; + + virtual uint32_t getCapabilities(); + wlr_tablet_tool* wlr(); + virtual eHIDType getType(); + wlr_surface* getSurface(); + void setSurface(wlr_surface*); + + WP self; + Vector2D tilt; + bool active = false; // true if in proximity + uint32_t toolCapabilities = 0; + + bool isDown = false; + std::vector buttonsDown; + Vector2D absolutePos; // last known absolute position. + + std::string hlName; + + private: + CTabletTool(wlr_tablet_tool* tool); + + void disconnectCallbacks(); + + wlr_surface* pSurface = nullptr; + + wlr_tablet_tool* tool = nullptr; + + DYNLISTENER(destroy); + DYNLISTENER(destroySurface); +}; \ No newline at end of file diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index f36a95de..16a64559 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -38,8 +38,8 @@ void Events::listener_newInput(wl_listener* listener, void* data) { g_pInputManager->newTouchDevice(DEVICE); break; case WLR_INPUT_DEVICE_TABLET: - Debug::log(LOG, "Attached a tablet tool with name {}", DEVICE->name); - g_pInputManager->newTabletTool(DEVICE); + Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name); + g_pInputManager->newTablet(DEVICE); break; case WLR_INPUT_DEVICE_TABLET_PAD: Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d0e777ed..fa68655f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -146,20 +146,6 @@ void CMonitor::onConnect(bool noRule) { if (!noRule) g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); - for (const auto& PTOUCHDEV : g_pInputManager->m_vTouches) { - if (matchesStaticSelector(PTOUCHDEV->boundOutput)) { - Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, szName); - // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output); - } - } - - for (const auto& PTABLET : g_pInputManager->m_lTablets) { - if (matchesStaticSelector(PTABLET.boundOutput)) { - Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName); - // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output); - } - } - if (!state.commit()) Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index bed2b915..bc07f6ba 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -85,72 +85,6 @@ struct SDrag { DYNLISTENER(commitIcon); }; -struct STablet { - DYNLISTENER(Tip); - DYNLISTENER(Axis); - DYNLISTENER(Button); - DYNLISTENER(Proximity); - DYNLISTENER(Destroy); - - wlr_tablet* wlrTablet = nullptr; - wlr_tablet_v2_tablet* wlrTabletV2 = nullptr; - wlr_input_device* wlrDevice = nullptr; - - bool relativeInput = false; - - std::string name = ""; - - std::string boundOutput = ""; - - CBox activeArea; - - // - bool operator==(const STablet& b) const { - return wlrDevice == b.wlrDevice; - } -}; - -struct STabletTool { - wlr_tablet_tool* wlrTabletTool = nullptr; - wlr_tablet_v2_tablet_tool* wlrTabletToolV2 = nullptr; - - wlr_tablet_v2_tablet* wlrTabletOwnerV2 = nullptr; - - wlr_surface* pSurface = nullptr; - - double tiltX = 0; - double tiltY = 0; - - bool active = true; - - std::string name = ""; - - DYNLISTENER(TabletToolDestroy); - DYNLISTENER(TabletToolSetCursor); - - bool operator==(const STabletTool& b) const { - return wlrTabletTool == b.wlrTabletTool; - } -}; - -struct STabletPad { - wlr_tablet_v2_tablet_pad* wlrTabletPadV2 = nullptr; - STablet* pTabletParent = nullptr; - wlr_input_device* pWlrDevice = nullptr; - - std::string name = ""; - - DYNLISTENER(Attach); - DYNLISTENER(Button); - DYNLISTENER(Strip); - DYNLISTENER(Ring); - DYNLISTENER(Destroy); - - bool operator==(const STabletPad& b) const { - return wlrTabletPadV2 == b.wlrTabletPadV2; - } -}; - struct SSwipeGesture { PHLWORKSPACE pWorkspaceBegin = nullptr; diff --git a/src/includes.hpp b/src/includes.hpp index 57ea5d54..080dbd4e 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -69,7 +69,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index caff8d22..c6478b9a 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -635,37 +635,60 @@ void CPointerManager::warpTo(const Vector2D& logical) { void CPointerManager::move(const Vector2D& deltaLogical) { const auto oldPos = pointerPos; - auto newPos = oldPos + deltaLogical; + auto newPos = oldPos + Vector2D{std::isnan(deltaLogical.x) ? 0.0 : deltaLogical.x, std::isnan(deltaLogical.y) ? 0.0 : deltaLogical.y}; warpTo(newPos); } -void CPointerManager::warpAbsolute(const Vector2D& abs, SP dev) { +void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { SP currentMonitor = g_pCompositor->m_pLastMonitor.lock(); + if (!currentMonitor) + return; + + if (!std::isnan(abs.x)) + abs.x = std::clamp(abs.x, 0.0, 1.0); + if (!std::isnan(abs.y)) + abs.y = std::clamp(abs.y, 0.0, 1.0); + + // in logical global + CBox mappedArea = currentMonitor->logicalBox(); switch (dev->getType()) { - case HID_TYPE_TABLET: - //TODO: - break; - case HID_TYPE_TOUCH: { - auto TOUCH = SP(dev); - if (!TOUCH->boundOutput.empty()) { - const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); - if (PMONITOR) + case HID_TYPE_TABLET: { + CTablet* TAB = reinterpret_cast(dev.get()); + if (!TAB->boundOutput.empty()) { + if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TAB->boundOutput); PMONITOR) { currentMonitor = PMONITOR->self.lock(); + mappedArea = currentMonitor->logicalBox(); + } + } + + if (!TAB->boundBox.empty()) + mappedArea = TAB->boundBox.translate(currentMonitor->vecPosition); + break; + } + case HID_TYPE_TOUCH: { + ITouch* TOUCH = reinterpret_cast(dev.get()); + if (!TOUCH->boundOutput.empty()) { + if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); PMONITOR) { + currentMonitor = PMONITOR->self.lock(); + mappedArea = currentMonitor->logicalBox(); + } } break; } default: break; } - if (!currentMonitor) - return; - damageIfSoftware(); - pointerPos = currentMonitor->vecPosition + currentMonitor->vecSize * abs; + if (std::isnan(abs.x) || std::isnan(abs.y)) { + pointerPos.x = std::isnan(abs.x) ? pointerPos.x : mappedArea.x + mappedArea.w * abs.x; + pointerPos.y = std::isnan(abs.y) ? pointerPos.y : mappedArea.y + mappedArea.h * abs.y; + } else + pointerPos = mappedArea.pos() + mappedArea.size() * abs; + onCursorMoved(); recheckEnteredOutputs(); @@ -839,6 +862,47 @@ void CPointerManager::attachTouch(SP touch) { Debug::log(LOG, "Attached touch {} to global", touch->hlName); } +void CPointerManager::attachTablet(SP tablet) { + if (!tablet) + return; + + auto listener = tabletListeners.emplace_back(makeShared()); + + listener->tablet = tablet; + + // clang-format off + listener->destroy = tablet->events.destroy.registerListener([this] (std::any d) { + detachTablet(nullptr); + }); + + listener->axis = tablet->tabletEvents.axis.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTabletAxis(E); + }); + + listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTabletProximity(E); + }); + + listener->tip = tablet->tabletEvents.tip.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTabletTip(E); + }); + + listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { + auto E = std::any_cast(e); + + g_pInputManager->onTabletButton(E); + }); + // clang-format on + + Debug::log(LOG, "Attached tablet {} to global", tablet->hlName); +} + void CPointerManager::detachPointer(SP pointer) { std::erase_if(pointerListeners, [pointer](const auto& e) { return e->pointer.expired() || e->pointer == pointer; }); } @@ -847,6 +911,10 @@ void CPointerManager::detachTouch(SP touch) { std::erase_if(touchListeners, [touch](const auto& e) { return e->touch.expired() || e->touch == touch; }); } +void CPointerManager::detachTablet(SP tablet) { + std::erase_if(tabletListeners, [tablet](const auto& e) { return e->tablet.expired() || e->tablet == tablet; }); +} + void CPointerManager::damageCursor(SP pMonitor) { for (auto& mw : monitorStates) { if (mw->monitor != pMonitor) diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 2446cde7..71ab0fc2 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -2,6 +2,7 @@ #include "../devices/IPointer.hpp" #include "../devices/ITouch.hpp" +#include "../devices/Tablet.hpp" #include "../helpers/Box.hpp" #include "../helpers/Region.hpp" #include "../desktop/WLSurface.hpp" @@ -22,18 +23,18 @@ class CPointerManager { public: CPointerManager(); - // pointers will move the cursor on their respective events void attachPointer(SP pointer); - // touch inputs won't move the cursor, it needs to be done manually void attachTouch(SP touch); + void attachTablet(SP tablet); void detachPointer(SP pointer); void detachTouch(SP touch); + void detachTablet(SP tablet); // only clamps to the layout. void warpTo(const Vector2D& logical); void move(const Vector2D& deltaLogical); - void warpAbsolute(const Vector2D& abs, SP dev); + void warpAbsolute(Vector2D abs, SP dev); void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot); @@ -111,6 +112,17 @@ class CPointerManager { }; std::vector> touchListeners; + struct STabletListener { + CHyprSignalListener destroy; + CHyprSignalListener axis; + CHyprSignalListener proximity; + CHyprSignalListener tip; + CHyprSignalListener button; + + WP tablet; + }; + std::vector> tabletListeners; + struct { std::vector monitorBoxes; } currentMonitorLayout; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index ee27d35d..60fde1aa 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -25,6 +25,7 @@ #include "../protocols/OutputManagement.hpp" #include "../protocols/ServerDecorationKDE.hpp" #include "../protocols/FocusGrab.hpp" +#include "../protocols/Tablet.hpp" CProtocolManager::CProtocolManager() { @@ -53,6 +54,7 @@ CProtocolManager::CProtocolManager() { PROTO::outputManagement = std::make_unique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); + PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 22fc24d4..7e746cfc 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -58,9 +58,9 @@ CInputManager::~CInputManager() { m_vKeyboards.clear(); m_vPointers.clear(); m_vTouches.clear(); - m_lTablets.clear(); - m_lTabletTools.clear(); - m_lTabletPads.clear(); + m_vTablets.clear(); + m_vTabletTools.clear(); + m_vTabletPads.clear(); m_vIdleInhibitors.clear(); m_lSwitches.clear(); } @@ -777,6 +777,8 @@ void CInputManager::newVirtualKeyboard(SP keyboard) } void CInputManager::setupKeyboard(SP keeb) { + m_vHIDs.push_back(keeb); + try { keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name); } catch (std::exception& e) { @@ -977,6 +979,8 @@ void CInputManager::newMouse(wlr_input_device* mouse) { } void CInputManager::setupMouse(SP mauz) { + m_vHIDs.push_back(mauz); + try { mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name); } catch (std::exception& e) { @@ -1165,6 +1169,11 @@ void CInputManager::setPointerConfigs() { } } +static void removeFromHIDs(WP hid) { + std::erase_if(g_pInputManager->m_vHIDs, [hid](const auto& e) { return e.expired() || e == hid; }); + g_pInputManager->updateCapabilities(); +} + void CInputManager::destroyKeyboard(SP pKeyboard) { if (pKeyboard->xkbTranslationState) xkb_state_unref(pKeyboard->xkbTranslationState); @@ -1180,6 +1189,8 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { g_pCompositor->m_sSeat.keyboard.reset(); wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, nullptr); } + + removeFromHIDs(pKeyboard); } void CInputManager::destroyPointer(SP mouse) { @@ -1189,12 +1200,40 @@ void CInputManager::destroyPointer(SP mouse) { if (!g_pCompositor->m_sSeat.mouse.expired()) unconstrainMouse(); + + removeFromHIDs(mouse); } void CInputManager::destroyTouchDevice(SP touch) { Debug::log(LOG, "Touch device at {:x} removed", (uintptr_t)touch.get()); std::erase_if(m_vTouches, [touch](const auto& other) { return other == touch; }); + + removeFromHIDs(touch); +} + +void CInputManager::destroyTablet(SP tablet) { + Debug::log(LOG, "Tablet device at {:x} removed", (uintptr_t)tablet.get()); + + std::erase_if(m_vTablets, [tablet](const auto& other) { return other == tablet; }); + + removeFromHIDs(tablet); +} + +void CInputManager::destroyTabletTool(SP tool) { + Debug::log(LOG, "Tablet tool at {:x} removed", (uintptr_t)tool.get()); + + std::erase_if(m_vTabletTools, [tool](const auto& other) { return other == tool; }); + + removeFromHIDs(tool); +} + +void CInputManager::destroyTabletPad(SP pad) { + Debug::log(LOG, "Tablet pad at {:x} removed", (uintptr_t)pad.get()); + + std::erase_if(m_vTabletPads, [pad](const auto& other) { return other == pad; }); + + removeFromHIDs(pad); } void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { @@ -1338,14 +1377,19 @@ bool CInputManager::isConstrained() { void CInputManager::updateCapabilities() { uint32_t caps = 0; - if (!m_vKeyboards.empty()) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - if (!m_vPointers.empty()) - caps |= WL_SEAT_CAPABILITY_POINTER; - if (!m_vTouches.empty()) - caps |= WL_SEAT_CAPABILITY_TOUCH; - if (!m_lTabletTools.empty()) - caps |= WL_SEAT_CAPABILITY_POINTER; + for (auto& h : m_vHIDs) { + if (h.expired()) + continue; + + auto cap = h->getCapabilities(); + + if (cap & HID_INPUT_CAPABILITY_KEYBOARD) + caps |= WL_SEAT_CAPABILITY_KEYBOARD; + if (cap & HID_INPUT_CAPABILITY_POINTER) + caps |= WL_SEAT_CAPABILITY_POINTER; + if (cap & HID_INPUT_CAPABILITY_TOUCH) + caps |= WL_SEAT_CAPABILITY_TOUCH; + } wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps); m_uiCapabilities = caps; @@ -1380,6 +1424,7 @@ void CInputManager::disableAllKeyboards(bool virt) { void CInputManager::newTouchDevice(wlr_input_device* pDevice) { const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice))); + m_vHIDs.push_back(PNEWDEV); try { PNEWDEV->hlName = getNameForNewDevice(pDevice->name); @@ -1450,43 +1495,39 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { } void CInputManager::setTabletConfigs() { - for (auto& t : m_lTablets) { - if (wlr_input_device_is_libinput(t.wlrDevice)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(t.wlrDevice); + for (auto& t : m_vTablets) { + if (wlr_input_device_is_libinput(&t->wlr()->base)) { + const auto NAME = t->hlName; + const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&t->wlr()->base); - const auto RELINPUT = g_pConfigManager->getDeviceInt(t.name, "relative_input", "input:tablet:relative_input"); - t.relativeInput = RELINPUT; + const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input"); + t->relativeInput = RELINPUT; - const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(t.name, "transform", "input:tablet:transform"), 0, 7); - Debug::log(LOG, "Setting calibration matrix for device {}", t.name); + const int ROTATION = std::clamp(g_pConfigManager->getDeviceInt(NAME, "transform", "input:tablet:transform"), 0, 7); + Debug::log(LOG, "Setting calibration matrix for device {}", NAME); libinput_device_config_calibration_set_matrix(LIBINPUTDEV, MATRICES[ROTATION]); - if (g_pConfigManager->getDeviceInt(t.name, "left_handed", "input:tablet:left_handed") == 0) + if (g_pConfigManager->getDeviceInt(NAME, "left_handed", "input:tablet:left_handed") == 0) libinput_device_config_left_handed_set(LIBINPUTDEV, 0); else libinput_device_config_left_handed_set(LIBINPUTDEV, 1); - const auto OUTPUT = g_pConfigManager->getDeviceString(t.name, "output", "input:tablet:output"); - const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT); - if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) { - Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName); - // wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output); - // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr); - t.boundOutput = OUTPUT; - } else if (!PMONITOR) - Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT); + const auto OUTPUT = g_pConfigManager->getDeviceString(NAME, "output", "input:tablet:output"); + if (OUTPUT != STRVAL_EMPTY) { + Debug::log(LOG, "Binding tablet {} to output {}", NAME, OUTPUT); + t->boundOutput = OUTPUT; + } else + t->boundOutput = ""; - const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position"); - const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size"); - //auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y}; - // if (!regionBox.empty()) - // wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr()); + const auto REGION_POS = g_pConfigManager->getDeviceVec(NAME, "region_position", "input:tablet:region_position"); + const auto REGION_SIZE = g_pConfigManager->getDeviceVec(NAME, "region_size", "input:tablet:region_size"); + t->boundBox = {REGION_POS, REGION_SIZE}; - const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size"); - const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position"); + const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size"); + const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position"); if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) { - t.activeArea = CBox{ACTIVE_AREA_POS.x / t.wlrTablet->width_mm, ACTIVE_AREA_POS.y / t.wlrTablet->height_mm, - (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t.wlrTablet->width_mm, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t.wlrTablet->height_mm}; + t->activeArea = CBox{ACTIVE_AREA_POS.x / t->wlr()->width_mm, ACTIVE_AREA_POS.y / t->wlr()->height_mm, (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->wlr()->width_mm, + (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm}; } } } @@ -1575,16 +1616,16 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) { [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTouches.end()) dupeno++; - while (std::find_if(m_lTabletPads.begin(), m_lTabletPads.end(), - [&](const STabletPad& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletPads.end()) + while (std::find_if(m_vTabletPads.begin(), m_vTabletPads.end(), + [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletPads.end()) dupeno++; - while (std::find_if(m_lTablets.begin(), m_lTablets.end(), - [&](const STablet& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTablets.end()) + while (std::find_if(m_vTablets.begin(), m_vTablets.end(), + [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTablets.end()) dupeno++; - while (std::find_if(m_lTabletTools.begin(), m_lTabletTools.end(), - [&](const STabletTool& other) { return other.name == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_lTabletTools.end()) + while (std::find_if(m_vTabletTools.begin(), m_vTabletTools.end(), + [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletTools.end()) dupeno++; return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index a2caed46..970d53c8 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -9,6 +9,7 @@ #include "../../helpers/signal/Listener.hpp" #include "../../devices/IPointer.hpp" #include "../../devices/ITouch.hpp" +#include "../../devices/Tablet.hpp" class CPointerConstraint; class CWindow; @@ -87,9 +88,15 @@ class CInputManager { void newVirtualMouse(SP); void newTouchDevice(wlr_input_device*); void newSwitch(wlr_input_device*); + void newTabletTool(wlr_tablet_tool*); + void newTabletPad(wlr_input_device*); + void newTablet(wlr_input_device*); void destroyTouchDevice(SP); void destroyKeyboard(SP); void destroyPointer(SP); + void destroyTablet(SP); + void destroyTabletTool(SP); + void destroyTabletPad(SP); void destroySwitch(SSwitchDevice*); void unconstrainMouse(); @@ -116,6 +123,15 @@ class CInputManager { void onTouchUp(ITouch::SUpEvent); void onTouchMove(ITouch::SMotionEvent); + void onSwipeBegin(IPointer::SSwipeBeginEvent); + void onSwipeEnd(IPointer::SSwipeEndEvent); + void onSwipeUpdate(IPointer::SSwipeUpdateEvent); + + void onTabletAxis(CTablet::SAxisEvent); + void onTabletProximity(CTablet::SProximityEvent); + void onTabletTip(CTablet::STipEvent); + void onTabletButton(CTablet::SButtonEvent); + STouchData m_sTouchData; // for dragging floating windows @@ -124,18 +140,17 @@ class CInputManager { bool m_bWasDraggingWindow = false; // for refocus to be forced - PHLWINDOWREF m_pForcedFocus; + PHLWINDOWREF m_pForcedFocus; - SDrag m_sDrag; + SDrag m_sDrag; - std::vector> m_vKeyboards; - std::vector> m_vPointers; - std::vector> m_vTouches; - - // tablets - std::list m_lTablets; - std::list m_lTabletTools; - std::list m_lTabletPads; + std::vector> m_vKeyboards; + std::vector> m_vPointers; + std::vector> m_vTouches; + std::vector> m_vTablets; + std::vector> m_vTabletTools; + std::vector> m_vTabletPads; + std::vector> m_vHIDs; // general container for all HID devices connected to the input manager. // Switches std::list m_lSwitches; @@ -147,16 +162,9 @@ class CInputManager { std::vector> m_vConstraints; // - void newTabletTool(wlr_input_device*); - void newTabletPad(wlr_input_device*); - void focusTablet(STablet*, wlr_tablet_tool*, bool motion = false); void newIdleInhibitor(std::any); void recheckIdleInhibitorStatus(); - void onSwipeBegin(IPointer::SSwipeBeginEvent); - void onSwipeEnd(IPointer::SSwipeEndEvent); - void onSwipeUpdate(IPointer::SSwipeUpdateEvent); - SSwipeGesture m_sActiveSwipe; CTimer m_tmrLastCursorMovement; @@ -223,7 +231,7 @@ class CInputManager { void mouseMoveUnified(uint32_t, bool refocus = false); - STabletTool* ensureTabletToolPresent(wlr_tablet_tool*); + SP ensureTabletToolPresent(wlr_tablet_tool*); void applyConfigToKeyboard(SP); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index a0bd81ce..cf666ec6 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -1,290 +1,291 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" #include "../../protocols/IdleNotify.hpp" +#include "../../protocols/Tablet.hpp" +#include "../../devices/Tablet.hpp" +#include "../../managers/PointerManager.hpp" +#include "../../protocols/PointerConstraints.hpp" -void CInputManager::newTabletTool(wlr_input_device* pDevice) { - const auto PNEWTABLET = &m_lTablets.emplace_back(); +static void unfocusTool(SP tool) { + if (!tool->getSurface()) + return; + + tool->setSurface(nullptr); + if (tool->isDown) + PROTO::tablet->up(tool); + for (auto& b : tool->buttonsDown) { + PROTO::tablet->buttonTool(tool, b, false); + } + PROTO::tablet->proximityOut(tool); +} + +static void focusTool(SP tool, SP tablet, wlr_surface* surf) { + if (tool->getSurface() == surf || !surf) + return; + + if (tool->getSurface() && tool->getSurface() != surf) + unfocusTool(tool); + + tool->setSurface(surf); + PROTO::tablet->proximityIn(tool, tablet, surf); + if (tool->isDown) + PROTO::tablet->down(tool); + for (auto& b : tool->buttonsDown) { + PROTO::tablet->buttonTool(tool, b, true); + } +} + +static void refocusTablet(SP tab, SP tool, bool motion = false) { + const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pInputManager->m_pLastMouseSurface); + + if (!LASTHLSURFACE || !tool->active) { + if (tool->getSurface()) + unfocusTool(tool); + + return; + } + + const auto BOX = LASTHLSURFACE->getSurfaceBoxGlobal(); + + if (!BOX.has_value()) { + if (tool->getSurface()) + unfocusTool(tool); + + return; + } + + const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); + + focusTool(tool, tab, g_pInputManager->m_pLastMouseSurface); + + if (!motion) + return; + + if (LASTHLSURFACE->constraint() && tool->wlr()->type != WLR_TABLET_TOOL_TYPE_MOUSE) { + // cursor logic will completely break here as the cursor will be locked. + // let's just "map" the desired position to the constraint area. + + Vector2D local; + + // yes, this technically ignores any regions set by the app. Too bad! + if (LASTHLSURFACE->getWindow()) + local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize.goal(); + else + local = tool->absolutePos * BOX->size(); + + if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_bIsX11) + local = local * LASTHLSURFACE->getWindow()->m_fX11SurfaceScaledBy; + + PROTO::tablet->motion(tool, local); + return; + } + + auto local = CURSORPOS - BOX->pos(); + + if (LASTHLSURFACE->getWindow() && LASTHLSURFACE->getWindow()->m_bIsX11) + local = local * LASTHLSURFACE->getWindow()->m_fX11SurfaceScaledBy; + + PROTO::tablet->motion(tool, local); +} + +void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { + const auto PTAB = e.tablet; + const auto PTOOL = ensureTabletToolPresent(e.tool); + + if (PTOOL->active && (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y))) { + double x = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X) ? e.axis.x : NAN; + double dx = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X) ? e.axisDelta.x : NAN; + double y = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y) ? e.axis.y : NAN; + double dy = (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y) ? e.axisDelta.y : NAN; + + Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy}; + + switch (e.tool->type) { + case WLR_TABLET_TOOL_TYPE_MOUSE: { + g_pPointerManager->move(delta); + break; + } + default: { + if (!std::isnan(x)) + PTOOL->absolutePos.x = x; + if (!std::isnan(y)) + PTOOL->absolutePos.y = y; + + if (PTAB->relativeInput) + g_pPointerManager->move(delta); + else { + //Calculate transformations if active area is set + if (!PTAB->activeArea.empty()) { + if (!std::isnan(x)) + x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); + if (!std::isnan(y)) + y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); + } + g_pPointerManager->warpAbsolute({x, y}, PTAB); + } + break; + } + } + + refocusTablet(PTAB, PTOOL, true); + m_tmrLastCursorMovement.reset(); + } + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE) + PROTO::tablet->pressure(PTOOL, e.pressure); + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE) + PROTO::tablet->distance(PTOOL, e.distance); + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION) + PROTO::tablet->rotation(PTOOL, e.rotation); + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER) + PROTO::tablet->slider(PTOOL, e.slider); + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL) + PROTO::tablet->wheel(PTOOL, e.wheelDelta); + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X) + PTOOL->tilt.x = e.tilt.x; + + if (e.updatedAxes & CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y) + PTOOL->tilt.y = e.tilt.y; + + if (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y)) + PROTO::tablet->tilt(PTOOL, PTOOL->tilt); + + PROTO::idle->onActivity(); +} + +void CInputManager::onTabletTip(CTablet::STipEvent e) { + const auto PTAB = e.tablet; + const auto PTOOL = ensureTabletToolPresent(e.tool); + + if (e.in) { + simulateMouseMovement(); + refocusTablet(PTAB, PTOOL); + PROTO::tablet->down(PTOOL); + } else + PROTO::tablet->up(PTOOL); + + PTOOL->isDown = e.in; + + PROTO::idle->onActivity(); +} + +void CInputManager::onTabletButton(CTablet::SButtonEvent e) { + const auto PTOOL = ensureTabletToolPresent(e.tool); + + PROTO::tablet->buttonTool(PTOOL, e.button, e.down); + + if (e.down) + PTOOL->buttonsDown.push_back(e.button); + else + std::erase(PTOOL->buttonsDown, e.button); + + PROTO::idle->onActivity(); +} + +void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { + const auto PTAB = e.tablet; + const auto PTOOL = ensureTabletToolPresent(e.tool); + + PTOOL->active = e.in; + + if (!e.in) { + if (PTOOL->getSurface()) + unfocusTool(PTOOL); + } else { + simulateMouseMovement(); + refocusTablet(PTAB, PTOOL); + } + + PROTO::idle->onActivity(); +} + +void CInputManager::newTablet(wlr_input_device* pDevice) { + const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice))); + m_vHIDs.push_back(PNEWTABLET); try { - PNEWTABLET->name = deviceNameToInternalString(pDevice->name); + PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name); } catch (std::exception& e) { Debug::log(ERR, "Tablet had no name???"); // logic error } - PNEWTABLET->wlrTablet = wlr_tablet_from_input_device(pDevice); - PNEWTABLET->wlrDevice = pDevice; - PNEWTABLET->wlrTabletV2 = wlr_tablet_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice); - PNEWTABLET->wlrTablet->data = PNEWTABLET; + g_pPointerManager->attachTablet(PNEWTABLET); - Debug::log(LOG, "Attaching tablet to cursor!"); - - // wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice); - - PNEWTABLET->hyprListener_Destroy.initCallback( - &pDevice->events.destroy, - [](void* owner, void* data) { - const auto PTAB = (STablet*)owner; - - g_pInputManager->m_lTablets.remove(*PTAB); - - Debug::log(LOG, "Removed a tablet"); + PNEWTABLET->events.destroy.registerStaticListener( + [this](void* owner, std::any d) { + auto TABLET = ((CTablet*)owner)->self; + destroyTablet(TABLET.lock()); }, - PNEWTABLET, "Tablet"); - - PNEWTABLET->hyprListener_Axis.initCallback( - &wlr_tablet_from_input_device(pDevice)->events.axis, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_tool_axis_event*)data; - const auto PTAB = (STablet*)owner; - - switch (EVENT->tool->type) { - case WLR_TABLET_TOOL_TYPE_MOUSE: - // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy); - g_pInputManager->simulateMouseMovement(); - g_pInputManager->focusTablet(PTAB, EVENT->tool, true); - g_pInputManager->m_tmrLastCursorMovement.reset(); - break; - default: - double x = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->x : NAN; - double dx = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_X) ? EVENT->dx : NAN; - double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN; - double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN; - - // if (PTAB->relativeInput) - // wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy); - // else { - // Calculate transformations if active area is set - // if (!PTAB->activeArea.empty()) { - // x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); - // y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); - // } - // wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y); - // } - - g_pInputManager->simulateMouseMovement(); - g_pInputManager->focusTablet(PTAB, EVENT->tool, true); - g_pInputManager->m_tmrLastCursorMovement.reset(); - break; - } - - const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); - - // TODO: this might be wrong - if (PTOOL->active) { - g_pInputManager->simulateMouseMovement(); - - g_pInputManager->focusTablet(PTAB, EVENT->tool, true); - } - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) - wlr_tablet_v2_tablet_tool_notify_pressure(PTOOL->wlrTabletToolV2, EVENT->pressure); - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) - wlr_tablet_v2_tablet_tool_notify_distance(PTOOL->wlrTabletToolV2, EVENT->distance); - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) - wlr_tablet_v2_tablet_tool_notify_rotation(PTOOL->wlrTabletToolV2, EVENT->rotation); - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) - wlr_tablet_v2_tablet_tool_notify_slider(PTOOL->wlrTabletToolV2, EVENT->slider); - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) - wlr_tablet_v2_tablet_tool_notify_wheel(PTOOL->wlrTabletToolV2, EVENT->wheel_delta, 0); - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) - PTOOL->tiltX = EVENT->tilt_x; - - if (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) - PTOOL->tiltY = EVENT->tilt_y; - - if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) - wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY); - - PROTO::idle->onActivity(); - }, - PNEWTABLET, "Tablet"); - - PNEWTABLET->hyprListener_Tip.initCallback( - &wlr_tablet_from_input_device(pDevice)->events.tip, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_tool_tip_event*)data; - const auto PTAB = (STablet*)owner; - - const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); - - // TODO: this might be wrong - if (EVENT->state == WLR_TABLET_TOOL_TIP_DOWN) { - g_pInputManager->simulateMouseMovement(); - g_pInputManager->focusTablet(PTAB, EVENT->tool); - wlr_send_tablet_v2_tablet_tool_down(PTOOL->wlrTabletToolV2); - } else { - wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2); - } - - PROTO::idle->onActivity(); - }, - PNEWTABLET, "Tablet"); - - PNEWTABLET->hyprListener_Button.initCallback( - &wlr_tablet_from_input_device(pDevice)->events.button, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_tool_button_event*)data; - - const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); - - wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state); - PROTO::idle->onActivity(); - }, - PNEWTABLET, "Tablet"); - - PNEWTABLET->hyprListener_Proximity.initCallback( - &wlr_tablet_from_input_device(pDevice)->events.proximity, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_tool_proximity_event*)data; - const auto PTAB = (STablet*)owner; - - const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool); - - if (EVENT->state == WLR_TABLET_TOOL_PROXIMITY_OUT) { - PTOOL->active = false; - - if (PTOOL->pSurface) { - wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); - PTOOL->pSurface = nullptr; - } - - } else { - PTOOL->active = true; - g_pInputManager->simulateMouseMovement(); - g_pInputManager->focusTablet(PTAB, EVENT->tool); - } - - PROTO::idle->onActivity(); - }, - PNEWTABLET, "Tablet"); + PNEWTABLET.get()); setTabletConfigs(); } -STabletTool* CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { +SP CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { if (pTool->data == nullptr) { - const auto PTOOL = &m_lTabletTools.emplace_back(); + const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool)); + m_vHIDs.push_back(PTOOL); - Debug::log(LOG, "Creating tablet tool v2 for {:x}", (uintptr_t)pTool); - - PTOOL->wlrTabletTool = pTool; - pTool->data = PTOOL; - - PTOOL->wlrTabletToolV2 = wlr_tablet_tool_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pTool); - - PTOOL->hyprListener_TabletToolDestroy.initCallback( - &pTool->events.destroy, - [](void* owner, void* data) { - const auto PTOOL = (STabletTool*)owner; - - PTOOL->wlrTabletTool->data = nullptr; - g_pInputManager->m_lTabletTools.remove(*PTOOL); + PTOOL->events.destroy.registerStaticListener( + [this](void* owner, std::any d) { + auto TOOL = ((CTabletTool*)owner)->self; + destroyTabletTool(TOOL.lock()); }, - PTOOL, "Tablet Tool V1"); - - //TODO: set cursor request + PTOOL.get()); } - return (STabletTool*)pTool->data; + return CTabletTool::fromWlr(pTool); } void CInputManager::newTabletPad(wlr_input_device* pDevice) { - const auto PNEWPAD = &m_lTabletPads.emplace_back(); + const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice))); + m_vHIDs.push_back(PNEWPAD); try { - PNEWPAD->name = deviceNameToInternalString(pDevice->name); + PNEWPAD->hlName = deviceNameToInternalString(pDevice->name); } catch (std::exception& e) { Debug::log(ERR, "Pad had no name???"); // logic error } - PNEWPAD->wlrTabletPadV2 = wlr_tablet_pad_create(g_pCompositor->m_sWLRTabletManager, g_pCompositor->m_sSeat.seat, pDevice); - PNEWPAD->pWlrDevice = pDevice; + // clang-format off + PNEWPAD->events.destroy.registerStaticListener([this](void* owner, std::any d) { + auto PAD = ((CTabletPad*)owner)->self; + destroyTabletPad(PAD.lock()); + }, PNEWPAD.get()); - PNEWPAD->hyprListener_Button.initCallback( - &wlr_tablet_pad_from_input_device(pDevice)->events.button, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_pad_button_event*)data; - const auto PPAD = (STabletPad*)owner; + PNEWPAD->padEvents.button.registerStaticListener([this](void* owner, std::any e) { + const auto E = std::any_cast(e); + const auto PPAD = ((CTabletPad*)owner)->self.lock(); - wlr_tablet_v2_tablet_pad_notify_mode(PPAD->wlrTabletPadV2, EVENT->group, EVENT->mode, EVENT->time_msec); - wlr_tablet_v2_tablet_pad_notify_button(PPAD->wlrTabletPadV2, EVENT->button, EVENT->time_msec, (zwp_tablet_pad_v2_button_state)EVENT->state); - }, - PNEWPAD, "Tablet Pad"); + PROTO::tablet->mode(PPAD, 0, E.mode, E.timeMs); + PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down); + }, PNEWPAD.get()); - PNEWPAD->hyprListener_Strip.initCallback( - &wlr_tablet_pad_from_input_device(pDevice)->events.strip, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_pad_strip_event*)data; - const auto PPAD = (STabletPad*)owner; + PNEWPAD->padEvents.strip.registerStaticListener([this](void* owner, std::any e) { + const auto E = std::any_cast(e); + const auto PPAD = ((CTabletPad*)owner)->self.lock(); - wlr_tablet_v2_tablet_pad_notify_strip(PPAD->wlrTabletPadV2, EVENT->strip, EVENT->position, EVENT->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, EVENT->time_msec); - }, - PNEWPAD, "Tablet Pad"); + PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs); + }, PNEWPAD.get()); - PNEWPAD->hyprListener_Ring.initCallback( - &wlr_tablet_pad_from_input_device(pDevice)->events.strip, - [](void* owner, void* data) { - const auto EVENT = (wlr_tablet_pad_ring_event*)data; - const auto PPAD = (STabletPad*)owner; + PNEWPAD->padEvents.ring.registerStaticListener([this](void* owner, std::any e) { + const auto E = std::any_cast(e); + const auto PPAD = ((CTabletPad*)owner)->self.lock(); - wlr_tablet_v2_tablet_pad_notify_ring(PPAD->wlrTabletPadV2, EVENT->ring, EVENT->position, EVENT->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, EVENT->time_msec); - }, - PNEWPAD, "Tablet Pad"); + PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs); + }, PNEWPAD.get()); - PNEWPAD->hyprListener_Attach.initCallback( - &wlr_tablet_pad_from_input_device(pDevice)->events.strip, - [](void* owner, void* data) { - const auto TABLET = (wlr_tablet_tool*)data; - const auto PPAD = (STabletPad*)owner; + PNEWPAD->padEvents.attach.registerStaticListener([this](void* owner, std::any e) { + const auto PPAD = ((CTabletPad*)owner)->self.lock(); + const auto TOOL = std::any_cast>(e); - PPAD->pTabletParent = (STablet*)TABLET->data; + PPAD->parent = TOOL; + }, PNEWPAD.get()); - if (!PPAD->pTabletParent) - Debug::log(ERR, "tabletpad got attached to a nullptr tablet!! this might be bad."); - }, - PNEWPAD, "Tablet Pad"); - - PNEWPAD->hyprListener_Destroy.initCallback( - &pDevice->events.destroy, - [](void* owner, void* data) { - const auto PPAD = (STabletPad*)owner; - - g_pInputManager->m_lTabletPads.remove(*PPAD); - - Debug::log(LOG, "Removed a tablet pad"); - }, - PNEWPAD, "Tablet Pad"); -} - -void CInputManager::focusTablet(STablet* pTab, wlr_tablet_tool* pTool, bool motion) { - const auto PTOOL = g_pInputManager->ensureTabletToolPresent(pTool); - - if (const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); PWINDOW) { - const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); - - if (PTOOL->pSurface != g_pInputManager->m_pLastMouseSurface) - wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); - - if (g_pInputManager->m_pLastMouseSurface) { - PTOOL->pSurface = g_pCompositor->m_pLastFocus; - wlr_tablet_v2_tablet_tool_notify_proximity_in(PTOOL->wlrTabletToolV2, pTab->wlrTabletV2, g_pInputManager->m_pLastMouseSurface); - } - - if (motion) { - auto local = CURSORPOS - PWINDOW->m_vRealPosition.goal(); - - if (PWINDOW->m_bIsX11) - local = local * PWINDOW->m_fX11SurfaceScaledBy; - - wlr_tablet_v2_tablet_tool_notify_motion(PTOOL->wlrTabletToolV2, local.x, local.y); - } - } else { - if (PTOOL->pSurface) - wlr_tablet_v2_tablet_tool_notify_proximity_out(PTOOL->wlrTabletToolV2); - } + // clang-format on } diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp new file mode 100644 index 00000000..b3ca76f5 --- /dev/null +++ b/src/protocols/Tablet.cpp @@ -0,0 +1,656 @@ +#include "Tablet.hpp" +#include "../devices/Tablet.hpp" +#include "../Compositor.hpp" +#include + +#define LOGM PROTO::tablet->protoLog + +CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletPadStripV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletPadStripV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletPadStripV2Resource::good() { + return resource->resource(); +} + +CTabletPadRingV2Resource::CTabletPadRingV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletPadRingV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletPadRingV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletPadRingV2Resource::good() { + return resource->resource(); +} + +CTabletPadGroupV2Resource::CTabletPadGroupV2Resource(SP resource_, size_t idx_) : idx(idx_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletPadGroupV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletPadGroupV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletPadGroupV2Resource::good() { + return resource->resource(); +} + +void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_group* group) { + resource->sendModes(group->mode_count); + + wl_array buttonArr; + wl_array_init(&buttonArr); + wl_array_add(&buttonArr, group->button_count * sizeof(int)); + memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int)); + resource->sendButtons(&buttonArr); + wl_array_release(&buttonArr); + + for (size_t i = 0; i < group->strip_count; ++i) { + const auto RESOURCE = + PROTO::tablet->m_vStrips.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vStrips.pop_back(); + return; + } + + resource->sendStrip(RESOURCE->resource.get()); + } + + for (size_t i = 0; i < group->ring_count; ++i) { + const auto RESOURCE = + PROTO::tablet->m_vRings.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vRings.pop_back(); + return; + } + + resource->sendRing(RESOURCE->resource.get()); + } + + resource->sendDone(); +} + +CTabletPadV2Resource::CTabletPadV2Resource(SP resource_, SP pad_, SP seat_) : pad(pad_), seat(seat_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletPadV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletPadV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletPadV2Resource::good() { + return resource->resource(); +} + +void CTabletPadV2Resource::sendData() { + // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts + const char** path_ptr; + for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) { + resource->sendPath(*path_ptr); + } + + resource->sendButtons(pad->wlr()->button_count); + + wlr_tablet_pad_group* group; + size_t i = 0; + wl_list_for_each(group, &pad->wlr()->groups, link) { + createGroup(group, i++); + } + + resource->sendDone(); +} + +void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) { + const auto RESOURCE = + PROTO::tablet->m_vGroups.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), idx)); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vGroups.pop_back(); + return; + } + + resource->sendGroup(RESOURCE->resource.get()); + + RESOURCE->sendData(pad.lock(), group); +} + +CTabletV2Resource::CTabletV2Resource(SP resource_, SP tablet_, SP seat_) : tablet(tablet_), seat(seat_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletV2Resource::good() { + return resource->resource(); +} + +void CTabletV2Resource::sendData() { + resource->sendName(tablet->deviceName.c_str()); + resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id); + + // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts + const char** path_ptr; + for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size); + (path_ptr)++) { + resource->sendPath(*path_ptr); + } + + resource->sendDone(); +} + +CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP tool_, SP seat_) : tool(tool_), seat(seat_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); + + resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { + wlr_seat_pointer_request_set_cursor_event e; + e.hotspot_x = hot_x; + e.hotspot_y = hot_y; + e.surface = surf ? wlr_surface_from_resource(surf) : nullptr; + e.serial = serial; + g_pInputManager->processMouseRequest(&e); + }); +} + +CTabletToolV2Resource::~CTabletToolV2Resource() { + if (frameSource) + wl_event_source_remove(frameSource); +} + +bool CTabletToolV2Resource::good() { + return resource->resource(); +} + +void CTabletToolV2Resource::sendData() { + static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type { + switch (wlr) { + case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; + case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; + case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; + case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; + case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; + case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; + case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; + default: ASSERT(false); + } + UNREACHABLE(); + }; + + resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type)); + resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF); + resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_ROTATION) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_SLIDER) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_TILT) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_TILT); + if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_WHEEL) + resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL); + resource->sendDone(); +} + +void CTabletToolV2Resource::queueFrame() { + if (frameSource) + return; + + frameSource = wl_event_loop_add_idle( + g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this); +} + +void CTabletToolV2Resource::sendFrame(bool removeSource) { + if (frameSource) { + if (removeSource) + wl_event_source_remove(frameSource); + frameSource = nullptr; + } + + if (!current) + return; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + resource->sendFrame(now.tv_sec * 1000 + now.tv_nsec / 1000000); +} + +CTabletSeat::CTabletSeat(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpTabletSeatV2* r) { PROTO::tablet->destroyResource(this); }); + resource->setOnDestroy([this](CZwpTabletSeatV2* r) { PROTO::tablet->destroyResource(this); }); +} + +bool CTabletSeat::good() { + return resource->resource(); +} + +void CTabletSeat::sendTool(SP tool) { + const auto RESOURCE = + PROTO::tablet->m_vTools.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), tool, self.lock())); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vTools.pop_back(); + return; + } + + resource->sendToolAdded(RESOURCE->resource.get()); + + RESOURCE->sendData(); + tools.push_back(RESOURCE); +} + +void CTabletSeat::sendPad(SP pad) { + const auto RESOURCE = + PROTO::tablet->m_vPads.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), pad, self.lock())); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vPads.pop_back(); + return; + } + + resource->sendPadAdded(RESOURCE->resource.get()); + + RESOURCE->sendData(); + pads.push_back(RESOURCE); +} + +void CTabletSeat::sendTablet(SP tablet) { + const auto RESOURCE = + PROTO::tablet->m_vTablets.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), tablet, self.lock())); + + if (!RESOURCE->good()) { + resource->noMemory(); + PROTO::tablet->m_vTablets.pop_back(); + return; + } + + resource->sendTabletAdded(RESOURCE->resource.get()); + + RESOURCE->sendData(); + tablets.push_back(RESOURCE); +} + +void CTabletSeat::sendData() { + for (auto& tw : PROTO::tablet->tablets) { + if (tw.expired()) + continue; + + sendTablet(tw.lock()); + } + + for (auto& tw : PROTO::tablet->tools) { + if (tw.expired()) + continue; + + sendTool(tw.lock()); + } + + for (auto& tw : PROTO::tablet->pads) { + if (tw.expired()) + continue; + + sendPad(tw.lock()); + } +} + +CTabletV2Protocol::CTabletV2Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CTabletV2Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwpTabletManagerV2* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CZwpTabletManagerV2* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetTabletSeat([this](CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat) { this->onGetSeat(pMgr, id, seat); }); +} + +void CTabletV2Protocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CTabletV2Protocol::destroyResource(CTabletSeat* resource) { + std::erase_if(m_vSeats, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletToolV2Resource* resource) { + std::erase_if(m_vTools, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletV2Resource* resource) { + std::erase_if(m_vTablets, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletPadV2Resource* resource) { + std::erase_if(m_vPads, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletPadGroupV2Resource* resource) { + std::erase_if(m_vGroups, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletPadRingV2Resource* resource) { + std::erase_if(m_vRings, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::destroyResource(CTabletPadStripV2Resource* resource) { + std::erase_if(m_vStrips, [&](const auto& other) { return other.get() == resource; }); +} + +void CTabletV2Protocol::onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat) { + const auto RESOURCE = m_vSeats.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vSeats.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + RESOURCE->sendData(); +} + +void CTabletV2Protocol::registerDevice(SP tablet) { + for (auto& s : m_vSeats) { + s->sendTablet(tablet); + } + + tablets.push_back(tablet); +} + +void CTabletV2Protocol::registerDevice(SP tool) { + for (auto& s : m_vSeats) { + s->sendTool(tool); + } + + tools.push_back(tool); +} + +void CTabletV2Protocol::registerDevice(SP pad) { + for (auto& s : m_vSeats) { + s->sendPad(pad); + } + + pads.push_back(pad); +} + +void CTabletV2Protocol::unregisterDevice(SP tablet) { + for (auto& t : m_vTablets) { + if (t->tablet == tablet) { + t->resource->sendRemoved(); + t->inert = true; + } + } + std::erase_if(tablets, [tablet](const auto& e) { return e.expired() || e == tablet; }); +} + +void CTabletV2Protocol::unregisterDevice(SP tool) { + for (auto& t : m_vTools) { + if (t->tool == tool) { + t->resource->sendRemoved(); + t->inert = true; + } + } + std::erase_if(tools, [tool](const auto& e) { return e.expired() || e == tool; }); +} + +void CTabletV2Protocol::unregisterDevice(SP pad) { + for (auto& t : m_vPads) { + if (t->pad == pad) { + t->resource->sendRemoved(); + t->inert = true; + } + } + std::erase_if(pads, [pad](const auto& e) { return e.expired() || e == pad; }); +} + +void CTabletV2Protocol::recheckRegisteredDevices() { + std::erase_if(tablets, [](const auto& e) { return e.expired(); }); + std::erase_if(tools, [](const auto& e) { return e.expired(); }); + std::erase_if(pads, [](const auto& e) { return e.expired(); }); + + // now we need to send removed events + for (auto& t : m_vTablets) { + if (!t->tablet.expired() || t->inert) + continue; + + t->resource->sendRemoved(); + t->inert = true; + } + + for (auto& t : m_vTools) { + if (!t->tool.expired() || t->inert) + continue; + + if (t->current) { + t->resource->sendProximityOut(); + t->sendFrame(); + t->lastSurf = nullptr; + } + + t->resource->sendRemoved(); + t->inert = true; + } + + for (auto& t : m_vPads) { + if (!t->pad.expired() || t->inert) + continue; + + t->resource->sendRemoved(); + t->inert = true; + } +} + +void CTabletV2Protocol::pressure(SP tool, double value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendPressure(std::clamp(value * 65535, 0.0, 65535.0)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::distance(SP tool, double value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendDistance(std::clamp(value * 65535, 0.0, 65535.0)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::rotation(SP tool, double value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendRotation(wl_fixed_from_double(value)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::slider(SP tool, double value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendSlider(std::clamp(value * 65535, -65535.0, 65535.0)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::wheel(SP tool, double value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendWheel(wl_fixed_from_double(value), 0); + t->queueFrame(); + } +} + +void CTabletV2Protocol::tilt(SP tool, const Vector2D& value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendTilt(wl_fixed_from_double(value.x), wl_fixed_from_double(value.y)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::up(SP tool) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendUp(); + t->queueFrame(); + } +} + +void CTabletV2Protocol::down(SP tool) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + t->resource->sendDown(serial); + t->queueFrame(); + } +} + +void CTabletV2Protocol::proximityIn(SP tool, SP tablet, wlr_surface* surf) { + proximityOut(tool); + const auto CLIENT = wl_resource_get_client(surf->resource); + + SP toolResource; + SP tabletResource; + + for (auto& t : m_vTools) { + if (t->tool != tool || t->resource->client() != CLIENT) + continue; + + if (t->seat.expired()) { + LOGM(ERR, "proximityIn on a tool without a seat parent"); + return; + } + + if (t->lastSurf == surf) + return; + + toolResource = t; + + for (auto& tab : m_vTablets) { + if (tab->tablet != tablet) + continue; + + if (tab->seat != t->seat || !tab->seat) + continue; + + tabletResource = tab; + break; + } + } + + if (!tabletResource || !toolResource) { + LOGM(ERR, "proximityIn on a tool and tablet without valid resource(s)??"); + return; + } + + toolResource->current = true; + toolResource->lastSurf = surf; + + auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, toolResource->resource->client())); + toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource); + toolResource->queueFrame(); + + LOGM(ERR, "proximityIn: found no resource to send enter"); +} + +void CTabletV2Protocol::proximityOut(SP tool) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->current = false; + t->lastSurf = nullptr; + t->resource->sendProximityOut(); + t->sendFrame(); + } +} + +void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32_t state) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + t->resource->sendButton(serial, button, (zwpTabletToolV2ButtonState)state); + t->queueFrame(); + } +} + +void CTabletV2Protocol::motion(SP tool, const Vector2D& value) { + for (auto& t : m_vTools) { + if (t->tool != tool || !t->current) + continue; + + t->resource->sendMotion(wl_fixed_from_double(value.x), wl_fixed_from_double(value.y)); + t->queueFrame(); + } +} + +void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, uint32_t timeMs) { + for (auto& t : m_vPads) { + if (t->pad != pad) + continue; + if (t->groups.size() <= group) { + LOGM(ERR, "BUG THIS: group >= t->groups.size()"); + return; + } + auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + t->groups.at(group)->resource->sendModeSwitch(timeMs, serial, mode); + } +} + +void CTabletV2Protocol::buttonPad(SP pad, uint32_t button, uint32_t timeMs, uint32_t state) { + for (auto& t : m_vPads) { + if (t->pad != pad) + continue; + t->resource->sendButton(timeMs, button, zwpTabletToolV2ButtonState{state}); + } +} + +void CTabletV2Protocol::strip(SP pad, uint32_t strip, double position, bool finger, uint32_t timeMs) { + LOGM(ERR, "FIXME: STUB: CTabletV2Protocol::strip not implemented"); +} + +void CTabletV2Protocol::ring(SP pad, uint32_t ring, double position, bool finger, uint32_t timeMs) { + LOGM(ERR, "FIXME: STUB: CTabletV2Protocol::ring not implemented"); +} diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp new file mode 100644 index 00000000..74a45c63 --- /dev/null +++ b/src/protocols/Tablet.hpp @@ -0,0 +1,236 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "tablet-v2.hpp" +#include "../helpers/Vector2D.hpp" + +class CTablet; +class CTabletTool; +class CTabletPad; +class CEventLoopTimer; +class CTabletSeat; + +class CTabletPadStripV2Resource { + public: + CTabletPadStripV2Resource(SP resource_, uint32_t id); + + bool good(); + + uint32_t id = 0; + + private: + SP resource; + + friend class CTabletSeat; + friend class CTabletPadGroupV2Resource; + friend class CTabletV2Protocol; +}; + +class CTabletPadRingV2Resource { + public: + CTabletPadRingV2Resource(SP resource_, uint32_t id); + + bool good(); + + uint32_t id = 0; + + private: + SP resource; + + friend class CTabletSeat; + friend class CTabletPadGroupV2Resource; + friend class CTabletV2Protocol; +}; + +class CTabletPadGroupV2Resource { + public: + CTabletPadGroupV2Resource(SP resource_, size_t idx); + + bool good(); + void sendData(SP pad, wlr_tablet_pad_group* group); + + std::vector> rings; + std::vector> strips; + + size_t idx = 0; + + private: + SP resource; + + friend class CTabletSeat; + friend class CTabletPadV2Resource; + friend class CTabletV2Protocol; +}; + +class CTabletPadV2Resource { + public: + CTabletPadV2Resource(SP resource_, SP pad_, SP seat_); + + bool good(); + void sendData(); + + std::vector> groups; + + WP pad; + WP seat; + + bool inert = false; // removed was sent + + private: + SP resource; + + void createGroup(wlr_tablet_pad_group* group, size_t idx); + + friend class CTabletSeat; + friend class CTabletV2Protocol; +}; + +class CTabletV2Resource { + public: + CTabletV2Resource(SP resource_, SP tablet_, SP seat_); + + bool good(); + void sendData(); + + WP tablet; + WP seat; + + bool inert = false; // removed was sent + + private: + SP resource; + + friend class CTabletSeat; + friend class CTabletV2Protocol; +}; + +class CTabletToolV2Resource { + public: + CTabletToolV2Resource(SP resource_, SP tool_, SP seat_); + ~CTabletToolV2Resource(); + + bool good(); + void sendData(); + void queueFrame(); + void sendFrame(bool removeSource = true); + + bool current = false; + wlr_surface* lastSurf = nullptr; // READ-ONLY + + WP tool; + WP seat; + wl_event_source* frameSource = nullptr; + + bool inert = false; // removed was sent + + private: + SP resource; + + friend class CTabletSeat; + friend class CTabletV2Protocol; +}; + +class CTabletSeat { + public: + CTabletSeat(SP resource_); + + bool good(); + void sendData(); + + std::vector> tools; + std::vector> pads; + std::vector> tablets; + + void sendTool(SP tool); + void sendPad(SP pad); + void sendTablet(SP tablet); + + private: + SP resource; + WP self; + + friend class CTabletV2Protocol; +}; + +class CTabletV2Protocol : public IWaylandProtocol { + public: + CTabletV2Protocol(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); + + void registerDevice(SP tablet); + void registerDevice(SP tool); + void registerDevice(SP pad); + + void unregisterDevice(SP tablet); + void unregisterDevice(SP tool); + void unregisterDevice(SP pad); + + void recheckRegisteredDevices(); + + // Tablet tool events + void pressure(SP tool, double value); + void distance(SP tool, double value); + void rotation(SP tool, double value); + void slider(SP tool, double value); + void wheel(SP tool, double value); + void tilt(SP tool, const Vector2D& value); + void up(SP tool); + void down(SP tool); + void proximityIn(SP tool, SP tablet, wlr_surface* surf); + void proximityOut(SP tool); + void buttonTool(SP tool, uint32_t button, uint32_t state); + void motion(SP tool, const Vector2D& value); + + // Tablet pad events + void mode(SP pad, uint32_t group, uint32_t mode, uint32_t timeMs); + void buttonPad(SP pad, uint32_t button, uint32_t timeMs, uint32_t state); + void strip(SP pad, uint32_t strip, double position, bool finger, uint32_t timeMs); + void ring(SP pad, uint32_t ring, double position, bool finger, uint32_t timeMs); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CTabletSeat* resource); + void destroyResource(CTabletToolV2Resource* resource); + void destroyResource(CTabletV2Resource* resource); + void destroyResource(CTabletPadV2Resource* resource); + void destroyResource(CTabletPadGroupV2Resource* resource); + void destroyResource(CTabletPadRingV2Resource* resource); + void destroyResource(CTabletPadStripV2Resource* resource); + void onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat); + + // + std::vector> m_vManagers; + std::vector> m_vSeats; + std::vector> m_vTools; + std::vector> m_vTablets; + std::vector> m_vPads; + std::vector> m_vGroups; + std::vector> m_vRings; + std::vector> m_vStrips; + + // registered + std::vector> tablets; + std::vector> tools; + std::vector> pads; + + // FIXME: rings and strips are broken, I don't understand how this shit works. + // It's 2am. + SP ringForID(SP pad, uint32_t id); + SP stripForID(SP pad, uint32_t id); + + friend class CTabletSeat; + friend class CTabletToolV2Resource; + friend class CTabletV2Resource; + friend class CTabletPadV2Resource; + friend class CTabletPadGroupV2Resource; + friend class CTabletPadRingV2Resource; + friend class CTabletPadStripV2Resource; +}; + +namespace PROTO { + inline UP tablet; +}; From 67a5377b41f121017ed4295a3a592a19b4b7fbfb Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Thu, 9 May 2024 07:39:15 -0500 Subject: [PATCH 0035/2393] core: remove wayland sockets on exit (#5959) --- src/Compositor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a31b1a57..90ef2b66 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -408,6 +408,10 @@ void CCompositor::cleanup() { 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"); } void CCompositor::initManagers(eManagersInitStage stage) { From c98acaed62db806c41b7d1b5ad63a89f18bce70a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 14:07:21 +0100 Subject: [PATCH 0036/2393] virtual-keyboard: release keys before destroy --- src/managers/input/InputManager.cpp | 2 ++ src/protocols/VirtualKeyboard.cpp | 18 ++++++++++++++++++ src/protocols/VirtualKeyboard.hpp | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 7e746cfc..8d67760d 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -800,6 +800,7 @@ void CInputManager::setupKeyboard(SP keeb) { keeb->keyboardEvents.key.registerStaticListener( [this](void* owner, std::any data) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); + onKeyboardKey(data, PKEEB); }, keeb.get()); @@ -807,6 +808,7 @@ void CInputManager::setupKeyboard(SP keeb) { keeb->keyboardEvents.modifiers.registerStaticListener( [this](void* owner, std::any data) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); + onKeyboardMod(PKEEB); }, keeb.get()); diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 3d67bd06..7325f7cd 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -12,10 +12,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; resource->setDestroy([this](CZwpVirtualKeyboardV1* r) { + releasePressed(); events.destroy.emit(); PROTO::virtualKeyboard->destroyResource(this); }); resource->setOnDestroy([this](CZwpVirtualKeyboardV1* r) { + releasePressed(); events.destroy.emit(); PROTO::virtualKeyboard->destroyResource(this); }); @@ -101,6 +103,22 @@ wl_client* CVirtualKeyboardV1Resource::client() { return resource->client(); } +void CVirtualKeyboardV1Resource::releasePressed() { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + size_t keycodesNum = keyboard.num_keycodes; + + for (size_t i = 0; i < keycodesNum; ++i) { + struct wlr_keyboard_key_event event = { + .time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000), + .keycode = keyboard.keycodes[keycodesNum - i - 1], + .update_state = false, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }; + wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes + } +} + CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 5ce3d748..447b5db9 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -24,6 +24,8 @@ class CVirtualKeyboardV1Resource { SP resource; wlr_keyboard keyboard; + void releasePressed(); + bool hasKeymap = false; }; From d7aed240db408259228bf09708986c82bdca23eb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 14:27:48 +0100 Subject: [PATCH 0037/2393] text-input-v3: atomically enable/disable on commit --- src/protocols/TextInputV3.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 233f5209..b463c6d6 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -8,7 +8,6 @@ void CTextInputV3::SState::reset() { surrounding.updated = false; contentType.updated = false; box.updated = false; - enabled = false; } CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) { @@ -21,9 +20,18 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); }); resource->setCommit([this](CZwpTextInputV3* r) { + bool wasEnabled = current.enabled; + current = pending; - events.onCommit.emit(); serial++; + + if (wasEnabled && !current.enabled) { + current.reset(); + events.disable.emit(); + } else if (!wasEnabled && current.enabled) + events.enable.emit(); + else + events.onCommit.emit(); }); resource->setSetSurroundingText([this](CZwpTextInputV3* r, const char* text, int32_t cursor, int32_t anchor) { @@ -46,13 +54,9 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) pending.box.cursorBox = {x, y, w, h}; }); - resource->setEnable([this](CZwpTextInputV3* r) { - events.enable.emit(); - pending.enabled = true; - }); + resource->setEnable([this](CZwpTextInputV3* r) { pending.enabled = true; }); resource->setDisable([this](CZwpTextInputV3* r) { - events.disable.emit(); pending.enabled = false; pending.reset(); }); From fe4737fb9d578400ecfc63dc6ab4d684993362b8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 19:17:04 +0100 Subject: [PATCH 0038/2393] pointer: don't calculate hw hotspot for missing hw cursors ref #5964 --- src/managers/PointerManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index c6478b9a..21c6998f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -518,6 +518,9 @@ Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { } Vector2D CPointerManager::transformedHotspot(SP pMonitor) { + if (!pMonitor->output->cursor_swapchain) + return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors + return CBox{currentCursorImage.hotspot, {0, 0}} .transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) .pos(); From 85f7f69046c07c61f59b0ef7cccd01e88b316413 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 9 May 2024 18:19:32 +0000 Subject: [PATCH 0039/2393] decorations: fix groupbar input (#5963) modified: src/render/decorations/CHyprGroupBarDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.hpp --- .../decorations/CHyprGroupBarDecoration.cpp | 18 +++++++++--------- .../decorations/CHyprGroupBarDecoration.hpp | 5 +++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index e854d63a..1ea0aac2 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -422,7 +422,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND return true; } -bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_pointer_button_event* e) { +bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPointer::SButtonEvent& e) { if (m_pWindow->m_bIsFullscreen && m_pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) return true; @@ -431,18 +431,18 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); // close window on middle click - if (e->button == 274) { + if (e.button == 274) { static Vector2D pressedCursorPos; - if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) + if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) pressedCursorPos = pos; - else if (e->state == WL_POINTER_BUTTON_STATE_RELEASED && pressedCursorPos == pos) + else if (e.state == WL_POINTER_BUTTON_STATE_RELEASED && pressedCursorPos == pos) g_pXWaylandManager->sendCloseWindow(m_pWindow->getGroupWindowByIndex(WINDOWINDEX)); return true; } - if (e->state != WL_POINTER_BUTTON_STATE_PRESSED) + if (e.state != WL_POINTER_BUTTON_STATE_PRESSED) return true; // click on padding @@ -466,13 +466,13 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, wlr_point return true; } -bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, wlr_pointer_axis_event* e) { +bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, const IPointer::SAxisEvent e) { static auto PGROUPBARSCROLLING = CConfigValue("group:groupbar:scrolling"); if (!*PGROUPBARSCROLLING || m_pWindow->m_sGroupData.pNextWindow.expired()) return false; - if (e->delta > 0) + if (e.delta > 0) m_pWindow->setGroupCurrent(m_pWindow->m_sGroupData.pNextWindow.lock()); else m_pWindow->setGroupCurrent(m_pWindow->getGroupPrevious()); @@ -482,8 +482,8 @@ bool CHyprGroupBarDecoration::onScrollOnDeco(const Vector2D& pos, wlr_pointer_ax bool CHyprGroupBarDecoration::onInputOnDeco(const eInputType type, const Vector2D& mouseCoords, std::any data) { switch (type) { - case INPUT_TYPE_AXIS: return onScrollOnDeco(mouseCoords, std::any_cast(data)); - case INPUT_TYPE_BUTTON: return onMouseButtonOnDeco(mouseCoords, std::any_cast(data)); + case INPUT_TYPE_AXIS: return onScrollOnDeco(mouseCoords, std::any_cast(data)); + case INPUT_TYPE_BUTTON: return onMouseButtonOnDeco(mouseCoords, std::any_cast(data)); case INPUT_TYPE_DRAG_START: return onBeginWindowDragOnDeco(mouseCoords); case INPUT_TYPE_DRAG_END: return onEndWindowDragOnDeco(mouseCoords, std::any_cast(data)); default: return false; diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index d316d01a..45881add 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -1,6 +1,7 @@ #pragma once #include "IHyprWindowDecoration.hpp" +#include "../../devices/IPointer.hpp" #include #include "../Texture.hpp" #include @@ -61,8 +62,8 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { bool onBeginWindowDragOnDeco(const Vector2D&); bool onEndWindowDragOnDeco(const Vector2D&, PHLWINDOW); - bool onMouseButtonOnDeco(const Vector2D&, wlr_pointer_button_event*); - bool onScrollOnDeco(const Vector2D&, wlr_pointer_axis_event*); + bool onMouseButtonOnDeco(const Vector2D&, const IPointer::SButtonEvent&); + bool onScrollOnDeco(const Vector2D&, const IPointer::SAxisEvent); struct STitleTexs { // STitleTexs* overriden = nullptr; // TODO: make shit shared in-group to decrease VRAM usage. From 635a02d83fe9d598cf5f6aba47e672647608fb76 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 21:47:21 +0100 Subject: [PATCH 0040/2393] layer-shell: move to new impl Also bumps the hw-s dep --- CMakeLists.txt | 4 +- protocols/meson.build | 2 +- protocols/wlr-layer-shell-unstable-v1.xml | 21 +- src/Compositor.cpp | 77 +++----- src/Compositor.hpp | 5 +- src/config/ConfigManager.cpp | 7 +- src/desktop/LayerSurface.cpp | 156 ++++----------- src/desktop/LayerSurface.hpp | 25 +-- src/desktop/Popup.cpp | 47 ++++- src/desktop/Popup.hpp | 45 +++-- src/events/Windows.cpp | 3 +- src/helpers/Monitor.cpp | 3 +- src/helpers/Monitor.hpp | 2 +- src/includes.hpp | 1 - src/managers/AnimationManager.cpp | 2 +- src/managers/ProtocolManager.cpp | 2 + src/managers/input/InputManager.cpp | 5 +- src/managers/input/Swipe.cpp | 4 +- src/managers/input/Touch.cpp | 2 +- src/protocols/LayerShell.cpp | 224 ++++++++++++++++++++++ src/protocols/LayerShell.hpp | 95 +++++++++ src/render/OpenGL.cpp | 1 + src/render/Renderer.cpp | 44 +++-- src/render/Renderer.hpp | 2 +- 24 files changed, 544 insertions(+), 235 deletions(-) create mode 100644 src/protocols/LayerShell.cpp create mode 100644 src/protocols/LayerShell.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 513f06bb..eb766005 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.5 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.6 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -251,7 +251,6 @@ target_link_libraries(Hyprland uuid ) -protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) @@ -268,6 +267,7 @@ protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) +protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-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 345b47ee..4206b56a 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-layer-shell-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] @@ -42,6 +41,7 @@ new_protocols = [ ['wlr-virtual-pointer-unstable-v1.xml'], ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], + ['wlr-layer-shell-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml index d62fd51e..e9f27e4f 100644 --- a/protocols/wlr-layer-shell-unstable-v1.xml +++ b/protocols/wlr-layer-shell-unstable-v1.xml @@ -25,7 +25,7 @@ THIS SOFTWARE. - + Clients can use this interface to assign the surface_layer role to wl_surfaces. Such surfaces are assigned to a "layer" of the output and @@ -100,7 +100,7 @@ - + An interface that may be implemented by a wl_surface, for surfaces that are designed to be rendered as a layer of a stacked desktop-like @@ -367,6 +367,7 @@ + @@ -386,5 +387,21 @@ + + + + + + Requests an edge for the exclusive zone to apply. The exclusive + edge will be automatically deduced from anchor points when possible, + but when the surface is anchored to a corner, it will be necessary + to set it explicitly to disambiguate, as it is not possible to deduce + which one of the two corner edges should be used. + + The edge must be one the surface is anchored to, otherwise the + invalid_exclusive_edge protocol error will be raised. + + + diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 90ef2b66..da2b643c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -16,6 +16,7 @@ #include "helpers/VarList.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" +#include "protocols/LayerShell.hpp" #include "desktop/LayerSurface.hpp" #include @@ -234,8 +235,6 @@ void CCompositor::initServer() { m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); - m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4); - 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"); @@ -271,7 +270,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat"); - addWLSignal(&m_sWLRLayerShell->events.new_surface, &Events::listen_newLayerSurface, m_sWLRLayerShell, "LayerShell"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -291,7 +289,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_startDrag); removeWLSignal(&Events::listen_requestSetSel); removeWLSignal(&Events::listen_requestSetPrimarySel); - removeWLSignal(&Events::listen_newLayerSurface); removeWLSignal(&Events::listen_RendererDestroy); if (m_sWRLDRMLeaseMgr) @@ -1088,17 +1085,15 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) continue; - auto SURFACEAT = wlr_layer_surface_v1_popup_surface_at(ls->layerSurface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); + auto SURFACEAT = ls->popupHead->at(pos, true); if (SURFACEAT) { - if (!pixman_region32_not_empty(&SURFACEAT->input_region)) - continue; - - *ppLayerSurfaceFound = ls; - return SURFACEAT; + *ppLayerSurfaceFound = ls.lock(); + *sCoords = pos - SURFACEAT->coordsGlobal(); + return SURFACEAT->m_sWLSurface.wlr(); } } } @@ -1106,7 +1101,7 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito return nullptr; } -wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1117,7 +1112,7 @@ wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector< if (!pixman_region32_not_empty(&SURFACEAT->input_region)) continue; - *ppLayerSurfaceFound = ls; + *ppLayerSurfaceFound = ls.lock(); return SURFACEAT; } } @@ -1355,7 +1350,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { void CCompositor::cleanupFadingOut(const int& monid) { for (auto& ww : m_vWindowsFadingOut) { - const auto w = ww.lock(); + auto w = ww.lock(); if (w->m_iMonitorID != (long unsigned int)monid) continue; @@ -1369,6 +1364,8 @@ void CCompositor::cleanupFadingOut(const int& monid) { removeWindowFromVectorSafe(w); + w.reset(); + Debug::log(LOG, "Cleanup: destroyed a window"); return; } @@ -1398,6 +1395,9 @@ void CCompositor::cleanupFadingOut(const int& monid) { } std::erase_if(m_vSurfacesFadingOut, [ls](const auto& el) { return el.lock() == ls; }); + std::erase_if(m_vLayers, [ls](const auto& el) { return el == ls; }); + + ls.reset(); Debug::log(LOG, "Cleanup: destroyed a layersurface"); @@ -2414,19 +2414,6 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { setActiveMonitor(PMONITORNEW); } -PHLLS CCompositor::getLayerSurfaceFromWlr(wlr_layer_surface_v1* pLS) { - for (auto& m : m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { - if (ls->layerSurface == pLS) - return ls; - } - } - } - - return nullptr; -} - void CCompositor::closeWindow(PHLWINDOW pWindow) { if (pWindow && validMapped(pWindow)) { g_pXWaylandManager->sendCloseWindow(pWindow); @@ -2436,28 +2423,24 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { PHLLS CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) { std::pair result = {pSurface, false}; - for (auto& m : m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { - if (ls->layerSurface && ls->layerSurface->surface == pSurface) - return ls; + for (auto& ls : m_vLayers) { + if (ls->layerSurface && ls->layerSurface->surface == pSurface) + return ls; - static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void { - if (surf == ((std::pair*)data)->first) { - *(bool*)data = true; - return; - } - }; - - if (!ls->layerSurface || !ls->mapped) - continue; - - wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result); - - if (result.second) - return ls; + static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void { + if (surf == ((std::pair*)data)->first) { + *(bool*)data = true; + return; } - } + }; + + if (!ls->layerSurface || !ls->mapped) + continue; + + wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result); + + if (result.second) + return ls; } return nullptr; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 96557b8d..9659df5c 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -51,7 +51,6 @@ class CCompositor { wlr_data_device_manager* m_sWLRDataDevMgr; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_layer_shell_v1* m_sWLRLayerShell; wlr_xdg_shell* m_sWLRXDGShell; wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; @@ -71,6 +70,7 @@ class CCompositor { std::vector> m_vMonitors; std::vector> m_vRealMonitors; // for all monitors, even those turned off std::vector m_vWindows; + std::vector m_vLayers; std::vector m_vWorkspaces; std::vector m_vWindowsFadingOut; std::vector m_vSurfacesFadingOut; @@ -112,7 +112,7 @@ class CCompositor { void focusSurface(wlr_surface*, PHLWINDOW pWindowOwner = nullptr); bool monitorExists(CMonitor*); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); - wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); + wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); wlr_surface* vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, wlr_surface*); @@ -162,7 +162,6 @@ class CCompositor { void addToFadingOutSafe(PHLWINDOW); PHLWINDOW getWindowByRegex(const std::string&); void warpCursorTo(const Vector2D&, bool force = false); - PHLLS getLayerSurfaceFromWlr(wlr_layer_surface_v1*); PHLLS getLayerSurfaceFromSurface(wlr_surface*); void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 135a6a94..7804a511 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -4,6 +4,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" #include "helpers/VarList.hpp" +#include "../protocols/LayerShell.hpp" #include #include @@ -1204,7 +1205,7 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { } else { std::regex NSCHECK(lr.targetNamespace); - if (!pLS->layerSurface->_namespace || !std::regex_search(pLS->layerSurface->_namespace, NSCHECK)) + if (!std::regex_search(pLS->layerSurface->layerNamespace, NSCHECK)) continue; } @@ -1212,8 +1213,8 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { returns.push_back(lr); } - if (pLS->layerSurface->_namespace && shouldBlurLS(pLS->layerSurface->_namespace)) - returns.push_back({pLS->layerSurface->_namespace, "blur"}); + if (shouldBlurLS(pLS->layerSurface->layerNamespace)) + returns.push_back({pLS->layerSurface->layerNamespace, "blur"}); return returns; } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index aeaf1aa8..c9750dc9 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -1,81 +1,29 @@ #include "LayerSurface.hpp" #include "../Compositor.hpp" #include "../events/Events.hpp" +#include "../protocols/LayerShell.hpp" -void Events::listener_newLayerSurface(wl_listener* listener, void* data) { - const auto WLRLAYERSURFACE = (wlr_layer_surface_v1*)data; +PHLLS CLayerSurface::create(SP resource) { + PHLLS pLS = SP(new CLayerSurface(resource)); - if (!WLRLAYERSURFACE->output) { - const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); + CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); - if (!PMONITOR) { - Debug::log(ERR, "No monitor at cursor on new layer without a monitor. Ignoring."); - wlr_layer_surface_v1_destroy(WLRLAYERSURFACE); - return; - } - - Debug::log(LOG, "New LayerSurface has no preferred monitor. Assigning Monitor {}", PMONITOR->szName); - - WLRLAYERSURFACE->output = PMONITOR->output; + if (!pMonitor) { + Debug::log(ERR, "New LS has no monitor??"); + return pLS; } - auto PMONITOR = g_pCompositor->getMonitorFromOutput(WLRLAYERSURFACE->output); - - if (!WLRLAYERSURFACE->output || !PMONITOR || PMONITOR->pMirrorOf) { - PMONITOR = g_pCompositor->m_vMonitors.front().get(); - WLRLAYERSURFACE->output = PMONITOR->output; // TODO: current mon - } - - const auto PLS = PMONITOR->m_aLayerSurfaceLayers[WLRLAYERSURFACE->pending.layer].emplace_back(CLayerSurface::create(WLRLAYERSURFACE)); - - Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)WLRLAYERSURFACE, WLRLAYERSURFACE->_namespace, (int)PLS->layer, PMONITOR->szName); -} - -static void onCommit(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onCommit(); -} - -static void onMap(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onMap(); -} - -static void onUnmap(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onUnmap(); -} - -static void onDestroy(void* owner, void* data) { - const auto LS = ((CLayerSurface*)owner)->self.lock(); - - LS->onDestroy(); -} - -// IMPL - -PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { - PHLLS pLS = SP(new CLayerSurface); - - auto PMONITOR = g_pCompositor->getMonitorFromOutput(pWLRLS->output); + if (pMonitor->pMirrorOf) + pMonitor = g_pCompositor->m_vMonitors.front().get(); pLS->self = pLS; - pLS->szNamespace = pWLRLS->_namespace; + pLS->szNamespace = resource->layerNamespace; - pLS->hyprListener_commitLayerSurface.initCallback(&pWLRLS->surface->events.commit, ::onCommit, pLS.get(), "layerSurface"); - pLS->hyprListener_destroyLayerSurface.initCallback(&pWLRLS->events.destroy, ::onDestroy, pLS.get(), "layerSurface"); - pLS->hyprListener_mapLayerSurface.initCallback(&pWLRLS->surface->events.map, ::onMap, pLS.get(), "layerSurface"); - pLS->hyprListener_unmapLayerSurface.initCallback(&pWLRLS->surface->events.unmap, ::onUnmap, pLS.get(), "layerSurface"); - - pLS->layerSurface = pWLRLS; - pLS->layer = pWLRLS->current.layer; - pWLRLS->data = pLS.get(); - pLS->monitorID = PMONITOR->ID; - pLS->popupHead = std::make_unique(pLS); + pLS->layer = resource->current.layer; + pLS->popupHead = std::make_unique(pLS); + pLS->monitorID = pMonitor->ID; + pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); @@ -90,7 +38,9 @@ PHLLS CLayerSurface::create(wlr_layer_surface_v1* pWLRLS) { pLS->alpha.setValueAndWarp(0.f); - pLS->surface.assign(pWLRLS->surface, pLS); + pLS->surface.assign(resource->surface, pLS); + + Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); return pLS; } @@ -102,8 +52,11 @@ void CLayerSurface::registerCallbacks() { }); } -CLayerSurface::CLayerSurface() { - ; +CLayerSurface::CLayerSurface(SP resource_) : layerSurface(resource_) { + listeners.commit = layerSurface->events.commit.registerListener([this](std::any d) { onCommit(); }); + listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); }); + listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); + listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); } CLayerSurface::~CLayerSurface() { @@ -139,11 +92,6 @@ void CLayerSurface::onDestroy() { noProcess = true; - hyprListener_commitLayerSurface.removeCallback(); - hyprListener_destroyLayerSurface.removeCallback(); - hyprListener_mapLayerSurface.removeCallback(); - hyprListener_unmapLayerSurface.removeCallback(); - // rearrange to fix the reserved areas if (PMONITOR) { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); @@ -155,7 +103,7 @@ void CLayerSurface::onDestroy() { } readyToDelete = true; - layerSurface = nullptr; + layerSurface.reset(); surface.unassign(); } @@ -163,7 +111,7 @@ void CLayerSurface::onMap() { Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); mapped = true; - keyboardExclusive = layerSurface->current.keyboard_interactive; + keyboardExclusive = layerSurface->current.interactivity; // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -173,28 +121,16 @@ void CLayerSurface::onMap() { applyRules(); - if ((uint64_t)monitorID != PMONITOR->ID) { - const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); - for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self) { - PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); - POLDMON->m_aLayerSurfaceLayers[layer].erase(it); - break; - } - } - monitorID = PMONITOR->ID; - PMONITOR->scheduledRecalc = true; - g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID); - } + PMONITOR->scheduledRecalc = true; g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); wlr_surface_send_enter(surface.wlr(), PMONITOR->output); - if (layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); - const bool GRABSFOCUS = layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && // don't focus if constrained (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()); @@ -229,7 +165,7 @@ void CLayerSurface::onMap() { void CLayerSurface::onUnmap() { Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface); - g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", std::string(layerSurface->_namespace ? layerSurface->_namespace : "")}); + g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); EMIT_HOOK_EVENT("closeLayer", self.lock()); std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); @@ -257,7 +193,7 @@ void CLayerSurface::onUnmap() { g_pCompositor->addToFadingOutSafe(self.lock()); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layerSurface->output); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layerSurface->surface; @@ -306,10 +242,10 @@ void CLayerSurface::onUnmap() { } void CLayerSurface::onCommit() { - if (!layerSurface || !layerSurface->output) + if (!layerSurface) return; - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(layerSurface->output); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); if (!PMONITOR) return; @@ -320,25 +256,8 @@ void CLayerSurface::onCommit() { CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); - // fix if it changed its mon - if ((uint64_t)monitorID != PMONITOR->ID) { - const auto POLDMON = g_pCompositor->getMonitorFromID(monitorID); - - for (auto it = POLDMON->m_aLayerSurfaceLayers[layer].begin(); it != POLDMON->m_aLayerSurfaceLayers[layer].end(); it++) { - if (*it == self) { - PMONITOR->m_aLayerSurfaceLayers[layer].emplace_back(std::move(*it)); - POLDMON->m_aLayerSurfaceLayers[layer].erase(it); - break; - } - } - - monitorID = PMONITOR->ID; - PMONITOR->scheduledRecalc = true; - g_pHyprRenderer->arrangeLayersForMonitor(POLDMON->ID); - } - if (layerSurface->current.committed != 0) { - if (layer != layerSurface->current.layer) { + if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { if (*it == self) { @@ -383,7 +302,7 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.keyboard_interactive && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained + if (layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained && !keyboardExclusive && mapped) { g_pCompositor->focusSurface(layerSurface->surface); @@ -391,11 +310,11 @@ void CLayerSurface::onCommit() { wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layerSurface->surface, LOCAL.x, LOCAL.y); wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.keyboard_interactive && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { + } else if (!layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { g_pInputManager->refocus(); } - keyboardExclusive = layerSurface->current.keyboard_interactive; + keyboardExclusive = layerSurface->current.interactivity; g_pHyprRenderer->damageSurface(layerSurface->surface, position.x, position.y); @@ -582,8 +501,7 @@ int CLayerSurface::popupsCount() { if (!layerSurface || !mapped || fadingOut) return 0; - int no = 0; - wlr_layer_surface_v1_for_each_popup_surface( - layerSurface, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no); + int no = -1; // we have one dummy + popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; } \ No newline at end of file diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index f1540be5..d60a6dd0 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -4,19 +4,20 @@ #include "../defines.hpp" #include "WLSurface.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "wlr-layer-shell-unstable-v1-protocol.h" struct SLayerRule { std::string targetNamespace = ""; std::string rule = ""; }; +class CLayerShellResource; + class CLayerSurface { public: - static PHLLS create(wlr_layer_surface_v1*); + static PHLLS create(SP); private: - CLayerSurface(); + CLayerSurface(SP); public: ~CLayerSurface(); @@ -30,7 +31,7 @@ class CLayerSurface { CAnimatedVariable realSize; CAnimatedVariable alpha; - wlr_layer_surface_v1* layerSurface; + WP layerSurface; wl_list link; bool keyboardExclusive = false; @@ -38,6 +39,7 @@ class CLayerSurface { CWLSurface surface; bool mapped = false; + uint32_t layer = 0; int monitorID = -1; @@ -55,13 +57,12 @@ class CLayerSurface { std::optional animationStyle; - zwlr_layer_shell_v1_layer layer; - PHLLSREF self; CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; + std::unique_ptr popupHead; void onDestroy(); void onMap(); @@ -69,12 +70,12 @@ class CLayerSurface { void onCommit(); private: - std::unique_ptr popupHead; - - DYNLISTENER(destroyLayerSurface); - DYNLISTENER(mapLayerSurface); - DYNLISTENER(unmapLayerSurface); - DYNLISTENER(commitLayerSurface); + struct { + CHyprSignalListener destroy; + CHyprSignalListener map; + CHyprSignalListener unmap; + CHyprSignalListener commit; + } listeners; void registerCallbacks(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 73a29560..f1517083 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -1,6 +1,8 @@ #include "Popup.hpp" #include "../config/ConfigValue.hpp" #include "../Compositor.hpp" +#include "../protocols/LayerShell.hpp" +#include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { initAllSignals(); @@ -72,7 +74,7 @@ void CPopup::initAllSignals() { if (!m_pWindowOwner.expired()) hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); else if (!m_pLayerOwner.expired()) - hyprListener_newPopup.initCallback(&m_pLayerOwner->layerSurface->events.new_popup, ::onNewPopup, this, "CPopup Head"); + listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast(d)); }); else ASSERT(false); @@ -278,3 +280,46 @@ bool CPopup::visible() { return false; } + +void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { + for (auto& n : nodes) { + fn(n, data); + } + + std::vector nodes2; + + for (auto& n : nodes) { + for (auto& c : n->m_vChildren) { + nodes2.push_back(c.get()); + } + } + + bfHelper(nodes2, fn, data); +} + +void CPopup::breadthfirst(std::function fn, void* data) { + std::vector popups; + popups.push_back(this); +} + +CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { + std::vector popups; + breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); + + for (auto& p : popups | std::views::reverse) { + if (!p->m_pWLR) + continue; + + if (!allowsInput) { + const auto BOX = CBox{p->coordsGlobal(), p->size()}; + if (BOX.containsPoint(globalCoords)) + return p; + } else { + const auto REGION = CRegion{&m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal()); + if (REGION.containsPoint(globalCoords)) + return p; + } + } + + return nullptr; +} diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index cadbf244..6aa7ce61 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -3,6 +3,7 @@ #include #include #include "Subsurface.hpp" +#include "../helpers/signal/Listener.hpp" class CPopup { public: @@ -15,22 +16,27 @@ class CPopup { ~CPopup(); - Vector2D coordsRelativeToParent(); - Vector2D coordsGlobal(); + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); - Vector2D size(); + Vector2D size(); - void onNewPopup(wlr_xdg_popup* popup); - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(bool ignoreSiblings = false); - void onReposition(); + void onNewPopup(wlr_xdg_popup* popup); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(bool ignoreSiblings = false); + void onReposition(); - void recheckTree(); + void recheckTree(); - bool visible(); + bool visible(); + // will also loop over this node + void breadthfirst(std::function fn, void* data); + CPopup* at(const Vector2D& globalCoords, bool allowsInput = false); + + // CWLSurface m_sWLSurface; private: @@ -62,11 +68,16 @@ class CPopup { DYNLISTENER(commitPopup); DYNLISTENER(repositionPopup); - void initAllSignals(); - void unconstrain(); - void recheckChildrenRecursive(); - void sendScale(); + struct { + CHyprSignalListener newPopup; + } listeners; - Vector2D localToGlobal(const Vector2D& rel); - Vector2D t1ParentCoords(); + void initAllSignals(); + void unconstrain(); + void recheckChildrenRecursive(); + void sendScale(); + + Vector2D localToGlobal(const Vector2D& rel); + Vector2D t1ParentCoords(); + static void bfHelper(std::vector nodes, std::function fn, void* data); }; \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 221348ff..4ccf8e41 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -6,6 +6,7 @@ #include "../managers/TokenManager.hpp" #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" +#include "../protocols/LayerShell.hpp" // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -481,7 +482,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // check LS focus grab const auto PFORCEFOCUS = g_pCompositor->getForceFocus(); const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); - if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.keyboard_interactive) + if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { if (*PNEWTAKESOVERFS == 0) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fa68655f..31d8d22f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -4,6 +4,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" #include "../devices/ITouch.hpp" +#include "../protocols/LayerShell.hpp" int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); @@ -254,7 +255,7 @@ void CMonitor::onDisconnect(bool destroy) { for (size_t i = 0; i < 4; ++i) { for (auto& ls : m_aLayerSurfaceLayers[i]) { if (ls->layerSurface && !ls->fadingOut) - wlr_layer_surface_v1_destroy(ls->layerSurface); + ls->layerSurface->sendClosed(); } m_aLayerSurfaceLayers[i].clear(); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2d49aeb3..48bb67e5 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -140,7 +140,7 @@ class CMonitor { CSignal modeChanged; } events; - std::array, 4> m_aLayerSurfaceLayers; + std::array, 4> m_aLayerSurfaceLayers; DYNLISTENER(monitorFrame); DYNLISTENER(monitorDestroy); diff --git a/src/includes.hpp b/src/includes.hpp index 080dbd4e..c16fe777 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -48,7 +48,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 21c1055f..f8cb0184 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -224,7 +224,7 @@ void CAnimationManager::tick() { g_pHyprRenderer->damageWindow(w); } } else if (PLAYER) { - if (PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND || PLAYER->layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) + if (PLAYER->layer <= 1) g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // some fucking layers miss 1 pixel??? diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 60fde1aa..73f33a20 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -26,6 +26,7 @@ #include "../protocols/ServerDecorationKDE.hpp" #include "../protocols/FocusGrab.hpp" #include "../protocols/Tablet.hpp" +#include "../protocols/LayerShell.hpp" CProtocolManager::CProtocolManager() { @@ -55,6 +56,7 @@ CProtocolManager::CProtocolManager() { PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); + PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 8d67760d..76f76126 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -13,6 +13,7 @@ #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/VirtualKeyboard.hpp" #include "../../protocols/VirtualPointer.hpp" +#include "../../protocols/LayerShell.hpp" #include "../../devices/Mouse.hpp" #include "../../devices/VirtualPointer.hpp" @@ -399,7 +400,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!refocus && g_pCompositor->m_pLastFocus) { const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); - if (PLS && PLS->layerSurface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + if (PLS && PLS->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) allowKeyboardRefocus = false; } @@ -479,7 +480,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { unsetCursorImage(); } - if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && + if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && allowKeyboardRefocus) { g_pCompositor->focusSurface(foundSurface); } diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 63adc8ca..44623671 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -37,7 +37,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.speedPoints = 0; if (PWORKSPACE->m_bHasFullscreenWindow) { - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = 1.f; } } @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { g_pInputManager->refocus(); // apply alpha - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; } } diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 60d85aa6..4a6484c2 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -33,7 +33,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { if (m_sActiveSwipe.pWorkspaceBegin) { return; // TODO: Don't swipe if you touched a floating window. - } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)) { + } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1)) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp new file mode 100644 index 00000000..ced765fd --- /dev/null +++ b/src/protocols/LayerShell.cpp @@ -0,0 +1,224 @@ +#include "LayerShell.hpp" +#include "../Compositor.hpp" + +#define LOGM PROTO::layerShell->protoLog + +void CLayerShellResource::SState::reset() { + anchor = 0; + exclusive = 0; + interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + desiredSize = {}; + margin = {0, 0, 0, 0}; +} + +CLayerShellResource::CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : + layerNamespace(namespace_), surface(surf_), resource(resource_) { + if (!good()) + return; + + current.layer = layer; + monitor = pMonitor ? pMonitor->szName : ""; + + resource->setDestroy([this](CZwlrLayerSurfaceV1* r) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); + resource->setOnDestroy([this](CZwlrLayerSurfaceV1* r) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); + + hyprListener_destroySurface.initCallback( + &surf_->events.destroy, + [this](void* owner, void* data) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }, + this, "CLayerShellResource"); + + hyprListener_commitSurface.initCallback( + &surf_->events.commit, + [this](void* owner, void* data) { + current = pending; + pending.committed = 0; + + bool attachedBuffer = surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0; + + if (attachedBuffer && !configured) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "layerSurface was not configured, but a buffer was attached"); + return; + } + + constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + + if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "x == 0 but anchor doesn't have left and right"); + return; + } + + if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { + wlr_surface_reject_pending(surface, resource->resource(), -1, "y == 0 but anchor doesn't have top and bottom"); + return; + } + + if (attachedBuffer && !mapped) { + mapped = true; + wlr_surface_map(surface); + events.map.emit(); + return; + } + + if (!attachedBuffer && mapped) { + mapped = false; + wlr_surface_unmap(surface); + events.unmap.emit(); + return; + } + + events.commit.emit(); + }, + this, "CLayerShellResource"); + + resource->setSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) { + pending.committed |= STATE_SIZE; + pending.desiredSize = {x, y}; + }); + + resource->setSetAnchor([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { + if (anchor > (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR, "Invalid anchor"); + return; + } + + pending.committed |= STATE_ANCHOR; + pending.anchor = anchor; + }); + + resource->setSetExclusiveZone([this](CZwlrLayerSurfaceV1* r, int32_t zone) { + pending.committed |= STATE_EXCLUSIVE; + pending.exclusive = zone; + }); + + resource->setSetMargin([this](CZwlrLayerSurfaceV1* r, int32_t top, int32_t right, int32_t bottom, int32_t left) { + pending.committed |= STATE_MARGIN; + pending.margin = {left, right, top, bottom}; + }); + + resource->setSetKeyboardInteractivity([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1KeyboardInteractivity kbi) { + if (kbi > ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_KEYBOARD_INTERACTIVITY, "Invalid keyboard interactivity"); + return; + } + + pending.committed |= STATE_INTERACTIVITY; + pending.interactivity = kbi; + }); + + resource->setGetPopup([this](CZwlrLayerSurfaceV1* r, wl_resource* popup_) { + auto popup = wlr_xdg_popup_from_resource(popup_); + + if (popup->parent) { + r->error(-1, "Parent already exists!"); + return; + } + + popup->parent = surface; + events.newPopup.emit(popup); + }); + + resource->setAckConfigure([this](CZwlrLayerSurfaceV1* r, uint32_t serial) { + auto serialFound = std::find_if(serials.begin(), serials.end(), [serial](const auto& e) { return e.first == serial; }); + + if (serialFound == serials.end()) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, "Serial invalid in ack_configure"); + return; + } + + configured = true; + size = serialFound->second; + + serials.erase(serialFound); + }); + + resource->setSetLayer([this](CZwlrLayerSurfaceV1* r, uint32_t layer) { + if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { + r->error(ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, "Invalid layer"); + return; + } + + pending.committed |= STATE_LAYER; + pending.layer = (zwlrLayerShellV1Layer)layer; + }); + + resource->setSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { + pending.committed |= STATE_EDGE; + pending.exclusiveEdge = anchor; + }); +} + +CLayerShellResource::~CLayerShellResource() { + events.destroy.emit(); +} + +bool CLayerShellResource::good() { + return resource->resource(); +} + +void CLayerShellResource::sendClosed() { + if (closed) + return; + closed = true; + resource->sendClosed(); +} + +void CLayerShellResource::configure(const Vector2D& size_) { + size = size_; + + auto serial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); + + serials.push_back({serial, size_}); + + resource->sendConfigure(serial, size_.x, size_.y); +} + +CLayerShellProtocol::CLayerShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CLayerShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CZwlrLayerShellV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CZwlrLayerShellV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetLayerSurface([this](CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { + this->onGetLayerSurface(pMgr, id, surface, output, layer, namespace_); + }); +} + +void CLayerShellProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { + std::erase_if(m_vLayers, [&](const auto& other) { return other.get() == surf; }); +} + +void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { + const auto CLIENT = pMgr->client(); + const auto PMONITOR = output ? g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)) : nullptr; + const auto RESOURCE = m_vLayers.emplace_back( + makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), namespace_, PMONITOR, layer)); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vLayers.pop_back(); + return; + } + + g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE)); + + LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get()); +} diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp new file mode 100644 index 00000000..9ed6bc66 --- /dev/null +++ b/src/protocols/LayerShell.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wlr-layer-shell-unstable-v1.hpp" +#include "../helpers/Vector2D.hpp" +#include "../helpers/signal/Signal.hpp" + +class CMonitor; + +class CLayerShellResource { + public: + CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); + ~CLayerShellResource(); + + bool good(); + void configure(const Vector2D& size); + void sendClosed(); + + enum eCommittedState { + STATE_SIZE = (1 << 0), + STATE_ANCHOR = (1 << 1), + STATE_EXCLUSIVE = (1 << 2), + STATE_MARGIN = (1 << 3), + STATE_INTERACTIVITY = (1 << 4), + STATE_LAYER = (1 << 5), + STATE_EDGE = (1 << 6), + }; + + struct { + CSignal destroy; + CSignal commit; + CSignal map; + CSignal unmap; + CSignal newPopup; // wlr_xdg_popup* + } events; + + struct SState { + uint32_t anchor = 0; + int32_t exclusive = 0; + Vector2D desiredSize; + zwlrLayerSurfaceV1KeyboardInteractivity interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + zwlrLayerShellV1Layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; + zwlrLayerSurfaceV1Anchor exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + uint32_t committed = 0; + + struct { + double left = 0, right = 0, top = 0, bottom = 0; + } margin; + + void reset(); + } current, pending; + + Vector2D size; + std::string layerNamespace; + std::string monitor = ""; + wlr_surface* surface = nullptr; + bool mapped = false; + bool configured = false; + + private: + SP resource; + + DYNLISTENER(destroySurface); + DYNLISTENER(commitSurface); + + bool closed = false; + + std::vector> serials; +}; + +class CLayerShellProtocol : public IWaylandProtocol { + public: + CLayerShellProtocol(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); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CLayerShellResource* surf); + void onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_); + + // + std::vector> m_vManagers; + std::vector> m_vLayers; + + friend class CLayerShellResource; +}; + +namespace PROTO { + inline UP layerShell; +}; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 5cbac942..14a9dcba 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -6,6 +6,7 @@ #include #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" +#include "../protocols/LayerShell.hpp" inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a671bd40..76f761d2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -9,6 +9,7 @@ #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" +#include "../protocols/LayerShell.hpp" extern "C" { #include @@ -709,8 +710,17 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time renderdata.dontRound = true; renderdata.popup = true; renderdata.blur = pLayer->forceBlurPopups; - if (popups) - wlr_layer_surface_v1_for_each_popup_surface(pLayer->layerSurface, renderSurface, &renderdata); + if (popups) { + pLayer->popupHead->breadthfirst( + [](CPopup* popup, void* data) { + if (!popup->m_sWLSurface.wlr()) + return; + + Vector2D pos = popup->coordsRelativeToParent(); + renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data); + }, + &renderdata); + } g_pHyprOpenGL->m_pCurrentLayer = nullptr; g_pHyprOpenGL->m_RenderData.clipBox = {}; @@ -786,16 +796,16 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->blend(true); for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } g_pHyprOpenGL->m_RenderData.renderModif = {}; @@ -826,10 +836,10 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->blend(true); for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } g_pHyprOpenGL->m_RenderData.damage = preOccludedDamage; @@ -896,7 +906,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC // Render surfaces above windows for monitor for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } // Render IME popups @@ -905,12 +915,12 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - renderLayer(ls, pMonitor, time); + renderLayer(ls.lock(), pMonitor, time); } for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { for (auto& ls : lsl) { - renderLayer(ls, pMonitor, time, true); + renderLayer(ls.lock(), pMonitor, time, true); } } @@ -1514,7 +1524,7 @@ static void applyExclusive(wlr_box& usableArea, uint32_t anchor, int32_t exclusi } } -void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { +void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { @@ -1523,18 +1533,18 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorlayerSurface; const auto PSTATE = &PLAYER->current; - if (exclusiveZone != (PSTATE->exclusive_zone > 0)) + if (exclusiveZone != (PSTATE->exclusive > 0)) continue; CBox bounds; - if (PSTATE->exclusive_zone == -1) + if (PSTATE->exclusive == -1) bounds = full_area; else bounds = *usableArea; const Vector2D OLDSIZE = {ls->geometry.width, ls->geometry.height}; - CBox box = {0, 0, PSTATE->desired_width, PSTATE->desired_height}; + CBox box = {{}, PSTATE->desiredSize}; // Horizontal axis const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; if (box.width == 0) { @@ -1589,12 +1599,12 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgeometry = box; - applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive_zone, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); + applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); usableArea->applyFromWlr(); if (Vector2D{box.width, box.height} != OLDSIZE) - wlr_layer_surface_v1_configure(ls->layerSurface, box.width, box.height); + ls->layerSurface->configure(box.size()); ls->realPosition = box.pos(); ls->realSize = box.size(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 748a055f..da38fed2 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -105,7 +105,7 @@ class CHyprRenderer { } m_sLastCursorData; private: - void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); + void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); From eeebbc0e7ee842a9572fa533cb8d01a8114f9ec9 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 9 May 2024 20:47:59 +0000 Subject: [PATCH 0041/2393] groupbar: fix title scaling (#5969) modified: src/render/decorations/CHyprGroupBarDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.hpp --- src/render/decorations/CHyprGroupBarDecoration.cpp | 8 ++++---- src/render/decorations/CHyprGroupBarDecoration.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 1ea0aac2..451701b4 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -154,8 +154,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { if (!pTitleTex) pTitleTex = m_sTitleTexs.titleTexs - .emplace_back(std::make_unique(m_dwGroupMembers[i].lock(), - Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale})) + .emplace_back(std::make_unique( + m_dwGroupMembers[i].lock(), Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) .get(); rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; @@ -184,7 +184,7 @@ void CHyprGroupBarDecoration::invalidateTextures() { m_sTitleTexs.titleTexs.clear(); } -CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize) { +CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { szContent = pWindow->m_szTitle; pWindowOwner = pWindow; const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); @@ -207,7 +207,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize) { pango_layout_set_text(layout, szContent.c_str(), -1); PangoFontDescription* fontDesc = pango_font_description_from_string((*PTITLEFONTFAMILY).c_str()); - pango_font_description_set_size(fontDesc, *PTITLEFONTSIZE * PANGO_SCALE); + pango_font_description_set_size(fontDesc, *PTITLEFONTSIZE * PANGO_SCALE * monitorScale); pango_layout_set_font_description(layout, fontDesc); pango_font_description_free(fontDesc); diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 45881add..3fe653cc 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -9,7 +9,7 @@ class CTitleTex { public: - CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize); + CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); ~CTitleTex(); CTexture tex; From 4f26ae70fde3b4cd5ad8ef096a7f0cb6c2dc5528 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 22:01:19 +0100 Subject: [PATCH 0042/2393] core: drop unused protocol impls xdg_foreign is not used by hyprland wlr_export_dmabuf is old, broken and unused as well --- src/Compositor.cpp | 6 ------ src/Compositor.hpp | 1 - src/includes.hpp | 4 ---- 3 files changed, 11 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index da2b643c..5de30a74 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -224,7 +224,6 @@ void CCompositor::initServer() { m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay); m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay); - wlr_export_dmabuf_manager_v1_create(m_sWLDisplay); wlr_data_control_manager_v1_create(m_sWLDisplay); wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); wlr_viewporter_create(m_sWLDisplay); @@ -241,11 +240,6 @@ void CCompositor::initServer() { Debug::log(INFO, "VR will not be available"); } - m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay); - - wlr_xdg_foreign_v1_create(m_sWLDisplay, m_sWLRForeignRegistry); - wlr_xdg_foreign_v2_create(m_sWLDisplay, m_sWLRForeignRegistry); - m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop); if (!m_sWLRHeadlessBackend) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 9659df5c..20437113 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -55,7 +55,6 @@ class CCompositor { wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; int m_iDRMFD; - wlr_xdg_foreign_registry* m_sWLRForeignRegistry; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; wlr_backend* m_sWLRHeadlessBackend; // ------------------------------------------------- // diff --git a/src/includes.hpp b/src/includes.hpp index c16fe777..98416a1a 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -43,7 +43,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -74,9 +73,6 @@ extern "C" { #include #include #include -#include -#include -#include #include #include #include From 51b0da2c0daca17adcfdd6df9d0ee2feb88121b1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 10 May 2024 00:04:15 +0300 Subject: [PATCH 0043/2393] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 39d7fbdd..2c2d62f3 100644 --- a/flake.lock +++ b/flake.lock @@ -38,11 +38,11 @@ ] }, "locked": { - "lastModified": 1714869498, - "narHash": "sha256-vbLVOWvQqo4n1yvkg/Q70VTlPbMmTiCQfNTgcWDCfJM=", + "lastModified": 1691753796, + "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "e06482e0e611130cd1929f75e8c1cf679e57d161", + "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", "type": "github" }, "original": { @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715090986, - "narHash": "sha256-FXpQvmS9R7alwZ47XK5UIcAbC9YKSxc0+GOVYqwa0jM=", + "lastModified": 1715287423, + "narHash": "sha256-B7AJIjOyWgVMKhu7DlOnWa0VprdhywUVHuB/j+EwSxM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "94e32ec37e7215b16d5c1b41b1773ff6742e704b", + "rev": "e2fc1c0eb8b392110588f478cce644348ead7271", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1714253743, - "narHash": "sha256-mdTQw2XlariysyScCv2tTE45QSU9v/ezLcHJ22f0Nxc=", + "lastModified": 1715087517, + "narHash": "sha256-CLU5Tsg24Ke4+7sH8azHWXKd0CFd4mhLWfhYgUiDBpQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "58a1abdbae3217ca6b702f03d3b35125d88a2994", + "rev": "b211b392b8486ee79df6cdfb1157ad2133427a29", "type": "github" }, "original": { @@ -152,11 +152,11 @@ ] }, "locked": { - "lastModified": 1714060055, - "narHash": "sha256-j43TS9wv9luaAlpxcxw0sjxkbcc2mGANVR2RYgo3RCw=", + "lastModified": 1714662532, + "narHash": "sha256-Pj2xGSYhapYbXL7sk7TTlOtCZcTfPQoL3fPbZeg7L4Y=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "0fe840441e43da12cd7865ed9aa8cdc35a8da85a", + "rev": "1f228ba2f1f254195c0b571302b37482861abee3", "type": "github" }, "original": { From 7cf810b1813a610e25f169ca9bb2d8ab9b967666 Mon Sep 17 00:00:00 2001 From: sub-kek <100521725+sub-kek@users.noreply.github.com> Date: Fri, 10 May 2024 00:05:13 +0300 Subject: [PATCH 0044/2393] keybinds: Fix classic global keybinds(pass dispatcher) (#5967) --- src/managers/KeybindManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 62265e00..f06dd703 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1964,7 +1964,7 @@ void CKeybindManager::pass(std::string regexp) { } if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PLASTSRF, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers); + wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers); else wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), SL.x, SL.y); } From b0861b6709c1735dc5b4275e5d87b7c83f1ef1f0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 22:23:01 +0100 Subject: [PATCH 0045/2393] config: move various cursor-related vars to cursor: --- src/Compositor.cpp | 4 ++-- src/config/ConfigManager.cpp | 16 ++++++++-------- src/debug/HyprCtl.cpp | 2 +- src/events/Monitors.cpp | 2 +- src/helpers/Monitor.cpp | 4 ++-- src/managers/CursorManager.cpp | 2 +- src/managers/input/InputManager.cpp | 2 +- src/render/OpenGL.cpp | 2 +- src/render/Renderer.cpp | 8 ++++---- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5de30a74..72502db3 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2394,9 +2394,9 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { // warpCursorTo should only be used for warps that - // should be disabled with no_cursor_warps + // should be disabled with no_warps - static auto PNOWARPS = CConfigValue("general:no_cursor_warps"); + static auto PNOWARPS = CConfigValue("cursor:no_warps"); if (*PNOWARPS && !force) return; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 7804a511..38bf8173 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -311,8 +311,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("general:gaps_in", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "5"}); m_pConfig->addConfigValue("general:gaps_out", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "20"}); m_pConfig->addConfigValue("general:gaps_workspaces", Hyprlang::INT{0}); - m_pConfig->addConfigValue("general:cursor_inactive_timeout", Hyprlang::INT{0}); - m_pConfig->addConfigValue("general:no_cursor_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:no_focus_fallback", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:resize_on_border", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:extend_border_grab_area", Hyprlang::INT{15}); @@ -320,7 +318,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("general:layout", {"dwindle"}); m_pConfig->addConfigValue("general:allow_tearing", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:resize_corner", Hyprlang::INT{0}); - m_pConfig->addConfigValue("general:default_cursor_monitor", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); @@ -341,18 +338,13 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1}); - m_pConfig->addConfigValue("misc:hide_cursor_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1}); - m_pConfig->addConfigValue("misc:cursor_zoom_factor", {1.f}); - m_pConfig->addConfigValue("misc:cursor_zoom_rigid", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:allow_session_lock_restore", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); - m_pConfig->addConfigValue("misc:enable_hyprcursor", Hyprlang::INT{1}); - m_pConfig->addConfigValue("misc:hide_cursor_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); @@ -519,6 +511,14 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY}); + m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); + m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 56b7bd2b..a89e0710 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -955,7 +955,7 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { } // decorations will probably need a repaint - if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("cursor_zoom_factor") || COMMAND == "source") { + if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { for (auto& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m.get()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index ab8fc7b0..e3f8f03a 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -18,7 +18,7 @@ static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { - static auto PCURSORMONITOR = CConfigValue("general:default_cursor_monitor"); + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); static auto firstMonitorAdded = std::chrono::system_clock::now(); static bool cursorDefaultDone = false; static bool firstLaunch = true; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 31d8d22f..2814bc84 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -327,7 +327,7 @@ void CMonitor::onDisconnect(bool destroy) { } void CMonitor::addDamage(const pixman_region32_t* rg) { - static auto PZOOMFACTOR = CConfigValue("misc:cursor_zoom_factor"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { wlr_damage_ring_add_whole(&damage); g_pCompositor->scheduleFrameForMonitor(this); @@ -340,7 +340,7 @@ void CMonitor::addDamage(const CRegion* rg) { } void CMonitor::addDamage(const CBox* box) { - static auto PZOOMFACTOR = CConfigValue("misc:cursor_zoom_factor"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { wlr_damage_ring_add_whole(&damage); g_pCompositor->scheduleFrameForMonitor(this); diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 4ee3adfc..ea36b9b2 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -156,7 +156,7 @@ void CCursorManager::setXCursor(const std::string& name) { void CCursorManager::setCursorFromName(const std::string& name) { - static auto PUSEHYPRCURSOR = CConfigValue("misc:enable_hyprcursor"); + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { setXCursor(name); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 76f76126..1d09dbb9 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -132,7 +132,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); - static auto PZOOMFACTOR = CConfigValue("misc:cursor_zoom_factor"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 14a9dcba..a8a20f30 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -394,7 +394,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu } void CHyprOpenGLImpl::end() { - static auto PZOOMRIGID = CConfigValue("misc:cursor_zoom_rigid"); + static auto PZOOMRIGID = CConfigValue("cursor:zoom_rigid"); TRACY_GPU_ZONE("RenderEnd"); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 76f761d2..d1baf461 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1092,7 +1092,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static auto PDAMAGEBLINK = CConfigValue("debug:damage_blink"); static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); static auto PVFR = CConfigValue("misc:vfr"); - static auto PZOOMFACTOR = CConfigValue("misc:cursor_zoom_factor"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); static auto PANIMENABLED = CConfigValue("animations:enabled"); static auto PFIRSTLAUNCHANIM = CConfigValue("animations:first_launch_animation"); static auto PTEARINGENABLED = CConfigValue("general:allow_tearing"); @@ -2278,9 +2278,9 @@ void CHyprRenderer::setCursorFromName(const std::string& name, bool force) { } void CHyprRenderer::ensureCursorRenderingMode() { - static auto PCURSORTIMEOUT = CConfigValue("general:cursor_inactive_timeout"); - static auto PHIDEONTOUCH = CConfigValue("misc:hide_cursor_on_touch"); - static auto PHIDEONKEY = CConfigValue("misc:hide_cursor_on_key_press"); + static auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); + static auto PHIDEONTOUCH = CConfigValue("cursor:hide_on_touch"); + static auto PHIDEONKEY = CConfigValue("cursor:hide_on_key_press"); if (*PCURSORTIMEOUT <= 0) m_sCursorHiddenConditions.hiddenOnTimeout = false; From 1753059b07be52cf78fa2676c4c71d2edb560199 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 9 May 2024 23:08:40 +0100 Subject: [PATCH 0046/2393] pointermgr: reset entered outputs when resetting surface fixes #5970 --- src/managers/PointerManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 21c6998f..663456f8 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -297,6 +297,13 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.scale = 1.F; currentCursorImage.hotspot = {0, 0}; + for (auto& s : monitorStates) { + if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) + continue; + + s->entered = false; + } + if (!apply) return; From a7e23d2f1e27c241c2a72262d14d5dde9ea2e860 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 02:27:54 +0100 Subject: [PATCH 0047/2393] presentation-time: move to new impl --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 2 - src/Compositor.hpp | 1 - src/helpers/Monitor.cpp | 25 ++++-- src/helpers/Monitor.hpp | 1 + src/includes.hpp | 1 - src/managers/ProtocolManager.cpp | 2 + src/protocols/PresentationTime.cpp | 125 +++++++++++++++++++++++++++++ src/protocols/PresentationTime.hpp | 73 +++++++++++++++++ src/render/Renderer.cpp | 12 ++- 11 files changed, 231 insertions(+), 13 deletions(-) create mode 100644 src/protocols/PresentationTime.cpp create mode 100644 src/protocols/PresentationTime.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index eb766005..c334ab06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,7 @@ protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" f protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) +protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 4206b56a..95c9fec4 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -60,6 +60,7 @@ new_protocols = [ [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], + [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 72502db3..bed2b203 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -232,8 +232,6 @@ void CCompositor::initServer() { m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0"); - m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend); - 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"); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 20437113..8812f8c8 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -52,7 +52,6 @@ class CCompositor { wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; wlr_xdg_shell* m_sWLRXDGShell; - wlr_presentation* m_sWLRPresentation; wlr_egl* m_sWLREGL; int m_iDRMFD; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 2814bc84..d13acf0c 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -5,6 +5,7 @@ #include "../protocols/GammaControl.hpp" #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/PresentationTime.hpp" int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); @@ -30,6 +31,13 @@ CMonitor::~CMonitor() { events.destroy.emit(); } +static void onPresented(void* owner, void* data) { + const auto PMONITOR = (CMonitor*)owner; + auto E = (wlr_output_event_present*)data; + + PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags); +} + void CMonitor::onConnect(bool noRule) { hyprListener_monitorDestroy.removeCallback(); hyprListener_monitorFrame.removeCallback(); @@ -38,13 +46,15 @@ void CMonitor::onConnect(bool noRule) { hyprListener_monitorNeedsFrame.removeCallback(); hyprListener_monitorCommit.removeCallback(); hyprListener_monitorBind.removeCallback(); - hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this); - hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this); - hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this); - hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this); - hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this); - hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this); - hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this); + hyprListener_monitorPresented.removeCallback(); + hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor"); + hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor"); + hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor"); + hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor"); + hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor"); + hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor"); + hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor"); + hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor"); tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm @@ -247,6 +257,7 @@ void CMonitor::onDisconnect(bool destroy) { } hyprListener_monitorFrame.removeCallback(); + hyprListener_monitorPresented.removeCallback(); hyprListener_monitorDamage.removeCallback(); hyprListener_monitorNeedsFrame.removeCallback(); hyprListener_monitorCommit.removeCallback(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 48bb67e5..7aa07a86 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -149,6 +149,7 @@ class CMonitor { DYNLISTENER(monitorNeedsFrame); DYNLISTENER(monitorCommit); DYNLISTENER(monitorBind); + DYNLISTENER(monitorPresented); // methods void onConnect(bool noRule); diff --git a/src/includes.hpp b/src/includes.hpp index 98416a1a..eb01f4a1 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -51,7 +51,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 73f33a20..2904ed53 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -27,6 +27,7 @@ #include "../protocols/FocusGrab.hpp" #include "../protocols/Tablet.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/PresentationTime.hpp" CProtocolManager::CProtocolManager() { @@ -57,6 +58,7 @@ CProtocolManager::CProtocolManager() { PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); + PROTO::presentation = std::make_unique(&wp_presentation_interface, 1, "Presentation"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp new file mode 100644 index 00000000..e21c8403 --- /dev/null +++ b/src/protocols/PresentationTime.cpp @@ -0,0 +1,125 @@ +#include "PresentationTime.hpp" +#include +#include "../helpers/Monitor.hpp" +#include "../managers/HookSystemManager.hpp" + +#define LOGM PROTO::presentation->protoLog + +CQueuedPresentationData::CQueuedPresentationData(wlr_surface* surf) : surface(surf) { + ; +} + +void CQueuedPresentationData::setPresentationType(bool zeroCopy_) { + zeroCopy = zeroCopy_; +} + +void CQueuedPresentationData::attachMonitor(CMonitor* pMonitor_) { + pMonitor = pMonitor_; +} + +void CQueuedPresentationData::presented() { + wasPresented = true; +} + +void CQueuedPresentationData::discarded() { + wasPresented = false; +} + +CPresentationFeedback::CPresentationFeedback(SP resource_, wlr_surface* surf) : resource(resource_), surface(surf) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpPresentationFeedback* pMgr) { + if (!done) // if it's done, it's probably already destroyed. If not, it will be in a sec. + PROTO::presentation->destroyResource(this); + }); +} + +bool CPresentationFeedback::good() { + return resource->resource(); +} + +void CPresentationFeedback::sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { + auto client = resource->client(); + wl_resource* res; + wl_resource_for_each(res, &data->pMonitor->output->resources) { + if (client == wl_resource_get_client(res)) { + resource->sendSyncOutput(res); + break; + } + } + + uint32_t flags = 0; + if (!data->pMonitor->tearingState.activelyTearing) + flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC; + if (data->zeroCopy) + flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; + if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK) + flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; + if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) + flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; + + if (data->wasPresented) + resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), + (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); + else + resource->sendDiscarded(); +} + +CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { + const auto PMONITOR = std::any_cast(param); + std::erase_if(m_vQueue, [PMONITOR, this](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); + }); +} + +void CPresentationProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CWpPresentation* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CWpPresentation* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setFeedback([this](CWpPresentation* pMgr, wl_resource* surf, uint32_t id) { this->onGetFeedback(pMgr, surf, id); }); +} + +void CPresentationProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CPresentationProtocol::destroyResource(CPresentationFeedback* feedback) { + std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == feedback; }); +} + +void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id) { + const auto CLIENT = pMgr->client(); + const auto RESOURCE = + m_vFeedbacks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); + + if (!RESOURCE->good()) { + pMgr->noMemory(); + m_vFeedbacks.pop_back(); + return; + } +} + +void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { + for (auto& feedback : m_vFeedbacks) { + if (!feedback->surface) + continue; + + for (auto& data : m_vQueue) { + if (!data->surface || data->surface != feedback->surface) + continue; + + feedback->sendQueued(data, when, untilRefreshNs, seq, reportedFlags); + feedback->done = true; + break; + } + } + + std::erase_if(m_vFeedbacks, [pMonitor, this](const auto& other) { return !other->surface || other->done; }); + std::erase_if(m_vQueue, [pMonitor, this](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); +} + +void CPresentationProtocol::queueData(SP data) { + m_vQueue.emplace_back(data); +} diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp new file mode 100644 index 00000000..2df1c781 --- /dev/null +++ b/src/protocols/PresentationTime.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "presentation-time.hpp" + +class CMonitor; + +class CQueuedPresentationData { + public: + CQueuedPresentationData(wlr_surface* surf); + + void setPresentationType(bool zeroCopy); + void attachMonitor(CMonitor* pMonitor); + + void presented(); + void discarded(); + + private: + bool wasPresented = false; + bool zeroCopy = false; + CMonitor* pMonitor = nullptr; + wlr_surface* surface = nullptr; // READ-ONLY + + DYNLISTENER(destroySurface); + + friend class CPresentationFeedback; + friend class CPresentationProtocol; +}; + +class CPresentationFeedback { + public: + CPresentationFeedback(SP resource_, wlr_surface* surf); + + bool good(); + + void sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); + + private: + SP resource; + wlr_surface* surface = nullptr; // READ-ONLY + bool done = false; + + friend class CPresentationProtocol; +}; + +class CPresentationProtocol : public IWaylandProtocol { + public: + CPresentationProtocol(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); + + void onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); + void queueData(SP data); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CPresentationFeedback* feedback); + void onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id); + + // + std::vector> m_vManagers; + std::vector> m_vFeedbacks; + std::vector> m_vQueue; + + friend class CPresentationFeedback; +}; + +namespace PROTO { + inline UP presentation; +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d1baf461..d02ed4e2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -10,6 +10,7 @@ #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/PresentationTime.hpp" extern "C" { #include @@ -206,7 +207,10 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { wlr_surface_send_frame_done(surface, RDATA->when); - wlr_presentation_surface_textured_on_output(surface, RDATA->pMonitor->output); + auto FEEDBACK = makeShared(surface); + FEEDBACK->attachMonitor(RDATA->pMonitor); + FEEDBACK->presented(); + PROTO::presentation->queueData(FEEDBACK); } g_pHyprOpenGL->blend(true); @@ -1067,7 +1071,11 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); wlr_surface_send_frame_done(PSURFACE, &now); - wlr_presentation_surface_scanned_out_on_output(PSURFACE, pMonitor->output); + auto FEEDBACK = makeShared(PSURFACE); + FEEDBACK->attachMonitor(pMonitor); + FEEDBACK->presented(); + FEEDBACK->setPresentationType(true); + PROTO::presentation->queueData(FEEDBACK); if (pMonitor->state.commit()) { if (m_pLastScanout.expired()) { From db30ff63e6dc3d3b631f9da55ccadc07c4440948 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 02:28:21 +0100 Subject: [PATCH 0048/2393] popups: avoid infinite recursion in bf --- src/desktop/Popup.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index f1517083..05e79b4e 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -294,7 +294,8 @@ void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { From 2ba6bb69c4b455ff6327596a63bf1785d0910d2c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 02:36:56 +0100 Subject: [PATCH 0049/2393] popups: fix breadthfirst and at fixes #5977 --- src/desktop/Popup.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 05e79b4e..e172744d 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -301,6 +301,7 @@ void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { std::vector popups; popups.push_back(this); + bfHelper(popups, fn, data); } CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { @@ -316,7 +317,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { if (BOX.containsPoint(globalCoords)) return p; } else { - const auto REGION = CRegion{&m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal()); + const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal()); if (REGION.containsPoint(globalCoords)) return p; } From 337422911895bb55099e00208bff929651dcb5d2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 03:20:26 +0100 Subject: [PATCH 0050/2393] core: remove unused includes and fix warn --- src/includes.hpp | 4 ---- src/managers/KeybindManager.cpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/includes.hpp b/src/includes.hpp index eb01f4a1..844a9173 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -44,23 +44,19 @@ extern "C" { #include #include #include -#include #include #include #include #include -#include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f06dd703..15f667f0 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1902,8 +1902,6 @@ void CKeybindManager::pass(std::string regexp) { return; } - const auto PLASTSRF = g_pCompositor->m_pLastFocus; - const auto KEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); if (!KEYBOARD) { From 2549f0cc9725919d2d3ef466eff60bd10e1a321e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 12:03:38 +0100 Subject: [PATCH 0051/2393] layersurface: reset popuphead after unmap fixes #5980 --- src/desktop/LayerSurface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index c9750dc9..8bff5850 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -73,8 +73,6 @@ void CLayerSurface::onDestroy() { const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); - popupHead.reset(); - if (!g_pCompositor->getMonitorFromID(monitorID)) Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); @@ -90,6 +88,8 @@ void CLayerSurface::onDestroy() { } } + popupHead.reset(); + noProcess = true; // rearrange to fix the reserved areas From cc4ac52309a7715c09c1e19545bc0fa4048c4604 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 12:22:47 +0100 Subject: [PATCH 0052/2393] github: update issue template with new path --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 0bdaff4d..08a9ad9c 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -62,6 +62,6 @@ body: label: Crash reports, logs, images, videos description: | Anything that can help. Please always ATTACH and not paste them. - Logs can be found in /tmp/hypr + Logs can be found in $XDG_RUNTIME_DIR/hypr Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland From c19903eaf8f3908e864e57c8449325e9b5e0c9bd Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Fri, 10 May 2024 11:27:54 +0000 Subject: [PATCH 0053/2393] windowrules add focusonactivate (#5976) modified: src/config/ConfigManager.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp --- src/config/ConfigManager.cpp | 4 ++-- src/desktop/Window.cpp | 6 +++++- src/desktop/Window.hpp | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 38bf8173..4a75ca1d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1997,8 +1997,8 @@ bool windowRuleValid(const std::string& RULE) { RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" || RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "fakefullscreen" || RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" || RULE == "maximize" || RULE == "keepaspectratio" || - RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") || RULE == "forcergbx" || - RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") || + RULE == "focusonactivate" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") || + RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") || RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor" || RULE.starts_with("suppressevent") || RULE.starts_with("plugin:"); } diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 2b95ad4c..e87bd99c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -671,6 +671,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { m_sAdditionalConfigData.dimAround = true; } else if (r.szRule == "keepaspectratio") { m_sAdditionalConfigData.keepAspectRatio = true; + } else if (r.szRule.starts_with("focusonactivate")) { + m_sAdditionalConfigData.focusOnActivate = true; } else if (r.szRule.starts_with("xray")) { CVarList vars(r.szRule, 0, ' '); @@ -745,6 +747,7 @@ void CWindow::updateDynamicRules() { m_sAdditionalConfigData.forceRGBX = false; m_sAdditionalConfigData.borderSize = -1; m_sAdditionalConfigData.keepAspectRatio = false; + m_sAdditionalConfigData.focusOnActivate = false; m_sAdditionalConfigData.xray = -1; m_sAdditionalConfigData.forceTearing = false; m_sAdditionalConfigData.nearestNeighbor = false; @@ -1282,7 +1285,8 @@ void CWindow::activate(bool force) { m_bIsUrgent = true; - if (!force && (!*PFOCUSONACTIVATE || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) + if (!force && + (!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) return; if (m_bIsFloating) diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ed79c896..efccb41c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -164,6 +164,7 @@ struct SWindowAdditionalConfigData { CWindowOverridableVar dimAround = false; CWindowOverridableVar forceRGBX = false; CWindowOverridableVar keepAspectRatio = false; + CWindowOverridableVar focusOnActivate = false; CWindowOverridableVar xray = -1; // -1 means unset, takes precedence over the renderdata one CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one CWindowOverridableVar forceTearing = false; From 37a84c5223279ce16152db69fba204df365c4eda Mon Sep 17 00:00:00 2001 From: underengineering <103371090+underengineering@users.noreply.github.com> Date: Fri, 10 May 2024 14:32:50 +0300 Subject: [PATCH 0054/2393] socket2: fix events being reordered (#5955) * socket2: fix events being reordered * remove WL_EVENT_READABLE * initialize eventSource in SClient * add more logs oopsie * replace unordered_map with vector * fix reordering when socket becomes writable before queue is flushed * ignore EAGAIN when accepting connection * use g_pEventManager --- src/Compositor.cpp | 4 - src/managers/EventManager.cpp | 214 +++++++++++++++++++--------------- src/managers/EventManager.hpp | 41 ++++--- 3 files changed, 142 insertions(+), 117 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index bed2b203..9a9ea30b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -338,9 +338,6 @@ void CCompositor::cleanup() { m_pLastFocus = nullptr; m_pLastWindow.reset(); - // end threads - g_pEventManager->m_tThread = std::thread(); - m_vWorkspaces.clear(); m_vWindows.clear(); @@ -463,7 +460,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the EventManager!"); g_pEventManager = std::make_unique(); - g_pEventManager->startThread(); Debug::log(LOG, "Creating the HyprDebugOverlay!"); g_pDebugOverlay = std::make_unique(); diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index 8605768c..75c98e2a 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -1,154 +1,178 @@ #include "EventManager.hpp" #include "../Compositor.hpp" -#include -#include +#include #include -#include -#include -#include #include #include #include #include #include -#include - -#include -#include - -CEventManager::CEventManager() {} - -int fdHandleWrite(int fd, uint32_t mask, void* data) { - const auto PEVMGR = (CEventManager*)data; - return PEVMGR->onFDWrite(fd, mask); -} - -int socket2HandleWrite(int fd, uint32_t mask, void* data) { - const auto PEVMGR = (CEventManager*)data; - return PEVMGR->onSocket2Write(fd, mask); -} - -void CEventManager::startThread() { - - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); +CEventManager::CEventManager() { + m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); if (m_iSocketFD < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); return; } sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; - std::string socketPath = g_pCompositor->m_szInstancePath + "/.socket2.sock"; - strncpy(SERVERADDRESS.sun_path, socketPath.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); + const auto PATH = g_pCompositor->m_szInstancePath + "/.socket2.sock"; + if (PATH.length() > sizeof(SERVERADDRESS.sun_path) - 1) { + Debug::log(ERR, "Socket2 path is too long. (2) IPC will not work."); + return; + } - bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); + strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); + + if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); + return; + } // 10 max queued. - listen(m_iSocketFD, 10); + if (listen(m_iSocketFD, 10) < 0) { + Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); + return; + } - m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, socket2HandleWrite, this); + m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr); } -int CEventManager::onSocket2Write(int fd, uint32_t mask) { +CEventManager::~CEventManager() { + for (const auto& client : m_vClients) { + wl_event_source_remove(client.eventSource); + close(client.fd); + } + if (m_pEventSource != nullptr) + wl_event_source_remove(m_pEventSource); + + if (m_iSocketFD >= 0) + close(m_iSocketFD); +} + +int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { + return g_pEventManager->onClientEvent(fd, mask); +} + +int CEventManager::onClientEvent(int fd, uint32_t mask, void* data) { + return g_pEventManager->onServerEvent(fd, mask); +} + +int CEventManager::onServerEvent(int fd, uint32_t mask) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) { Debug::log(ERR, "Socket2 hangup?? IPC broke"); + wl_event_source_remove(m_pEventSource); + m_pEventSource = nullptr; close(fd); + m_iSocketFD = -1; + return 0; } sockaddr_in clientAddress; socklen_t clientSize = sizeof(clientAddress); const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK); + if (ACCEPTEDCONNECTION < 0) { + if (errno != EAGAIN) { + Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); + wl_event_source_remove(m_pEventSource); + m_pEventSource = nullptr; + close(fd); + m_iSocketFD = -1; + } - if (ACCEPTEDCONNECTION > 0) { - Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); - - // add to event loop so we can close it when we need to - m_dAcceptedSocketFDs.push_back( - std::make_pair<>(ACCEPTEDCONNECTION, wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, WL_EVENT_READABLE, fdHandleWrite, this))); - } else { - Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); - close(fd); + return 0; } + Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); + + // add to event loop so we can close it when we need to + auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr); + m_vClients.emplace_back(SClient{ + ACCEPTEDCONNECTION, + {}, + eventSource, + }); + return 0; } -int CEventManager::onFDWrite(int fd, uint32_t mask) { - auto removeFD = [this](int fd) -> void { - for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) { - if (it->first == fd) { - wl_event_source_remove(it->second); // remove this fd listener - it = m_dAcceptedSocketFDs.erase(it); - } else { - it++; - } - } - - close(fd); - }; - +int CEventManager::onClientEvent(int fd, uint32_t mask) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) { - // remove, hanged up - removeFD(fd); + Debug::log(LOG, "Socket2 fd {} hung up", fd); + removeClientByFD(fd); return 0; } - int availableBytes; - if (ioctl(fd, FIONREAD, &availableBytes) == -1) { - Debug::log(ERR, "fd {} sent invalid data (1)", fd); - removeFD(fd); - return 0; - } + if (mask & WL_EVENT_WRITABLE) { + const auto CLIENTIT = findClientByFD(fd); - char buf[availableBytes]; - const auto RECEIVED = recv(fd, buf, availableBytes, 0); - if (RECEIVED == -1) { - Debug::log(ERR, "fd {} sent invalid data (2)", fd); - removeFD(fd); - return 0; + // send all queued events + while (!CLIENTIT->events.empty()) { + const auto& event = CLIENTIT->events.front(); + if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0) + break; + + CLIENTIT->events.pop_front(); + } + + // stop polling when we sent all events + if (CLIENTIT->events.empty()) + wl_event_source_fd_update(CLIENTIT->eventSource, 0); } return 0; } -void CEventManager::flushEvents() { - eventQueueMutex.lock(); - - for (auto& ev : m_dQueuedEvents) { - std::string eventString = (ev.event + ">>" + ev.data).substr(0, 1022) + "\n"; - for (auto& fd : m_dAcceptedSocketFDs) { - try { - write(fd.first, eventString.c_str(), eventString.length()); - } catch (...) {} - } - } - - m_dQueuedEvents.clear(); - - eventQueueMutex.unlock(); +std::vector::iterator CEventManager::findClientByFD(int fd) { + return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; }); } -void CEventManager::postEvent(const SHyprIPCEvent event) { +std::vector::iterator CEventManager::removeClientByFD(int fd) { + const auto CLIENTIT = findClientByFD(fd); + wl_event_source_remove(CLIENTIT->eventSource); + close(fd); + return m_vClients.erase(CLIENTIT); +} + +std::string CEventManager::formatEvent(const SHyprIPCEvent& event) const { + std::string_view data = event.data; + auto eventString = std::format("{}>>{}\n", event.event, data.substr(0, 1024)); + std::replace(eventString.begin() + event.event.length() + 2, eventString.end() - 1, '\n', ' '); + return eventString; +} + +void CEventManager::postEvent(const SHyprIPCEvent& event) { if (g_pCompositor->m_bIsShuttingDown) { - Debug::log(WARN, "Suppressed (ignoreevents true / shutting down) event of type {}, content: {}", event.event, event.data); + Debug::log(WARN, "Suppressed (shutting down) event of type {}, content: {}", event.event, event.data); return; } - std::thread( - [this](SHyprIPCEvent ev) { - std::replace(ev.data.begin(), ev.data.end(), '\n', ' '); + const size_t MAX_QUEUED_EVENTS = 64; + auto sharedEvent = makeShared(formatEvent(event)); + for (auto it = m_vClients.begin(); it != m_vClients.end();) { + // try to send the event immediately if the queue is empty + const auto QUEUESIZE = it->events.size(); + if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) { + if (QUEUESIZE >= MAX_QUEUED_EVENTS) { + // too many events queued, remove the client + Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd); + it = removeClientByFD(it->fd); + continue; + } - eventQueueMutex.lock(); - m_dQueuedEvents.push_back(ev); - eventQueueMutex.unlock(); + // queue it to send later if failed + it->events.push_back(sharedEvent); - flushEvents(); - }, - event) - .detach(); + // poll for write if queue was empty + if (QUEUESIZE == 0) + wl_event_source_fd_update(it->eventSource, WL_EVENT_WRITABLE); + } + + ++it; + } } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index ed681dba..94dbab59 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,10 +1,9 @@ #pragma once #include -#include -#include +#include #include "../defines.hpp" -#include "../helpers/MiscFunctions.hpp" +#include "../helpers/memory/SharedPtr.hpp" struct SHyprIPCEvent { std::string event; @@ -14,27 +13,33 @@ struct SHyprIPCEvent { class CEventManager { public: CEventManager(); + ~CEventManager(); - void postEvent(const SHyprIPCEvent event); - - void startThread(); - - std::thread m_tThread; - - int m_iSocketFD = -1; - - int onSocket2Write(int fd, uint32_t mask); - int onFDWrite(int fd, uint32_t mask); + void postEvent(const SHyprIPCEvent& event); private: - void flushEvents(); + std::string formatEvent(const SHyprIPCEvent& event) const; - std::mutex eventQueueMutex; - std::deque m_dQueuedEvents; + static int onServerEvent(int fd, uint32_t mask, void* data); + static int onClientEvent(int fd, uint32_t mask, void* data); - std::deque> m_dAcceptedSocketFDs; + int onServerEvent(int fd, uint32_t mask); + int onClientEvent(int fd, uint32_t mask); - wl_event_source* m_pEventSource = nullptr; + struct SClient { + int fd = -1; + std::deque> events; + wl_event_source* eventSource = nullptr; + }; + + std::vector::iterator findClientByFD(int fd); + std::vector::iterator removeClientByFD(int fd); + + private: + int m_iSocketFD = -1; + wl_event_source* m_pEventSource = nullptr; + + std::vector m_vClients; }; inline std::unique_ptr g_pEventManager; From 38911d6df4977b6b00557cc887eb151d032e505b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 12:58:53 +0100 Subject: [PATCH 0055/2393] box: fix noNegativeSize --- src/helpers/Box.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp index 77406ecf..4b7f5726 100644 --- a/src/helpers/Box.cpp +++ b/src/helpers/Box.cpp @@ -115,8 +115,8 @@ CBox& CBox::expand(const double& value) { } CBox& CBox::noNegativeSize() { - std::clamp(w, 0.0, std::numeric_limits::infinity()); - std::clamp(h, 0.0, std::numeric_limits::infinity()); + w = std::clamp(w, 0.0, std::numeric_limits::infinity()); + h = std::clamp(h, 0.0, std::numeric_limits::infinity()); return *this; } From 19186de11834df43494378478d2d3a374e2409ae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 23:38:46 +0100 Subject: [PATCH 0056/2393] renderer: avoid locking during rendering it can trigger pointermgr to render which fucks up our pass fixes #5998 --- src/render/Renderer.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d02ed4e2..2574a015 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1247,6 +1247,10 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->forceFullFrames = 10; } + bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; + if (lockSoftware) + g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); + CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); @@ -1341,21 +1345,16 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { if (renderCursor) { TRACY_GPU_ZONE("RenderCursor"); - - bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; - - if (lockSoftware) { - g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); - g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); - g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); - } else - g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); + g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage); } EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT); endRender(); + if (lockSoftware) + g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); + TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { From 6e594e44162ed5ad8fd9db3e552723e32169158a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 23:41:32 +0100 Subject: [PATCH 0057/2393] hyprpm: force en_US locale for date calcs ref #5994 --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 7b454d8d..8fa5a988 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -444,7 +444,7 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. - const std::string SHALLOW_DATE = removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + const std::string SHALLOW_DATE = removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); From a8ab1b1679e639ef23952f1a1d0834859d1c01b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Fri, 10 May 2024 23:51:53 +0100 Subject: [PATCH 0058/2393] nix: build improvements (#5952) * scripts: allow using existing variable values in generateVersion.sh * nix: populate versioning variables * nix: remove unused meson input * nix: remove unnecessary hyprland-protocols dependency * Nix: remove nixConfig from flake It's more annoying than helpful. * CI/Nix: fix PR build failure --------- Co-authored-by: Mihai Fufezan --- .github/workflows/nix-ci.yml | 1 + flake.nix | 8 -------- nix/default.nix | 21 ++++----------------- scripts/generateVersion.sh | 14 +++++++------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index 3b017576..a66307c4 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -4,6 +4,7 @@ on: [push, pull_request, workflow_dispatch] jobs: update-inputs: + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' uses: ./.github/workflows/nix-update-inputs.yml secrets: inherit diff --git a/flake.nix b/flake.nix index eff2b3cd..82e3e4bb 100644 --- a/flake.nix +++ b/flake.nix @@ -74,9 +74,6 @@ # hyprland-extras xdg-desktop-portal-hyprland - # dependencies - - hyprland-protocols ; }); @@ -97,9 +94,4 @@ nixosModules.default = import ./nix/module.nix inputs; homeManagerModules.default = import ./nix/hm-module.nix self; }; - - nixConfig = { - extra-substituters = ["https://hyprland.cachix.org"]; - extra-trusted-public-keys = ["hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="]; - }; } diff --git a/nix/default.nix b/nix/default.nix index 4ab9c19d..419b1429 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -5,7 +5,6 @@ pkgconf, makeWrapper, cmake, - meson, ninja, binutils, cairo, @@ -13,7 +12,6 @@ fribidi, git, hyprcursor, - hyprland-protocols, hyprlang, hyprwayland-scanner, jq, @@ -72,22 +70,12 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp - - # Generate version.h - cp src/version.h.in src/version.h - substituteInPlace src/version.h \ - --replace-warn "@HASH@" '${commit}' \ - --replace-warn "@BRANCH@" "" \ - --replace-warn "@MESSAGE@" "" \ - --replace-warn "@DATE@" "${date}" \ - --replace-warn "@TAG@" "" \ - --replace-warn "@DIRTY@" '${ - if commit == "" - then "dirty" - else "" - }' ''; + DATE = date; + HASH = commit; + DIRTY = if commit == "" then "dirty" else ""; + nativeBuildInputs = lib.concatLists [ [ hyprwayland-scanner @@ -118,7 +106,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov fribidi git hyprcursor.dev - hyprland-protocols hyprlang libGL libdrm diff --git a/scripts/generateVersion.sh b/scripts/generateVersion.sh index 6b1afb7b..fdcc4712 100755 --- a/scripts/generateVersion.sh +++ b/scripts/generateVersion.sh @@ -1,13 +1,13 @@ #!/bin/sh cp -fr ./src/version.h.in ./src/version.h -HASH=$(git rev-parse HEAD) -BRANCH=$(git branch --show-current) -MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g') -DATE=$(git show ${GIT_COMMIT_HASH} --no-patch --format=%cd --date=local) -DIRTY=$(git diff-index --quiet HEAD -- || echo dirty) -TAG=$(git describe --tags) -COMMITS=$(git rev-list --count HEAD) +HASH=${HASH-$(git rev-parse HEAD)} +BRANCH=${BRANCH-$(git branch --show-current)} +MESSAGE=${MESSAGE-$(git show | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')} +DATE=${DATE-$(git show --no-patch --format=%cd --date=local)} +DIRTY=${DIRTY-$(git diff-index --quiet HEAD -- || echo dirty)} +TAG=${TAG-$(git describe --tags)} +COMMITS=${COMMITS-$(git rev-list --count HEAD)} sed -i -e "s#@HASH@#${HASH}#" ./src/version.h sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h From ed3a888fc274e09a5097ebbe3d206e4bc85bbb87 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 23:56:49 +0100 Subject: [PATCH 0059/2393] hyprpm: fix style --- hyprpm/src/core/PluginManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 8fa5a988..affc7eea 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -444,7 +444,8 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. - const std::string SHALLOW_DATE = removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + const std::string SHALLOW_DATE = + removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); From 3529fbc6d4db298c4d50a39732e59ca38b463c9f Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Sat, 11 May 2024 18:35:20 +0900 Subject: [PATCH 0060/2393] compositor: fix getMonitorFromVector getting wrong monitor (#6010) --- src/macros.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.hpp b/src/macros.hpp index b57d9737..66dfe783 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -35,7 +35,7 @@ #define DYNLISTENER(name) CHyprWLListener hyprListener_##name #define DYNMULTILISTENER(name) wl_listener listen_##name -#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x <= (x2) && (vec).y >= (y1) && (vec).y <= (y2)) +#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) #define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < (delta)) From b6a7fb9e9125e56bf742f68e0ec46f52d5c34f4c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 11 May 2024 14:43:39 +0100 Subject: [PATCH 0061/2393] layersurface: fix invalid use of std::move fixes #6014 --- src/desktop/LayerSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8bff5850..50b0a430 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -261,7 +261,7 @@ void CLayerSurface::onCommit() { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { if (*it == self) { - PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(std::move(*it)); + PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(*it); PMONITOR->m_aLayerSurfaceLayers[layer].erase(it); break; } From 494b9415a1157279a1e1782ba635fc2ef6a18155 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 11 May 2024 18:31:50 +0100 Subject: [PATCH 0062/2393] layersurface: avoid restack on identical layers ref #6014 --- src/desktop/LayerSurface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 50b0a430..2312de72 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -261,6 +261,8 @@ void CLayerSurface::onCommit() { for (auto it = PMONITOR->m_aLayerSurfaceLayers[layer].begin(); it != PMONITOR->m_aLayerSurfaceLayers[layer].end(); it++) { if (*it == self) { + if (layerSurface->current.layer == layer) + break; PMONITOR->m_aLayerSurfaceLayers[layerSurface->current.layer].emplace_back(*it); PMONITOR->m_aLayerSurfaceLayers[layer].erase(it); break; From 8562d3847777317e98e689d443e4d203b568c630 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 11 May 2024 22:10:42 +0100 Subject: [PATCH 0063/2393] screencopy: don't spam sw cursor locks --- src/protocols/Screencopy.cpp | 31 ++++++++++++++++++++++++------- src/protocols/Screencopy.hpp | 4 ++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index a4d62506..7c25ed3f 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -1,5 +1,6 @@ #include "Screencopy.hpp" #include "../Compositor.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/PointerManager.hpp" #include @@ -35,6 +36,20 @@ CScreencopyProtocolManager::CScreencopyProtocolManager() { wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); Debug::log(LOG, "ScreencopyProtocolManager started successfully!"); + + m_pSoftwareCursorTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + // TODO: make it per-monitor + for (auto& m : g_pCompositor->m_vMonitors) { + g_pPointerManager->unlockSoftwareForMonitor(m); + } + m_bTimerArmed = false; + + Debug::log(LOG, "[screencopy] Releasing software cursor lock"); + }, + nullptr); + g_pEventLoopManager->addTimer(m_pSoftwareCursorTimer); } static void handleCaptureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output) { @@ -184,11 +199,6 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force if (!frame) return; - if (frame->lockedSWCursors) { - g_pPointerManager->unlockSoftwareForMonitor(frame->pMonitor->self.lock()); - g_pPointerManager->damageCursor(frame->pMonitor->self.lock()); - } - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); @@ -360,8 +370,15 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou g_pHyprRenderer->m_bDirectScanoutBlocked = true; if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) { PFRAME->lockedSWCursors = true; - g_pPointerManager->lockSoftwareForMonitor(PFRAME->pMonitor->self.lock()); - g_pPointerManager->damageCursor(PFRAME->pMonitor->self.lock()); + // TODO: make it per-monitor + if (!m_bTimerArmed) { + for (auto& m : g_pCompositor->m_vMonitors) { + g_pPointerManager->lockSoftwareForMonitor(m); + } + m_bTimerArmed = true; + Debug::log(LOG, "[screencopy] Locking sw cursors due to screensharing"); + } + m_pSoftwareCursorTimer->updateTimeout(std::chrono::seconds(1)); } if (!PFRAME->withDamage) diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 7b9a5770..1bdf6963 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -7,6 +7,7 @@ #include #include "../managers/HookSystemManager.hpp" #include "../helpers/Timer.hpp" +#include "../managers/eventLoop/EventLoopTimer.hpp" class CMonitor; @@ -84,6 +85,9 @@ class CScreencopyProtocolManager { std::list m_lFrames; std::list m_lClients; + SP m_pSoftwareCursorTimer; + bool m_bTimerArmed = false; + wl_listener m_liDisplayDestroy; std::vector m_vFramesAwaitingWrite; From 15072831cfd9efccebd1ad27b21c5604f224aa1b Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Sat, 11 May 2024 17:02:26 -0600 Subject: [PATCH 0064/2393] keybinds: fix release binds in submaps (#6025) --- src/managers/KeybindManager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 15f667f0..286372c4 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -386,8 +386,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { bool foundInPressedKeys = false; for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { if (it->keycode == KEYCODE) { - if (it->submapAtPress == m_szCurrentSelectedSubmap) - handleKeybinds(MODS, *it, false); + handleKeybinds(MODS, *it, false); foundInPressedKeys = true; suppressEvent = !it->sent; it = m_dPressedKeys.erase(it); @@ -570,7 +569,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (key.keycode != k.keycode) continue; } else if (k.catchAll) { - if (found) + if (found || key.submapAtPress != m_szCurrentSelectedSubmap) continue; } else { // oMg such performance hit!!11! From 33a7b7bb6b307d6e4a093f75ffdda0419cd7ffaf Mon Sep 17 00:00:00 2001 From: Brenno Lemos Date: Sat, 11 May 2024 20:03:32 -0300 Subject: [PATCH 0065/2393] core: fix on-empty workspace being called too often (#6026) --- src/Compositor.cpp | 4 ++-- src/Compositor.hpp | 2 +- src/desktop/Workspace.cpp | 12 +++++++----- src/desktop/Workspace.hpp | 6 ++++-- src/managers/KeybindManager.cpp | 4 ++-- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9a9ea30b..c532f958 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2492,7 +2492,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { } } -PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name) { +PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name, bool isEmtpy) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2503,7 +2503,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, co const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; - const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL)); + const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmtpy)); PWORKSPACE->m_fAlpha.setValueAndWarp(0); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 8812f8c8..c8bb8743 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -164,7 +164,7 @@ class CCompositor { void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); void forceReportSizesToWindowsOnWorkspace(const int&); - PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = ""); // will be deleted next frame if left empty and unfocused! + PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! void renameWorkspace(const int&, const std::string& name = ""); void setActiveMonitor(CMonitor*); bool isWorkspaceSpecial(const int&); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index b730c9ab..7a836b3b 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -2,17 +2,18 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" -PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special) { - PHLWORKSPACE workspace = makeShared(id, monitorID, name, special); +PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { + PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special) { +CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) { m_iMonitorID = monitorID; m_iID = id; m_szName = name; m_bIsSpecialWorkspace = special; + m_bWasCreatedEmtpy = isEmtpy; } void CWorkspace::init(PHLWORKSPACE self) { @@ -44,8 +45,9 @@ void CWorkspace::init(PHLWORKSPACE self) { const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); m_bPersistent = WORKSPACERULE.isPersistent; - if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) - g_pKeybindManager->spawn(*cmd); + if (self->m_bWasCreatedEmtpy) + if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) + g_pKeybindManager->spawn(*cmd); g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 3fae3dfc..17431215 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -15,9 +15,9 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false); + static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true); // use create() don't use this - CWorkspace(int id, int monitorID, std::string name, bool special = false); + CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); // Workspaces ID-based have IDs > 0 @@ -58,6 +58,8 @@ class CWorkspace { // last monitor (used on reconnect) std::string m_szLastMonitor = ""; + bool m_bWasCreatedEmtpy = true; + bool m_bPersistent = false; // Inert: destroyed and invalid. If this is true, release the ptr you have. diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 286372c4..146dd221 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1102,7 +1102,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); g_pCompositor->setActiveMonitor(pMonitor); } else { - pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName); + pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } @@ -1158,7 +1158,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { if (pWorkspace) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } else { - pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName); + pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } From 6be765b7a1f4677f67f31f6aa45389d40109d4c8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 9 May 2024 19:24:31 +0300 Subject: [PATCH 0066/2393] Nix: fix pkgconfig prefix --- nix/default.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nix/default.nix b/nix/default.nix index 419b1429..5da00d72 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -70,6 +70,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp + + # Remove extra @PREFIX@ to fix pkg-config paths + sed -i "s#@PREFIX@/##g" hyprland.pc.in ''; DATE = date; From cee639d9df68842e8ad321fba8ec99d794829621 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 9 May 2024 19:38:42 +0300 Subject: [PATCH 0067/2393] pkg-config: fix wlroots dir --- hyprland.pc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprland.pc.in b/hyprland.pc.in index 6484b95f..382fb1e6 100644 --- a/hyprland.pc.in +++ b/hyprland.pc.in @@ -4,4 +4,4 @@ Name: Hyprland URL: https://github.com/hyprwm/Hyprland Description: Hyprland header files Version: @HYPRLAND_VERSION@ -Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlroots-hyprland +Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlr From c8ae9a2e832251683cbb11edba79ab7c3a2443b2 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 11 May 2024 00:56:45 +0300 Subject: [PATCH 0068/2393] Meson: fix Cflags --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 40883073..9b278198 100644 --- a/meson.build +++ b/meson.build @@ -89,5 +89,5 @@ import('pkgconfig').generate( url: 'https://github.com/hyprwm/Hyprland', description: 'Hyprland header files', install_dir: pkg_install_dir, - subdirs: ['', 'hyprland/protocols', 'hyprland/wlroots'], + subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'], ) From 071f6977dff6a4c49c2b52ac7030c7cbf666c9a5 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 11 May 2024 01:59:06 +0300 Subject: [PATCH 0069/2393] wlroots: bump --- subprojects/wlroots-hyprland | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland index 5c1d51c5..a336b9b1 160000 --- a/subprojects/wlroots-hyprland +++ b/subprojects/wlroots-hyprland @@ -1 +1 @@ -Subproject commit 5c1d51c5a2793480f5b6c4341ad0797052aec2ea +Subproject commit a336b9b1fb415433e849de002df68c45034d0419 From ff93820bbb9313e004e23afb1257aa774a922be1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 11 May 2024 14:46:04 +0300 Subject: [PATCH 0070/2393] Makefile: fix wlr dir --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 53ac0fdf..fd9eab4d 100644 --- a/Makefile +++ b/Makefile @@ -46,17 +46,17 @@ pluginenv: installheaders: @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi + # remove previous headers from hyprpm's dir rm -fr ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland/protocols - mkdir -p ${PREFIX}/include/hyprland/wlroots-hyprland + mkdir -p ${PREFIX}/include/hyprland/wlr mkdir -p ${PREFIX}/share/pkgconfig find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland - cd subprojects/wlroots-hyprland/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../.. - cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlroots-hyprland && cd ../../../.. - cp ./protocols/*.h ${PREFIX}/include/hyprland/protocols - cp ./protocols/*.hpp ${PREFIX}/include/hyprland/protocols + cd subprojects/wlroots-hyprland/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../.. + cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. + cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi From 2ccd45a84475fab46c6fecd2fe226d3173104743 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 12 May 2024 02:53:50 +0300 Subject: [PATCH 0071/2393] hyprpm: don't shallow clone on non-main branches --- hyprpm/src/core/PluginManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index affc7eea..dc3bc548 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -442,15 +442,18 @@ bool CPluginManager::updateHeaders(bool force) { progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); + const bool bShallow = HLVER.branch == "main" || HLVER.branch == ""; + // let us give a bit of leg-room for shallowing // due to timezones, etc. const std::string SHALLOW_DATE = removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); - if (m_bVerbose) + if (m_bVerbose && bShallow) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); - std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + " --shallow-since='" + SHALLOW_DATE + "'"); + std::string ret = + execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); if (!std::filesystem::exists(WORKINGDIR)) { progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Clone failed. Retrying without shallow."); From fd35b35000fa11ce540d944966ff17c71c31fd27 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 12 May 2024 16:00:55 +0100 Subject: [PATCH 0072/2393] keybinds: fix pass reverts #5967 fixes #6022 --- src/managers/KeybindManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 146dd221..c5d7067d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1911,6 +1911,7 @@ void CKeybindManager::pass(std::string regexp) { const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; const auto SL = Vector2D(g_pCompositor->m_sSeat.seat->pointer_state.sx, g_pCompositor->m_sSeat.seat->pointer_state.sy); uint32_t keycodes[32] = {0}; + const auto LASTSRF = g_pCompositor->m_pLastFocus; // pass all mf shit if (!XWTOXW) { @@ -1961,7 +1962,7 @@ void CKeybindManager::pass(std::string regexp) { } if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers); + wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, LASTSRF, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers); else wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), SL.x, SL.y); } From 064bdb06f1f10676d18c333cc24caee2eb199408 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 13 May 2024 16:57:06 +0300 Subject: [PATCH 0073/2393] hyprctl: Add locked cmd to requests (#6042) Co-authored-by: Leftas --- src/debug/HyprCtl.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a89e0710..f8fdb03f 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1550,6 +1550,18 @@ std::string dispatchDismissNotify(eHyprCtlOutputFormat format, std::string reque return "ok"; } +std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) { + std::string lockedStr = g_pSessionLockManager->isSessionLocked() ? "true" : "false"; + if (format == eHyprCtlOutputFormat::FORMAT_JSON) + lockedStr = std::format(R"#( +{{ + "locked": {} +}} +)#", + lockedStr); + return lockedStr; +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1569,6 +1581,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"rollinglog", true, rollinglogRequest}); registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest}); registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); + registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); From 4c625ce6734be79bf0ddd8dda80a161994b19892 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 13 May 2024 13:58:35 +0000 Subject: [PATCH 0074/2393] [gha] Nix: update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 2c2d62f3..98dda5bd 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715287423, - "narHash": "sha256-B7AJIjOyWgVMKhu7DlOnWa0VprdhywUVHuB/j+EwSxM=", + "lastModified": 1715608589, + "narHash": "sha256-vimNaLjLcoNIvBhF37GaB6PRYEvKMamY3UnDE9M5MW8=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "e2fc1c0eb8b392110588f478cce644348ead7271", + "rev": "65c2636484e5cb00583b8a7446c3fb657f568883", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1715087517, - "narHash": "sha256-CLU5Tsg24Ke4+7sH8azHWXKd0CFd4mhLWfhYgUiDBpQ=", + "lastModified": 1715534503, + "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b211b392b8486ee79df6cdfb1157ad2133427a29", + "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", "type": "github" }, "original": { From 60be4298e13b02913f241dd79fe7517f185299d0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 13 May 2024 15:16:10 +0100 Subject: [PATCH 0075/2393] makefile: fix wlroots headers dir --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fd9eab4d..e7b9c1b6 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ installheaders: mkdir -p ${PREFIX}/share/pkgconfig find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland - cd subprojects/wlroots-hyprland/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../.. + cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig From 47874f09f4d14703fe0c483a46b345c7be601ace Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 13 May 2024 15:29:18 +0100 Subject: [PATCH 0076/2393] cmake: remove forceful ffi and wayland deps for asan fixes #6050 --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c334ab06..cfcaa686 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,8 +130,6 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Enabling ASan") target_link_libraries(Hyprland asan) - pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) - target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) target_compile_options(Hyprland PUBLIC -fsanitize=address) endif() From ba696521930059aa489ac6ffabe28553edaf2fa3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 13 May 2024 22:21:06 +0100 Subject: [PATCH 0077/2393] window: set sane default pseudo size --- src/desktop/Window.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index efccb41c..6bff095c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -261,7 +261,7 @@ class CWindow { // this is used for pseudotiling bool m_bIsPseudotiled = false; - Vector2D m_vPseudoSize = Vector2D(0, 0); + Vector2D m_vPseudoSize = Vector2D(1280, 720); bool m_bFirstMap = false; // for layouts bool m_bIsFloating = false; From 1584679004435d93d5fe2dd794d2aefaa0c9574a Mon Sep 17 00:00:00 2001 From: Daniil <118675096+dnvery@users.noreply.github.com> Date: Tue, 14 May 2024 12:33:20 +0000 Subject: [PATCH 0078/2393] xwayland: Remove delta for real position with xwayland zero scaling (#6057) --- src/events/Windows.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 4ccf8e41..7e0e3569 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -1144,9 +1144,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { - const Vector2D DELTA = PWINDOW->m_vRealSize.goal() - PWINDOW->m_vRealSize.goal() / PMONITOR->scale; PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); - PWINDOW->m_vRealPosition.setValueAndWarp(PWINDOW->m_vRealPosition.goal() + DELTA / 2.0); } } From d0a4a0e0d8ecc0a47c0bcfbf84c090cae8cee7af Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Wed, 15 May 2024 00:14:43 +0900 Subject: [PATCH 0079/2393] input: fix modifier and leds (#6062) --- src/devices/IKeyboard.cpp | 11 ++++++++++- src/devices/IKeyboard.hpp | 1 + src/managers/input/InputManager.cpp | 28 ++++++++++++++++++++++------ src/managers/input/InputManager.hpp | 1 + src/protocols/InputMethodV2.cpp | 3 ++- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 3bd42eac..7e4dd912 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -131,8 +131,17 @@ void IKeyboard::updateLEDs() { leds |= (1 << i); } + updateLEDs(leds); +} + +void IKeyboard::updateLEDs(uint32_t leds) { + auto keyboard = wlr(); + + if (!keyboard || keyboard->xkb_state == nullptr) + return; + if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) return; - wlr_keyboard_led_update(wlr(), leds); + wlr_keyboard_led_update(keyboard, leds); } diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index d90550da..ec58ff5b 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -42,6 +42,7 @@ class IKeyboard : public IHID { void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); std::string getActiveLayout(); void updateLEDs(); + void updateLEDs(uint32_t leds); bool active = false; bool enabled = true; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 1d09dbb9..958fb255 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1239,6 +1239,26 @@ void CInputManager::destroyTabletPad(SP pad) { removeFromHIDs(pad); } +void CInputManager::updateKeyboardsLeds(SP pKeyboard) { + if (!pKeyboard) + return; + + auto keyboard = pKeyboard->wlr(); + + if (!keyboard || keyboard->xkb_state == nullptr) + return; + + uint32_t leds = 0; + for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { + if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) + leds |= (1 << i); + } + + for (auto& k : m_vKeyboards) { + k->updateLEDs(leds); + } +} + void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { if (!pKeyboard->enabled) return; @@ -1271,9 +1291,7 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e.timeMs, e.keycode, e.state); } - for (auto& k : m_vKeyboards) { - k->updateLEDs(); - } + updateKeyboardsLeds(pKeyboard); } } @@ -1299,9 +1317,7 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS); } - for (auto& k : m_vKeyboards) { - k->updateLEDs(); - } + updateKeyboardsLeds(pKeyboard); if (PWLRKB->modifiers.group != pKeyboard->activeLayout) { pKeyboard->activeLayout = PWLRKB->modifiers.group; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 970d53c8..df36b975 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -114,6 +114,7 @@ class CInputManager { void updateDragIcon(); void updateCapabilities(); + void updateKeyboardsLeds(SP); void setClickMode(eClickBehaviorMode); eClickBehaviorMode getClickMode(); diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index d84f6772..9e5c863b 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -53,7 +53,8 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { close(keymapFD); - sendMods(0, 0, 0, 0); + const auto MODS = keyboard->modifiers; + sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay); } From 4cdddcfe466cb21db81af0ac39e51cc15f574da9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 14 May 2024 16:45:01 +0100 Subject: [PATCH 0080/2393] cursor: minor fixes for unhiding surfaces the surface equality check is done in CPointerManager, the one in renderer can be wrong fixes #5975 --- src/managers/PointerManager.cpp | 2 +- src/render/Renderer.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 663456f8..3ddd7c23 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -223,7 +223,7 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot }, nullptr, "CPointerManager"); - if (surf->wlr()->current.buffer) { + if (wlr_surface_has_buffer(surf->wlr())) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); wlr_surface_send_frame_done(surf->wlr(), &now); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2574a015..d9529b6f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2255,9 +2255,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; - if (surf == m_sLastCursorData.surf && hotspotX == m_sLastCursorData.hotspotX && hotspotY == m_sLastCursorData.hotspotY && !force) - return; - m_sLastCursorData.name = ""; m_sLastCursorData.surf = surf; m_sLastCursorData.hotspotX = hotspotX; From 121d3a72137d4780602cf245704615f63357ea22 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 18:27:57 +0100 Subject: [PATCH 0081/2393] wl_seat: move to hyprland impl --- CMakeLists.txt | 10 + src/Compositor.cpp | 75 ++--- src/Compositor.hpp | 4 - src/desktop/LayerSurface.cpp | 13 +- src/desktop/WLSurface.cpp | 2 - src/events/Devices.cpp | 6 - src/events/Events.hpp | 1 - src/events/Misc.cpp | 24 +- src/events/Windows.cpp | 3 +- src/helpers/WLClasses.hpp | 8 - src/includes.hpp | 1 - src/managers/KeybindManager.cpp | 64 ++-- src/managers/PointerManager.cpp | 5 +- src/managers/ProtocolManager.cpp | 5 + src/managers/SeatManager.cpp | 391 ++++++++++++++++++++++++ src/managers/SeatManager.hpp | 106 +++++++ src/managers/input/InputManager.cpp | 138 ++++----- src/managers/input/InputManager.hpp | 4 +- src/managers/input/Tablets.cpp | 5 +- src/managers/input/Touch.cpp | 14 +- src/protocols/FocusGrab.cpp | 245 +++++++-------- src/protocols/FocusGrab.hpp | 8 +- src/protocols/InputMethodV2.cpp | 12 +- src/protocols/PointerConstraints.cpp | 5 +- src/protocols/PointerGestures.cpp | 52 ++-- src/protocols/RelativePointer.cpp | 8 +- src/protocols/SessionLock.cpp | 3 +- src/protocols/Tablet.cpp | 20 +- src/protocols/core/Seat.cpp | 437 +++++++++++++++++++++++++++ src/protocols/core/Seat.hpp | 163 ++++++++++ src/render/Renderer.cpp | 4 +- 31 files changed, 1441 insertions(+), 395 deletions(-) create mode 100644 src/managers/SeatManager.cpp create mode 100644 src/managers/SeatManager.hpp create mode 100644 src/protocols/core/Seat.cpp create mode 100644 src/protocols/core/Seat.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cfcaa686..608ccc62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,7 @@ pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) message(STATUS "Found WaylandScanner at ${WaylandScanner}") pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") +pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake") @@ -239,6 +240,13 @@ function(protocolNew protoPath protoName external) target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) endif() endfunction() +function(protocolWayland) + execute_process( + COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + target_sources(Hyprland PRIVATE protocols/wayland.cpp) +endfunction() target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a @@ -285,6 +293,8 @@ protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) +protocolWayland() + # tools add_subdirectory(hyprctl) add_subdirectory(hyprpm) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c532f958..efc02a5f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -4,6 +4,7 @@ #include "managers/CursorManager.hpp" #include "managers/TokenManager.hpp" #include "managers/PointerManager.hpp" +#include "managers/SeatManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -222,16 +223,14 @@ void CCompositor::initServer() { m_sWLRCompositor = wlr_compositor_create(m_sWLDisplay, 6, m_sWLRRenderer); m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay); - m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay); + // m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay); - wlr_data_control_manager_v1_create(m_sWLDisplay); - wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); + // wlr_data_control_manager_v1_create(m_sWLDisplay); + // wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); wlr_viewporter_create(m_sWLDisplay); m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6); - m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0"); - 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"); @@ -256,12 +255,11 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat"); - addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); - addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat"); - addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat"); - addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); - addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat"); + // addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); + // addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat"); + // addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat"); + // addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); + // addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -275,7 +273,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newOutput); removeWLSignal(&Events::listen_newXDGToplevel); removeWLSignal(&Events::listen_newInput); - removeWLSignal(&Events::listen_requestMouse); removeWLSignal(&Events::listen_requestSetSel); removeWLSignal(&Events::listen_requestDrag); removeWLSignal(&Events::listen_startDrag); @@ -379,9 +376,8 @@ void CCompositor::cleanup() { g_pHookSystem.reset(); g_pWatchdog.reset(); g_pXWaylandManager.reset(); - - if (m_sSeat.seat) - wlr_seat_destroy(m_sSeat.seat); + g_pPointerManager.reset(); + g_pSeatManager.reset(); if (m_sWLRRenderer) wlr_renderer_destroy(m_sWLRRenderer); @@ -412,6 +408,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the ProtocolManager!"); g_pProtocolManager = std::make_unique(); + Debug::log(LOG, "Creating the SeatManager!"); + g_pSeatManager = std::make_unique(); + Debug::log(LOG, "Creating the KeybindManager!"); g_pKeybindManager = std::make_unique(); @@ -890,8 +889,8 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); - if (g_pCompositor->m_sSeat.exclusiveClient) { - Debug::log(LOG, "Disallowing setting focus to a window due to there being an active input inhibitor layer."); + if (g_pSessionLockManager->isSessionLocked()) { + Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock"); return; } @@ -919,7 +918,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { g_pXWaylandManager->activateWindow(PLASTWINDOW, false); } - wlr_seat_keyboard_notify_clear_focus(m_sSeat.seat); + g_pSeatManager->setKeyboardFocus(nullptr); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); @@ -939,7 +938,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { return; } - if (m_pLastWindow.lock() == pWindow && m_sSeat.seat->keyboard_state.focused_surface == pSurface) + if (m_pLastWindow.lock() == pWindow && g_pSeatManager->state.keyboardFocus == pSurface) return; if (pWindow->m_bPinned) @@ -1017,7 +1016,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { - if (m_sSeat.seat->keyboard_state.focused_surface == pSurface || (pWindowOwner && m_sSeat.seat->keyboard_state.focused_surface == pWindowOwner->m_pWLSurface.wlr())) + if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface.wlr())) return; // Don't focus when already focused on this. if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) @@ -1030,7 +1029,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { g_pXWaylandManager->activateSurface(m_pLastFocus, false); if (!pSurface) { - wlr_seat_keyboard_clear_focus(m_sSeat.seat); + g_pSeatManager->setKeyboardFocus(nullptr); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); EMIT_HOOK_EVENT("keyboardFocus", (wlr_surface*)nullptr); @@ -1038,17 +1037,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { return; } - if (const auto KEYBOARD = wlr_seat_get_keyboard(m_sSeat.seat); KEYBOARD) { - uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP] = {0}; // TODO: maybe send valid, non-keybind codes? - wlr_seat_keyboard_notify_enter(m_sSeat.seat, pSurface, keycodes, 0, &KEYBOARD->modifiers); - - wlr_seat_keyboard_focus_change_event event = { - .seat = m_sSeat.seat, - .old_surface = m_pLastFocus, - .new_surface = pSurface, - }; - wl_signal_emit_mutable(&m_sSeat.seat->keyboard_state.events.focus_change, &event); - } + if (g_pSeatManager->keyboard) + g_pSeatManager->setKeyboardFocus(pSurface); if (pWindowOwner) Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner); @@ -1245,27 +1235,6 @@ PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const int& id) { return nullptr; } -bool CCompositor::doesSeatAcceptInput(wlr_surface* surface) { - if (g_pSessionLockManager->isSessionLocked()) { - if (g_pSessionLockManager->isSurfaceSessionLock(surface)) - return true; - - if (surface && m_sSeat.exclusiveClient == wl_resource_get_client(surface->resource)) - return true; - - return false; - } - - if (m_sSeat.exclusiveClient) { - if (surface && m_sSeat.exclusiveClient == wl_resource_get_client(surface->resource)) - return true; - - return false; - } - - return true; -} - bool CCompositor::isWindowActive(PHLWINDOW pWindow) { if (m_pLastWindow.expired() && !m_pLastFocus) return false; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index c8bb8743..eedcea56 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -48,7 +48,6 @@ class CCompositor { wlr_allocator* m_sWLRAllocator; wlr_compositor* m_sWLRCompositor; wlr_subcompositor* m_sWLRSubCompositor; - wlr_data_device_manager* m_sWLRDataDevMgr; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; wlr_xdg_shell* m_sWLRXDGShell; @@ -87,8 +86,6 @@ class CCompositor { std::vector m_vWindowFocusHistory; // first element is the most recently focused. - SSeat m_sSeat; - bool m_bReadyToProcess = false; bool m_bSessionActive = true; bool m_bDPMSStateON = true; @@ -132,7 +129,6 @@ class CCompositor { PHLWINDOW getFirstWindowOnWorkspace(const int&); PHLWINDOW getTopLeftWindowOnWorkspace(const int&); PHLWINDOW getFullscreenWindowOnWorkspace(const int&); - bool doesSeatAcceptInput(wlr_surface*); bool isWindowActive(PHLWINDOW); void changeWindowZOrder(PHLWINDOW, bool); void cleanupFadingOut(const int& monid); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 2312de72..cb10079c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../events/Events.hpp" #include "../protocols/LayerShell.hpp" +#include "../managers/SeatManager.hpp" PHLLS CLayerSurface::create(SP resource) { PHLLS pLS = SP(new CLayerSurface(resource)); @@ -132,15 +133,14 @@ void CLayerSurface::onMap() { const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && // don't focus if constrained - (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()); + (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); if (GRABSFOCUS) { g_pInputManager->releaseAllMouseButtons(); g_pCompositor->focusSurface(surface.wlr()); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, surface.wlr(), LOCAL.x, LOCAL.y); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); + g_pSeatManager->setPointerFocus(surface.wlr(), LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; } @@ -304,15 +304,14 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained + if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained && !keyboardExclusive && mapped) { g_pCompositor->focusSurface(layerSurface->surface); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, layerSurface->surface, LOCAL.x, LOCAL.y); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, 0, LOCAL.x, LOCAL.y); + g_pSeatManager->setPointerFocus(layerSurface->surface, LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.interactivity && (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { + } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { g_pInputManager->refocus(); } diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index c09d8fda..78b50d45 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -120,8 +120,6 @@ void CWLSurface::destroy() { if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface) g_pCompositor->m_pLastFocus = nullptr; - if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface) - g_pInputManager->m_pLastMouseSurface = nullptr; if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this) g_pHyprRenderer->m_sLastCursorData.surf.reset(); diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp index 16a64559..fedc844e 100644 --- a/src/events/Devices.cpp +++ b/src/events/Devices.cpp @@ -15,12 +15,6 @@ // // // ---------------------------------------------------- // -void Events::listener_requestMouse(wl_listener* listener, void* data) { - const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data; - - g_pInputManager->processMouseRequest(EVENT); -} - void Events::listener_newInput(wl_listener* listener, void* data) { const auto DEVICE = (wlr_input_device*)data; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 69da2d09..2e627d39 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -46,7 +46,6 @@ namespace Events { LISTENER(newVirtPtr); // Various - LISTENER(requestMouse); LISTENER(requestSetSel); LISTENER(requestSetPrimarySel); diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index a67a6753..703dba6a 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -26,13 +26,13 @@ void Events::listener_leaseRequest(wl_listener* listener, void* data) { } void Events::listener_requestSetPrimarySel(wl_listener* listener, void* data) { - const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data; - wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); + // const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data; + // wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); } void Events::listener_requestSetSel(wl_listener* listener, void* data) { - const auto EVENT = (wlr_seat_request_set_selection_event*)data; - wlr_seat_set_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); + // const auto EVENT = (wlr_seat_request_set_selection_event*)data; + // wlr_seat_set_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); } void Events::listener_readyXWayland(wl_listener* listener, void* data) { @@ -58,7 +58,7 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) { free(reply); } - wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat); + //wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat); g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland); @@ -80,15 +80,15 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) { } void Events::listener_requestDrag(wl_listener* listener, void* data) { - const auto E = (wlr_seat_request_start_drag_event*)data; + // const auto E = (wlr_seat_request_start_drag_event*)data; - if (!wlr_seat_validate_pointer_grab_serial(g_pCompositor->m_sSeat.seat, E->origin, E->serial)) { - Debug::log(LOG, "Ignoring drag and drop request: serial mismatch."); - wlr_data_source_destroy(E->drag->source); - return; - } + // if (!wlr_seat_validate_pointer_grab_serial(g_pCompositor->m_sSeat.seat, E->origin, E->serial)) { + // Debug::log(LOG, "Ignoring drag and drop request: serial mismatch."); + // wlr_data_source_destroy(E->drag->source); + // return; + // } - wlr_seat_start_pointer_drag(g_pCompositor->m_sSeat.seat, E->drag, E->serial); + // wlr_seat_start_pointer_drag(g_pCompositor->m_sSeat.seat, E->drag, E->serial); } void Events::listener_startDrag(wl_listener* listener, void* data) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 7e0e3569..b85ed6e1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -4,6 +4,7 @@ #include "../helpers/WLClasses.hpp" #include "../managers/input/InputManager.hpp" #include "../managers/TokenManager.hpp" +#include "../managers/SeatManager.hpp" #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/LayerShell.hpp" @@ -668,7 +669,7 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform); - if (g_pCompositor->m_sSeat.mouse.expired() || !g_pInputManager->isConstrained()) + if (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) g_pInputManager->sendMotionEventsToFocused(); // fix some xwayland apps that don't behave nicely diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index bc07f6ba..7b24de7d 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -58,14 +58,6 @@ struct SExtensionFindingData { wlr_surface** found; }; -struct SSeat { - wlr_seat* seat = nullptr; - wl_client* exclusiveClient = nullptr; - - WP mouse; - WP keyboard; -}; - struct SDrag { wlr_drag* drag = nullptr; diff --git a/src/includes.hpp b/src/includes.hpp index 844a9173..c75796b9 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -51,7 +51,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c5d7067d..ead83fa8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -6,6 +6,7 @@ #include "TokenManager.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../devices/IKeyboard.hpp" +#include "../managers/SeatManager.hpp" #include #include @@ -522,7 +523,7 @@ void CKeybindManager::onSwitchOffEvent(const std::string& switchName) { int repeatKeyHandler(void* data) { SKeybind** ppActiveKeybind = (SKeybind**)data; - if (!*ppActiveKeybind || g_pCompositor->m_sSeat.keyboard.expired()) + if (!*ppActiveKeybind || g_pSeatManager->keyboard.expired()) return 0; const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find((*ppActiveKeybind)->handler); @@ -530,16 +531,13 @@ int repeatKeyHandler(void* data) { Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); DISPATCHER->second((*ppActiveKeybind)->arg); - wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pCompositor->m_sSeat.keyboard->repeatRate); + wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->wlr()->repeat_info.rate); return 0; } bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { - bool found = false; - - if (g_pCompositor->m_sSeat.exclusiveClient) - Debug::log(LOG, "Keybind handling only locked (inhibitor)"); + bool found = false; static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); @@ -558,8 +556,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (!k.locked && g_pSessionLockManager->isSessionLocked()) continue; - if (!IGNORECONDITIONS && - ((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) + if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) continue; if (!key.keyName.empty()) { @@ -653,7 +650,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi m_pActiveKeybind = &k; m_pActiveKeybindEventSource = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, repeatKeyHandler, &m_pActiveKeybind); - const auto PACTIVEKEEB = g_pCompositor->m_sSeat.keyboard.lock(); + const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); wl_event_source_timer_update(m_pActiveKeybindEventSource, PACTIVEKEEB->repeatDelay); } @@ -1901,47 +1898,42 @@ void CKeybindManager::pass(std::string regexp) { return; } - const auto KEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); - - if (!KEYBOARD) { + if (!g_pSeatManager->keyboard) { Debug::log(ERR, "No kb in pass?"); return; } - const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; - const auto SL = Vector2D(g_pCompositor->m_sSeat.seat->pointer_state.sx, g_pCompositor->m_sSeat.seat->pointer_state.sy); - uint32_t keycodes[32] = {0}; - const auto LASTSRF = g_pCompositor->m_pLastFocus; + const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; + const auto LASTSRF = g_pCompositor->m_pLastFocus; // pass all mf shit if (!XWTOXW) { if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), keycodes, 0, &KEYBOARD->modifiers); + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); else - wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), 1, 1); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); } - wlr_keyboard_modifiers kbmods = {g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0}; - wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &kbmods); + g_pSeatManager->sendKeyboardMods(g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0); if (g_pKeybindManager->m_iPassPressed == 1) { if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_PRESSED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); else - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED); } else if (g_pKeybindManager->m_iPassPressed == 0) if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); else - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED); else { // dynamic call of the dispatcher if (g_pKeybindManager->m_uLastCode != 0) { - wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_PRESSED); - wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WLR_BUTTON_RELEASED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastCode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); } else { - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED); - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_PRESSED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, g_pKeybindManager->m_uLastMouseCode, WL_POINTER_BUTTON_STATE_RELEASED); } } @@ -1949,22 +1941,24 @@ void CKeybindManager::pass(std::string regexp) { return; // Massive hack: - // this will make wlroots NOT send the leave event to XWayland apps, provided we are not on an XWayland window already. + // this will make g_pSeatManager NOT send the leave event to XWayland apps, provided we are not on an XWayland window already. // please kill me if (PWINDOW->m_bIsX11) { if (g_pKeybindManager->m_uLastCode != 0) { - g_pCompositor->m_sSeat.seat->keyboard_state.focused_client = nullptr; - g_pCompositor->m_sSeat.seat->keyboard_state.focused_surface = nullptr; + g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocusResource.reset(); } else { - g_pCompositor->m_sSeat.seat->pointer_state.focused_client = nullptr; - g_pCompositor->m_sSeat.seat->pointer_state.focused_surface = nullptr; + g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocusResource.reset(); } } + const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + if (g_pKeybindManager->m_uLastCode != 0) - wlr_seat_keyboard_enter(g_pCompositor->m_sSeat.seat, LASTSRF, KEYBOARD->keycodes, KEYBOARD->num_keycodes, &KEYBOARD->modifiers); + g_pSeatManager->setKeyboardFocus(LASTSRF); else - wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, PWINDOW->m_pWLSurface.wlr(), SL.x, SL.y); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL); } void CKeybindManager::layoutmsg(std::string msg) { diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3ddd7c23..60d11e7f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" +#include "SeatManager.hpp" #include #include #include @@ -774,7 +775,7 @@ void CPointerManager::attachPointer(SP pointer) { }); listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { - wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); + g_pSeatManager->sendPointerFrame(); }); listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) { @@ -865,7 +866,7 @@ void CPointerManager::attachTouch(SP touch) { }); listener->frame = touch->touchEvents.frame.registerListener([this] (std::any e) { - wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat); + g_pSeatManager->sendTouchFrame(); }); // clang-format on diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 2904ed53..f853e16f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -28,9 +28,14 @@ #include "../protocols/Tablet.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include "../protocols/core/Seat.hpp" CProtocolManager::CProtocolManager() { + // Core + PROTO::seat = std::make_unique(&wl_seat_interface, 9, "WLSeat"); + + // Extensions 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"); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp new file mode 100644 index 00000000..f9d394b5 --- /dev/null +++ b/src/managers/SeatManager.cpp @@ -0,0 +1,391 @@ +#include "SeatManager.hpp" +#include "../protocols/core/Seat.hpp" +#include "../Compositor.hpp" +#include "../devices/IKeyboard.hpp" +#include + +CSeatManager::CSeatManager() { + listeners.newSeatResource = PROTO::seat->events.newSeatResource.registerListener([this](std::any res) { onNewSeatResource(std::any_cast>(res)); }); +} + +CSeatManager::SSeatResourceContainer::SSeatResourceContainer(SP res) { + resource = res; + listeners.destroy = res->events.destroy.registerListener( + [this](std::any data) { std::erase_if(g_pSeatManager->seatResources, [this](const auto& e) { return e->resource.expired() || e->resource == resource; }); }); +} + +void CSeatManager::onNewSeatResource(SP resource) { + seatResources.emplace_back(makeShared(resource)); +} + +SP CSeatManager::containerForResource(SP seatResource) { + for (auto& c : seatResources) { + if (c->resource == seatResource) + return c; + } + + return nullptr; +} + +uint32_t CSeatManager::nextSerial(SP seatResource) { + if (!seatResource) + return 0; + + auto container = containerForResource(seatResource); + + ASSERT(container); + + auto serial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); + + container->serials.emplace_back(serial); + + if (container->serials.size() > MAX_SERIAL_STORE_LEN) + container->serials.erase(container->serials.begin()); + + return serial; +} + +bool CSeatManager::serialValid(SP seatResource, uint32_t serial) { + if (!seatResource) + return false; + + auto container = containerForResource(seatResource); + + ASSERT(container); + + for (auto it = container->serials.begin(); it != container->serials.end(); ++it) { + if (*it == serial) { + container->serials.erase(it); + return true; + } + } + + return false; +} + +void CSeatManager::updateCapabilities(uint32_t capabilities) { + PROTO::seat->updateCapabilities(capabilities); +} + +void CSeatManager::setMouse(SP MAUZ) { + if (mouse == MAUZ) + return; + + mouse = MAUZ; +} + +void CSeatManager::setKeyboard(SP KEEB) { + if (keyboard == KEEB) + return; + + if (keyboard) + keyboard->active = false; + keyboard = KEEB; + + if (KEEB) { + KEEB->active = true; + PROTO::seat->updateRepeatInfo(KEEB->wlr()->repeat_info.rate, KEEB->wlr()->repeat_info.delay); + } + PROTO::seat->updateKeymap(); +} + +void CSeatManager::setKeyboardFocus(wlr_surface* surf) { + if (state.keyboardFocus == surf) + return; + + if (!keyboard || !keyboard->wlr()) { + Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set"); + return; + } + + hyprListener_keyboardSurfaceDestroy.removeCallback(); + + if (state.keyboardFocusResource) { + for (auto& k : state.keyboardFocusResource->keyboards) { + if (!k) + continue; + + k->sendLeave(); + } + } + + state.keyboardFocusResource.reset(); + state.keyboardFocus = surf; + + if (!surf) { + events.keyboardFocusChange.emit(); + return; + } + + auto client = wl_resource_get_client(surf->resource); + for (auto& r : seatResources) { + if (r->resource->client() == client) { + state.keyboardFocusResource = r->resource; + for (auto& k : state.keyboardFocusResource->keyboards) { + if (!k) + continue; + + k->sendEnter(surf); + k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); + } + + break; + } + } + + hyprListener_keyboardSurfaceDestroy.initCallback( + &surf->events.destroy, [this](void* owner, void* data) { setKeyboardFocus(nullptr); }, nullptr, "CSeatManager"); + + events.keyboardFocusChange.emit(); +} + +void CSeatManager::sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state_) { + if (!state.keyboardFocusResource) + return; + + for (auto& k : state.keyboardFocusResource->keyboards) { + if (!k) + continue; + + k->sendKey(timeMs, key, state_); + } +} + +void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!state.keyboardFocusResource) + return; + + for (auto& k : state.keyboardFocusResource->keyboards) { + if (!k) + continue; + + k->sendMods(depressed, latched, locked, group); + } +} + +void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { + if (state.pointerFocus == surf) + return; + + if (!mouse || !mouse->wlr()) { + Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); + return; + } + + hyprListener_pointerSurfaceDestroy.removeCallback(); + + if (state.pointerFocusResource) { + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendLeave(); + } + } + + state.pointerFocusResource.reset(); + state.pointerFocus = surf; + + if (!surf) { + events.pointerFocusChange.emit(); + return; + } + + auto client = wl_resource_get_client(surf->resource); + for (auto& r : seatResources) { + if (r->resource->client() == client) { + state.pointerFocusResource = r->resource; + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendEnter(surf, local); + } + + break; + } + } + + hyprListener_pointerSurfaceDestroy.initCallback( + &surf->events.destroy, [this](void* owner, void* data) { setPointerFocus(nullptr, {}); }, nullptr, "CSeatManager"); + + events.pointerFocusChange.emit(); +} + +void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { + if (!state.pointerFocusResource) + return; + + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendMotion(timeMs, local); + } +} + +void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state_) { + if (!state.pointerFocusResource) + return; + + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendButton(timeMs, key, state_); + } +} + +void CSeatManager::sendPointerFrame() { + if (!state.pointerFocusResource) + return; + + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendFrame(); + } +} + +void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, + wl_pointer_axis_relative_direction relative) { + if (!state.pointerFocusResource) + return; + + for (auto& p : state.pointerFocusResource->pointers) { + if (!p) + continue; + + p->sendAxis(timeMs, axis, value); + p->sendAxisSource(source); + p->sendAxisRelativeDirection(axis, relative); + } +} + +void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local) { + if (state.touchFocus == surf) + return; + + hyprListener_touchSurfaceDestroy.removeCallback(); + + if (state.touchFocusResource) { + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendUp(timeMs, id); + } + } + + state.touchFocusResource.reset(); + state.touchFocus = surf; + + if (!surf) { + events.touchFocusChange.emit(); + return; + } + + auto client = wl_resource_get_client(surf->resource); + for (auto& r : seatResources) { + if (r->resource->client() == client) { + state.touchFocusResource = r->resource; + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendDown(surf, timeMs, id, local); + } + + break; + } + } + + hyprListener_touchSurfaceDestroy.initCallback( + &surf->events.destroy, [this, timeMs, id](void* owner, void* data) { sendTouchUp(timeMs + 10, id); }, nullptr, "CSeatManager"); + + events.touchFocusChange.emit(); +} + +void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) { + sendTouchDown(nullptr, timeMs, id, {}); +} + +void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { + if (!state.touchFocusResource) + return; + + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendMotion(timeMs, id, local); + } +} + +void CSeatManager::sendTouchFrame() { + if (!state.touchFocusResource) + return; + + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendFrame(); + } +} + +void CSeatManager::sendTouchCancel() { + if (!state.touchFocusResource) + return; + + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendCancel(); + } +} + +void CSeatManager::sendTouchShape(int32_t id, const Vector2D& shape) { + if (!state.touchFocusResource) + return; + + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendShape(id, shape); + } +} + +void CSeatManager::sendTouchOrientation(int32_t id, double angle) { + if (!state.touchFocusResource) + return; + + for (auto& t : state.touchFocusResource->touches) { + if (!t) + continue; + + t->sendOrientation(id, angle); + } +} + +void CSeatManager::onSetCursor(SP seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) { + if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) { + Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus"); + return; + } + + // TODO: fix this. Probably should be done in the CWlPointer as the serial could be lost by us. + // if (!serialValid(seatResource, serial)) { + // Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the serial is invalid"); + // return; + // } + + events.setCursor.emit(SSetCursorEvent{surf, hotspot}); +} + +SP CSeatManager::seatResourceForClient(wl_client* client) { + return PROTO::seat->seatResourceForClient(client); +} diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp new file mode 100644 index 00000000..ef114024 --- /dev/null +++ b/src/managers/SeatManager.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include +#include "../helpers/WLListener.hpp" +#include "../macros.hpp" +#include "../helpers/signal/Signal.hpp" +#include "../helpers/Vector2D.hpp" +#include + +constexpr size_t MAX_SERIAL_STORE_LEN = 100; + +struct wlr_surface; +class CWLSeatResource; +class IPointer; +class IKeyboard; + +class CSeatManager { + public: + CSeatManager(); + + void updateCapabilities(uint32_t capabilities); // in IHID caps + + void setMouse(SP mouse); + void setKeyboard(SP keeb); + + void setKeyboardFocus(wlr_surface* surf); + void sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); + void sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + + void setPointerFocus(wlr_surface* surf, const Vector2D& local); + void sendPointerMotion(uint32_t timeMs, const Vector2D& local); + void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state); + void sendPointerFrame(); + void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative); + + void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendTouchUp(uint32_t timeMs, int32_t id); + void sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local); + void sendTouchFrame(); + void sendTouchCancel(); + void sendTouchShape(int32_t id, const Vector2D& shape); + void sendTouchOrientation(int32_t id, double angle); + + uint32_t nextSerial(SP seatResource); + // pops the serial if it was valid, meaning it is consumed. + bool serialValid(SP seatResource, uint32_t serial); + + void onSetCursor(SP seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot); + + SP seatResourceForClient(wl_client* client); + + struct { + wlr_surface* keyboardFocus = nullptr; + WP keyboardFocusResource; + + wlr_surface* pointerFocus = nullptr; + WP pointerFocusResource; + + wlr_surface* touchFocus = nullptr; + WP touchFocusResource; + } state; + + struct SSetCursorEvent { + wlr_surface* surf = nullptr; + Vector2D hotspot; + }; + + struct { + CSignal keyboardFocusChange; + CSignal pointerFocusChange; + CSignal touchFocusChange; + CSignal setCursor; // SSetCursorEvent + } events; + + // do not write to directly, use set... + WP mouse; + WP keyboard; + + private: + struct SSeatResourceContainer { + SSeatResourceContainer(SP); + + WP resource; + std::vector serials; // old -> new + + struct { + CHyprSignalListener destroy; + } listeners; + }; + + std::vector> seatResources; + void onNewSeatResource(SP resource); + SP containerForResource(SP seatResource); + + struct { + CHyprSignalListener newSeatResource; + } listeners; + + DYNLISTENER(keyboardSurfaceDestroy); + DYNLISTENER(pointerSurfaceDestroy); + DYNLISTENER(touchSurfaceDestroy); + + friend struct SSeatResourceContainer; +}; + +inline UP g_pSeatManager; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 958fb255..62d9e687 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -14,6 +14,7 @@ #include "../../protocols/VirtualKeyboard.hpp" #include "../../protocols/VirtualPointer.hpp" #include "../../protocols/LayerShell.hpp" +#include "../../protocols/core/Seat.hpp" #include "../../devices/Mouse.hpp" #include "../../devices/VirtualPointer.hpp" @@ -22,6 +23,7 @@ #include "../../devices/TouchDevice.hpp" #include "../../managers/PointerManager.hpp" +#include "../../managers/SeatManager.hpp" CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { @@ -30,10 +32,10 @@ CInputManager::CInputManager() { auto event = std::any_cast(data); - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - if (wl_resource_get_client(event.pMgr->resource()) != g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client) + if (wl_resource_get_client(event.pMgr->resource()) != g_pSeatManager->state.pointerFocusResource->client()) return; Debug::log(LOG, "cursorImage request: shape {} -> {}", (uint32_t)event.shape, event.shapeName); @@ -52,6 +54,7 @@ CInputManager::CInputManager() { PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { this->newVirtualKeyboard(std::any_cast>(data)); }); m_sListeners.newVirtualMouse = PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast>(data)); }); + m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); }); } CInputManager::~CInputManager() { @@ -119,8 +122,7 @@ void CInputManager::sendMotionEventsToFocused() { m_bEmptyFocusCursorSet = false; - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, g_pCompositor->m_pLastFocus, LOCAL.x, LOCAL.y); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, now.tv_sec * 1000 + now.tv_nsec / 10000000, LOCAL.x, LOCAL.y); + g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus, LOCAL); } void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { @@ -190,7 +192,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } // constraints - if (!g_pCompositor->m_sSeat.mouse.expired() && isConstrained()) { + if (!g_pSeatManager->mouse.expired() && isConstrained()) { const auto SURF = CWLSurface::surfaceFromWlr(g_pCompositor->m_pLastFocus); const auto CONSTRAINT = SURF->constraint(); @@ -205,7 +207,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (SURF->getWindow() ? SURF->getWindow()->m_fX11SurfaceScaledBy : 1.0); g_pCompositor->warpCursorTo(CLOSEST, true); - wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y); + g_pSeatManager->sendPointerMotion(time, CLOSESTLOCAL); PROTO::relativePointer->sendRelativeMotion((uint64_t)time * 1000, {}, {}); } @@ -218,8 +220,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // update stuff updateDragIcon(); - if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && m_pLastMouseSurface) { - foundSurface = m_pLastMouseSurface; + if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus) { + foundSurface = g_pSeatManager->state.pointerFocus; pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); if (pFoundLayerSurface) { surfacePos = pFoundLayerSurface->position; @@ -232,7 +234,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_bFocusHeldByButtons = true; m_bRefocusHeldByButtons = refocus; } else if (!g_pCompositor->m_pLastWindow.expired()) { - foundSurface = m_pLastMouseSurface; + foundSurface = g_pSeatManager->state.pointerFocus; pFoundWindow = g_pCompositor->m_pLastWindow.lock(); surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface); @@ -371,8 +373,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_bEmptyFocusCursorSet = true; } - wlr_seat_pointer_clear_focus(g_pCompositor->m_sSeat.seat); - m_pLastMouseSurface = nullptr; + g_pSeatManager->setPointerFocus(nullptr, {}); if (refocus || g_pCompositor->m_pLastWindow.expired()) // if we are forcing a refocus, and we don't find a surface, clear the kb focus too! g_pCompositor->focusWindow(nullptr); @@ -412,8 +413,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (currentlyDraggedWindow.lock() && pFoundWindow != currentlyDraggedWindow) { - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); return; } @@ -441,20 +441,15 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // enter if change floating style if (FOLLOWMOUSE != 3 && allowKeyboardRefocus) g_pCompositor->focusWindow(pFoundWindow, foundSurface); - m_pLastMouseSurface = foundSurface; - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); - } else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) { - m_pLastMouseSurface = foundSurface; - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); - } + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); + } else if (FOLLOWMOUSE == 2 || FOLLOWMOUSE == 3) + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); - if (pFoundWindow == g_pCompositor->m_pLastWindow) { - m_pLastMouseSurface = foundSurface; - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); - } + if (pFoundWindow == g_pCompositor->m_pLastWindow) + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow) - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); m_bLastFocusOnLS = false; return; // don't enter any new surfaces @@ -489,9 +484,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_bLastFocusOnLS = true; } - m_pLastMouseSurface = foundSurface; - wlr_seat_pointer_notify_enter(g_pCompositor->m_sSeat.seat, foundSurface, surfaceLocal.x, surfaceLocal.y); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y); + g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); + g_pSeatManager->sendPointerMotion(time, surfaceLocal); } void CInputManager::onMouseButton(IPointer::SButtonEvent e) { @@ -526,34 +520,33 @@ void CInputManager::onMouseButton(IPointer::SButtonEvent e) { } } -void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e) { +void CInputManager::processMouseRequest(std::any E) { if (!cursorImageUnlocked()) return; - Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e->surface); + auto e = std::any_cast(E); - if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) { + Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf); - if (e->surface != m_sCursorSurfaceInfo.wlSurface.wlr()) { - m_sCursorSurfaceInfo.wlSurface.unassign(); + if (e.surf != m_sCursorSurfaceInfo.wlSurface.wlr()) { + m_sCursorSurfaceInfo.wlSurface.unassign(); - if (e->surface) - m_sCursorSurfaceInfo.wlSurface.assign(e->surface); - } - - if (e->surface) { - m_sCursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y}; - m_sCursorSurfaceInfo.hidden = false; - } else { - m_sCursorSurfaceInfo.vHotspot = {}; - m_sCursorSurfaceInfo.hidden = true; - } - - m_sCursorSurfaceInfo.name = ""; - - m_sCursorSurfaceInfo.inUse = true; - g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e->hotspot_x, e->hotspot_y); + if (e.surf) + m_sCursorSurfaceInfo.wlSurface.assign(e.surf); } + + if (e.surf) { + m_sCursorSurfaceInfo.vHotspot = e.hotspot; + m_sCursorSurfaceInfo.hidden = false; + } else { + m_sCursorSurfaceInfo.vHotspot = {}; + m_sCursorSurfaceInfo.hidden = true; + } + + m_sCursorSurfaceInfo.name = ""; + + m_sCursorSurfaceInfo.inUse = true; + g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y); } void CInputManager::restoreCursorIconToApp() { @@ -659,7 +652,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { if (*PFOLLOWMOUSE == 3) // don't refocus on full loose break; - if ((g_pCompositor->m_sSeat.mouse.expired() || !isConstrained()) /* No constraints */ + if ((g_pSeatManager->mouse.expired() || !isConstrained()) /* No constraints */ && (w && g_pCompositor->m_pLastWindow.lock() != w) /* window should change */) { // a bit hacky // if we only pressed one button, allow us to refocus. m_lCurrentlyHeldButtons.size() > 0 will stick the focus @@ -681,8 +674,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { } // notify app if we didnt handle it - if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus)) - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e.timeMs, e.button, e.state); + g_pSeatManager->sendPointerButton(e.timeMs, e.button, e.state); if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON) g_pCompositor->setActiveMonitor(PMON); @@ -747,14 +739,13 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { if (*POFFWINDOWAXIS == 3) g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true); - wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, TEMPCURX - BOX.x, TEMPCURY - BOX.y); - wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat); + g_pSeatManager->sendPointerMotion(e.timeMs, Vector2D{TEMPCURX, TEMPCURY} - BOX.pos()); + g_pSeatManager->sendPointerFrame(); } } } - wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source, - WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { @@ -826,13 +817,9 @@ void CInputManager::setupKeyboard(SP keeb) { disableAllKeyboards(false); - g_pCompositor->m_sSeat.keyboard = keeb; - - keeb->active = true; - applyConfigToKeyboard(keeb); - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, keeb->wlr()); + g_pSeatManager->setKeyboard(keeb); } void CInputManager::setKeyboardLayout() { @@ -1015,7 +1002,7 @@ void CInputManager::setupMouse(SP mauz) { }, mauz.get()); - g_pCompositor->m_sSeat.mouse = mauz; + g_pSeatManager->setMouse(mauz); m_tmrLastCursorMovement.reset(); } @@ -1185,12 +1172,11 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { - g_pCompositor->m_sSeat.keyboard = m_vKeyboards.back(); - g_pCompositor->m_sSeat.keyboard->active = true; - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, g_pCompositor->m_sSeat.keyboard->wlr()); + const auto PNEWKEYBOARD = m_vKeyboards.back(); + g_pSeatManager->setKeyboard(PNEWKEYBOARD); + PNEWKEYBOARD->active = true; } else { - g_pCompositor->m_sSeat.keyboard.reset(); - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, nullptr); + g_pSeatManager->setKeyboard(nullptr); } removeFromHIDs(pKeyboard); @@ -1199,9 +1185,9 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { void CInputManager::destroyPointer(SP mouse) { std::erase_if(m_vPointers, [mouse](const auto& other) { return other == mouse; }); - g_pCompositor->m_sSeat.mouse = m_vPointers.size() > 0 ? m_vPointers.front() : nullptr; + g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr); - if (!g_pCompositor->m_sSeat.mouse.expired()) + if (!g_pSeatManager->mouse.expired()) unconstrainMouse(); removeFromHIDs(mouse); @@ -1287,8 +1273,8 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { IME->setKeyboard(pKeyboard->wlr()); IME->sendKey(e.timeMs, e.keycode, e.state); } else { - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, pKeyboard->wlr()); - wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, e.timeMs, e.keycode, e.state); + g_pSeatManager->setKeyboard(pKeyboard); + g_pSeatManager->sendKeyboardKey(e.timeMs, e.keycode, e.state); } updateKeyboardsLeds(pKeyboard); @@ -1313,8 +1299,8 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { IME->setKeyboard(PWLRKB); IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); } else { - wlr_seat_set_keyboard(g_pCompositor->m_sSeat.seat, PWLRKB); - wlr_seat_keyboard_notify_modifiers(g_pCompositor->m_sSeat.seat, &MODS); + g_pSeatManager->setKeyboard(pKeyboard); + g_pSeatManager->sendKeyboardMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); } updateKeyboardsLeds(pKeyboard); @@ -1361,7 +1347,7 @@ void CInputManager::updateDragIcon() { } void CInputManager::unconstrainMouse() { - if (g_pCompositor->m_sSeat.mouse.expired()) + if (g_pSeatManager->mouse.expired()) return; for (auto& c : m_vConstraints) { @@ -1410,7 +1396,7 @@ void CInputManager::updateCapabilities() { caps |= WL_SEAT_CAPABILITY_TOUCH; } - wlr_seat_set_capabilities(g_pCompositor->m_sSeat.seat, caps); + g_pSeatManager->updateCapabilities(caps); m_uiCapabilities = caps; } @@ -1422,7 +1408,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; - if (!kb->enabled) + if (!kb->enabled || !kb->wlr()) continue; finalMask |= wlr_keyboard_get_modifiers(kb->wlr()); @@ -1657,7 +1643,7 @@ void CInputManager::releaseAllMouseButtons() { return; for (auto& mb : buttonsCopy) { - wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, 0, mb, WL_POINTER_BUTTON_STATE_RELEASED); + g_pSeatManager->sendPointerButton(0, mb, WL_POINTER_BUTTON_STATE_RELEASED); } m_lCurrentlyHeldButtons.clear(); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index df36b975..42c9d3da 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -118,7 +118,7 @@ class CInputManager { void setClickMode(eClickBehaviorMode); eClickBehaviorMode getClickMode(); - void processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e); + void processMouseRequest(std::any e); void onTouchDown(ITouch::SDownEvent); void onTouchUp(ITouch::SUpEvent); @@ -197,7 +197,6 @@ class CInputManager { // for tracking mouse refocus PHLWINDOWREF m_pLastMouseFocus; - wlr_surface* m_pLastMouseSurface = nullptr; // bool m_bEmptyFocusCursorSet = false; @@ -209,6 +208,7 @@ class CInputManager { CHyprSignalListener newIdleInhibitor; CHyprSignalListener newVirtualKeyboard; CHyprSignalListener newVirtualMouse; + CHyprSignalListener setCursor; } m_sListeners; bool m_bCursorImageOverridden = false; diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index cf666ec6..56e817ec 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -4,6 +4,7 @@ #include "../../protocols/Tablet.hpp" #include "../../devices/Tablet.hpp" #include "../../managers/PointerManager.hpp" +#include "../../managers/SeatManager.hpp" #include "../../protocols/PointerConstraints.hpp" static void unfocusTool(SP tool) { @@ -36,7 +37,7 @@ static void focusTool(SP tool, SP tablet, wlr_surface* sur } static void refocusTablet(SP tab, SP tool, bool motion = false) { - const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pInputManager->m_pLastMouseSurface); + const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); if (!LASTHLSURFACE || !tool->active) { if (tool->getSurface()) @@ -56,7 +57,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); - focusTool(tool, tab, g_pInputManager->m_pLastMouseSurface); + focusTool(tool, tab, g_pSeatManager->state.pointerFocus); if (!motion) return; diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 4a6484c2..7748813b 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -3,6 +3,7 @@ #include "../../config/ConfigValue.hpp" #include "../../protocols/IdleNotify.hpp" #include "../../devices/ITouch.hpp" +#include "../SeatManager.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { static auto PSWIPETOUCH = CConfigValue("gestures:workspace_swipe_touch"); @@ -76,7 +77,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } else return; // oops, nothing found. - wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local.x, local.y); + g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local); PROTO::idle->onActivity(); } @@ -90,9 +91,8 @@ void CInputManager::onTouchUp(ITouch::SUpEvent e) { return; } - if (m_sTouchData.touchFocusSurface) { - wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID); - } + if (m_sTouchData.touchFocusSurface) + g_pSeatManager->sendTouchUp(e.timeMs, e.touchID); } void CInputManager::onTouchMove(ITouch::SMotionEvent e) { @@ -131,8 +131,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { if (m_sTouchData.touchFocusWindow->m_bIsX11) local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); - // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); + g_pSeatManager->sendTouchMotion(e.timeMs, e.touchID, local); } else if (!m_sTouchData.touchFocusLS.expired()) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); @@ -140,7 +139,6 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin; - wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y); - // wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y); + g_pSeatManager->sendTouchMotion(e.timeMs, e.touchID, local); } } diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 1ab4d4a6..4189ed6e 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -1,124 +1,125 @@ #include "FocusGrab.hpp" #include "Compositor.hpp" #include -#include +#include "../managers/input/InputManager.hpp" +#include "../managers/SeatManager.hpp" #include #include #include -static void focus_grab_pointer_enter(wlr_seat_pointer_grab* grab, wlr_surface* surface, double sx, double sy) { - if (static_cast(grab->data)->isSurfaceComitted(surface)) - wlr_seat_pointer_enter(grab->seat, surface, sx, sy); - else - wlr_seat_pointer_clear_focus(grab->seat); -} +// static void focus_grab_pointer_enter(wlr_seat_pointer_grab* grab, wlr_surface* surface, double sx, double sy) { +// if (static_cast(grab->data)->isSurfaceComitted(surface)) +// wlr_seat_pointer_enter(grab->seat, surface, sx, sy); +// else +// wlr_seat_pointer_clear_focus(grab->seat); +// } -static void focus_grab_pointer_clear_focus(wlr_seat_pointer_grab* grab) { - wlr_seat_pointer_clear_focus(grab->seat); -} +// static void focus_grab_pointer_clear_focus(wlr_seat_pointer_grab* grab) { +// wlr_seat_pointer_clear_focus(grab->seat); +// } -static void focus_grab_pointer_motion(wlr_seat_pointer_grab* grab, uint32_t time, double sx, double sy) { - wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); -} +// static void focus_grab_pointer_motion(wlr_seat_pointer_grab* grab, uint32_t time, double sx, double sy) { +// wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +// } -static uint32_t focus_grab_pointer_button(wlr_seat_pointer_grab* grab, uint32_t time, uint32_t button, wl_pointer_button_state state) { - uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state); +// static uint32_t focus_grab_pointer_button(wlr_seat_pointer_grab* grab, uint32_t time, uint32_t button, wl_pointer_button_state state) { +// uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state); - if (serial) - return serial; - else { - static_cast(grab->data)->finish(true); - return 0; - } -} +// if (serial) +// return serial; +// else { +// static_cast(grab->data)->finish(true); +// return 0; +// } +// } -static void focus_grab_pointer_axis(wlr_seat_pointer_grab* grab, uint32_t time, enum wl_pointer_axis orientation, double value, int32_t value_discrete, - enum wl_pointer_axis_source source, enum wl_pointer_axis_relative_direction relative_direction) { - wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, value_discrete, source, relative_direction); -} +// static void focus_grab_pointer_axis(wlr_seat_pointer_grab* grab, uint32_t time, enum wl_pointer_axis orientation, double value, int32_t value_discrete, +// enum wl_pointer_axis_source source, enum wl_pointer_axis_relative_direction relative_direction) { +// wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, value_discrete, source, relative_direction); +// } -static void focus_grab_pointer_frame(wlr_seat_pointer_grab* grab) { - wlr_seat_pointer_send_frame(grab->seat); -} +// static void focus_grab_pointer_frame(wlr_seat_pointer_grab* grab) { +// wlr_seat_pointer_send_frame(grab->seat); +// } -static void focus_grab_pointer_cancel(wlr_seat_pointer_grab* grab) { - static_cast(grab->data)->finish(true); -} +// static void focus_grab_pointer_cancel(wlr_seat_pointer_grab* grab) { +// static_cast(grab->data)->finish(true); +// } -static const wlr_pointer_grab_interface focus_grab_pointer_impl = { - .enter = focus_grab_pointer_enter, - .clear_focus = focus_grab_pointer_clear_focus, - .motion = focus_grab_pointer_motion, - .button = focus_grab_pointer_button, - .axis = focus_grab_pointer_axis, - .frame = focus_grab_pointer_frame, - .cancel = focus_grab_pointer_cancel, -}; +// static const wlr_pointer_grab_interface focus_grab_pointer_impl = { +// .enter = focus_grab_pointer_enter, +// .clear_focus = focus_grab_pointer_clear_focus, +// .motion = focus_grab_pointer_motion, +// .button = focus_grab_pointer_button, +// .axis = focus_grab_pointer_axis, +// .frame = focus_grab_pointer_frame, +// .cancel = focus_grab_pointer_cancel, +// }; -static void focus_grab_keyboard_enter(wlr_seat_keyboard_grab* grab, wlr_surface* surface, const uint32_t keycodes[], size_t num_keycodes, const wlr_keyboard_modifiers* modifiers) { - if (static_cast(grab->data)->isSurfaceComitted(surface)) - wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers); +// static void focus_grab_keyboard_enter(wlr_seat_keyboard_grab* grab, wlr_surface* surface, const uint32_t keycodes[], size_t num_keycodes, const wlr_keyboard_modifiers* modifiers) { +// if (static_cast(grab->data)->isSurfaceComitted(surface)) +// wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers); - // otherwise the last grabbed window should retain keyboard focus. -} +// // otherwise the last grabbed window should retain keyboard focus. +// } -static void focus_grab_keyboard_clear_focus(wlr_seat_keyboard_grab* grab) { - static_cast(grab->data)->finish(true); -} +// static void focus_grab_keyboard_clear_focus(wlr_seat_keyboard_grab* grab) { +// static_cast(grab->data)->finish(true); +// } -static void focus_grab_keyboard_key(wlr_seat_keyboard_grab* grab, uint32_t time, uint32_t key, uint32_t state) { - wlr_seat_keyboard_send_key(grab->seat, time, key, state); -} +// static void focus_grab_keyboard_key(wlr_seat_keyboard_grab* grab, uint32_t time, uint32_t key, uint32_t state) { +// wlr_seat_keyboard_send_key(grab->seat, time, key, state); +// } -static void focus_grab_keyboard_modifiers(wlr_seat_keyboard_grab* grab, const wlr_keyboard_modifiers* modifiers) { - wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); -} +// static void focus_grab_keyboard_modifiers(wlr_seat_keyboard_grab* grab, const wlr_keyboard_modifiers* modifiers) { +// wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); +// } -static void focus_grab_keyboard_cancel(wlr_seat_keyboard_grab* grab) { - static_cast(grab->data)->finish(true); -} +// static void focus_grab_keyboard_cancel(wlr_seat_keyboard_grab* grab) { +// static_cast(grab->data)->finish(true); +// } -static const wlr_keyboard_grab_interface focus_grab_keyboard_impl = { - .enter = focus_grab_keyboard_enter, - .clear_focus = focus_grab_keyboard_clear_focus, - .key = focus_grab_keyboard_key, - .modifiers = focus_grab_keyboard_modifiers, - .cancel = focus_grab_keyboard_cancel, -}; +// static const wlr_keyboard_grab_interface focus_grab_keyboard_impl = { +// .enter = focus_grab_keyboard_enter, +// .clear_focus = focus_grab_keyboard_clear_focus, +// .key = focus_grab_keyboard_key, +// .modifiers = focus_grab_keyboard_modifiers, +// .cancel = focus_grab_keyboard_cancel, +// }; -static uint32_t focus_grab_touch_down(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { - if (!static_cast(grab->data)->isSurfaceComitted(point->surface)) - return 0; +// static uint32_t focus_grab_touch_down(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { +// if (!static_cast(grab->data)->isSurfaceComitted(point->surface)) +// return 0; - return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); -} +// return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); +// } -static void focus_grab_touch_up(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { - wlr_seat_touch_send_up(grab->seat, time, point->touch_id); -} +// static void focus_grab_touch_up(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { +// wlr_seat_touch_send_up(grab->seat, time, point->touch_id); +// } -static void focus_grab_touch_motion(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { - wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, point->sy); -} +// static void focus_grab_touch_motion(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { +// wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, point->sy); +// } -static void focus_grab_touch_enter(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {} +// static void focus_grab_touch_enter(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {} -static void focus_grab_touch_frame(wlr_seat_touch_grab* grab) { - wlr_seat_touch_send_frame(grab->seat); -} +// static void focus_grab_touch_frame(wlr_seat_touch_grab* grab) { +// wlr_seat_touch_send_frame(grab->seat); +// } -static void focus_grab_touch_cancel(wlr_seat_touch_grab* grab) { - static_cast(grab->data)->finish(true); -} +// static void focus_grab_touch_cancel(wlr_seat_touch_grab* grab) { +// static_cast(grab->data)->finish(true); +// } -static const wlr_touch_grab_interface focus_grab_touch_impl = { - .down = focus_grab_touch_down, - .up = focus_grab_touch_up, - .motion = focus_grab_touch_motion, - .enter = focus_grab_touch_enter, - .frame = focus_grab_touch_frame, - .cancel = focus_grab_touch_cancel, -}; +// static const wlr_touch_grab_interface focus_grab_touch_impl = { +// .down = focus_grab_touch_down, +// .up = focus_grab_touch_up, +// .motion = focus_grab_touch_motion, +// .enter = focus_grab_touch_enter, +// .frame = focus_grab_touch_frame, +// .cancel = focus_grab_touch_cancel, +// }; CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) { hyprListener_surfaceDestroy.initCallback( @@ -133,14 +134,14 @@ CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) if (!resource->resource()) return; - m_sPointerGrab.interface = &focus_grab_pointer_impl; - m_sPointerGrab.data = this; + // m_sPointerGrab.interface = &focus_grab_pointer_impl; + // m_sPointerGrab.data = this; - m_sKeyboardGrab.interface = &focus_grab_keyboard_impl; - m_sKeyboardGrab.data = this; + // m_sKeyboardGrab.interface = &focus_grab_keyboard_impl; + // m_sKeyboardGrab.data = this; - m_sTouchGrab.interface = &focus_grab_touch_impl; - m_sTouchGrab.data = this; + // m_sTouchGrab.interface = &focus_grab_touch_impl; + // m_sTouchGrab.data = this; resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); @@ -167,21 +168,21 @@ bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) { void CFocusGrab::start() { if (!m_bGrabActive) { - wlr_seat_pointer_start_grab(g_pCompositor->m_sSeat.seat, &m_sPointerGrab); - wlr_seat_keyboard_start_grab(g_pCompositor->m_sSeat.seat, &m_sKeyboardGrab); - wlr_seat_touch_start_grab(g_pCompositor->m_sSeat.seat, &m_sTouchGrab); + // wlr_seat_pointer_start_grab(g_pCompositor->m_sSeat.seat, &m_sPointerGrab); + // wlr_seat_keyboard_start_grab(g_pCompositor->m_sSeat.seat, &m_sKeyboardGrab); + // wlr_seat_touch_start_grab(g_pCompositor->m_sSeat.seat, &m_sTouchGrab); m_bGrabActive = true; // Ensure the grab ends if another grab begins, including from xdg_popup::grab. - hyprListener_pointerGrabStarted.initCallback( - &g_pCompositor->m_sSeat.seat->events.pointer_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + // hyprListener_pointerGrabStarted.initCallback( + // &g_pCompositor->m_sSeat.seat->events.pointer_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); - hyprListener_keyboardGrabStarted.initCallback( - &g_pCompositor->m_sSeat.seat->events.keyboard_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + // hyprListener_keyboardGrabStarted.initCallback( + // &g_pCompositor->m_sSeat.seat->events.keyboard_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); - hyprListener_touchGrabStarted.initCallback( - &g_pCompositor->m_sSeat.seat->events.touch_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + // hyprListener_touchGrabStarted.initCallback( + // &g_pCompositor->m_sSeat.seat->events.touch_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); } // Ensure new surfaces are focused if under the mouse when comitted. @@ -192,28 +193,28 @@ void CFocusGrab::start() { void CFocusGrab::finish(bool sendCleared) { if (m_bGrabActive) { m_bGrabActive = false; - hyprListener_pointerGrabStarted.removeCallback(); - hyprListener_keyboardGrabStarted.removeCallback(); - hyprListener_touchGrabStarted.removeCallback(); + // hyprListener_pointerGrabStarted.removeCallback(); + // hyprListener_keyboardGrabStarted.removeCallback(); + // hyprListener_touchGrabStarted.removeCallback(); // Only clear grabs that belong to this focus grab. When superseded by another grab // or xdg_popup grab we might not own the current grab. bool hadGrab = false; - if (g_pCompositor->m_sSeat.seat->pointer_state.grab == &m_sPointerGrab) { - wlr_seat_pointer_end_grab(g_pCompositor->m_sSeat.seat); - hadGrab = true; - } + // if (g_pCompositor->m_sSeat.seat->pointer_state.grab == &m_sPointerGrab) { + // wlr_seat_pointer_end_grab(g_pCompositor->m_sSeat.seat); + // hadGrab = true; + // } - if (g_pCompositor->m_sSeat.seat->keyboard_state.grab == &m_sKeyboardGrab) { - wlr_seat_keyboard_end_grab(g_pCompositor->m_sSeat.seat); - hadGrab = true; - } + // if (g_pCompositor->m_sSeat.seat->keyboard_state.grab == &m_sKeyboardGrab) { + // wlr_seat_keyboard_end_grab(g_pCompositor->m_sSeat.seat); + // hadGrab = true; + // } - if (g_pCompositor->m_sSeat.seat->touch_state.grab == &m_sTouchGrab) { - wlr_seat_touch_end_grab(g_pCompositor->m_sSeat.seat); - hadGrab = true; - } + // if (g_pCompositor->m_sSeat.seat->touch_state.grab == &m_sTouchGrab) { + // wlr_seat_touch_end_grab(g_pCompositor->m_sSeat.seat); + // hadGrab = true; + // } m_mSurfaces.clear(); @@ -248,7 +249,7 @@ void CFocusGrab::eraseSurface(wlr_surface* surface) { } void CFocusGrab::refocusKeyboard() { - auto keyboardSurface = g_pCompositor->m_sSeat.seat->keyboard_state.focused_surface; + auto keyboardSurface = g_pSeatManager->state.keyboardFocus; if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface)) return; diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 11c26774..3e5d36ab 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -44,10 +44,10 @@ class CFocusGrab { SP resource; std::unordered_map> m_mSurfaces; - wlr_seat_pointer_grab m_sPointerGrab; - wlr_seat_keyboard_grab m_sKeyboardGrab; - wlr_seat_touch_grab m_sTouchGrab; - bool m_bGrabActive = false; + // wlr_seat_pointer_grab m_sPointerGrab; + // wlr_seat_keyboard_grab m_sKeyboardGrab; + // wlr_seat_touch_grab m_sTouchGrab; + bool m_bGrabActive = false; DYNLISTENER(pointerGrabStarted); DYNLISTENER(keyboardGrabStarted); diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 9e5c863b..93ca38c0 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -1,5 +1,7 @@ #include "InputMethodV2.hpp" #include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "../devices/IKeyboard.hpp" #include #define LOGM PROTO::ime->protoLog @@ -11,14 +13,12 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SPsetRelease([this](CZwpInputMethodKeyboardGrabV2* r) { PROTO::ime->destroyResource(this); }); resource->setOnDestroy([this](CZwpInputMethodKeyboardGrabV2* r) { PROTO::ime->destroyResource(this); }); - const auto PKEYBOARD = wlr_seat_get_keyboard(g_pCompositor->m_sSeat.seat); - - if (!PKEYBOARD) { + if (!g_pSeatManager->keyboard) { LOGM(ERR, "IME called but no active keyboard???"); return; } - sendKeyboardData(PKEYBOARD); + sendKeyboardData(g_pSeatManager->keyboard->wlr()); } CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { @@ -60,13 +60,13 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { } void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { - const auto SERIAL = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, resource->client())); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(resource->client())); resource->sendKey(SERIAL, time, key, (uint32_t)state); } void CInputMethodKeyboardGrabV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { - const auto SERIAL = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, resource->client())); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(resource->client())); resource->sendModifiers(SERIAL, depressed, latched, locked, group); } diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 7b5729c0..87abdcdd 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -2,6 +2,7 @@ #include "../desktop/WLSurface.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "../managers/SeatManager.hpp" #define LOGM PROTO::constraints->protoLog @@ -125,10 +126,10 @@ void CPointerConstraint::activate() { return; // TODO: hack, probably not a super duper great idea - if (g_pCompositor->m_sSeat.seat->pointer_state.focused_surface != pHLSurface->wlr()) { + if (g_pSeatManager->state.pointerFocus != pHLSurface->wlr()) { const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{}; - wlr_seat_pointer_enter(g_pCompositor->m_sSeat.seat, pHLSurface->wlr(), LOCAL.x, LOCAL.y); + g_pSeatManager->setPointerFocus(pHLSurface->wlr(), LOCAL); } if (locked) diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 5b5d1c52..2bfd74da 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -1,5 +1,7 @@ #include "PointerGestures.hpp" #include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" #define LOGM PROTO::pointerGestures->protoLog @@ -103,26 +105,26 @@ void CPointerGesturesProtocol::onGetHoldGesture(CZwpPointerGesturesV1* pMgr, uin } void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pCompositor->m_sSeat.seat->pointer_state.focused_surface->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); } } void CPointerGesturesProtocol::swipeUpdate(uint32_t timeMs, const Vector2D& delta) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); for (auto& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) @@ -133,12 +135,12 @@ void CPointerGesturesProtocol::swipeUpdate(uint32_t timeMs, const Vector2D& delt } void CPointerGesturesProtocol::swipeEnd(uint32_t timeMs, bool cancelled) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) @@ -149,26 +151,26 @@ void CPointerGesturesProtocol::swipeEnd(uint32_t timeMs, bool cancelled) { } void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pCompositor->m_sSeat.seat->pointer_state.focused_surface->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); } } void CPointerGesturesProtocol::pinchUpdate(uint32_t timeMs, const Vector2D& delta, double scale, double rotation) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); for (auto& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) @@ -179,12 +181,12 @@ void CPointerGesturesProtocol::pinchUpdate(uint32_t timeMs, const Vector2D& delt } void CPointerGesturesProtocol::pinchEnd(uint32_t timeMs, bool cancelled) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) @@ -195,28 +197,28 @@ void CPointerGesturesProtocol::pinchEnd(uint32_t timeMs, bool cancelled) { } void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pCompositor->m_sSeat.seat->pointer_state.focused_surface->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); } } void CPointerGesturesProtocol::holdEnd(uint32_t timeMs, bool cancelled) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSEDCLIENT = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - const auto SERIAL = wlr_seat_client_next_serial(g_pCompositor->m_sSeat.seat->pointer_state.focused_client); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); for (auto& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index c64687ee..e4818758 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -1,5 +1,7 @@ #include "RelativePointer.hpp" -#include "Compositor.hpp" +#include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" #include CRelativePointer::CRelativePointer(SP resource_) : resource(resource_) { @@ -58,10 +60,10 @@ void CRelativePointerProtocol::onGetRelativePointer(CZwpRelativePointerManagerV1 void CRelativePointerProtocol::sendRelativeMotion(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) { - if (!g_pCompositor->m_sSeat.seat->pointer_state.focused_client) + if (!g_pSeatManager->state.pointerFocusResource) return; - const auto FOCUSED = g_pCompositor->m_sSeat.seat->pointer_state.focused_client->client; + const auto FOCUSED = g_pSeatManager->state.pointerFocusResource->client(); for (auto& rp : m_vRelativePointers) { if (FOCUSED != rp->client()) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index db3404be..fd803eda 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -1,5 +1,6 @@ #include "SessionLock.hpp" #include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" #include "FractionalScale.hpp" #define LOGM PROTO::sessionLock->protoLog @@ -76,7 +77,7 @@ CSessionLockSurface::~CSessionLockSurface() { } void CSessionLockSurface::sendConfigure() { - const auto SERIAL = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, resource->client())); + const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(resource->client())); resource->sendConfigure(SERIAL, pMonitor->vecSize.x, pMonitor->vecSize.y); } diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index b3ca76f5..7c54a116 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -1,6 +1,8 @@ #include "Tablet.hpp" #include "../devices/Tablet.hpp" #include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" #include #define LOGM PROTO::tablet->protoLog @@ -159,12 +161,10 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP< resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { - wlr_seat_pointer_request_set_cursor_event e; - e.hotspot_x = hot_x; - e.hotspot_y = hot_y; - e.surface = surf ? wlr_surface_from_resource(surf) : nullptr; - e.serial = serial; - g_pInputManager->processMouseRequest(&e); + if (!g_pSeatManager->state.pointerFocusResource || g_pSeatManager->state.pointerFocusResource->client() != r->client()) + return; + + g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{wlr_surface_from_resource(surf), {hot_x, hot_y}}); }); } @@ -539,7 +539,7 @@ void CTabletV2Protocol::down(SP tool) { if (t->tool != tool || !t->current) continue; - auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(t->resource->client())); t->resource->sendDown(serial); t->queueFrame(); } @@ -586,7 +586,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, wl toolResource->current = true; toolResource->lastSurf = surf; - auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, toolResource->resource->client())); + auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(toolResource->resource->client())); toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource); toolResource->queueFrame(); @@ -610,7 +610,7 @@ void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32 if (t->tool != tool || !t->current) continue; - auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(t->resource->client())); t->resource->sendButton(serial, button, (zwpTabletToolV2ButtonState)state); t->queueFrame(); } @@ -634,7 +634,7 @@ void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, LOGM(ERR, "BUG THIS: group >= t->groups.size()"); return; } - auto serial = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, t->resource->client())); + auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(t->resource->client())); t->groups.at(group)->resource->sendModeSwitch(timeMs, serial, mode); } } diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp new file mode 100644 index 00000000..489fced7 --- /dev/null +++ b/src/protocols/core/Seat.cpp @@ -0,0 +1,437 @@ +#include "Seat.hpp" +#include "../../devices/IKeyboard.hpp" +#include "../../managers/SeatManager.hpp" +#include "../../config/ConfigValue.hpp" +#include + +#include + +#define LOGM PROTO::seat->protoLog + +CWLTouchResource::CWLTouchResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlTouch* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlTouch* r) { PROTO::seat->destroyResource(this); }); +} + +bool CWLTouchResource::good() { + return resource->resource(); +} + +void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local) { + if (!owner) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLTouchResource::sendDown without sendUp first."); + sendUp(timeMs, id); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this, id, timeMs](void* owner, void* data) { sendUp(timeMs + 10 /* hack */, id); }, this, "CWLTouchResource"); + + // FIXME: + // fix this once we get our own wlr_surface, this is horrible + resource->sendDownRaw(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->resource, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { + if (!owner || !currentSurface) + return; + + resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { + if (!owner || !currentSurface) + return; + + resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLTouchResource::sendFrame() { + if (!owner || !currentSurface) + return; + + resource->sendFrame(); +} + +void CWLTouchResource::sendCancel() { + if (!owner || !currentSurface) + return; + + resource->sendCancel(); +} + +void CWLTouchResource::sendShape(int32_t id, const Vector2D& shape) { + if (!owner || !currentSurface || resource->version() < 6) + return; + + resource->sendShape(id, wl_fixed_from_double(shape.x), wl_fixed_from_double(shape.y)); +} + +void CWLTouchResource::sendOrientation(int32_t id, double angle) { + if (!owner || !currentSurface || resource->version() < 6) + return; + + resource->sendOrientation(id, wl_fixed_from_double(angle)); +} + +CWLPointerResource::CWLPointerResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlPointer* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlPointer* r) { PROTO::seat->destroyResource(this); }); + + resource->setSetCursor([this](CWlPointer* r, uint32_t serial, wl_resource* surf, int32_t hotX, int32_t hotY) { + if (!owner) { + LOGM(ERR, "Client bug: setCursor when seatClient is already dead"); + return; + } + + g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? wlr_surface_from_resource(surf) : nullptr, {hotX, hotY}); + }); +} + +bool CWLPointerResource::good() { + return resource->resource(); +} + +void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) { + if (!owner || currentSurface == surface) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLPointerResource::sendEnter without sendLeave first."); + sendLeave(); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLPointerResource"); + + resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLPointerResource::sendLeave() { + if (!owner || !currentSurface) + return; + + resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) { + if (!owner || !currentSurface) + return; + + resource->sendMotion(timeMs, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLPointerResource::sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state) { + if (!owner || !currentSurface) + return; + + resource->sendButton(g_pSeatManager->nextSerial(owner.lock()), timeMs, button, state); +} + +void CWLPointerResource::sendAxis(uint32_t timeMs, wl_pointer_axis axis, double value) { + if (!owner || !currentSurface) + return; + + resource->sendAxis(timeMs, axis, wl_fixed_from_double(value)); +} + +void CWLPointerResource::sendFrame() { + if (!owner || resource->version() < 5) + return; + + resource->sendFrame(); +} + +void CWLPointerResource::sendAxisSource(wl_pointer_axis_source source) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisSource(source); +} + +void CWLPointerResource::sendAxisStop(uint32_t timeMs, wl_pointer_axis axis) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisStop(timeMs, axis); +} + +void CWLPointerResource::sendAxisDiscrete(wl_pointer_axis axis, int32_t discrete) { + if (!owner || !currentSurface || resource->version() < 5) + return; + + resource->sendAxisDiscrete(axis, discrete); +} + +void CWLPointerResource::sendAxisValue120(wl_pointer_axis axis, int32_t value120) { + if (!owner || !currentSurface || resource->version() < 8) + return; + + resource->sendAxisValue120(axis, value120); +} + +void CWLPointerResource::sendAxisRelativeDirection(wl_pointer_axis axis, wl_pointer_axis_relative_direction direction) { + if (!owner || !currentSurface || resource->version() < 9) + return; + + resource->sendAxisRelativeDirection(axis, direction); +} + +CWLKeyboardResource::CWLKeyboardResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); + resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); + + static auto REPEAT = CConfigValue("input:repeat_rate"); + static auto DELAY = CConfigValue("input:repeat_delay"); + sendKeymap(g_pSeatManager->keyboard.lock()); + repeatInfo(*REPEAT, *DELAY); +} + +bool CWLKeyboardResource::good() { + return resource->resource(); +} + +void CWLKeyboardResource::sendKeymap(SP keyboard) { + wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; + int fd; + uint32_t size; + if (keyboard) { + fd = keyboard->wlr()->keymap_fd; + size = keyboard->wlr()->keymap_size; + } else { + fd = open("/dev/null", O_RDONLY | O_CLOEXEC); + if (fd < 0) { + LOGM(ERR, "Failed to open /dev/null"); + return; + } + size = 0; + } + + resource->sendKeymap(format, fd, size); + + if (!keyboard) + close(fd); +} + +void CWLKeyboardResource::sendEnter(wlr_surface* surface) { + if (!owner || currentSurface == surface) + return; + + if (currentSurface) { + LOGM(WARN, "requested CWLKeyboardResource::sendEnter without sendLeave first."); + sendLeave(); + } + + ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + + currentSurface = surface; + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLKeyboardResource"); + + wl_array arr; + wl_array_init(&arr); + + resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, &arr); + + wl_array_release(&arr); +} + +void CWLKeyboardResource::sendLeave() { + if (!owner || !currentSurface) + return; + + resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); + currentSurface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); +} + +void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) { + if (!owner || !currentSurface) + return; + + resource->sendKey(g_pSeatManager->nextSerial(owner.lock()), timeMs, key, state); +} + +void CWLKeyboardResource::sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!owner || !currentSurface) + return; + + resource->sendModifiers(g_pSeatManager->nextSerial(owner.lock()), depressed, latched, locked, group); +} + +void CWLKeyboardResource::repeatInfo(uint32_t rate, uint32_t delayMs) { + if (!owner || resource->version() < 4) + return; + + resource->sendRepeatInfo(rate, delayMs); +} + +CWLSeatResource::CWLSeatResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSeat* r) { + events.destroy.emit(); + PROTO::seat->destroyResource(this); + }); + resource->setRelease([this](CWlSeat* r) { + events.destroy.emit(); + PROTO::seat->destroyResource(this); + }); + + pClient = resource->client(); + + resource->setGetKeyboard([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vKeyboards.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vKeyboards.pop_back(); + return; + } + + keyboards.push_back(RESOURCE); + }); + + resource->setGetPointer([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vPointers.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vPointers.pop_back(); + return; + } + + pointers.push_back(RESOURCE); + }); + + resource->setGetTouch([this](CWlSeat* r, uint32_t id) { + const auto RESOURCE = PROTO::seat->m_vTouches.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::seat->m_vTouches.pop_back(); + return; + } + + touches.push_back(RESOURCE); + }); + + if (resource->version() >= 2) + resource->sendName(HL_SEAT_NAME); + + sendCapabilities(PROTO::seat->currentCaps); +} + +CWLSeatResource::~CWLSeatResource() { + events.destroy.emit(); +} + +void CWLSeatResource::sendCapabilities(uint32_t caps) { + uint32_t wlCaps = 0; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD) + wlCaps |= WL_SEAT_CAPABILITY_KEYBOARD; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER) + wlCaps |= WL_SEAT_CAPABILITY_POINTER; + if (caps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH) + wlCaps |= WL_SEAT_CAPABILITY_TOUCH; + + resource->sendCapabilities((wl_seat_capability)wlCaps); +} + +bool CWLSeatResource::good() { + return resource->resource(); +} + +wl_client* CWLSeatResource::client() { + return pClient; +} + +CWLSeatProtocol::CWLSeatProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSeatProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vSeatResources.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vSeatResources.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New seat resource bound at {:x}", (uintptr_t)RESOURCE.get()); + + events.newSeatResource.emit(RESOURCE); +} + +void CWLSeatProtocol::destroyResource(CWLSeatResource* seat) { + std::erase_if(m_vSeatResources, [&](const auto& other) { return other.get() == seat; }); +} + +void CWLSeatProtocol::destroyResource(CWLKeyboardResource* resource) { + std::erase_if(m_vKeyboards, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::destroyResource(CWLPointerResource* resource) { + std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::destroyResource(CWLTouchResource* resource) { + std::erase_if(m_vTouches, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSeatProtocol::updateCapabilities(uint32_t caps) { + if (caps == currentCaps) + return; + + currentCaps = caps; + + for (auto& s : m_vSeatResources) { + s->sendCapabilities(caps); + } +} + +void CWLSeatProtocol::updateKeymap() { + for (auto& k : m_vKeyboards) { + k->sendKeymap(g_pSeatManager->keyboard.lock()); + } +} + +void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) { + for (auto& k : m_vKeyboards) { + k->repeatInfo(rate, delayMs); + } +} + +SP CWLSeatProtocol::seatResourceForClient(wl_client* client) { + for (auto& r : m_vSeatResources) { + if (r->client() == client) + return r; + } + + return nullptr; +} diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp new file mode 100644 index 00000000..4cd0d124 --- /dev/null +++ b/src/protocols/core/Seat.hpp @@ -0,0 +1,163 @@ +#pragma once + +/* + Implementations for: + - wl_seat + - wl_keyboard + - wl_pointer + - wl_touch +*/ + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../helpers/Vector2D.hpp" + +constexpr const char* HL_SEAT_NAME = "Hyprland"; + +class IKeyboard; + +class CWLPointerResource; +class CWLKeyboardResource; +class CWLTouchResource; +class CWLSeatResource; + +class CWLTouchResource { + public: + CWLTouchResource(SP resource_, SP owner_); + + bool good(); + void sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendUp(uint32_t timeMs, int32_t id); + void sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local); + void sendFrame(); + void sendCancel(); + void sendShape(int32_t id, const Vector2D& shape); + void sendOrientation(int32_t id, double angle); + + WP owner; + + private: + SP resource; + wlr_surface* currentSurface = nullptr; + + DYNLISTENER(surfaceDestroy); +}; + +class CWLPointerResource { + public: + CWLPointerResource(SP resource_, SP owner_); + + bool good(); + void sendEnter(wlr_surface* surface, const Vector2D& local); + void sendLeave(); + void sendMotion(uint32_t timeMs, const Vector2D& local); + void sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state); + void sendAxis(uint32_t timeMs, wl_pointer_axis axis, double value); + void sendFrame(); + void sendAxisSource(wl_pointer_axis_source source); + void sendAxisStop(uint32_t timeMs, wl_pointer_axis axis); + void sendAxisDiscrete(wl_pointer_axis axis, int32_t discrete); + void sendAxisValue120(wl_pointer_axis axis, int32_t value120); + void sendAxisRelativeDirection(wl_pointer_axis axis, wl_pointer_axis_relative_direction direction); + + WP owner; + + private: + SP resource; + wlr_surface* currentSurface = nullptr; + + DYNLISTENER(surfaceDestroy); +}; + +class CWLKeyboardResource { + public: + CWLKeyboardResource(SP resource_, SP owner_); + + bool good(); + void sendKeymap(SP keeb); + void sendEnter(wlr_surface* surface); + void sendLeave(); + void sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); + void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + void repeatInfo(uint32_t rate, uint32_t delayMs); + + WP owner; + + private: + SP resource; + wlr_surface* currentSurface = nullptr; + + DYNLISTENER(surfaceDestroy); +}; + +class CWLSeatResource { + public: + CWLSeatResource(SP resource_); + ~CWLSeatResource(); + + void sendCapabilities(uint32_t caps); // uses IHID capabilities + + bool good(); + wl_client* client(); + + std::vector> pointers; + std::vector> keyboards; + std::vector> touches; + + WP self; + + struct { + CSignal destroy; + } events; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CWLSeatProtocol : public IWaylandProtocol { + public: + CWLSeatProtocol(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); + + struct { + CSignal newSeatResource; // SP + } events; + + private: + void updateCapabilities(uint32_t caps); // in IHID caps + void updateRepeatInfo(uint32_t rate, uint32_t delayMs); + void updateKeymap(); + + void destroyResource(CWLSeatResource* resource); + void destroyResource(CWLKeyboardResource* resource); + void destroyResource(CWLTouchResource* resource); + void destroyResource(CWLPointerResource* resource); + + // + std::vector> m_vSeatResources; + std::vector> m_vKeyboards; + std::vector> m_vTouches; + std::vector> m_vPointers; + + SP seatResourceForClient(wl_client* client); + + // + uint32_t currentCaps = 0; + + friend class CWLSeatResource; + friend class CWLKeyboardResource; + friend class CWLTouchResource; + friend class CWLPointerResource; + friend class CSeatManager; +}; + +namespace PROTO { + inline UP seat; +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d9529b6f..38dba439 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2490,8 +2490,8 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { const auto PWORKSPACE = pMonitor->activeWorkspace; - if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->activeSpecialWorkspace || - PWORKSPACE->m_fAlpha.value() != 1.f || PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) + if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha.value() != 1.f || + PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) return; const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); From 0cfdde3d1acbfbf698af17f6986fbc4d644214da Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 10 May 2024 23:28:33 +0100 Subject: [PATCH 0082/2393] xdg-shell: move to new impl --- CMakeLists.txt | 4 +- protocols/meson.build | 1 + src/Compositor.cpp | 51 +- src/Compositor.hpp | 1 - src/config/ConfigManager.cpp | 4 +- src/debug/HyprCtl.cpp | 12 +- src/desktop/Popup.cpp | 116 ++--- src/desktop/Popup.hpp | 31 +- src/desktop/Window.cpp | 206 ++++++-- src/desktop/Window.hpp | 31 +- src/events/Events.hpp | 3 - src/events/Windows.cpp | 175 ++----- src/includes.hpp | 2 - src/layout/IHyprLayout.cpp | 11 +- src/managers/ProtocolManager.cpp | 2 + src/managers/XWaylandManager.cpp | 121 ++--- src/managers/XWaylandManager.hpp | 3 - src/managers/input/InputManager.cpp | 6 +- src/protocols/ForeignToplevel.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 4 +- src/protocols/LayerShell.cpp | 7 +- src/protocols/XDGShell.cpp | 697 +++++++++++++++++++++++++++ src/protocols/XDGShell.hpp | 256 ++++++++++ src/render/Renderer.cpp | 27 +- 24 files changed, 1352 insertions(+), 421 deletions(-) create mode 100644 src/protocols/XDGShell.cpp create mode 100644 src/protocols/XDGShell.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 608ccc62..80483c4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.6 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.7 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -260,7 +260,6 @@ target_link_libraries(Hyprland protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) -protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) @@ -292,6 +291,7 @@ protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1 protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) +protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) protocolWayland() diff --git a/protocols/meson.build b/protocols/meson.build index 95c9fec4..4b7aa200 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -61,6 +61,7 @@ new_protocols = [ [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index efc02a5f..c56dd280 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -18,6 +18,7 @@ #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" +#include "protocols/XDGShell.hpp" #include "desktop/LayerSurface.hpp" #include @@ -229,8 +230,6 @@ void CCompositor::initServer() { // wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); wlr_viewporter_create(m_sWLDisplay); - m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6); - 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"); @@ -253,7 +252,6 @@ void CCompositor::initServer() { void CCompositor::initAllSignals() { addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); // addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); // addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat"); @@ -271,7 +269,6 @@ void CCompositor::initAllSignals() { void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newOutput); - removeWLSignal(&Events::listen_newXDGToplevel); removeWLSignal(&Events::listen_newInput); removeWLSignal(&Events::listen_requestSetSel); removeWLSignal(&Events::listen_requestDrag); @@ -805,22 +802,28 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW p RASSERT(!pWindow->m_bIsX11, "Cannot call vectorWindowToSurface on an X11 window!"); - const auto PSURFACE = pWindow->m_uSurface.xdg; + double subx, suby; - double subx, suby; + CBox geom = pWindow->m_pXDGSurface->current.geometry; - // calc for oversized windows... fucking bullshit, again. - CBox geom; - wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr()); - geom.applyFromWlr(); + // try popups first + const auto PPOPUP = pWindow->m_pPopupHead->at(pos); - const auto PFOUND = - wlr_xdg_surface_surface_at(PSURFACE, pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, &suby); + wlr_surface* found = PPOPUP ? PPOPUP->m_sWLSurface.wlr() : nullptr; - if (PFOUND) { + if (!PPOPUP) + found = wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, + &suby); + else { + const auto OFF = PPOPUP->coordsRelativeToParent(); + subx = pos.x - OFF.x + geom.x - pWindow->m_vRealPosition.goal().x; + suby = pos.y - OFF.y + geom.y - pWindow->m_vRealPosition.goal().y; + } + + if (found) { sl.x = subx; sl.y = suby; - return PFOUND; + return found; } sl.x = pos.x - pWindow->m_vRealPosition.value().x; @@ -829,7 +832,7 @@ wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW p sl.x += geom.x; sl.y += geom.y; - return PSURFACE->surface; + return pWindow->m_pWLSurface.wlr(); } Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, wlr_surface* pSurface) { @@ -839,12 +842,14 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo if (pWindow->m_bIsX11) return vec - pWindow->m_vRealPosition.goal(); - const auto PSURFACE = pWindow->m_uSurface.xdg; + const auto PPOPUP = pWindow->m_pPopupHead->at(vec); + if (PPOPUP) + return vec - PPOPUP->coordsGlobal(); std::tuple iterData = {pSurface, -1337, -1337}; - wlr_xdg_surface_for_each_surface( - PSURFACE, + wlr_surface_for_each_surface( + pWindow->m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { const auto PDATA = (std::tuple*)data; if (surf == std::get<0>(*PDATA)) { @@ -854,9 +859,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo }, &iterData); - CBox geom = {}; - wlr_xdg_surface_get_geometry(PSURFACE, geom.pWlr()); - geom.applyFromWlr(); + CBox geom = pWindow->m_pXDGSurface->current.geometry; if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337) return vec - pWindow->m_vRealPosition.goal(); @@ -993,7 +996,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { pWindow->m_bIsUrgent = false; // Send an event - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(pWindow) + "," + pWindow->m_szTitle}); + g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", pWindow->m_szClass + "," + pWindow->m_szTitle}); g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)pWindow.get())}); EMIT_HOOK_EVENT("activeWindow", pWindow); @@ -2310,7 +2313,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { switch (mode) { case MODE_CLASS_REGEX: { - const auto windowClass = g_pXWaylandManager->getAppIDClass(w); + const auto windowClass = w->m_szClass; if (!std::regex_search(windowClass, regexCheck)) continue; break; @@ -2322,7 +2325,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { break; } case MODE_TITLE_REGEX: { - const auto windowTitle = g_pXWaylandManager->getTitle(w); + const auto windowTitle = w->m_szTitle; if (!std::regex_search(windowTitle, regexCheck)) continue; break; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index eedcea56..574889bc 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -50,7 +50,6 @@ class CCompositor { wlr_subcompositor* m_sWLRSubCompositor; wlr_drm* m_sWRLDRM; wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_xdg_shell* m_sWLRXDGShell; wlr_egl* m_sWLREGL; int m_iDRMFD; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 4a75ca1d..15d5ae81 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1042,8 +1042,8 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo std::vector returns; - std::string title = g_pXWaylandManager->getTitle(pWindow); - std::string appidclass = g_pXWaylandManager->getAppIDClass(pWindow); + std::string title = pWindow->m_szTitle; + std::string appidclass = pWindow->m_szClass; Debug::log(LOG, "Searching for matching rules for {} (title: {})", appidclass, title); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f8fdb03f..51071533 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -210,10 +210,10 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID, - escapeJSONStrings(g_pXWaylandManager->getAppIDClass(w)), escapeJSONStrings(g_pXWaylandManager->getTitle(w)), escapeJSONStrings(w->m_szInitialClass), - escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), - (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), - w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), + ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"), + (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), + (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } else { return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " @@ -221,8 +221,8 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, - (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, g_pXWaylandManager->getAppIDClass(w), - g_pXWaylandManager->getTitle(w), w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, + (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, + w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index e172744d..605dfdfd 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -2,6 +2,7 @@ #include "../config/ConfigValue.hpp" #include "../Compositor.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/XDGShell.hpp" #include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { @@ -12,14 +13,13 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { initAllSignals(); } -CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR(popup) { - m_pWLR->base->data = this; - m_sWLSurface.assign(popup->base->surface, this); +CPopup::CPopup(SP popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) { + m_sWLSurface.assign(popup->surface->surface, this); m_pLayerOwner = pOwner->m_pLayerOwner; m_pWindowOwner = pOwner->m_pWindowOwner; - m_vLastSize = {m_pWLR->current.geometry.width, m_pWLR->current.geometry.height}; + m_vLastSize = popup->surface->current.geometry.size(); unconstrain(); initAllSignals(); @@ -27,71 +27,32 @@ CPopup::CPopup(wlr_xdg_popup* popup, CPopup* pOwner) : m_pParent(pOwner), m_pWLR CPopup::~CPopup() { m_sWLSurface.unassign(); - if (m_pWLR) - m_pWLR->base->data = nullptr; - - hyprListener_commitPopup.removeCallback(); - hyprListener_repositionPopup.removeCallback(); - hyprListener_mapPopup.removeCallback(); - hyprListener_unmapPopup.removeCallback(); - hyprListener_newPopup.removeCallback(); - hyprListener_destroyPopup.removeCallback(); -} - -static void onNewPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onNewPopup((wlr_xdg_popup*)data); -} - -static void onMapPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onMap(); -} - -static void onDestroyPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onDestroy(); -} - -static void onUnmapPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onUnmap(); -} - -static void onCommitPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onCommit(); -} - -static void onRepositionPopup(void* owner, void* data) { - const auto POPUP = (CPopup*)owner; - POPUP->onReposition(); } void CPopup::initAllSignals() { - if (!m_pWLR) { + if (!m_pResource) { if (!m_pWindowOwner.expired()) - hyprListener_newPopup.initCallback(&m_pWindowOwner->m_uSurface.xdg->events.new_popup, ::onNewPopup, this, "CPopup Head"); + listeners.newPopup = m_pWindowOwner->m_pXDGSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast>(d)); }); else if (!m_pLayerOwner.expired()) - listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast(d)); }); + listeners.newPopup = m_pLayerOwner->layerSurface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast>(d)); }); else ASSERT(false); return; } - hyprListener_repositionPopup.initCallback(&m_pWLR->events.reposition, ::onRepositionPopup, this, "CPopup"); - hyprListener_destroyPopup.initCallback(&m_pWLR->events.destroy, ::onDestroyPopup, this, "CPopup"); - hyprListener_mapPopup.initCallback(&m_sWLSurface.wlr()->events.map, ::onMapPopup, this, "CPopup"); - hyprListener_unmapPopup.initCallback(&m_sWLSurface.wlr()->events.unmap, ::onUnmapPopup, this, "CPopup"); - hyprListener_commitPopup.initCallback(&m_sWLSurface.wlr()->events.commit, ::onCommitPopup, this, "CPopup"); - hyprListener_newPopup.initCallback(&m_pWLR->base->events.new_popup, ::onNewPopup, this, "CPopup"); + listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); }); + listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); }); + listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); + listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); }); + listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); }); + listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast>(d)); }); } -void CPopup::onNewPopup(wlr_xdg_popup* popup) { +void CPopup::onNewPopup(SP popup) { const auto POPUP = m_vChildren.emplace_back(std::make_unique(popup, this)).get(); - Debug::log(LOG, "New popup at wlr {:x} and hl {:x}", (uintptr_t)popup, (uintptr_t)POPUP); + Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } void CPopup::onDestroy() { @@ -104,7 +65,7 @@ void CPopup::onDestroy() { } void CPopup::onMap() { - m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height}; + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; const auto COORDS = coordsGlobal(); CBox box; @@ -126,7 +87,9 @@ void CPopup::onMap() { } void CPopup::onUnmap() { - m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height}; + if (!m_pResource || !m_pResource->surface) + return; + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; const auto COORDS = coordsGlobal(); CBox box; @@ -140,16 +103,27 @@ void CPopup::onUnmap() { if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); + + // damage all children + breadthfirst( + [this](CPopup* p, void* data) { + if (!p->m_pResource) + return; + + auto box = CBox{p->coordsGlobal(), p->size()}; + g_pHyprRenderer->damageBox(&box); + }, + nullptr); } void CPopup::onCommit(bool ignoreSiblings) { - if (m_pWLR->base->initial_commit) { - wlr_xdg_surface_schedule_configure(m_pWLR->base); + if (m_pResource->surface->initialCommit) { + m_pResource->surface->scheduleConfigure(); return; } if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) { - m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height}; + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); if (*PLOGDAMAGE) @@ -157,16 +131,17 @@ void CPopup::onCommit(bool ignoreSiblings) { return; } - if (!m_pWLR->base->surface->mapped) + if (!m_pResource->surface->mapped) return; const auto COORDS = coordsGlobal(); const auto COORDSLOCAL = coordsRelativeToParent(); - if (m_vLastSize != Vector2D{m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height} || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { + if (m_vLastSize != Vector2D{m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height} || m_bRequestedReposition || + m_vLastPos != COORDSLOCAL) { CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; g_pHyprRenderer->damageBox(&box); - m_vLastSize = {m_pWLR->base->current.geometry.width, m_pWLR->base->current.geometry.height}; + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); @@ -202,20 +177,25 @@ void CPopup::unconstrain() { return; CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - wlr_xdg_popup_unconstrain_from_box(m_pWLR, box.pWlr()); + m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition); + wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output); } Vector2D CPopup::coordsRelativeToParent() { Vector2D offset; - CPopup* current = this; + if (!m_pResource) + return {}; - offset -= {m_pWLR->base->current.geometry.x, m_pWLR->base->current.geometry.y}; + CPopup* current = this; + offset -= current->m_pResource->surface->current.geometry.pos(); - while (current->m_pParent) { + offset -= m_pResource->surface->current.geometry.pos(); + + while (current->m_pParent && current->m_pResource) { offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; - offset += {current->m_pWLR->current.geometry.x, current->m_pWLR->current.geometry.y}; + offset += current->m_pResource->geometry.pos(); current = current->m_pParent; } @@ -309,7 +289,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); for (auto& p : popups | std::views::reverse) { - if (!p->m_pWLR) + if (!p->m_pResource) continue; if (!allowsInput) { diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 6aa7ce61..e6c35e68 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -5,6 +5,8 @@ #include "Subsurface.hpp" #include "../helpers/signal/Listener.hpp" +class CXDGPopupResource; + class CPopup { public: // dummy head nodes @@ -12,7 +14,7 @@ class CPopup { CPopup(PHLLS pOwner); // real nodes - CPopup(wlr_xdg_popup* popup, CPopup* pOwner); + CPopup(SP popup, CPopup* pOwner); ~CPopup(); @@ -21,7 +23,7 @@ class CPopup { Vector2D size(); - void onNewPopup(wlr_xdg_popup* popup); + void onNewPopup(SP popup); void onDestroy(); void onMap(); void onUnmap(); @@ -45,31 +47,28 @@ class CPopup { PHLLSREF m_pLayerOwner; // T2 owners - CPopup* m_pParent = nullptr; + CPopup* m_pParent = nullptr; - wlr_xdg_popup* m_pWLR = nullptr; + WP m_pResource; - Vector2D m_vLastSize = {}; - Vector2D m_vLastPos = {}; + Vector2D m_vLastSize = {}; + Vector2D m_vLastPos = {}; - bool m_bRequestedReposition = false; + bool m_bRequestedReposition = false; - bool m_bInert = false; + bool m_bInert = false; // std::vector> m_vChildren; std::unique_ptr m_pSubsurfaceHead; - // signals - DYNLISTENER(newPopup); - DYNLISTENER(destroyPopup); - DYNLISTENER(mapPopup); - DYNLISTENER(unmapPopup); - DYNLISTENER(commitPopup); - DYNLISTENER(repositionPopup); - struct { CHyprSignalListener newPopup; + CHyprSignalListener destroy; + CHyprSignalListener map; + CHyprSignalListener unmap; + CHyprSignalListener commit; + CHyprSignalListener reposition; } listeners; void initAllSignals(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e87bd99c..c11a714b 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -6,6 +6,7 @@ #include "../config/ConfigValue.hpp" #include #include "../managers/TokenManager.hpp" +#include "../protocols/XDGShell.hpp" PHLWINDOW CWindow::create() { PHLWINDOW pWindow = SP(new CWindow); @@ -27,6 +28,39 @@ PHLWINDOW CWindow::create() { return pWindow; } +PHLWINDOW CWindow::create(SP resource) { + PHLWINDOW pWindow = SP(new CWindow(resource)); + + pWindow->m_pSelf = pWindow; + resource->toplevel->window = pWindow; + + pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); + pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); + pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); + pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + + pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(std::make_unique(pWindow)); + + pWindow->m_pWLSurface.assign(pWindow->m_pXDGSurface->surface, pWindow); + + return pWindow; +} + +CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { + listeners.map = m_pXDGSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); + listeners.ack = m_pXDGSurface->events.ack.registerListener([this](std::any d) { onAck(std::any_cast(d)); }); + listeners.unmap = m_pXDGSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); + listeners.destroy = m_pXDGSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); + listeners.commit = m_pXDGSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); + listeners.updateState = m_pXDGSurface->toplevel->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); + listeners.updateMetadata = m_pXDGSurface->toplevel->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); +} + CWindow::CWindow() { ; } @@ -74,21 +108,24 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - if (m_pWLSurface.exists() && !m_bIsX11) { + if (m_pWLSurface.exists() && !m_bIsX11 && m_pPopupHead) { CBox surfaceExtents = {0, 0, 0, 0}; // TODO: this could be better, perhaps make a getFullWindowRegion? - wlr_xdg_surface_for_each_popup_surface( - m_uSurface.xdg, - [](wlr_surface* surf, int sx, int sy, void* data) { + m_pPopupHead->breadthfirst( + [](CPopup* popup, void* data) { + if (!popup->m_sWLSurface.wlr()) + return; + CBox* pSurfaceExtents = (CBox*)data; - if (sx < pSurfaceExtents->x) - pSurfaceExtents->x = sx; - if (sy < pSurfaceExtents->y) - pSurfaceExtents->y = sy; - if (sx + surf->current.width > pSurfaceExtents->width) - pSurfaceExtents->width = sx + surf->current.width - pSurfaceExtents->x; - if (sy + surf->current.height > pSurfaceExtents->height) - pSurfaceExtents->height = sy + surf->current.height - pSurfaceExtents->y; + CBox surf = CBox{popup->coordsRelativeToParent(), popup->size()}; + if (surf.x < pSurfaceExtents->x) + pSurfaceExtents->x = surf.x; + if (surf.y < pSurfaceExtents->y) + pSurfaceExtents->y = surf.y; + if (surf.x + surf.w > pSurfaceExtents->width) + pSurfaceExtents->width = surf.x + surf.w - pSurfaceExtents->x; + if (surf.y + surf.h > pSurfaceExtents->height) + pSurfaceExtents->height = surf.y + surf.h - pSurfaceExtents->y; }, &surfaceExtents); @@ -258,10 +295,10 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor pid_t CWindow::getPID() { pid_t PID = -1; if (!m_bIsX11) { - if (!m_uSurface.xdg) + if (!m_pXDGSurface || !m_pXDGSurface->owner /* happens at unmap */) return -1; - wl_client_get_credentials(wl_resource_get_client(m_uSurface.xdg->resource), &PID, nullptr, nullptr); + wl_client_get_credentials(m_pXDGSurface->owner->client(), &PID, nullptr, nullptr); } else { if (!m_uSurface.xwayland) return -1; @@ -511,8 +548,8 @@ void CWindow::onMap() { g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); - hyprListener_unmapWindow.initCallback(m_bIsX11 ? &m_uSurface.xwayland->surface->events.unmap : &m_uSurface.xdg->surface->events.unmap, &Events::listener_unmapWindow, this, - "CWindow"); + if (m_bIsX11) + hyprListener_unmapWindow.initCallback(&m_uSurface.xwayland->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow"); m_vReportedSize = m_vPendingReportedSize; m_bAnimatingIn = true; @@ -793,26 +830,14 @@ bool CWindow::isInCurvedCorner(double x, double y) { return false; } -void findExtensionForVector2D(wlr_surface* surface, int x, int y, void* data) { - const auto DATA = (SExtensionFindingData*)data; - - CBox box = {DATA->origin.x + x, DATA->origin.y + y, surface->current.width, surface->current.height}; - - if (box.containsPoint(DATA->vec)) - *DATA->found = surface; -} - // checks if the wayland window has a popup at pos bool CWindow::hasPopupAt(const Vector2D& pos) { if (m_bIsX11) return false; - wlr_surface* resultSurf = nullptr; - Vector2D origin = m_vRealPosition.value(); - SExtensionFindingData data = {origin, pos, &resultSurf}; - wlr_xdg_surface_for_each_popup_surface(m_uSurface.xdg, findExtensionForVector2D, &data); + CPopup* popup = m_pPopupHead->at(pos); - return resultSurf; + return popup && popup->m_sWLSurface.wlr(); } void CWindow::applyGroupRules() { @@ -1096,11 +1121,11 @@ bool CWindow::opaque() { if (m_bIsX11) return !m_uSurface.xwayland->has_alpha; - if (m_uSurface.xdg->surface->opaque) + if (m_pXDGSurface->surface->opaque) return true; - const auto EXTENTS = pixman_region32_extents(&m_uSurface.xdg->surface->opaque_region); - if (EXTENTS->x2 - EXTENTS->x1 >= m_uSurface.xdg->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_uSurface.xdg->surface->current.buffer_height) + const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region); + if (EXTENTS->x2 - EXTENTS->x1 >= m_pXDGSurface->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_pXDGSurface->surface->current.buffer_height) return true; return false; @@ -1162,10 +1187,10 @@ void CWindow::setSuspended(bool suspend) { if (suspend == m_bSuspended) return; - if (m_bIsX11) + if (m_bIsX11 || !m_pXDGSurface->toplevel) return; - wlr_xdg_toplevel_set_suspended(m_uSurface.xdg->toplevel, suspend); + m_pXDGSurface->toplevel->setSuspeneded(suspend); m_bSuspended = suspend; } @@ -1221,12 +1246,21 @@ void CWindow::onWorkspaceAnimUpdate() { } int CWindow::popupsCount() { + if (m_bIsX11) + return 0; + + int no = -1; + m_pPopupHead->breadthfirst([](CPopup* p, void* d) { *((int*)d) += 1; }, &no); + return no; +} + +int CWindow::surfacesCount() { if (m_bIsX11) return 1; int no = 0; - wlr_xdg_surface_for_each_popup_surface( - m_uSurface.xdg, [](wlr_surface* s, int x, int y, void* data) { *(int*)data += 1; }, &no); + wlr_surface_for_each_surface( + m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { *((int*)data) += 1; }, &no); return no; } @@ -1278,6 +1312,9 @@ std::unordered_map CWindow::getEnv() { } void CWindow::activate(bool force) { + if (g_pCompositor->m_pLastWindow == m_pSelf) + return; + static auto PFOCUSONACTIVATE = CConfigValue("misc:focus_on_activate"); g_pEventManager->postEvent(SHyprIPCEvent{"urgent", std::format("{:x}", (uintptr_t)this)}); @@ -1295,3 +1332,98 @@ void CWindow::activate(bool force) { g_pCompositor->focusWindow(m_pSelf.lock()); g_pCompositor->warpCursorTo(middle()); } + +void CWindow::onUpdateState() { + if (!m_pXDGSurface) + return; + + if (m_pXDGSurface->toplevel->state.requestsFullscreen) { + bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value(); + + if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) + g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL); + + if (!m_pXDGSurface->mapped) + m_bWantsInitialFullscreen = fs; + } + + if (m_pXDGSurface->toplevel->state.requestsMaximize) { + bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value(); + + if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) + g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED); + } +} + +void CWindow::onUpdateMeta() { + const auto NEWTITLE = fetchTitle(); + + if (m_szTitle != NEWTITLE) { + m_szTitle = NEWTITLE; + g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)}); + EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock()); + + if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others + g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", m_szClass + "," + m_szTitle}); + g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)this)}); + EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock()); + } + + updateDynamicRules(); + g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock()); + updateToplevel(); + + Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle); + } + + const auto NEWCLASS = fetchClass(); + if (m_szClass != NEWCLASS) { + m_szClass = NEWCLASS; + + if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others + g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", m_szClass + "," + m_szTitle}); + g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)this)}); + EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock()); + } + + updateDynamicRules(); + g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock()); + updateToplevel(); + + Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass); + } +} + +std::string CWindow::fetchTitle() { + if (!m_bIsX11) { + if (m_pXDGSurface && m_pXDGSurface->toplevel) + return m_pXDGSurface->toplevel->state.title; + } else { + if (m_uSurface.xwayland && m_uSurface.xwayland->title) + return m_uSurface.xwayland->title; + } + + return ""; +} + +std::string CWindow::fetchClass() { + if (!m_bIsX11) { + if (m_pXDGSurface && m_pXDGSurface->toplevel) + return m_pXDGSurface->toplevel->state.appid; + } else { + if (m_uSurface.xwayland && m_uSurface.xwayland->_class) + return m_uSurface.xwayland->_class; + } + + return ""; +} + +void CWindow::onAck(uint32_t serial) { + const auto SERIAL = std::find_if(m_vPendingSizeAcks.rbegin(), m_vPendingSizeAcks.rend(), [serial](const auto& e) { return e.first == serial; }); + + if (SERIAL == m_vPendingSizeAcks.rend()) + return; + + m_pPendingSizeAck = *SERIAL; + std::erase_if(m_vPendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; }); +} \ No newline at end of file diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 6bff095c..24d9562b 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -14,6 +14,8 @@ #include "DesktopTypes.hpp" #include "../helpers/signal/Signal.hpp" +class CXDGSurfaceResource; + enum eIdleInhibitMode { IDLEINHIBIT_NONE = 0, IDLEINHIBIT_ALWAYS, @@ -196,9 +198,12 @@ struct SInitialWorkspaceToken { class CWindow { public: + static PHLWINDOW create(SP); + // xwl static PHLWINDOW create(); private: + CWindow(SP resource); CWindow(); public: @@ -233,9 +238,9 @@ class CWindow { } events; union { - wlr_xdg_surface* xdg; wlr_xwayland_surface* xwayland; } m_uSurface; + WP m_pXDGSurface; // this is the position and size of the "bounding box" Vector2D m_vPosition = Vector2D(0, 0); @@ -271,6 +276,7 @@ class CWindow { bool m_bWasMaximized = false; uint64_t m_iMonitorID = -1; std::string m_szTitle = ""; + std::string m_szClass = ""; std::string m_szInitialTitle = ""; std::string m_szInitialClass = ""; PHLWORKSPACE m_pWorkspace; @@ -385,7 +391,7 @@ class CWindow { // For the list lookup bool operator==(const CWindow& rhs) { - return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && + return m_pXDGSurface == rhs.m_pXDGSurface && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; } @@ -424,6 +430,7 @@ class CWindow { int workspaceID(); bool onSpecialWorkspace(); void activate(bool force = false); + int surfacesCount(); int getRealBorderSize(); void updateSpecialRenderData(); @@ -450,6 +457,13 @@ class CWindow { void switchWithWindowInGroup(PHLWINDOW pWindow); void setAnimationsToMove(); void onWorkspaceAnimUpdate(); + void onUpdateState(); + void onUpdateMeta(); + std::string fetchTitle(); + std::string fetchClass(); + + // listeners + void onAck(uint32_t serial); // std::unordered_map getEnv(); @@ -457,6 +471,17 @@ class CWindow { // PHLWINDOWREF m_pSelf; + // make private once we move listeners to inside CWindow + struct { + CHyprSignalListener map; + CHyprSignalListener ack; + CHyprSignalListener unmap; + CHyprSignalListener commit; + CHyprSignalListener destroy; + CHyprSignalListener updateState; + CHyprSignalListener updateMetadata; + } listeners; + private: // For hidden windows and stuff bool m_bHidden = false; @@ -520,7 +545,7 @@ struct std::formatter : std::formatter { if (formatMonitor) std::format_to(out, ", monitor: {}", w->m_iMonitorID); if (formatClass) - std::format_to(out, ", class: {}", g_pXWaylandManager->getAppIDClass(w)); + std::format_to(out, ", class: {}", w->m_szClass); return std::format_to(out, "]"); } }; diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 2e627d39..7cc0eb32 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -18,9 +18,6 @@ namespace Events { // Layer events LISTENER(newLayerSurface); - // Surface XDG (window) - LISTENER(newXDGToplevel); - // Window events DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(mapWindow); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index b85ed6e1..384ea9ed 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -8,6 +8,7 @@ #include "../render/Renderer.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/XDGShell.hpp" // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -25,11 +26,10 @@ void addViewCoords(void* pWindow, int* x, int* y) { *y += PWINDOW->m_vRealPosition.goal().y; if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) { - wlr_box geom; - wlr_xdg_surface_get_geometry(PWINDOW->m_uSurface.xdg, &geom); + Vector2D pos = PWINDOW->m_pXDGSurface->current.geometry.pos(); - *x -= geom.x; - *y -= geom.y; + *x -= pos.x; + *y -= pos.y; } } @@ -67,11 +67,11 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bIsMapped = true; PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bFadingOut = false; - PWINDOW->m_szTitle = g_pXWaylandManager->getTitle(PWINDOW); + PWINDOW->m_szTitle = PWINDOW->fetchTitle(); PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1; PWINDOW->m_bFirstMap = true; PWINDOW->m_szInitialTitle = PWINDOW->m_szTitle; - PWINDOW->m_szInitialClass = g_pXWaylandManager->getAppIDClass(PWINDOW); + PWINDOW->m_szInitialClass = PWINDOW->fetchClass(); // check for token std::string requestedWorkspace = ""; @@ -111,9 +111,6 @@ void Events::listener_mapWindow(void* owner, void* data) { if (g_pInputManager->m_bLastFocusOnLS) // waybar fix g_pInputManager->releaseAllMouseButtons(); - // Set all windows tiled regardless of anything - g_pXWaylandManager->setWindowStyleTiled(PWINDOW, WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM); - // checks if the window wants borders and sets the appropriate flag g_pXWaylandManager->checkBorders(PWINDOW); @@ -146,10 +143,8 @@ void Events::listener_mapWindow(void* owner, void* data) { } // window rules - PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); - bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || - (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL && PWINDOW->m_uSurface.xdg->toplevel->requested.fullscreen) || - (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen); + PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); + bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen); bool requestsFakeFullscreen = false; bool requestsMaximize = false; bool overridingNoFullscreen = false; @@ -508,19 +503,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_fDimPercent.setValueAndWarp(0); } - if (!PWINDOW->m_bIsX11) { - PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.set_title, &Events::listener_setTitleWindow, PWINDOW.get(), "XDG Window Late"); - PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_maximize, &Events::listener_requestMaximize, PWINDOW.get(), - "XDG Window Late"); - PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_minimize, &Events::listener_requestMinimize, PWINDOW.get(), - "XDG Window Late"); - PWINDOW->hyprListener_requestMove.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_move, &Events::listener_requestMove, PWINDOW.get(), "XDG Window Late"); - PWINDOW->hyprListener_requestResize.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_resize, &Events::listener_requestResize, PWINDOW.get(), - "XDG Window Late"); - PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xdg->toplevel->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(), - "XDG Window Late"); - PWINDOW->hyprListener_ackConfigure.initCallback(&PWINDOW->m_uSurface.xdg->events.ack_configure, &Events::listener_ackConfigure, PWINDOW.get(), "XDG Window Late"); - } else { + if (PWINDOW->m_bIsX11) { PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(), "XWayland Window Late"); PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW.get(), @@ -573,7 +556,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) { // don't swallow ourselves std::regex rgx(*PSWALLOWREGEX); - if (!std::regex_match(g_pXWaylandManager->getAppIDClass(PWINDOW), rgx)) { + if (!std::regex_match(PWINDOW->m_szClass, rgx)) { // check parent int ppid = getPPIDof(PWINDOW->getPID()); @@ -615,12 +598,12 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (finalFound) { - bool valid = std::regex_match(g_pXWaylandManager->getAppIDClass(finalFound), rgx); + bool valid = std::regex_match(PWINDOW->m_szClass, rgx); if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) { std::regex exc(*PSWALLOWEXREGEX); - valid = valid && !std::regex_match(g_pXWaylandManager->getTitle(finalFound), exc); + valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc); } // check if it's the window we want & not exempt from getting swallowed @@ -644,7 +627,7 @@ void Events::listener_mapWindow(void* owner, void* data) { Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal()); auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; - g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, g_pXWaylandManager->getAppIDClass(PWINDOW), PWINDOW->m_szTitle)}); + g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)}); EMIT_HOOK_EVENT("openWindow", PWINDOW); // apply data from default decos. Borders, shadows. @@ -705,15 +688,6 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW); if (!PWINDOW->m_bIsX11) { - Debug::log(LOG, "Unregistered late callbacks XDG"); - PWINDOW->hyprListener_setTitleWindow.removeCallback(); - PWINDOW->hyprListener_requestMaximize.removeCallback(); - PWINDOW->hyprListener_requestMinimize.removeCallback(); - PWINDOW->hyprListener_requestMove.removeCallback(); - PWINDOW->hyprListener_requestResize.removeCallback(); - PWINDOW->hyprListener_fullscreenWindow.removeCallback(); - PWINDOW->hyprListener_ackConfigure.removeCallback(); - } else { Debug::log(LOG, "Unregistered late callbacks XWL"); PWINDOW->hyprListener_fullscreenWindow.removeCallback(); PWINDOW->hyprListener_activateX11.removeCallback(); @@ -804,29 +778,15 @@ void Events::listener_unmapWindow(void* owner, void* data) { PWINDOW->onUnmap(); } -void Events::listener_ackConfigure(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - const auto E = (wlr_xdg_surface_configure*)data; - - // find last matching serial - const auto SERIAL = std::find_if(PWINDOW->m_vPendingSizeAcks.rbegin(), PWINDOW->m_vPendingSizeAcks.rend(), [&](const auto& e) { return e.first == E->serial; }); - - if (SERIAL == PWINDOW->m_vPendingSizeAcks.rend()) - return; - - PWINDOW->m_pPendingSizeAck = *SERIAL; - std::erase_if(PWINDOW->m_vPendingSizeAcks, [&](const auto& el) { return el.first == SERIAL->first; }); -} - void Events::listener_commitWindow(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - if (!PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xdg->initial_commit) { + if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface->initialCommit) { Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(PWINDOW); Debug::log(LOG, "Layout predicts size {} for {}", predSize, PWINDOW); - wlr_xdg_toplevel_set_size(PWINDOW->m_uSurface.xdg->toplevel, predSize.x, predSize.y); + PWINDOW->m_pXDGSurface->toplevel->setSize(predSize); return; } @@ -841,8 +801,8 @@ void Events::listener_commitWindow(void* owner, void* data) { } if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { - const auto MINSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.min_width, PWINDOW->m_uSurface.xdg->toplevel->current.min_height}; - const auto MAXSIZE = Vector2D{PWINDOW->m_uSurface.xdg->toplevel->current.max_width, PWINDOW->m_uSurface.xdg->toplevel->current.max_height}; + const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; + const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; if (MAXSIZE > Vector2D{1, 1}) { const auto REALSIZE = PWINDOW->m_vRealSize.goal(); @@ -861,7 +821,7 @@ void Events::listener_commitWindow(void* owner, void* data) { PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0; PWINDOW->m_vRealSize = newSize; - g_pXWaylandManager->setWindowSize(PWINDOW, newSize, true); + g_pXWaylandManager->setWindowSize(PWINDOW, newSize); g_pHyprRenderer->damageWindow(PWINDOW); } } @@ -918,11 +878,13 @@ void Events::listener_destroyWindow(void* owner, void* data) { PWINDOW->hyprListener_associateX11.removeCallback(); PWINDOW->hyprListener_dissociateX11.removeCallback(); + PWINDOW->listeners = {}; + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); PWINDOW->m_bReadyToDelete = true; - PWINDOW->m_uSurface.xdg = nullptr; + PWINDOW->m_pXDGSurface.reset(); if (!PWINDOW->m_bFadingOut) { Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); @@ -936,31 +898,14 @@ void Events::listener_setTitleWindow(void* owner, void* data) { if (!validMapped(PWINDOW)) return; - const auto NEWTITLE = g_pXWaylandManager->getTitle(PWINDOW); - - if (NEWTITLE == PWINDOW->m_szTitle) - return; - - PWINDOW->m_szTitle = NEWTITLE; - g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)PWINDOW.get())}); - EMIT_HOOK_EVENT("windowTitle", PWINDOW); - - if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { // if it's the active, let's post an event to update others - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", g_pXWaylandManager->getAppIDClass(PWINDOW) + "," + PWINDOW->m_szTitle}); - g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)PWINDOW.get())}); - EMIT_HOOK_EVENT("activeWindow", PWINDOW); - } - - PWINDOW->updateDynamicRules(); - g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); - PWINDOW->updateToplevel(); - - Debug::log(LOG, "Window {:x} set title to {}", PWINDOW, PWINDOW->m_szTitle); + PWINDOW->onUpdateMeta(); } void Events::listener_fullscreenWindow(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); + // x11 only + if (!PWINDOW->m_bIsMapped) { PWINDOW->m_bWantsInitialFullscreen = true; return; @@ -971,41 +916,13 @@ void Events::listener_fullscreenWindow(void* owner, void* data) { bool requestedFullState = false; - if (!PWINDOW->m_bIsX11) { - const auto REQUESTED = &PWINDOW->m_uSurface.xdg->toplevel->requested; + if (!PWINDOW->m_uSurface.xwayland->surface->mapped) + return; - if (REQUESTED->fullscreen && PWINDOW->m_bIsFullscreen) { - const auto PWORKSPACE = PWINDOW->m_pWorkspace; - if (PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) { - // Store that we were maximized - PWINDOW->m_bWasMaximized = true; - g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_MAXIMIZED); - g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); - } else - PWINDOW->m_bWasMaximized = false; - } else if (REQUESTED->fullscreen != PWINDOW->m_bIsFullscreen && !PWINDOW->m_bFakeFullscreenState) { - g_pCompositor->setWindowFullscreen(PWINDOW, REQUESTED->fullscreen, FULLSCREEN_FULL); - if (PWINDOW->m_bWasMaximized && !REQUESTED->fullscreen) { - // Was maximized before the fullscreen request, return now back to maximized instead of normal - g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_MAXIMIZED); - } - } + if (!PWINDOW->m_bFakeFullscreenState) + g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL); - // Disable the maximize flag when we receive a de-fullscreen request - PWINDOW->m_bWasMaximized &= REQUESTED->fullscreen; - - requestedFullState = REQUESTED->fullscreen; - - wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); - } else { - if (!PWINDOW->m_uSurface.xwayland->surface->mapped) - return; - - if (!PWINDOW->m_bFakeFullscreenState) - g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL); - - requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen; - } + requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen; if (!requestedFullState && PWINDOW->m_bFakeFullscreenState) { g_pXWaylandManager->setWindowFullscreen(PWINDOW, false); // fixes for apps expecting a de-fullscreen (e.g. ff) @@ -1177,7 +1094,7 @@ void Events::listener_associateX11(void* owner, void* data) { PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW.get(), "XWayland Window"); PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW.get(), "XWayland Window"); - PWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PWINDOW), PWINDOW); + PWINDOW->m_pWLSurface.assign(PWINDOW->m_uSurface.xwayland->surface, PWINDOW); } void Events::listener_dissociateX11(void* owner, void* data) { @@ -1211,23 +1128,6 @@ void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW.get(), "XWayland Window"); } -void Events::listener_newXDGToplevel(wl_listener* listener, void* data) { - // A window got opened - const auto XDGTOPLEVEL = (wlr_xdg_toplevel*)data; - const auto XDGSURFACE = XDGTOPLEVEL->base; - - Debug::log(LOG, "New XDG Toplevel created. (class: {})", XDGSURFACE->toplevel->app_id ? XDGSURFACE->toplevel->app_id : "null"); - - const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(CWindow::create()); - PNEWWINDOW->m_uSurface.xdg = XDGSURFACE; - - PNEWWINDOW->hyprListener_mapWindow.initCallback(&XDGSURFACE->surface->events.map, &Events::listener_mapWindow, PNEWWINDOW.get(), "XDG Window"); - PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XDGSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW.get(), "XDG Window"); - PNEWWINDOW->hyprListener_commitWindow.initCallback(&XDGSURFACE->surface->events.commit, &Events::listener_commitWindow, PNEWWINDOW.get(), "XDG Window"); - - PNEWWINDOW->m_pWLSurface.assign(g_pXWaylandManager->getWindowSurface(PNEWWINDOW), PNEWWINDOW); -} - void Events::listener_requestMaximize(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); @@ -1240,7 +1140,6 @@ void Events::listener_requestMaximize(void* owner, void* data) { 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); } else { if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1) return; @@ -1269,17 +1168,3 @@ void Events::listener_requestMinimize(void* owner, void* data) { EMIT_HOOK_EVENT("minimize", (std::vector{PWINDOW, (int64_t)(1)})); } } - -void Events::listener_requestMove(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - // ignore - wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); -} - -void Events::listener_requestResize(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - // ignore - wlr_xdg_surface_schedule_configure(PWINDOW->m_uSurface.xdg); -} diff --git a/src/includes.hpp b/src/includes.hpp index c75796b9..dfbe0221 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -52,8 +52,6 @@ extern "C" { #include #include #include -#include -#include #include #include #include diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 6f7252d2..a31180e1 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -4,6 +4,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" +#include "../protocols/XDGShell.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { if (pWindow->m_bIsFloating) { @@ -140,8 +141,12 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { // TODO: detect a popup in a more consistent way. if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_bIsX11) { - // if it's not, fall back to the center placement - pWindow->m_vRealPosition = PMONITOR->vecPosition + Vector2D((PMONITOR->vecSize.x - desiredGeometry.width) / 2.f, (PMONITOR->vecSize.y - desiredGeometry.height) / 2.f); + // if the pos isn't set, fall back to the center placement if it's not a child, otherwise middle of parent if available + if (!pWindow->m_bIsX11 && pWindow->m_pXDGSurface->toplevel->parent && validMapped(pWindow->m_pXDGSurface->toplevel->parent->window)) + pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() + + pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F; + else + pWindow->m_vRealPosition = PMONITOR->vecPosition + desiredGeometry.size() / 2.F; } else { // if it is, we respect where it wants to put itself, but apply monitor offset if outside // most of these are popups @@ -693,7 +698,7 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) { else sizePredicted = predictSizeForNewWindowFloating(pWindow); - Vector2D maxSize = Vector2D{pWindow->m_uSurface.xdg->toplevel->pending.max_width, pWindow->m_uSurface.xdg->toplevel->pending.max_height}; + Vector2D maxSize = pWindow->m_pXDGSurface->toplevel->pending.maxSize; if ((maxSize.x > 0 && maxSize.x < sizePredicted.x) || (maxSize.y > 0 && maxSize.y < sizePredicted.y)) sizePredicted = {}; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index f853e16f..e53eb111 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -29,6 +29,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/core/Seat.hpp" +#include "../protocols/XDGShell.hpp" CProtocolManager::CProtocolManager() { @@ -64,6 +65,7 @@ CProtocolManager::CProtocolManager() { PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); PROTO::presentation = std::make_unique(&wp_presentation_interface, 1, "Presentation"); + PROTO::xdgShell = std::make_unique(&xdg_wm_base_interface, 6, "XDGShell"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 423c45ca..390c6ece 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../events/Events.hpp" #include "../config/ConfigValue.hpp" +#include "../protocols/XDGShell.hpp" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 @@ -34,27 +35,32 @@ CHyprXWaylandManager::~CHyprXWaylandManager() { } wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { - if (pWindow->m_bIsX11) - return pWindow->m_uSurface.xwayland->surface; - - return pWindow->m_uSurface.xdg->surface; + return pWindow->m_pWLSurface.wlr(); } void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) { if (!pSurface) return; - if (wlr_xdg_surface_try_from_wlr_surface(pSurface)) { - if (const auto PSURF = wlr_xdg_surface_try_from_wlr_surface(pSurface); PSURF && PSURF->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) - wlr_xdg_toplevel_set_activated(PSURF->toplevel, activate); - - } else if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) { + if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) { const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface); wlr_xwayland_surface_activate(XSURF, activate); if (activate && !XSURF->override_redirect) wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE); } + + // TODO: + // this cannot be nicely done until we rewrite wlr_surface + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bIsX11 || !w->m_bIsMapped) + continue; + + if (w->m_pWLSurface.wlr() != pSurface) + continue; + + w->m_pXDGSurface->toplevel->setActive(activate); + } } void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { @@ -68,8 +74,8 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { } wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate); - } else - wlr_xdg_toplevel_set_activated(pWindow->m_uSurface.xdg->toplevel, activate); + } else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) + pWindow->m_pXDGSurface->toplevel->setActive(activate); if (activate) { g_pCompositor->m_pLastFocus = getWindowSurface(pWindow); @@ -95,64 +101,15 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { pbox->width = pWindow->m_uSurface.xwayland->width; pbox->height = pWindow->m_uSurface.xwayland->height; } - } else { - wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, pbox->pWlr()); - pbox->applyFromWlr(); - } -} - -std::string CHyprXWaylandManager::getTitle(PHLWINDOW pWindow) { - try { - if (pWindow->m_bIsX11) { - if (!pWindow->m_bIsMapped) - return ""; - - if (pWindow->m_uSurface.xwayland && pWindow->m_uSurface.xwayland->title) { - return std::string(pWindow->m_uSurface.xwayland->title); - } - } else if (pWindow->m_uSurface.xdg) { - if (pWindow->m_bFadingOut || !pWindow->m_uSurface.xdg) - return ""; - - if (pWindow->m_uSurface.xdg->toplevel && pWindow->m_uSurface.xdg->toplevel->title) { - return std::string(pWindow->m_uSurface.xdg->toplevel->title); - } - } else { - return ""; - } - } catch (...) { Debug::log(ERR, "Error in getTitle (probably null title)"); } - - return ""; -} - -std::string CHyprXWaylandManager::getAppIDClass(PHLWINDOW pWindow) { - try { - if (pWindow->m_bIsX11) { - if (!pWindow->m_bIsMapped) - return ""; - - if (pWindow->m_uSurface.xwayland && pWindow->m_uSurface.xwayland->_class) { - return std::string(pWindow->m_uSurface.xwayland->_class); - } - } else if (pWindow->m_uSurface.xdg) { - if (pWindow->m_bFadingOut || !pWindow->m_uSurface.xdg) - return ""; - - if (pWindow->m_uSurface.xdg->toplevel && pWindow->m_uSurface.xdg->toplevel->app_id) { - return std::string(pWindow->m_uSurface.xdg->toplevel->app_id); - } - } else - return ""; - } catch (std::logic_error& e) { Debug::log(ERR, "Error in getAppIDClass: {}", e.what()); } - - return ""; + } else if (pWindow->m_pXDGSurface) + *pbox = pWindow->m_pXDGSurface->current.geometry; } void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) { if (pWindow->m_bIsX11) wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland); - else - wlr_xdg_toplevel_send_close(pWindow->m_uSurface.xdg->toplevel); + else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) + pWindow->m_pXDGSurface->toplevel->close(); } void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool force) { @@ -189,23 +146,12 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool if (pWindow->m_bIsX11) wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y); - else - pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(wlr_xdg_toplevel_set_size(pWindow->m_uSurface.xdg->toplevel, size.x, size.y), size.floor())); -} - -void CHyprXWaylandManager::setWindowStyleTiled(PHLWINDOW pWindow, uint32_t edgez) { - if (pWindow->m_bIsX11) - return; - - wlr_xdg_toplevel_set_tiled(pWindow->m_uSurface.xdg->toplevel, edgez); - wlr_xdg_toplevel_set_maximized(pWindow->m_uSurface.xdg->toplevel, true); + else if (pWindow->m_pXDGSurface->toplevel) + pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); } wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& client, Vector2D& surface) { - if (pWindow->m_bIsX11) - return wlr_surface_surface_at(pWindow->m_uSurface.xwayland->surface, client.x, client.y, &surface.x, &surface.y); - - return wlr_xdg_surface_surface_at(pWindow->m_uSurface.xdg, client.x, client.y, &surface.x, &surface.y); + return wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), client.x, client.y, &surface.x, &surface.y); } bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { @@ -251,10 +197,10 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (SIZEHINTS && (pWindow->m_uSurface.xwayland->parent || ((SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height)))) return true; } else { - const auto PSTATE = pending ? &pWindow->m_uSurface.xdg->toplevel->pending : &pWindow->m_uSurface.xdg->toplevel->current; + const auto PSTATE = pending ? &pWindow->m_pXDGSurface->toplevel->pending : &pWindow->m_pXDGSurface->toplevel->current; - if ((PSTATE->min_width != 0 && PSTATE->min_height != 0 && (PSTATE->min_width == PSTATE->max_width || PSTATE->min_height == PSTATE->max_height)) || - pWindow->m_uSurface.xdg->toplevel->parent) + if (pWindow->m_pXDGSurface->toplevel->parent || + (PSTATE->minSize.x != 0 && PSTATE->minSize.y != 0 && (PSTATE->minSize.x == PSTATE->maxSize.x || PSTATE->minSize.y == PSTATE->maxSize.y))) return true; } @@ -297,20 +243,19 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { if (pWindow->m_bIsX11) wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen); - else - wlr_xdg_toplevel_set_fullscreen(pWindow->m_uSurface.xdg->toplevel, fullscreen); + else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) + pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen); } Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return Vector2D(99999, 99999); - if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel) || - pWindow->m_sAdditionalConfigData.noMaxSize) + if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize) return Vector2D(99999, 99999); auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) : - Vector2D(pWindow->m_uSurface.xdg->toplevel->current.max_width, pWindow->m_uSurface.xdg->toplevel->current.max_height); + pWindow->m_pXDGSurface->toplevel->current.maxSize; if (MAXSIZE.x < 5) MAXSIZE.x = 99999; @@ -324,11 +269,11 @@ Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return Vector2D(0, 0); - if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_uSurface.xdg->toplevel)) + if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel)) return Vector2D(0, 0); auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->min_width, pWindow->m_uSurface.xwayland->size_hints->min_height) : - Vector2D(pWindow->m_uSurface.xdg->toplevel->current.min_width, pWindow->m_uSurface.xdg->toplevel->current.min_height); + pWindow->m_pXDGSurface->toplevel->current.minSize; MINSIZE = MINSIZE.clamp({1, 1}); diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 6edadd71..8889eb61 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -17,11 +17,8 @@ class CHyprXWaylandManager { void activateSurface(wlr_surface*, bool); void activateWindow(PHLWINDOW, bool); void getGeometryForWindow(PHLWINDOW, CBox*); - std::string getTitle(PHLWINDOW); - std::string getAppIDClass(PHLWINDOW); void sendCloseWindow(PHLWINDOW); void setWindowSize(PHLWINDOW, Vector2D, bool force = false); - void setWindowStyleTiled(PHLWINDOW, uint32_t); void setWindowFullscreen(PHLWINDOW, bool); wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&); bool shouldBeFloated(PHLWINDOW, bool pending = false); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 62d9e687..bb0ab65a 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -15,6 +15,7 @@ #include "../../protocols/VirtualPointer.hpp" #include "../../protocols/LayerShell.hpp" #include "../../protocols/core/Seat.hpp" +#include "../../protocols/XDGShell.hpp" #include "../../devices/Mouse.hpp" #include "../../devices/VirtualPointer.hpp" @@ -387,10 +388,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (pFoundWindow && !pFoundWindow->m_bIsX11 && surfacePos != Vector2D(-1337, -1337)) { // calc for oversized windows... fucking bullshit. - wlr_box geom; - wlr_xdg_surface_get_geometry(pFoundWindow->m_uSurface.xdg, &geom); + CBox geom = pFoundWindow->m_pXDGSurface->current.geometry; - surfaceLocal = mouseCoords - surfacePos + Vector2D(geom.x, geom.y); + surfaceLocal = mouseCoords - surfacePos + geom.pos(); } if (pFoundWindow && pFoundWindow->m_bIsX11) // for x11 force scale zero diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 0d2a7e57..40420da7 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -91,7 +91,7 @@ void CForeignToplevelList::onClass(PHLWINDOW pWindow) { if (!H || H->closed) return; - H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); + H->resource->sendAppId(pWindow->m_szClass.c_str()); } void CForeignToplevelList::onUnmap(PHLWINDOW pWindow) { diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 1762ad2a..782fbc0e 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -195,7 +195,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { LOGM(LOG, "Newly mapped window {:016x}", (uintptr_t)pWindow.get()); resource->sendToplevel(NEWHANDLE->resource.get()); - NEWHANDLE->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); + NEWHANDLE->resource->sendAppId(pWindow->m_szClass.c_str()); NEWHANDLE->resource->sendTitle(pWindow->m_szTitle.c_str()); if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) NEWHANDLE->sendMonitor(PMONITOR); @@ -231,7 +231,7 @@ void CForeignToplevelWlrManager::onClass(PHLWINDOW pWindow) { if (!H || H->closed) return; - H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); + H->resource->sendAppId(pWindow->m_szClass.c_str()); H->resource->sendDone(); } diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index ced765fd..962b89a3 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -1,5 +1,6 @@ #include "LayerShell.hpp" #include "../Compositor.hpp" +#include "XDGShell.hpp" #define LOGM PROTO::layerShell->protoLog @@ -118,14 +119,14 @@ CLayerShellResource::CLayerShellResource(SP resource_, wlr_ }); resource->setGetPopup([this](CZwlrLayerSurfaceV1* r, wl_resource* popup_) { - auto popup = wlr_xdg_popup_from_resource(popup_); + auto popup = CXDGPopupResource::fromResource(popup_); - if (popup->parent) { + if (popup->taken) { r->error(-1, "Parent already exists!"); return; } - popup->parent = surface; + popup->taken = true; events.newPopup.emit(popup); }); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp new file mode 100644 index 00000000..fcb2d63b --- /dev/null +++ b/src/protocols/XDGShell.cpp @@ -0,0 +1,697 @@ +#include "XDGShell.hpp" +#include +#include "../Compositor.hpp" + +#define LOGM PROTO::xdgShell->protoLog + +CXDGPopupResource::CXDGPopupResource(SP resource_, SP owner_, SP surface_, SP positioner) : + surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CXdgPopup* r) { + if (surface && surface->mapped) + surface->events.unmap.emit(); + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + resource->setOnDestroy([this](CXdgPopup* r) { + if (surface && surface->mapped) + surface->events.unmap.emit(); + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + + resource->setReposition([this](CXdgPopup* r, wl_resource* positionerRes, uint32_t token) { + LOGM(LOG, "Popup {:x} asks for reposition", (uintptr_t)this); + lastRepositionToken = token; + auto pos = CXDGPositionerResource::fromResource(positionerRes); + if (!pos) + return; + positionerRules = CXDGPositionerRules{pos}; + events.reposition.emit(); + }); + + if (parent) + taken = true; +} + +CXDGPopupResource::~CXDGPopupResource() { + events.destroy.emit(); +} + +void CXDGPopupResource::applyPositioning(const CBox& box, const Vector2D& t1coord) { + CBox constraint = box.copy().translate(surface->pending.geometry.pos()); + + geometry = positionerRules.getPosition(constraint, accumulateParentOffset() + t1coord); + + LOGM(LOG, "Popup {:x} gets unconstrained to {} {}", (uintptr_t)this, geometry.pos(), geometry.size()); + + configure(geometry); + + if (lastRepositionToken) + repositioned(); +} + +Vector2D CXDGPopupResource::accumulateParentOffset() { + SP current = parent.lock(); + Vector2D off; + while (current) { + off += current->current.geometry.pos(); + if (current->popup) { + off += current->popup->geometry.pos(); + current = current->popup->parent.lock(); + } else + break; + } + return off; +} + +SP CXDGPopupResource::fromResource(wl_resource* res) { + auto data = (CXDGPopupResource*)(((CXdgPopup*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CXDGPopupResource::good() { + return resource->resource(); +} + +void CXDGPopupResource::configure(const CBox& box) { + resource->sendConfigure(box.x, box.y, box.w, box.h); + if (surface) + surface->scheduleConfigure(); +} + +void CXDGPopupResource::done() { + resource->sendPopupDone(); +} + +void CXDGPopupResource::repositioned() { + if (!lastRepositionToken) + return; + + LOGM(LOG, "repositioned: sending reposition token {}", lastRepositionToken); + + resource->sendRepositioned(lastRepositionToken); + lastRepositionToken = 0; +} + +CXDGToplevelResource::CXDGToplevelResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CXdgToplevel* r) { + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + resource->setOnDestroy([this](CXdgToplevel* r) { + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + + if (resource->version() >= 5) { + wl_array arr; + wl_array_init(&arr); + auto p = (uint32_t*)wl_array_add(&arr, sizeof(uint32_t)); + *p = XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN; + p = (uint32_t*)wl_array_add(&arr, sizeof(uint32_t)); + *p = XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE; + resource->sendWmCapabilities(&arr); + wl_array_release(&arr); + } + + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM); + + resource->setSetTitle([this](CXdgToplevel* r, const char* t) { + state.title = t; + events.metadataChanged.emit(); + }); + + resource->setSetAppId([this](CXdgToplevel* r, const char* id) { + state.appid = id; + events.metadataChanged.emit(); + }); + + resource->setSetMaxSize([this](CXdgToplevel* r, int32_t x, int32_t y) { + pending.maxSize = {x, y}; + events.sizeLimitsChanged.emit(); + }); + + resource->setSetMinSize([this](CXdgToplevel* r, int32_t x, int32_t y) { + pending.minSize = {x, y}; + events.sizeLimitsChanged.emit(); + }); + + resource->setSetMaximized([this](CXdgToplevel* r) { + state.requestsMaximize = true; + events.stateChanged.emit(); + state.requestsMaximize.reset(); + }); + + resource->setUnsetMaximized([this](CXdgToplevel* r) { + state.requestsMaximize = false; + events.stateChanged.emit(); + state.requestsMaximize.reset(); + }); + + resource->setSetFullscreen([this](CXdgToplevel* r, wl_resource* output) { + state.requestsFullscreen = true; + events.stateChanged.emit(); + state.requestsFullscreen.reset(); + }); + + resource->setUnsetFullscreen([this](CXdgToplevel* r) { + state.requestsFullscreen = false; + events.stateChanged.emit(); + state.requestsFullscreen.reset(); + }); + + resource->setSetMinimized([this](CXdgToplevel* r) { + state.requestsMinimize = true; + events.stateChanged.emit(); + state.requestsFullscreen.reset(); + }); + + resource->setSetParent([this](CXdgToplevel* r, wl_resource* parentR) { + auto newp = parentR ? CXDGToplevelResource::fromResource(parentR) : nullptr; + parent = newp; + + LOGM(LOG, "Toplevel {:x} sets parent to {:x}", (uintptr_t)this, (uintptr_t)newp.get()); + }); +} + +CXDGToplevelResource::~CXDGToplevelResource() { + events.destroy.emit(); +} + +SP CXDGToplevelResource::fromResource(wl_resource* res) { + auto data = (CXDGToplevelResource*)(((CXdgToplevel*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CXDGToplevelResource::good() { + return resource->resource(); +} + +uint32_t CXDGToplevelResource::setSize(const Vector2D& size) { + pendingApply.size = size; + applyState(); + return owner->scheduleConfigure(); +} + +uint32_t CXDGToplevelResource::setMaximized(bool maximized) { + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_MAXIMIZED) != pendingApply.states.end(); + + if (maximized == set) + return owner->scheduledSerial; + + if (maximized && !set) + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_MAXIMIZED); + else if (!maximized && set) + std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_MAXIMIZED); + applyState(); + return owner->scheduleConfigure(); +} + +uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) { + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_FULLSCREEN) != pendingApply.states.end(); + + if (fullscreen == set) + return owner->scheduledSerial; + + if (fullscreen && !set) + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_FULLSCREEN); + else if (!fullscreen && set) + std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_FULLSCREEN); + applyState(); + return owner->scheduleConfigure(); +} + +uint32_t CXDGToplevelResource::setActive(bool active) { + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_ACTIVATED) != pendingApply.states.end(); + + if (active == set) + return owner->scheduledSerial; + + if (active && !set) + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_ACTIVATED); + else if (!active && set) + std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_ACTIVATED); + applyState(); + return owner->scheduleConfigure(); +} + +uint32_t CXDGToplevelResource::setSuspeneded(bool sus) { + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != pendingApply.states.end(); + + if (sus == set) + return owner->scheduledSerial; + + if (sus && !set) + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_SUSPENDED); + else if (!sus && set) + std::erase(pendingApply.states, XDG_TOPLEVEL_STATE_SUSPENDED); + applyState(); + return owner->scheduleConfigure(); +} + +void CXDGToplevelResource::applyState() { + wl_array arr; + wl_array_init(&arr); + wl_array_add(&arr, pendingApply.states.size() * sizeof(int)); + memcpy(arr.data, pendingApply.states.data(), pendingApply.states.size() * sizeof(int)); + + resource->sendConfigure(pendingApply.size.x, pendingApply.size.y, &arr); + + wl_array_release(&arr); +} + +void CXDGToplevelResource::close() { + resource->sendClose(); +} + +CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, wlr_surface* surface_) : owner(owner_), surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CXdgSurface* r) { + if (mapped) + events.unmap.emit(); + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + resource->setOnDestroy([this](CXdgSurface* r) { + if (mapped) + events.unmap.emit(); + events.destroy.emit(); + PROTO::xdgShell->destroyResource(this); + }); + + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, + [this](void* owner, void* data) { + LOGM(WARN, "wl_surface destroyed before its xdg_surface role object"); + hyprListener_surfaceDestroy.removeCallback(); + hyprListener_surfaceCommit.removeCallback(); + + if (mapped) + events.unmap.emit(); + + mapped = false; + surface = nullptr; + events.destroy.emit(); + }, + nullptr, "CXDGSurfaceResource"); + + hyprListener_surfaceCommit.initCallback( + &surface->events.commit, + [this](void* owner, void* data) { + current = pending; + if (toplevel) + toplevel->current = toplevel->pending; + + if (initialCommit && surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { + resource->error(-1, "Buffer attached before initial commit"); + return; + } + + if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { + // this forces apps to not draw CSD. + if (toplevel) + toplevel->setMaximized(true); + + mapped = true; + wlr_surface_map(surface); + events.map.emit(); + return; + } + + if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { + mapped = false; + wlr_surface_unmap(surface); + events.unmap.emit(); + return; + } + + events.commit.emit(); + initialCommit = false; + }, + nullptr, "CXDGSurfaceResource"); + + resource->setGetToplevel([this](CXdgSurface* r, uint32_t id) { + const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::xdgShell->m_vToplevels.pop_back(); + return; + } + + toplevel = RESOURCE; + toplevel->self = RESOURCE; + + LOGM(LOG, "xdg_surface {:x} gets a toplevel {:x}", (uintptr_t)owner.get(), (uintptr_t)RESOURCE.get()); + + g_pCompositor->m_vWindows.emplace_back(CWindow::create(self.lock())); + + for (auto& p : popups) { + if (!p) + continue; + events.newPopup.emit(p); + } + }); + + resource->setGetPopup([this](CXdgSurface* r, uint32_t id, wl_resource* parentXDG, wl_resource* positionerRes) { + auto parent = parentXDG ? CXDGSurfaceResource::fromResource(parentXDG) : nullptr; + auto positioner = CXDGPositionerResource::fromResource(positionerRes); + const auto RESOURCE = + PROTO::xdgShell->m_vPopups.emplace_back(makeShared(makeShared(r->client(), r->version(), id), parent, self.lock(), positioner)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::xdgShell->m_vPopups.pop_back(); + return; + } + + popup = RESOURCE; + RESOURCE->self = RESOURCE; + + LOGM(LOG, "xdg_surface {:x} gets a popup {:x} owner {:x}", (uintptr_t)self.get(), (uintptr_t)RESOURCE.get(), (uintptr_t)parent.get()); + + if (!parent) + return; + + parent->popups.emplace_back(RESOURCE); + if (parent->mapped) + parent->events.newPopup.emit(RESOURCE); + }); + + resource->setAckConfigure([this](CXdgSurface* r, uint32_t serial) { + events.ack.emit(serial); + ; // TODO: verify it + }); + + resource->setSetWindowGeometry([this](CXdgSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { + LOGM(LOG, "xdg_surface {:x} requests geometry {}x{} {}x{}", (uintptr_t)this, x, y, w, h); + pending.geometry = {x, y, w, h}; + }); +} + +CXDGSurfaceResource::~CXDGSurfaceResource() { + events.destroy.emit(); + if (configureSource) + wl_event_source_remove(configureSource); +} + +bool CXDGSurfaceResource::good() { + return resource->resource(); +} + +SP CXDGSurfaceResource::fromResource(wl_resource* res) { + auto data = (CXDGSurfaceResource*)(((CXdgSurface*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +static void onConfigure(void* data) { + ((CXDGSurfaceResource*)data)->configure(); +} + +uint32_t CXDGSurfaceResource::scheduleConfigure() { + if (configureSource) + return scheduledSerial; + + configureSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, onConfigure, this); + scheduledSerial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); + + return scheduledSerial; +} + +void CXDGSurfaceResource::configure() { + configureSource = nullptr; + resource->sendConfigure(scheduledSerial); +} + +CXDGPositionerResource::CXDGPositionerResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CXdgPositioner* r) { PROTO::xdgShell->destroyResource(this); }); + resource->setOnDestroy([this](CXdgPositioner* r) { PROTO::xdgShell->destroyResource(this); }); + + resource->setSetSize([this](CXdgPositioner* r, int32_t x, int32_t y) { + if (x <= 0 || y <= 0) { + r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid size"); + return; + } + + state.requestedSize = {x, y}; + }); + + resource->setSetAnchorRect([this](CXdgPositioner* r, int32_t x, int32_t y, int32_t w, int32_t h) { + if (w <= 0 || h <= 0) { + r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid box"); + return; + } + + state.anchorRect = {x, y, w, h}; + }); + + resource->setSetOffset([this](CXdgPositioner* r, int32_t x, int32_t y) { state.offset = {x, y}; }); + + resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.anchor = a; }); + + resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.gravity = g; }); + + resource->setSetConstraintAdjustment([this](CXdgPositioner* r, xdgPositionerConstraintAdjustment a) { state.constraintAdjustment = (uint32_t)a; }); + + // TODO: support this shit better. The current impl _works_, but is lacking and could be wrong in a few cases. + // doesn't matter _that_ much for now, though. +} + +SP CXDGPositionerResource::fromResource(wl_resource* res) { + auto data = (CXDGPositionerResource*)(((CXdgPositioner*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CXDGPositionerResource::good() { + return resource->resource(); +} + +CXDGPositionerRules::CXDGPositionerRules(SP positioner) { + state = positioner->state; +} + +static Vector2D pointForAnchor(const CBox& box, xdgPositionerAnchor anchor) { + switch (anchor) { + case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F, 0}; + case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F, box.size().y}; + case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F}; + case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F}; + case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos(); + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y}; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0}; + case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y}; + default: return box.pos(); + } + + return {}; +} + +CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& parentCoord) { + + Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord); + + CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.anchor) + state.offset, state.requestedSize}; + + bool success = predictedBox.inside(constraint); + + if (success) + return predictedBox.translate(-parentCoord - constraint.pos()); + + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) { + // attempt to flip + const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; + const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + + CBox test = predictedBox; + success = true; + if (flipX && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}).expand(-1).inside(constraint)) + test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}); + else if (flipY && test.copy().translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint)) + test.translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}); + else if (flipX && flipY && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint)) + test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h}); + else + success = false; + + if (success) + return test.translate(-parentCoord - constraint.pos()); + } + + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) { + // attempt to slide + const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; + const bool slideY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + + //const bool gravityLeft = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT; + //const bool gravityTop = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_TOP || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_RIGHT; + + const bool leftEdgeOut = predictedBox.x < constraint.x; + const bool topEdgeOut = predictedBox.y < constraint.y; + const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; + const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; + + CBox test = predictedBox; + + // TODO: this isn't truly conformant. + if (leftEdgeOut && slideX) + test.x = constraint.x; + if (rightEdgeOut && slideX) + test.x = constraint.x + constraint.w - predictedBox.w; + if (topEdgeOut && slideY) + test.y = constraint.y; + if (bottomEdgeOut && slideY) + test.y = constraint.y + constraint.h - predictedBox.y; + + success = test.copy().expand(-1).inside(constraint); + + if (success) + return test.translate(-parentCoord - constraint.pos()); + } + + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) { + const bool resizeX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; + const bool resizeY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + + const bool leftEdgeOut = predictedBox.x < constraint.x; + const bool topEdgeOut = predictedBox.y < constraint.y; + const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; + const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; + + CBox test = predictedBox; + + // TODO: this isn't truly conformant. + if (leftEdgeOut && resizeX) { + test.w = test.x + test.w - constraint.x; + test.x = constraint.x; + } + if (rightEdgeOut && resizeX) + test.w = -(constraint.w + constraint.x - test.w - test.x); + if (topEdgeOut && resizeY) { + test.h = test.y + test.h - constraint.y; + test.y = constraint.y; + } + if (bottomEdgeOut && resizeY) + test.h = -(constraint.h + constraint.y - test.h - test.y); + + success = test.copy().expand(-1).inside(constraint); + + if (success) + return test.translate(parentCoord - constraint.pos()); + } + + LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); + + return predictedBox.translate(-parentCoord - constraint.pos()); +} + +CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CXdgWmBase* r) { PROTO::xdgShell->destroyResource(this); }); + resource->setOnDestroy([this](CXdgWmBase* r) { PROTO::xdgShell->destroyResource(this); }); + + pClient = resource->client(); + + resource->setCreatePositioner([this](CXdgWmBase* r, uint32_t id) { + const auto RESOURCE = + PROTO::xdgShell->m_vPositioners.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::xdgShell->m_vPositioners.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + positioners.emplace_back(RESOURCE); + + LOGM(LOG, "New xdg_positioner at {:x}", (uintptr_t)RESOURCE.get()); + }); + + resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) { + const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surf))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::xdgShell->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + surfaces.emplace_back(RESOURCE); + + LOGM(LOG, "New xdg_surface at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CXDGWMBase::good() { + return resource->resource(); +} + +wl_client* CXDGWMBase::client() { + return pClient; +} + +CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CXDGShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vWMBases.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vWMBases.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New xdg_wm_base at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CXDGShellProtocol::destroyResource(CXDGWMBase* resource) { + std::erase_if(m_vWMBases, [&](const auto& other) { return other.get() == resource; }); +} + +void CXDGShellProtocol::destroyResource(CXDGPositionerResource* resource) { + std::erase_if(m_vPositioners, [&](const auto& other) { return other.get() == resource; }); +} + +void CXDGShellProtocol::destroyResource(CXDGSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CXDGShellProtocol::destroyResource(CXDGToplevelResource* resource) { + std::erase_if(m_vToplevels, [&](const auto& other) { return other.get() == resource; }); +} + +void CXDGShellProtocol::destroyResource(CXDGPopupResource* resource) { + std::erase_if(m_vPopups, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp new file mode 100644 index 00000000..e214b6ac --- /dev/null +++ b/src/protocols/XDGShell.hpp @@ -0,0 +1,256 @@ +#pragma once + +#include +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xdg-shell.hpp" +#include "../helpers/Vector2D.hpp" +#include "../helpers/Box.hpp" +#include "../helpers/signal/Signal.hpp" + +class CXDGWMBase; +class CXDGPositionerResource; +class CXDGSurfaceResource; +class CXDGToplevelResource; +class CXDGPopupResource; +class CSeatGrab; + +struct SXDGPositionerState { + Vector2D requestedSize; + CBox anchorRect; + xdgPositionerAnchor anchor = XDG_POSITIONER_ANCHOR_NONE; + xdgPositionerGravity gravity = XDG_POSITIONER_GRAVITY_NONE; + uint32_t constraintAdjustment = 0; + Vector2D offset; + bool reactive = false; + Vector2D parentSize; +}; + +class CXDGPositionerRules { + public: + CXDGPositionerRules(SP positioner); + + CBox getPosition(const CBox& constraint, const Vector2D& parentPos); + + private: + SXDGPositionerState state; +}; + +class CXDGPopupResource { + public: + CXDGPopupResource(SP resource_, SP parent_, SP surface_, SP positioner_); + ~CXDGPopupResource(); + + static SP fromResource(wl_resource*); + + bool good(); + + void applyPositioning(const CBox& availableBox, const Vector2D& t1coord /* relative to box */); + + WP surface; + WP parent; + WP self; + + bool taken = false; + + CBox geometry; + + struct { + CSignal reposition; + CSignal destroy; // only the role + } events; + + // schedules a configure event + void configure(const CBox& box); + + void done(); + void repositioned(); + + private: + SP resource; + + uint32_t lastRepositionToken = 0; + + Vector2D accumulateParentOffset(); + + CXDGPositionerRules positionerRules; +}; + +class CXDGToplevelResource { + public: + CXDGToplevelResource(SP resource_, SP owner_); + ~CXDGToplevelResource(); + + static SP fromResource(wl_resource*); + + WP owner; + WP self; + + PHLWINDOWREF window; + + bool good(); + + // schedule a configure event + uint32_t setSize(const Vector2D& size); + uint32_t setMaximized(bool maximized); + uint32_t setFullscreen(bool fullscreen); + uint32_t setActive(bool active); + uint32_t setSuspeneded(bool sus); + + void close(); + + struct { + CSignal sizeLimitsChanged; + CSignal stateChanged; // maximized, fs, minimized, etc. + CSignal metadataChanged; // title, appid + CSignal destroy; // only the role + } events; + + struct { + std::string title; + std::string appid; + + // volatile state: is reset after the stateChanged signal fires + std::optional requestsMaximize; + std::optional requestsFullscreen; + std::optional requestsMinimize; + } state; + + struct { + Vector2D size; + std::vector states; + } pendingApply; + + struct { + Vector2D minSize = {1, 1}; + Vector2D maxSize = {1337420, 694200}; + } pending, current; + + WP parent; + + private: + SP resource; + void applyState(); +}; + +class CXDGSurfaceResource { + public: + CXDGSurfaceResource(SP resource_, SP owner_, wlr_surface* surface_); + ~CXDGSurfaceResource(); + + static SP fromResource(wl_resource*); + + bool good(); + + WP owner; + wlr_surface* surface = nullptr; + + WP toplevel; + WP popup; + + WP self; + + struct { + CBox geometry; + } pending, current; + + struct { + CSignal ack; + CSignal commit; + CSignal map; + CSignal unmap; + CSignal destroy; + CSignal newPopup; // SP + } events; + + bool initialCommit = true; + bool mapped = false; + + uint32_t scheduleConfigure(); + // do not call directly + void configure(); + + private: + SP resource; + + uint32_t lastConfigureSerial = 0; + uint32_t scheduledSerial = 0; + + wl_event_source* configureSource = nullptr; + + // + std::vector> popups; + + DYNLISTENER(surfaceDestroy); + DYNLISTENER(surfaceCommit); + + friend class CXDGPopupResource; + friend class CXDGToplevelResource; +}; + +class CXDGPositionerResource { + public: + CXDGPositionerResource(SP resource_, SP owner_); + + static SP fromResource(wl_resource*); + + bool good(); + + SXDGPositionerState state; + + WP owner; + WP self; + + private: + SP resource; +}; + +class CXDGWMBase { + public: + CXDGWMBase(SP resource_); + + bool good(); + wl_client* client(); + + std::vector> positioners; + std::vector> surfaces; + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CXDGShellProtocol : public IWaylandProtocol { + public: + CXDGShellProtocol(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); + + private: + void destroyResource(CXDGWMBase* resource); + void destroyResource(CXDGPositionerResource* resource); + void destroyResource(CXDGSurfaceResource* resource); + void destroyResource(CXDGToplevelResource* resource); + void destroyResource(CXDGPopupResource* resource); + + // + std::vector> m_vWMBases; + std::vector> m_vPositioners; + std::vector> m_vSurfaces; + std::vector> m_vToplevels; + std::vector> m_vPopups; + + friend class CXDGWMBase; + friend class CXDGPositionerResource; + friend class CXDGSurfaceResource; + friend class CXDGToplevelResource; + friend class CXDGPopupResource; +}; + +namespace PROTO { + inline UP xdgShell; +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 38dba439..1aa246fb 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -10,6 +10,7 @@ #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/XDGShell.hpp" #include "../protocols/PresentationTime.hpp" extern "C" { @@ -615,9 +616,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (mode == RENDER_PASS_ALL || mode == RENDER_PASS_POPUP) { if (!pWindow->m_bIsX11) { - CBox geom; - wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr()); - geom.applyFromWlr(); + CBox geom = pWindow->m_pXDGSurface->current.geometry; renderdata.x -= geom.x; renderdata.y -= geom.y; @@ -643,7 +642,20 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - wlr_xdg_surface_for_each_popup_surface(pWindow->m_uSurface.xdg, renderSurface, &renderdata); + pWindow->m_pPopupHead->breadthfirst( + [](CPopup* popup, void* data) { + if (!popup->m_sWLSurface.wlr()) + return; + auto pos = popup->coordsRelativeToParent(); + auto rd = (SRenderData*)data; + Vector2D oldPos = {rd->x, rd->y}; + rd->x += pos.x; + rd->y += pos.y; + wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd); + rd->x = oldPos.x; + rd->y = oldPos.y; + }, + &renderdata); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; @@ -1000,9 +1012,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa if (!main || !pWindow) return; - CBox geom; - wlr_xdg_surface_get_geometry(pWindow->m_uSurface.xdg, geom.pWlr()); - geom.applyFromWlr(); + CBox geom = pWindow->m_pXDGSurface->current.geometry; // ignore X and Y, adjust uv if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { @@ -2530,8 +2540,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { if (PCANDIDATE->m_bIsX11) { surfaceCount = 1; } else { - wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount); - wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount); + surfaceCount = PCANDIDATE->popupsCount() + PCANDIDATE->surfacesCount(); } if (surfaceCount > 1) From fc72df8e58bc127442a245f2f29a3246acf77cce Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 11 May 2024 01:02:57 +0100 Subject: [PATCH 0083/2393] seatmgr: Add a grab class --- src/Compositor.cpp | 5 + src/desktop/LayerSurface.cpp | 2 + src/desktop/Popup.cpp | 20 +-- src/desktop/Popup.hpp | 1 + src/managers/SeatManager.cpp | 73 +++++++++++ src/managers/SeatManager.hpp | 37 ++++++ src/managers/input/InputManager.cpp | 26 ++++ src/managers/input/InputManager.hpp | 6 +- src/protocols/FocusGrab.cpp | 193 ++++------------------------ src/protocols/FocusGrab.hpp | 10 +- src/protocols/XDGShell.cpp | 57 +++++++- src/protocols/XDGShell.hpp | 15 ++- 12 files changed, 257 insertions(+), 188 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c56dd280..4e0a6357 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1025,6 +1025,11 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) return; + if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) { + Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface); + return; + } + const auto PLASTSURF = m_pLastFocus; // Unfocus last surface if should diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index cb10079c..759eb09f 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -136,6 +136,8 @@ void CLayerSurface::onMap() { (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); if (GRABSFOCUS) { + // TODO: use the new superb really very cool grab + g_pSeatManager->setGrab(nullptr); g_pInputManager->releaseAllMouseButtons(); g_pCompositor->focusSurface(surface.wlr()); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 605dfdfd..c652d298 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -45,6 +45,7 @@ void CPopup::initAllSignals() { listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); }); listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); }); listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); + listeners.dismissed = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); }); listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); }); listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast>(d)); }); @@ -65,8 +66,9 @@ void CPopup::onDestroy() { } void CPopup::onMap() { - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; - const auto COORDS = coordsGlobal(); + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + const auto COORDS = coordsGlobal(); + const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); CBox box; wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr()); @@ -79,8 +81,9 @@ void CPopup::onMap() { m_pSubsurfaceHead = std::make_unique(this); - unconstrain(); + //unconstrain(); sendScale(); + wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output); if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); @@ -178,7 +181,6 @@ void CPopup::unconstrain() { CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition); - wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output); } Vector2D CPopup::coordsRelativeToParent() { @@ -190,8 +192,6 @@ Vector2D CPopup::coordsRelativeToParent() { CPopup* current = this; offset -= current->m_pResource->surface->current.geometry.pos(); - offset -= m_pResource->surface->current.geometry.pos(); - while (current->m_pParent && current->m_pResource) { offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; @@ -293,11 +293,15 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { continue; if (!allowsInput) { - const auto BOX = CBox{p->coordsGlobal(), p->size()}; + const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; + const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); + + const auto BOX = CBox{p->coordsGlobal() + offset, size}; if (BOX.containsPoint(globalCoords)) return p; } else { - const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal()); + const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; + const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index e6c35e68..ba6da55a 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -68,6 +68,7 @@ class CPopup { CHyprSignalListener map; CHyprSignalListener unmap; CHyprSignalListener commit; + CHyprSignalListener dismissed; CHyprSignalListener reposition; } listeners; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index f9d394b5..d962dd84 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -371,6 +371,40 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) { } } +void CSeatManager::refocusGrab() { + if (!seatGrab) + return; + + if (seatGrab->surfs.size() > 0) { + // try to find a surf in focus first + const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); + for (auto& s : seatGrab->surfs) { + auto hlSurf = CWLSurface::surfaceFromWlr(s); + if (!hlSurf) + continue; + + auto b = hlSurf->getSurfaceBoxGlobal(); + if (!b.has_value()) + continue; + + if (!b->containsPoint(MOUSE)) + continue; + + if (seatGrab->keyboard) + setKeyboardFocus(s); + if (seatGrab->pointer) + setPointerFocus(s, MOUSE - b->pos()); + return; + } + + wlr_surface* surf = seatGrab->surfs.at(0); + if (seatGrab->keyboard) + setKeyboardFocus(surf); + if (seatGrab->pointer) + setPointerFocus(surf, {}); + } +} + void CSeatManager::onSetCursor(SP seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) { if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) { Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus"); @@ -389,3 +423,42 @@ void CSeatManager::onSetCursor(SP seatResource, uint32_t serial SP CSeatManager::seatResourceForClient(wl_client* client) { return PROTO::seat->seatResourceForClient(client); } + +void CSeatManager::setGrab(SP grab) { + if (seatGrab) { + auto oldGrab = seatGrab; + seatGrab.reset(); + g_pInputManager->refocus(); + if (oldGrab->onEnd) + oldGrab->onEnd(); + } + + if (!grab) + return; + + seatGrab = grab; + + refocusGrab(); +} + +bool CSeatGrab::accepts(wlr_surface* surf) { + return std::find(surfs.begin(), surfs.end(), surf) != surfs.end(); +} + +void CSeatGrab::add(wlr_surface* surf) { + surfs.push_back(surf); +} + +void CSeatGrab::remove(wlr_surface* surf) { + std::erase(surfs, surf); + if ((keyboard && g_pSeatManager->state.keyboardFocus == surf) || (pointer && g_pSeatManager->state.pointerFocus == surf)) + g_pSeatManager->refocusGrab(); +} + +void CSeatGrab::setCallback(std::function onEnd_) { + onEnd = onEnd_; +} + +void CSeatGrab::clear() { + surfs.clear(); +} diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index ef114024..16f11ffd 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -14,6 +14,37 @@ class CWLSeatResource; class IPointer; class IKeyboard; +/* + A seat grab defines a restricted set of surfaces that can be focused. + Only one grab can be active at a time + + when a grab is removed, refocus() will happen + + Different from a constraint. + + When first set with setGrab, SeatManager will try to find a surface that is at the mouse pointer to focus, + from first added to last added. If none are, first is focused. +*/ +class CSeatGrab { + public: + bool accepts(wlr_surface* surf); + void add(wlr_surface* surf); + void remove(wlr_surface* surf); + void setCallback(std::function onEnd_); + void clear(); + + bool keyboard = false; + bool pointer = false; + bool touch = false; + + bool removeOnInput = true; // on hard input e.g. click outside, remove + + private: + std::vector surfs; // read-only + std::function onEnd; + friend class CSeatManager; +}; + class CSeatManager { public: CSeatManager(); @@ -76,6 +107,9 @@ class CSeatManager { WP mouse; WP keyboard; + void setGrab(SP grab); // nullptr removes + SP seatGrab; + private: struct SSeatResourceContainer { SSeatResourceContainer(SP); @@ -92,6 +126,8 @@ class CSeatManager { void onNewSeatResource(SP resource); SP containerForResource(SP seatResource); + void refocusGrab(); + struct { CHyprSignalListener newSeatResource; } listeners; @@ -101,6 +137,7 @@ class CSeatManager { DYNLISTENER(touchSurfaceDestroy); friend struct SSeatResourceContainer; + friend class CSeatGrab; }; inline UP g_pSeatManager; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index bb0ab65a..fe19c98f 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -358,6 +358,26 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0) g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); + // grabs + if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { + if (m_bHardInput || refocus) { + g_pSeatManager->setGrab(nullptr); + return; // setGrab will refocus + } else { + // we need to grab the last surface. + foundSurface = g_pSeatManager->state.pointerFocus; + + auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + + if (HLSurface) { + const auto BOX = HLSurface->getSurfaceBoxGlobal(); + + if (BOX.has_value()) + surfacePos = BOX->pos(); + } + } + } + if (!foundSurface) { if (!m_bEmptyFocusCursorSet) { if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) { @@ -678,6 +698,12 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON) g_pCompositor->setActiveMonitor(PMON); + + if (g_pSeatManager->seatGrab && e.state == WL_POINTER_BUTTON_STATE_PRESSED) { + m_bHardInput = true; + simulateMouseMovement(); + m_bHardInput = false; + } } void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 42c9d3da..85efecb8 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -188,10 +188,12 @@ class CInputManager { void releaseAllMouseButtons(); // for some bugs in follow mouse 0 - bool m_bLastFocusOnLS = false; - + bool m_bLastFocusOnLS = false; bool m_bLastFocusOnIMEPopup = false; + // for hard input e.g. clicks + bool m_bHardInput = false; + // for hiding cursor on touch bool m_bLastInputTouch = false; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 4189ed6e..5f0771e0 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -7,119 +7,7 @@ #include #include -// static void focus_grab_pointer_enter(wlr_seat_pointer_grab* grab, wlr_surface* surface, double sx, double sy) { -// if (static_cast(grab->data)->isSurfaceComitted(surface)) -// wlr_seat_pointer_enter(grab->seat, surface, sx, sy); -// else -// wlr_seat_pointer_clear_focus(grab->seat); -// } - -// static void focus_grab_pointer_clear_focus(wlr_seat_pointer_grab* grab) { -// wlr_seat_pointer_clear_focus(grab->seat); -// } - -// static void focus_grab_pointer_motion(wlr_seat_pointer_grab* grab, uint32_t time, double sx, double sy) { -// wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); -// } - -// static uint32_t focus_grab_pointer_button(wlr_seat_pointer_grab* grab, uint32_t time, uint32_t button, wl_pointer_button_state state) { -// uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state); - -// if (serial) -// return serial; -// else { -// static_cast(grab->data)->finish(true); -// return 0; -// } -// } - -// static void focus_grab_pointer_axis(wlr_seat_pointer_grab* grab, uint32_t time, enum wl_pointer_axis orientation, double value, int32_t value_discrete, -// enum wl_pointer_axis_source source, enum wl_pointer_axis_relative_direction relative_direction) { -// wlr_seat_pointer_send_axis(grab->seat, time, orientation, value, value_discrete, source, relative_direction); -// } - -// static void focus_grab_pointer_frame(wlr_seat_pointer_grab* grab) { -// wlr_seat_pointer_send_frame(grab->seat); -// } - -// static void focus_grab_pointer_cancel(wlr_seat_pointer_grab* grab) { -// static_cast(grab->data)->finish(true); -// } - -// static const wlr_pointer_grab_interface focus_grab_pointer_impl = { -// .enter = focus_grab_pointer_enter, -// .clear_focus = focus_grab_pointer_clear_focus, -// .motion = focus_grab_pointer_motion, -// .button = focus_grab_pointer_button, -// .axis = focus_grab_pointer_axis, -// .frame = focus_grab_pointer_frame, -// .cancel = focus_grab_pointer_cancel, -// }; - -// static void focus_grab_keyboard_enter(wlr_seat_keyboard_grab* grab, wlr_surface* surface, const uint32_t keycodes[], size_t num_keycodes, const wlr_keyboard_modifiers* modifiers) { -// if (static_cast(grab->data)->isSurfaceComitted(surface)) -// wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers); - -// // otherwise the last grabbed window should retain keyboard focus. -// } - -// static void focus_grab_keyboard_clear_focus(wlr_seat_keyboard_grab* grab) { -// static_cast(grab->data)->finish(true); -// } - -// static void focus_grab_keyboard_key(wlr_seat_keyboard_grab* grab, uint32_t time, uint32_t key, uint32_t state) { -// wlr_seat_keyboard_send_key(grab->seat, time, key, state); -// } - -// static void focus_grab_keyboard_modifiers(wlr_seat_keyboard_grab* grab, const wlr_keyboard_modifiers* modifiers) { -// wlr_seat_keyboard_send_modifiers(grab->seat, modifiers); -// } - -// static void focus_grab_keyboard_cancel(wlr_seat_keyboard_grab* grab) { -// static_cast(grab->data)->finish(true); -// } - -// static const wlr_keyboard_grab_interface focus_grab_keyboard_impl = { -// .enter = focus_grab_keyboard_enter, -// .clear_focus = focus_grab_keyboard_clear_focus, -// .key = focus_grab_keyboard_key, -// .modifiers = focus_grab_keyboard_modifiers, -// .cancel = focus_grab_keyboard_cancel, -// }; - -// static uint32_t focus_grab_touch_down(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { -// if (!static_cast(grab->data)->isSurfaceComitted(point->surface)) -// return 0; - -// return wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, point->sx, point->sy); -// } - -// static void focus_grab_touch_up(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { -// wlr_seat_touch_send_up(grab->seat, time, point->touch_id); -// } - -// static void focus_grab_touch_motion(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) { -// wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, point->sy); -// } - -// static void focus_grab_touch_enter(wlr_seat_touch_grab* grab, uint32_t time, wlr_touch_point* point) {} - -// static void focus_grab_touch_frame(wlr_seat_touch_grab* grab) { -// wlr_seat_touch_send_frame(grab->seat); -// } - -// static void focus_grab_touch_cancel(wlr_seat_touch_grab* grab) { -// static_cast(grab->data)->finish(true); -// } - -// static const wlr_touch_grab_interface focus_grab_touch_impl = { -// .down = focus_grab_touch_down, -// .up = focus_grab_touch_up, -// .motion = focus_grab_touch_motion, -// .enter = focus_grab_touch_enter, -// .frame = focus_grab_touch_frame, -// .cancel = focus_grab_touch_cancel, -// }; +#define LOGM PROTO::focusGrab->protoLog CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) { hyprListener_surfaceDestroy.initCallback( @@ -134,14 +22,10 @@ CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) if (!resource->resource()) return; - // m_sPointerGrab.interface = &focus_grab_pointer_impl; - // m_sPointerGrab.data = this; - - // m_sKeyboardGrab.interface = &focus_grab_keyboard_impl; - // m_sKeyboardGrab.data = this; - - // m_sTouchGrab.interface = &focus_grab_touch_impl; - // m_sTouchGrab.data = this; + grab = makeShared(); + grab->keyboard = true; + grab->pointer = true; + grab->setCallback([this]() { finish(true); }); resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); @@ -168,21 +52,8 @@ bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) { void CFocusGrab::start() { if (!m_bGrabActive) { - // wlr_seat_pointer_start_grab(g_pCompositor->m_sSeat.seat, &m_sPointerGrab); - // wlr_seat_keyboard_start_grab(g_pCompositor->m_sSeat.seat, &m_sKeyboardGrab); - // wlr_seat_touch_start_grab(g_pCompositor->m_sSeat.seat, &m_sTouchGrab); m_bGrabActive = true; - - // Ensure the grab ends if another grab begins, including from xdg_popup::grab. - - // hyprListener_pointerGrabStarted.initCallback( - // &g_pCompositor->m_sSeat.seat->events.pointer_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); - - // hyprListener_keyboardGrabStarted.initCallback( - // &g_pCompositor->m_sSeat.seat->events.keyboard_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); - - // hyprListener_touchGrabStarted.initCallback( - // &g_pCompositor->m_sSeat.seat->events.touch_grab_begin, [this](void*, void*) { finish(true); }, this, "CFocusGrab"); + g_pSeatManager->setGrab(grab); } // Ensure new surfaces are focused if under the mouse when comitted. @@ -193,59 +64,39 @@ void CFocusGrab::start() { void CFocusGrab::finish(bool sendCleared) { if (m_bGrabActive) { m_bGrabActive = false; - // hyprListener_pointerGrabStarted.removeCallback(); - // hyprListener_keyboardGrabStarted.removeCallback(); - // hyprListener_touchGrabStarted.removeCallback(); - // Only clear grabs that belong to this focus grab. When superseded by another grab - // or xdg_popup grab we might not own the current grab. - - bool hadGrab = false; - // if (g_pCompositor->m_sSeat.seat->pointer_state.grab == &m_sPointerGrab) { - // wlr_seat_pointer_end_grab(g_pCompositor->m_sSeat.seat); - // hadGrab = true; - // } - - // if (g_pCompositor->m_sSeat.seat->keyboard_state.grab == &m_sKeyboardGrab) { - // wlr_seat_keyboard_end_grab(g_pCompositor->m_sSeat.seat); - // hadGrab = true; - // } - - // if (g_pCompositor->m_sSeat.seat->touch_state.grab == &m_sTouchGrab) { - // wlr_seat_touch_end_grab(g_pCompositor->m_sSeat.seat); - // hadGrab = true; - // } + if (g_pSeatManager->seatGrab == grab) { + g_pSeatManager->setGrab(nullptr); + } + grab->clear(); m_mSurfaces.clear(); if (sendCleared) resource->sendCleared(); - - // Ensure surfaces under the mouse when the grab ends get focus. - if (hadGrab) - g_pInputManager->refocus(); } } void CFocusGrab::addSurface(wlr_surface* surface) { auto iter = m_mSurfaces.find(surface); - if (iter == m_mSurfaces.end()) + if (iter == m_mSurfaces.end()) { m_mSurfaces.emplace(surface, std::make_unique(this, surface)); + } } void CFocusGrab::removeSurface(wlr_surface* surface) { auto iter = m_mSurfaces.find(surface); if (iter != m_mSurfaces.end()) { - if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) + if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) { m_mSurfaces.erase(iter); - else + } else iter->second->state = CFocusGrabSurfaceState::PendingRemoval; } } void CFocusGrab::eraseSurface(wlr_surface* surface) { removeSurface(surface); - commit(); + commit(true); } void CFocusGrab::refocusKeyboard() { @@ -264,22 +115,26 @@ void CFocusGrab::refocusKeyboard() { if (surface) g_pCompositor->focusSurface(surface); else - Debug::log(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen."); + LOGM(ERR, "CFocusGrab::refocusKeyboard called with no committed surfaces. This should never happen."); } -void CFocusGrab::commit() { +void CFocusGrab::commit(bool removeOnly) { auto surfacesChanged = false; auto anyComitted = false; for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) { switch (iter->second->state) { case CFocusGrabSurfaceState::PendingRemoval: + grab->remove(iter->first); iter = m_mSurfaces.erase(iter); surfacesChanged = true; continue; case CFocusGrabSurfaceState::PendingAddition: - iter->second->state = CFocusGrabSurfaceState::Comitted; - surfacesChanged = true; - anyComitted = true; + if (!removeOnly) { + iter->second->state = CFocusGrabSurfaceState::Comitted; + grab->add(iter->first); + surfacesChanged = true; + anyComitted = true; + } break; case CFocusGrabSurfaceState::Comitted: anyComitted = true; break; } diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 3e5d36ab..40922c22 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -8,6 +8,7 @@ #include class CFocusGrab; +class CSeatGrab; class CFocusGrabSurfaceState { public: @@ -40,14 +41,13 @@ class CFocusGrab { void removeSurface(wlr_surface* surface); void eraseSurface(wlr_surface* surface); void refocusKeyboard(); - void commit(); + void commit(bool removeOnly = false); SP resource; std::unordered_map> m_mSurfaces; - // wlr_seat_pointer_grab m_sPointerGrab; - // wlr_seat_keyboard_grab m_sKeyboardGrab; - // wlr_seat_touch_grab m_sTouchGrab; - bool m_bGrabActive = false; + SP grab; + + bool m_bGrabActive = false; DYNLISTENER(pointerGrabStarted); DYNLISTENER(keyboardGrabStarted); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index fcb2d63b..9777281f 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -1,6 +1,8 @@ #include "XDGShell.hpp" #include #include "../Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" #define LOGM PROTO::xdgShell->protoLog @@ -14,12 +16,14 @@ CXDGPopupResource::CXDGPopupResource(SP resource_, SPsetDestroy([this](CXdgPopup* r) { if (surface && surface->mapped) surface->events.unmap.emit(); + PROTO::xdgShell->onPopupDestroy(self); events.destroy.emit(); PROTO::xdgShell->destroyResource(this); }); resource->setOnDestroy([this](CXdgPopup* r) { if (surface && surface->mapped) surface->events.unmap.emit(); + PROTO::xdgShell->onPopupDestroy(self); events.destroy.emit(); PROTO::xdgShell->destroyResource(this); }); @@ -34,11 +38,17 @@ CXDGPopupResource::CXDGPopupResource(SP resource_, SPsetGrab([this](CXdgPopup* r, wl_resource* seat, uint32_t serial) { + LOGM(LOG, "xdg_popup {:x} requests grab", (uintptr_t)this); + PROTO::xdgShell->addOrStartGrab(self.lock()); + }); + if (parent) taken = true; } CXDGPopupResource::~CXDGPopupResource() { + PROTO::xdgShell->onPopupDestroy(self); events.destroy.emit(); } @@ -85,6 +95,7 @@ void CXDGPopupResource::configure(const CBox& box) { } void CXDGPopupResource::done() { + events.dismissed.emit(); resource->sendPopupDone(); } @@ -659,7 +670,15 @@ wl_client* CXDGWMBase::client() { } CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { - ; + grab = makeShared(); + grab->keyboard = true; + grab->pointer = true; + grab->setCallback([this]() { + for (auto& g : grabbed) { + g->done(); + } + grabbed.clear(); + }); } void CXDGShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { @@ -695,3 +714,39 @@ void CXDGShellProtocol::destroyResource(CXDGToplevelResource* resource) { void CXDGShellProtocol::destroyResource(CXDGPopupResource* resource) { std::erase_if(m_vPopups, [&](const auto& other) { return other.get() == resource; }); } + +void CXDGShellProtocol::addOrStartGrab(SP popup) { + if (!grabOwner) { + grabOwner = popup; + grabbed.clear(); + grab->clear(); + grab->add(popup->surface->surface); + if (popup->parent) + grab->add(popup->parent->surface); + g_pSeatManager->setGrab(grab); + grabbed.emplace_back(popup); + return; + } + + grabbed.emplace_back(popup); + + grab->add(popup->surface->surface); + + if (popup->parent) + grab->add(popup->parent->surface); +} + +void CXDGShellProtocol::onPopupDestroy(WP popup) { + if (popup == grabOwner) { + g_pSeatManager->setGrab(nullptr); + for (auto& g : grabbed) { + g->done(); + } + grabbed.clear(); + return; + } + + std::erase(grabbed, popup); + if (popup->surface) + grab->remove(popup->surface->surface); +} diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index e214b6ac..1dbeb209 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -59,6 +59,7 @@ class CXDGPopupResource { struct { CSignal reposition; + CSignal dismissed; CSignal destroy; // only the role } events; @@ -198,10 +199,10 @@ class CXDGPositionerResource { bool good(); - SXDGPositionerState state; + SXDGPositionerState state; - WP owner; - WP self; + WP owner; + WP self; private: SP resource; @@ -244,6 +245,14 @@ class CXDGShellProtocol : public IWaylandProtocol { std::vector> m_vToplevels; std::vector> m_vPopups; + // current popup grab + WP grabOwner; + SP grab; + std::vector> grabbed; + + void addOrStartGrab(SP popup); + void onPopupDestroy(WP popup); + friend class CXDGWMBase; friend class CXDGPositionerResource; friend class CXDGSurfaceResource; From 7eeee2c94e882a5df1914234df0571b221f9aa35 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 11 May 2024 17:13:20 +0100 Subject: [PATCH 0084/2393] wl-data-device: move to hyprland impl --- src/Compositor.cpp | 10 - src/events/Events.hpp | 10 - src/events/Misc.cpp | 92 ---- src/helpers/WLClasses.hpp | 19 - src/managers/PointerManager.cpp | 4 + src/managers/PointerManager.hpp | 1 + src/managers/ProtocolManager.cpp | 5 +- src/managers/SeatManager.cpp | 38 ++ src/managers/SeatManager.hpp | 12 + src/managers/input/InputManager.cpp | 28 +- src/managers/input/InputManager.hpp | 3 - src/protocols/core/DataDevice.cpp | 655 ++++++++++++++++++++++++++++ src/protocols/core/DataDevice.hpp | 194 ++++++++ src/protocols/types/DataDevice.cpp | 17 + src/protocols/types/DataDevice.hpp | 29 ++ src/render/Renderer.cpp | 17 +- 16 files changed, 963 insertions(+), 171 deletions(-) create mode 100644 src/protocols/core/DataDevice.cpp create mode 100644 src/protocols/core/DataDevice.hpp create mode 100644 src/protocols/types/DataDevice.cpp create mode 100644 src/protocols/types/DataDevice.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 4e0a6357..efbd997f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -253,11 +253,6 @@ void CCompositor::initServer() { void CCompositor::initAllSignals() { addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); - // addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); - // addWLSignal(&m_sSeat.seat->events.request_start_drag, &Events::listen_requestDrag, &m_sSeat, "Seat"); - // addWLSignal(&m_sSeat.seat->events.start_drag, &Events::listen_startDrag, &m_sSeat, "Seat"); - // addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat"); - // addWLSignal(&m_sSeat.seat->events.request_set_primary_selection, &Events::listen_requestSetPrimarySel, &m_sSeat, "Seat"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); if (m_sWRLDRMLeaseMgr) @@ -270,11 +265,6 @@ void CCompositor::initAllSignals() { void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newOutput); removeWLSignal(&Events::listen_newInput); - removeWLSignal(&Events::listen_requestSetSel); - removeWLSignal(&Events::listen_requestDrag); - removeWLSignal(&Events::listen_startDrag); - removeWLSignal(&Events::listen_requestSetSel); - removeWLSignal(&Events::listen_requestSetPrimarySel); removeWLSignal(&Events::listen_RendererDestroy); if (m_sWRLDRMLeaseMgr) diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 7cc0eb32..0b757842 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -59,16 +59,6 @@ namespace Events { LISTENER(readyXWayland); LISTENER(surfaceXWayland); - // Drag & Drop - LISTENER(requestDrag); - LISTENER(startDrag); - DYNLISTENFUNC(destroyDrag); - - DYNLISTENFUNC(mapDragIcon); - DYNLISTENFUNC(unmapDragIcon); - DYNLISTENFUNC(destroyDragIcon); - DYNLISTENFUNC(commitDragIcon); - // Renderer destroy LISTENER(RendererDestroy); diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index 703dba6a..7152730e 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -25,16 +25,6 @@ void Events::listener_leaseRequest(wl_listener* listener, void* data) { } } -void Events::listener_requestSetPrimarySel(wl_listener* listener, void* data) { - // const auto EVENT = (wlr_seat_request_set_primary_selection_event*)data; - // wlr_seat_set_primary_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); -} - -void Events::listener_requestSetSel(wl_listener* listener, void* data) { - // const auto EVENT = (wlr_seat_request_set_selection_event*)data; - // wlr_seat_set_selection(g_pCompositor->m_sSeat.seat, EVENT->source, EVENT->serial); -} - void Events::listener_readyXWayland(wl_listener* listener, void* data) { #ifndef NO_XWAYLAND const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL); @@ -79,88 +69,6 @@ void Events::listener_readyXWayland(wl_listener* listener, void* data) { #endif } -void Events::listener_requestDrag(wl_listener* listener, void* data) { - // const auto E = (wlr_seat_request_start_drag_event*)data; - - // if (!wlr_seat_validate_pointer_grab_serial(g_pCompositor->m_sSeat.seat, E->origin, E->serial)) { - // Debug::log(LOG, "Ignoring drag and drop request: serial mismatch."); - // wlr_data_source_destroy(E->drag->source); - // return; - // } - - // wlr_seat_start_pointer_drag(g_pCompositor->m_sSeat.seat, E->drag, E->serial); -} - -void Events::listener_startDrag(wl_listener* listener, void* data) { - - if (g_pInputManager->m_sDrag.drag) - return; // don't handle multiple drags - - g_pInputManager->m_sDrag.drag = (wlr_drag*)data; - - wlr_drag* wlrDrag = (wlr_drag*)data; - - Debug::log(LOG, "Started drag {:x}", (uintptr_t)wlrDrag); - - wlrDrag->data = data; - - g_pInputManager->m_sDrag.hyprListener_destroy.initCallback(&wlrDrag->events.destroy, &Events::listener_destroyDrag, &g_pInputManager->m_sDrag, "Drag"); - - if (wlrDrag->icon) { - Debug::log(LOG, "Drag started with an icon {:x}", (uintptr_t)wlrDrag->icon); - - g_pInputManager->m_sDrag.dragIcon = wlrDrag->icon; - wlrDrag->icon->data = g_pInputManager->m_sDrag.dragIcon; - - g_pInputManager->m_sDrag.hyprListener_mapIcon.initCallback(&wlrDrag->icon->surface->events.map, &Events::listener_mapDragIcon, &g_pInputManager->m_sDrag, "DragIcon"); - g_pInputManager->m_sDrag.hyprListener_unmapIcon.initCallback(&wlrDrag->icon->surface->events.unmap, &Events::listener_unmapDragIcon, &g_pInputManager->m_sDrag, "DragIcon"); - g_pInputManager->m_sDrag.hyprListener_destroyIcon.initCallback(&wlrDrag->icon->events.destroy, &Events::listener_destroyDragIcon, &g_pInputManager->m_sDrag, "DragIcon"); - g_pInputManager->m_sDrag.hyprListener_commitIcon.initCallback(&wlrDrag->icon->surface->events.commit, &Events::listener_commitDragIcon, &g_pInputManager->m_sDrag, - "DragIcon"); - } -} - -void Events::listener_destroyDrag(void* owner, void* data) { - Debug::log(LOG, "Drag destroyed."); - - if (g_pInputManager->m_sDrag.drag && g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.dragIcon->surface) - g_pHyprRenderer->damageBox(g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, - g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4); - - g_pInputManager->m_sDrag.drag = nullptr; - g_pInputManager->m_sDrag.dragIcon = nullptr; - g_pInputManager->m_sDrag.hyprListener_destroy.removeCallback(); - - g_pCompositor->focusWindow(g_pCompositor->m_pLastWindow.lock(), - g_pCompositor->m_pLastWindow.lock() ? g_pXWaylandManager->getWindowSurface(g_pCompositor->m_pLastWindow.lock()) : nullptr); -} - -void Events::listener_mapDragIcon(void* owner, void* data) { - Debug::log(LOG, "Drag icon mapped."); - g_pInputManager->m_sDrag.iconMapped = true; -} - -void Events::listener_unmapDragIcon(void* owner, void* data) { - Debug::log(LOG, "Drag icon unmapped."); - g_pInputManager->m_sDrag.iconMapped = false; -} - -void Events::listener_destroyDragIcon(void* owner, void* data) { - Debug::log(LOG, "Drag icon destroyed."); - - g_pInputManager->m_sDrag.dragIcon = nullptr; - g_pInputManager->m_sDrag.hyprListener_commitIcon.removeCallback(); - g_pInputManager->m_sDrag.hyprListener_destroyIcon.removeCallback(); - g_pInputManager->m_sDrag.hyprListener_mapIcon.removeCallback(); - g_pInputManager->m_sDrag.hyprListener_unmapIcon.removeCallback(); -} - -void Events::listener_commitDragIcon(void* owner, void* data) { - g_pInputManager->updateDragIcon(); - - Debug::log(LOG, "Drag icon committed."); -} - void Events::listener_RendererDestroy(wl_listener* listener, void* data) { Debug::log(LOG, "!!Renderer destroyed!!"); } diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 7b24de7d..30f5aebf 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -58,25 +58,6 @@ struct SExtensionFindingData { wlr_surface** found; }; -struct SDrag { - wlr_drag* drag = nullptr; - - DYNLISTENER(destroy); - - // Icon - - bool iconMapped = false; - - wlr_drag_icon* dragIcon = nullptr; - - Vector2D pos; - - DYNLISTENER(destroyIcon); - DYNLISTENER(mapIcon); - DYNLISTENER(unmapIcon); - DYNLISTENER(commitIcon); -}; - struct SSwipeGesture { PHLWORKSPACE pWorkspaceBegin = nullptr; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 60d11e7f..6a0fb984 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -941,3 +941,7 @@ void CPointerManager::damageCursor(SP pMonitor) { return; } } + +Vector2D CPointerManager::cursorSizeLogical() { + return currentCursorImage.size / currentCursorImage.scale; +} diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 71ab0fc2..b6cb0c7a 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -52,6 +52,7 @@ class CPointerManager { // Vector2D position(); + Vector2D cursorSizeLogical(); private: void recheckPointerPosition(); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index e53eb111..8167103f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -28,13 +28,16 @@ #include "../protocols/Tablet.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" -#include "../protocols/core/Seat.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Seat.hpp" +#include "../protocols/core/DataDevice.hpp" + CProtocolManager::CProtocolManager() { // Core PROTO::seat = std::make_unique(&wl_seat_interface, 9, "WLSeat"); + PROTO::data = std::make_unique(&wl_data_device_manager_interface, 3, "WLDataDevice"); // Extensions PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index d962dd84..76840bd3 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -1,5 +1,6 @@ #include "SeatManager.hpp" #include "../protocols/core/Seat.hpp" +#include "../protocols/core/DataDevice.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include @@ -222,6 +223,8 @@ void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { p->sendMotion(timeMs, local); } + + lastLocalCoords = local; } void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state_) { @@ -424,6 +427,28 @@ SP CSeatManager::seatResourceForClient(wl_client* client) { return PROTO::seat->seatResourceForClient(client); } +void CSeatManager::setCurrentSelection(SP source) { + if (source == selection.currentSelection) { + Debug::log(WARN, "[seat] duplicated setCurrentSelection?"); + return; + } + + selection.destroySelection.reset(); + + if (selection.currentSelection) + selection.currentSelection->cancelled(); + + if (!source) + PROTO::data->setSelection(nullptr); + + selection.currentSelection = source; + + if (source) { + selection.destroySelection = source->events.destroy.registerListener([this](std::any d) { setCurrentSelection(nullptr); }); + PROTO::data->setSelection(source); + } +} + void CSeatManager::setGrab(SP grab) { if (seatGrab) { auto oldGrab = seatGrab; @@ -441,6 +466,19 @@ void CSeatManager::setGrab(SP grab) { refocusGrab(); } +void CSeatManager::resendEnterEvents() { + wlr_surface* kb = state.keyboardFocus; + wlr_surface* pt = state.pointerFocus; + + auto last = lastLocalCoords; + + setKeyboardFocus(nullptr); + setPointerFocus(nullptr, {}); + + setKeyboardFocus(kb); + setPointerFocus(pt, last); +} + bool CSeatGrab::accepts(wlr_surface* surf) { return std::find(surfs.begin(), surfs.end(), surf) != surfs.end(); } diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 16f11ffd..81ca663d 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -5,6 +5,7 @@ #include "../macros.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/Vector2D.hpp" +#include "../protocols/types/DataDevice.hpp" #include constexpr size_t MAX_SERIAL_STORE_LEN = 100; @@ -72,6 +73,8 @@ class CSeatManager { void sendTouchShape(int32_t id, const Vector2D& shape); void sendTouchOrientation(int32_t id, double angle); + void resendEnterEvents(); + uint32_t nextSerial(SP seatResource); // pops the serial if it was valid, meaning it is consumed. bool serialValid(SP seatResource, uint32_t serial); @@ -103,6 +106,13 @@ class CSeatManager { CSignal setCursor; // SSetCursorEvent } events; + struct { + WP currentSelection; + CHyprSignalListener destroySelection; + } selection; + + void setCurrentSelection(SP source); + // do not write to directly, use set... WP mouse; WP keyboard; @@ -132,6 +142,8 @@ class CSeatManager { CHyprSignalListener newSeatResource; } listeners; + Vector2D lastLocalCoords; + DYNLISTENER(keyboardSurfaceDestroy); DYNLISTENER(pointerSurfaceDestroy); DYNLISTENER(touchSurfaceDestroy); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index fe19c98f..d74657d9 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -15,6 +15,7 @@ #include "../../protocols/VirtualPointer.hpp" #include "../../protocols/LayerShell.hpp" #include "../../protocols/core/Seat.hpp" +#include "../../protocols/core/DataDevice.hpp" #include "../../protocols/XDGShell.hpp" #include "../../devices/Mouse.hpp" @@ -137,7 +138,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); - const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE; + const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; m_pFoundSurfaceToFocus = nullptr; m_pFoundLSToFocus.reset(); @@ -218,10 +219,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT.get()); } - // update stuff - updateDragIcon(); - - if (!m_sDrag.drag && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus) { + // if we are holding a pointer button, + // and we're not dnd-ing, don't refocus. Keep focus on last surface. + if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { foundSurface = g_pSeatManager->state.pointerFocus; pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); if (pFoundLayerSurface) { @@ -1356,22 +1356,6 @@ void CInputManager::refocus() { mouseMoveUnified(0, true); } -void CInputManager::updateDragIcon() { - if (!m_sDrag.dragIcon) - return; - - switch (m_sDrag.dragIcon->drag->grab_type) { - case WLR_DRAG_GRAB_KEYBOARD: break; - case WLR_DRAG_GRAB_KEYBOARD_POINTER: { - CBox box = {m_sDrag.pos.x - 2, m_sDrag.pos.y - 2, m_sDrag.dragIcon->surface->current.width + 4, m_sDrag.dragIcon->surface->current.height + 4}; - g_pHyprRenderer->damageBox(&box); - m_sDrag.pos = getMouseCoordsInternal(); - break; - } - default: break; - } -} - void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; @@ -1665,7 +1649,7 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) { void CInputManager::releaseAllMouseButtons() { const auto buttonsCopy = m_lCurrentlyHeldButtons; - if (g_pInputManager->m_sDrag.drag) + if (PROTO::data->dndActive()) return; for (auto& mb : buttonsCopy) { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 85efecb8..f7d9ae57 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -112,7 +112,6 @@ class CInputManager { void setTouchDeviceConfigs(SP dev = nullptr); void setTabletConfigs(); - void updateDragIcon(); void updateCapabilities(); void updateKeyboardsLeds(SP); @@ -143,8 +142,6 @@ class CInputManager { // for refocus to be forced PHLWINDOWREF m_pForcedFocus; - SDrag m_sDrag; - std::vector> m_vKeyboards; std::vector> m_vPointers; std::vector> m_vTouches; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp new file mode 100644 index 00000000..d332a0be --- /dev/null +++ b/src/protocols/core/DataDevice.cpp @@ -0,0 +1,655 @@ +#include "DataDevice.hpp" +#include +#include "../../managers/SeatManager.hpp" +#include "../../managers/PointerManager.hpp" +#include "../../Compositor.hpp" +#include "Seat.hpp" + +#define LOGM PROTO::data->protoLog + +CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWlDataOffer* r) { + if (!dead) + PROTO::data->completeDrag(); + PROTO::data->destroyResource(this); + }); + resource->setOnDestroy([this](CWlDataOffer* r) { + if (!dead) + PROTO::data->completeDrag(); + PROTO::data->destroyResource(this); + }); + + resource->setAccept([this](CWlDataOffer* r, uint32_t serial, const char* mime) { + if (!source) { + LOGM(WARN, "Possible bug: Accept on an offer w/o a source"); + return; + } + + if (dead) { + LOGM(WARN, "Possible bug: Accept on an offer that's dead"); + return; + } + + LOGM(LOG, "Offer {:x} accepts data from source {:x} with mime {}", (uintptr_t)this, (uintptr_t)source.get(), mime ? mime : "null"); + + source->accepted(mime ? mime : ""); + accepted = mime; + }); + + resource->setReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + if (!source) { + LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); + close(fd); + return; + } + + if (dead) { + LOGM(WARN, "Possible bug: Receive on an offer that's dead"); + close(fd); + return; + } + + LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); + + if (!accepted) { + LOGM(WARN, "Offer was never accepted, sending accept first"); + source->accepted(mime ? mime : ""); + } + + source->send(mime ? mime : "", fd); + + recvd = true; + + // if (source->hasDnd()) + // PROTO::data->completeDrag(); + }); + + resource->setFinish([this](CWlDataOffer* r) { + dead = true; + if (!source || !recvd || !accepted) + PROTO::data->abortDrag(); + else + PROTO::data->completeDrag(); + }); +} + +bool CWLDataOfferResource::good() { + return resource->resource(); +} + +void CWLDataOfferResource::sendData() { + if (!source) + return; + + resource->sendSourceActions(7); + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + + for (auto& m : source->mimes()) { + LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); + resource->sendOffer(m.c_str()); + } +} + +CWLDataSourceResource::CWLDataSourceResource(SP resource_, SP device_) : device(device_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CWlDataSource* r) { + events.destroy.emit(); + PROTO::data->onDestroyDataSource(self); + PROTO::data->destroyResource(this); + }); + resource->setOnDestroy([this](CWlDataSource* r) { + events.destroy.emit(); + PROTO::data->onDestroyDataSource(self); + PROTO::data->destroyResource(this); + }); + + resource->setOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); }); + resource->setSetActions([this](CWlDataSource* r, uint32_t a) { + LOGM(LOG, "DataSource {:x} actions {}", (uintptr_t)this, a); + actions = (wl_data_device_manager_dnd_action)a; + }); +} + +CWLDataSourceResource::~CWLDataSourceResource() { + events.destroy.emit(); + PROTO::data->onDestroyDataSource(self); +} + +SP CWLDataSourceResource::fromResource(wl_resource* res) { + auto data = (CWLDataSourceResource*)(((CWlDataSource*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLDataSourceResource::good() { + return resource->resource(); +} + +void CWLDataSourceResource::accepted(const std::string& mime) { + if (mime.empty()) { + resource->sendTarget(nullptr); + return; + } + + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { + LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAccepted with non-existent mime"); + return; + } + + resource->sendTarget(mime.c_str()); +} + +std::vector CWLDataSourceResource::mimes() { + return mimeTypes; +} + +void CWLDataSourceResource::send(const std::string& mime, uint32_t fd) { + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { + LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); + close(fd); + return; + } + + resource->sendSend(mime.c_str(), fd); + close(fd); +} + +void CWLDataSourceResource::cancelled() { + resource->sendCancelled(); +} + +bool CWLDataSourceResource::hasDnd() { + return dnd; +} + +bool CWLDataSourceResource::dndDone() { + return dndSuccess; +} + +void CWLDataSourceResource::error(uint32_t code, const std::string& msg) { + resource->error(code, msg); +} + +void CWLDataSourceResource::sendDndDropPerformed() { + if (resource->version() < 3) + return; + resource->sendDndDropPerformed(); +} + +void CWLDataSourceResource::sendDndFinished() { + if (resource->version() < 3) + return; + resource->sendDndFinished(); +} + +void CWLDataSourceResource::sendDndAction(wl_data_device_manager_dnd_action a) { + if (resource->version() < 3) + return; + resource->sendAction(a); +} + +CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setRelease([this](CWlDataDevice* r) { PROTO::data->destroyResource(this); }); + resource->setOnDestroy([this](CWlDataDevice* r) { PROTO::data->destroyResource(this); }); + + pClient = resource->client(); + + resource->setSetSelection([this](CWlDataDevice* r, wl_resource* sourceR, uint32_t serial) { + auto source = sourceR ? CWLDataSourceResource::fromResource(sourceR) : CSharedPointer{}; + if (!source) { + LOGM(LOG, "Reset selection received"); + g_pSeatManager->setCurrentSelection(nullptr); + return; + } + + if (source && source->used) + LOGM(WARN, "setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this."); + + source->markUsed(); + + g_pSeatManager->setCurrentSelection(source); + }); + + resource->setStartDrag([this](CWlDataDevice* r, wl_resource* sourceR, wl_resource* origin, wl_resource* icon, uint32_t serial) { + auto source = CWLDataSourceResource::fromResource(sourceR); + if (!source) { + LOGM(ERR, "No source in drag"); + return; + } + + if (source && source->used) + LOGM(WARN, "setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this."); + + source->markUsed(); + + source->dnd = true; + + PROTO::data->initiateDrag(source, wlr_surface_from_resource(icon), wlr_surface_from_resource(origin)); + }); +} + +bool CWLDataDeviceResource::good() { + return resource->resource(); +} + +wl_client* CWLDataDeviceResource::client() { + return pClient; +} + +void CWLDataDeviceResource::sendDataOffer(SP offer) { + if (offer) + resource->sendDataOffer(offer->resource.get()); + else + resource->sendDataOfferRaw(nullptr); +} + +void CWLDataDeviceResource::sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP offer) { + resource->sendEnterRaw(serial, surf->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource()); +} + +void CWLDataDeviceResource::sendLeave() { + resource->sendLeave(); +} + +void CWLDataDeviceResource::sendMotion(uint32_t timeMs, const Vector2D& local) { + resource->sendMotion(timeMs, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); +} + +void CWLDataDeviceResource::sendDrop() { + resource->sendDrop(); +} + +void CWLDataDeviceResource::sendSelection(SP offer) { + if (!offer) + resource->sendSelectionRaw(nullptr); + else + resource->sendSelection(offer->resource.get()); +} + +CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlDataDeviceManager* r) { PROTO::data->destroyResource(this); }); + + resource->setCreateDataSource([this](CWlDataDeviceManager* r, uint32_t id) { + std::erase_if(sources, [](const auto& e) { return e.expired(); }); + + const auto RESOURCE = PROTO::data->m_vSources.emplace_back(makeShared(makeShared(r->client(), r->version(), id), device.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::data->m_vSources.pop_back(); + return; + } + + if (!device) + LOGM(WARN, "New data source before a device was created"); + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New data source bound at {:x}", (uintptr_t)RESOURCE.get()); + }); + + resource->setGetDataDevice([this](CWlDataDeviceManager* r, uint32_t id, wl_resource* seat) { + const auto RESOURCE = PROTO::data->m_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::data->m_vDevices.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + for (auto& s : sources) { + if (!s) + continue; + s->device = RESOURCE; + } + + LOGM(LOG, "New data device bound at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CWLDataDeviceManagerResource::good() { + return resource->resource(); +} + +CWLDataDeviceProtocol::CWLDataDeviceProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLDataDeviceProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New datamgr resource bound at {:x}", (uintptr_t)RESOURCE.get()); + + // we need to do it here because protocols come before seatMgr + if (!listeners.onKeyboardFocusChange) + listeners.onKeyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { this->onKeyboardFocus(); }); +} + +void CWLDataDeviceProtocol::destroyResource(CWLDataDeviceManagerResource* seat) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == seat; }); +} + +void CWLDataDeviceProtocol::destroyResource(CWLDataDeviceResource* resource) { + std::erase_if(m_vDevices, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLDataDeviceProtocol::destroyResource(CWLDataSourceResource* resource) { + std::erase_if(m_vSources, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLDataDeviceProtocol::destroyResource(CWLDataOfferResource* resource) { + std::erase_if(m_vOffers, [&](const auto& other) { return other.get() == resource; }); +} + +SP CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) { + auto it = std::find_if(m_vDevices.begin(), m_vDevices.end(), [c](const auto& e) { return e->client() == c; }); + if (it == m_vDevices.end()) + return nullptr; + return *it; +} + +void CWLDataDeviceProtocol::sendSelectionToDevice(SP dev, SP sel) { + if (!sel) { + dev->sendSelection(nullptr); + return; + } + + const auto OFFER = m_vOffers.emplace_back(makeShared(makeShared(dev->resource->client(), dev->resource->version(), 0), sel)); + + if (!OFFER->good()) { + dev->resource->noMemory(); + m_vOffers.pop_back(); + return; + } + + LOGM(LOG, "New offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)sel.get()); + + dev->sendDataOffer(OFFER); + OFFER->sendData(); + dev->sendSelection(OFFER); +} + +void CWLDataDeviceProtocol::onDestroyDataSource(WP source) { + if (dnd.currentSource == source) + abortDrag(); +} + +void CWLDataDeviceProtocol::setSelection(SP source) { + for (auto& o : m_vOffers) { + if (o->source && o->source->hasDnd()) + continue; + o->dead = true; + } + + if (!source) { + LOGM(LOG, "resetting selection"); + + if (!g_pSeatManager->state.keyboardFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client()); + if (DESTDEVICE) + sendSelectionToDevice(DESTDEVICE, nullptr); + + return; + } + + LOGM(LOG, "New selection for data source {:x}", (uintptr_t)source.get()); + + if (!g_pSeatManager->state.keyboardFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client()); + + if (!DESTDEVICE) { + LOGM(LOG, "CWLDataDeviceProtocol::setSelection: cannot send selection to a client without a data_device"); + return; + } + + sendSelectionToDevice(DESTDEVICE, source); +} + +void CWLDataDeviceProtocol::updateSelection() { + if (!g_pSeatManager->state.keyboardFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client()); + + if (!DESTDEVICE) { + LOGM(LOG, "CWLDataDeviceProtocol::onKeyboardFocus: cannot send selection to a client without a data_device"); + return; + } + + sendSelectionToDevice(DESTDEVICE, g_pSeatManager->selection.currentSelection.lock()); +} + +void CWLDataDeviceProtocol::onKeyboardFocus() { + for (auto& o : m_vOffers) { + o->dead = true; + } + + updateSelection(); + updateDrag(); +} + +void CWLDataDeviceProtocol::initiateDrag(WP currentSource, wlr_surface* dragSurface, wlr_surface* origin) { + + if (dnd.currentSource) { + LOGM(WARN, "New drag started while old drag still active??"); + abortDrag(); + } + + g_pInputManager->setCursorImageUntilUnset("grabbing"); + dnd.overriddenCursor = true; + + LOGM(LOG, "initiateDrag: source {:x}, surface: {:x}, origin: {:x}", (uintptr_t)currentSource.get(), (uintptr_t)dragSurface, (uintptr_t)origin); + + currentSource->used = true; + + dnd.currentSource = currentSource; + dnd.originSurface = origin; + dnd.dndSurface = dragSurface; + dnd.hyprListener_dndSurfaceDestroy.initCallback( + &dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag"); + dnd.hyprListener_dndSurfaceCommit.initCallback( + &dragSurface->events.commit, + [this](void* owner, void* data) { + if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) { + wlr_surface_map(dnd.dndSurface); + return; + } + + if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) { + wlr_surface_unmap(dnd.dndSurface); + return; + } + }, + nullptr, "CWLDataDeviceProtocol::drag"); + + dnd.mouseButton = g_pHookSystem->hookDynamic("mouseButton", [this](void* self, SCallbackInfo& info, std::any e) { + auto E = std::any_cast(e); + if (E.state == WL_POINTER_BUTTON_STATE_RELEASED) { + LOGM(LOG, "Dropping drag on mouseUp"); + dropDrag(); + } + }); + + dnd.touchUp = g_pHookSystem->hookDynamic("touchUp", [this](void* self, SCallbackInfo& info, std::any e) { + LOGM(LOG, "Dropping drag on touchUp"); + dropDrag(); + }); + + dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) { + auto V = std::any_cast(e); + if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { + auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + + if (!surf) + return; + + const auto box = surf->getSurfaceBoxGlobal(); + + if (!box.has_value()) + return; + + dnd.focusedDevice->sendMotion(0 /* this is a hack */, V - box->pos()); + LOGM(LOG, "Drag motion {}", V - box->pos()); + } + }); + + dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) { + auto E = std::any_cast(e); + if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { + auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + + if (!surf) + return; + + const auto box = surf->getSurfaceBoxGlobal(); + + if (!box.has_value()) + return; + + dnd.focusedDevice->sendMotion(E.timeMs, E.pos); + LOGM(LOG, "Drag motion {}", E.pos); + } + }); + + // make a new offer, etc + updateDrag(); +} + +void CWLDataDeviceProtocol::updateDrag() { + if (!dnd.currentSource) + return; + + if (dnd.focusedDevice) + dnd.focusedDevice->sendLeave(); + + if (!g_pSeatManager->state.keyboardFocusResource) + return; + + dnd.focusedDevice = dataDeviceForClient(g_pSeatManager->state.keyboardFocusResource->client()); + + if (!dnd.focusedDevice) + return; + + // make a new offer + const auto OFFER = m_vOffers.emplace_back( + makeShared(makeShared(dnd.focusedDevice->resource->client(), dnd.focusedDevice->resource->version(), 0), dnd.currentSource.lock())); + + if (!OFFER->good()) { + dnd.currentSource->resource->noMemory(); + m_vOffers.pop_back(); + return; + } + + LOGM(LOG, "New dnd offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)dnd.currentSource.get()); + + dnd.focusedDevice->sendDataOffer(OFFER); + OFFER->sendData(); + dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus, + Vector2D{g_pSeatManager->state.keyboardFocus->current.width, g_pSeatManager->state.keyboardFocus->current.height} / 2.F, OFFER); +} + +void CWLDataDeviceProtocol::resetDndState() { + dnd.dndSurface = nullptr; + dnd.hyprListener_dndSurfaceDestroy.removeCallback(); + dnd.hyprListener_dndSurfaceCommit.removeCallback(); + dnd.mouseButton.reset(); + dnd.mouseMove.reset(); + dnd.touchUp.reset(); + dnd.touchMove.reset(); +} + +void CWLDataDeviceProtocol::dropDrag() { + if (!dnd.focusedDevice || !dnd.currentSource) { + if (dnd.currentSource) + abortDrag(); + return; + } + + dnd.currentSource->sendDndDropPerformed(); + dnd.focusedDevice->sendDrop(); + dnd.focusedDevice->sendLeave(); + + resetDndState(); + + if (dnd.overriddenCursor) + g_pInputManager->unsetCursorImage(); + dnd.overriddenCursor = false; +} + +void CWLDataDeviceProtocol::completeDrag() { + resetDndState(); + + if (!dnd.focusedDevice || !dnd.currentSource) + return; + + dnd.currentSource->sendDndFinished(); + + dnd.focusedDevice.reset(); + dnd.currentSource.reset(); + + g_pSeatManager->resendEnterEvents(); +} + +void CWLDataDeviceProtocol::abortDrag() { + resetDndState(); + + if (dnd.overriddenCursor) + g_pInputManager->unsetCursorImage(); + dnd.overriddenCursor = false; + + if (!dnd.focusedDevice || !dnd.currentSource) + return; + + dnd.focusedDevice->sendLeave(); + dnd.currentSource->cancelled(); + + dnd.focusedDevice.reset(); + dnd.currentSource.reset(); + + g_pSeatManager->resendEnterEvents(); +} + +void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { + if (!dnd.dndSurface || !wlr_surface_get_texture(dnd.dndSurface)) + return; + + const auto POS = g_pInputManager->getMouseCoordsInternal(); + + CBox box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}} + .translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F) + .scale(pMonitor->scale); + g_pHyprOpenGL->renderTexture(wlr_surface_get_texture(dnd.dndSurface), &box, 1.F); + + box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); + g_pHyprRenderer->damageBox(&box); + + wlr_surface_send_frame_done(dnd.dndSurface, when); +} + +bool CWLDataDeviceProtocol::dndActive() { + return dnd.currentSource; +} diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp new file mode 100644 index 00000000..3112b720 --- /dev/null +++ b/src/protocols/core/DataDevice.hpp @@ -0,0 +1,194 @@ +#pragma once + +/* + Implementations for: + - wl_data_offer + - wl_data_source + - wl_data_device + - wl_data_device_manager +*/ + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../helpers/Vector2D.hpp" +#include "../types/DataDevice.hpp" + +class CWLDataDeviceResource; +class CWLDataDeviceManagerResource; +class CWLDataSourceResource; +class CWLDataOfferResource; + +class CMonitor; + +class CWLDataOfferResource { + public: + CWLDataOfferResource(SP resource_, SP source_); + + bool good(); + void sendData(); + + WP source; + + bool dead = false; + bool accepted = false; + bool recvd = false; + + uint32_t actions = 0; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CWLDataDeviceResource; +}; + +class CWLDataSourceResource : public IDataSource { + public: + CWLDataSourceResource(SP resource_, SP device_); + ~CWLDataSourceResource(); + static SP fromResource(wl_resource*); + + bool good(); + + virtual std::vector mimes(); + virtual void send(const std::string& mime, uint32_t fd); + virtual void accepted(const std::string& mime); + virtual void cancelled(); + virtual bool hasDnd(); + virtual bool dndDone(); + virtual void error(uint32_t code, const std::string& msg); + + void sendDndDropPerformed(); + void sendDndFinished(); + void sendDndAction(wl_data_device_manager_dnd_action a); + + bool used = false; + bool dnd = false; + bool dndSuccess = false; + + WP device; + WP self; + + std::vector mimeTypes; + uint32_t actions = 0; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CWLDataDeviceProtocol; +}; + +class CWLDataDeviceResource { + public: + CWLDataDeviceResource(SP resource_); + + bool good(); + wl_client* client(); + + void sendDataOffer(SP offer); + void sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP offer); + void sendLeave(); + void sendMotion(uint32_t timeMs, const Vector2D& local); + void sendDrop(); + void sendSelection(SP offer); + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CWLDataDeviceProtocol; +}; + +class CWLDataDeviceManagerResource { + public: + CWLDataDeviceManagerResource(SP resource_); + + bool good(); + + WP device; + std::vector> sources; + + private: + SP resource; +}; + +class CWLDataDeviceProtocol : public IWaylandProtocol { + public: + CWLDataDeviceProtocol(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); + + // renders and damages the dnd icon, if present + void renderDND(CMonitor* pMonitor, timespec* when); + // for inputmgr to force refocus + // TODO: move handling to seatmgr + bool dndActive(); + + private: + void destroyResource(CWLDataDeviceManagerResource* resource); + void destroyResource(CWLDataDeviceResource* resource); + void destroyResource(CWLDataSourceResource* resource); + void destroyResource(CWLDataOfferResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vDevices; + std::vector> m_vSources; + std::vector> m_vOffers; + + // + + void onDestroyDataSource(WP source); + void setSelection(SP source); + void sendSelectionToDevice(SP dev, SP sel); + void updateSelection(); + void onKeyboardFocus(); + + struct { + WP focusedDevice; + WP currentSource; + wlr_surface* dndSurface = nullptr; + wlr_surface* originSurface = nullptr; // READ-ONLY + bool overriddenCursor = false; + DYNLISTENER(dndSurfaceDestroy); + DYNLISTENER(dndSurfaceCommit); + + // for ending a dnd + SP mouseMove; + SP mouseButton; + SP touchUp; + SP touchMove; + } dnd; + + void abortDrag(); + void initiateDrag(WP currentSource, wlr_surface* dragSurface, wlr_surface* origin); + void updateDrag(); + void dropDrag(); + void completeDrag(); + void resetDndState(); + + // + SP dataDeviceForClient(wl_client*); + + friend class CSeatManager; + friend class CWLDataDeviceManagerResource; + friend class CWLDataDeviceResource; + friend class CWLDataSourceResource; + friend class CWLDataOfferResource; + + struct { + CHyprSignalListener onKeyboardFocusChange; + } listeners; +}; + +namespace PROTO { + inline UP data; +}; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp new file mode 100644 index 00000000..47cbda8b --- /dev/null +++ b/src/protocols/types/DataDevice.cpp @@ -0,0 +1,17 @@ +#include "DataDevice.hpp" + +bool IDataSource::hasDnd() { + return false; +} + +bool IDataSource::dndDone() { + return false; +} + +bool IDataSource::used() { + return wasUsed; +} + +void IDataSource::markUsed() { + wasUsed = true; +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp new file mode 100644 index 00000000..98a97c14 --- /dev/null +++ b/src/protocols/types/DataDevice.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include "../../helpers/signal/Signal.hpp" + +class IDataSource { + public: + IDataSource() {} + virtual ~IDataSource() {} + + virtual std::vector mimes() = 0; + virtual void send(const std::string& mime, uint32_t fd) = 0; + virtual void accepted(const std::string& mime) = 0; + virtual void cancelled() = 0; + virtual bool hasDnd(); + virtual bool dndDone(); + virtual bool used(); + virtual void markUsed(); + virtual void error(uint32_t code, const std::string& msg) = 0; + + struct { + CSignal destroy; + } events; + + private: + bool wasUsed = false; +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1aa246fb..c5c87ea1 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -12,6 +12,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/PresentationTime.hpp" +#include "../protocols/core/DataDevice.hpp" extern "C" { #include @@ -1806,19 +1807,7 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion } void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) { - if (!(g_pInputManager->m_sDrag.dragIcon && g_pInputManager->m_sDrag.iconMapped && g_pInputManager->m_sDrag.dragIcon->surface)) - return; - - SRenderData renderdata = {pMonitor, time, g_pInputManager->m_sDrag.pos.x, g_pInputManager->m_sDrag.pos.y}; - renderdata.surface = g_pInputManager->m_sDrag.dragIcon->surface; - renderdata.w = g_pInputManager->m_sDrag.dragIcon->surface->current.width; - renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height; - - wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata); - - CBox box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, - g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4}; - g_pHyprRenderer->damageBox(&box); + PROTO::data->renderDND(pMonitor, time); } DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) { @@ -2500,7 +2489,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { const auto PWORKSPACE = pMonitor->activeWorkspace; - if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha.value() != 1.f || + if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || PROTO::data->dndActive() || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha.value() != 1.f || PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) return; From eed1361f390590d406450c0747e4e2ce40a548fb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 12 May 2024 15:55:46 +0100 Subject: [PATCH 0085/2393] wlr-data-device: move to hyprland impl --- CMakeLists.txt | 1 + protocols/meson.build | 1 + protocols/wlr-data-control-unstable-v1.xml | 278 ++++++++++++++++++ src/managers/ProtocolManager.cpp | 2 + src/managers/SeatManager.cpp | 2 + src/protocols/DataDeviceWlr.cpp | 310 +++++++++++++++++++++ src/protocols/DataDeviceWlr.hpp | 121 ++++++++ src/protocols/core/DataDevice.cpp | 2 + 8 files changed, 717 insertions(+) create mode 100644 protocols/wlr-data-control-unstable-v1.xml create mode 100644 src/protocols/DataDeviceWlr.cpp create mode 100644 src/protocols/DataDeviceWlr.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 80483c4f..3cdae161 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,6 +271,7 @@ protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) +protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true) protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) diff --git a/protocols/meson.build b/protocols/meson.build index 4b7aa200..adedbf8e 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -42,6 +42,7 @@ new_protocols = [ ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], ['wlr-layer-shell-unstable-v1.xml'], + ['wlr-data-control-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], diff --git a/protocols/wlr-data-control-unstable-v1.xml b/protocols/wlr-data-control-unstable-v1.xml new file mode 100644 index 00000000..75e8671b --- /dev/null +++ b/protocols/wlr-data-control-unstable-v1.xml @@ -0,0 +1,278 @@ + + + + Copyright © 2018 Simon Ser + Copyright © 2019 Ivan Molodetskikh + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + This protocol allows a privileged client to control data devices. In + particular, the client will be able to manage the current selection and take + the role of a clipboard manager. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + This interface is a manager that allows creating per-seat data device + controls. + + + + + Create a new data source. + + + + + + + Create a data device that can be used to manage a seat's selection. + + + + + + + + All objects created by the manager will still remain valid, until their + appropriate destroy request has been called. + + + + + + + This interface allows a client to manage a seat's selection. + + When the seat is destroyed, this object becomes inert. + + + + + This request asks the compositor to set the selection to the data from + the source on behalf of the client. + + The given source may not be used in any further set_selection or + set_primary_selection requests. Attempting to use a previously used + source is a protocol error. + + To unset the selection, set the source to NULL. + + + + + + + Destroys the data device object. + + + + + + The data_offer event introduces a new wlr_data_control_offer object, + which will subsequently be used in either the + wlr_data_control_device.selection event (for the regular clipboard + selections) or the wlr_data_control_device.primary_selection event (for + the primary clipboard selections). Immediately following the + wlr_data_control_device.data_offer event, the new data_offer object + will send out wlr_data_control_offer.offer events to describe the MIME + types it offers. + + + + + + + The selection event is sent out to notify the client of a new + wlr_data_control_offer for the selection for this device. The + wlr_data_control_device.data_offer and the wlr_data_control_offer.offer + events are sent out immediately before this event to introduce the data + offer object. The selection event is sent to a client when a new + selection is set. The wlr_data_control_offer is valid until a new + wlr_data_control_offer or NULL is received. The client must destroy the + previous selection wlr_data_control_offer, if any, upon receiving this + event. + + The first selection event is sent upon binding the + wlr_data_control_device object. + + + + + + + This data control object is no longer valid and should be destroyed by + the client. + + + + + + + + The primary_selection event is sent out to notify the client of a new + wlr_data_control_offer for the primary selection for this device. The + wlr_data_control_device.data_offer and the wlr_data_control_offer.offer + events are sent out immediately before this event to introduce the data + offer object. The primary_selection event is sent to a client when a + new primary selection is set. The wlr_data_control_offer is valid until + a new wlr_data_control_offer or NULL is received. The client must + destroy the previous primary selection wlr_data_control_offer, if any, + upon receiving this event. + + If the compositor supports primary selection, the first + primary_selection event is sent upon binding the + wlr_data_control_device object. + + + + + + + This request asks the compositor to set the primary selection to the + data from the source on behalf of the client. + + The given source may not be used in any further set_selection or + set_primary_selection requests. Attempting to use a previously used + source is a protocol error. + + To unset the primary selection, set the source to NULL. + + The compositor will ignore this request if it does not support primary + selection. + + + + + + + + + + + + The wlr_data_control_source object is the source side of a + wlr_data_control_offer. It is created by the source client in a data + transfer and provides a way to describe the offered data and a way to + respond to requests to transfer the data. + + + + + + + + + This request adds a MIME type to the set of MIME types advertised to + targets. Can be called several times to offer multiple types. + + Calling this after wlr_data_control_device.set_selection is a protocol + error. + + + + + + + Destroys the data source object. + + + + + + Request for data from the client. Send the data as the specified MIME + type over the passed file descriptor, then close it. + + + + + + + + This data source is no longer valid. The data source has been replaced + by another data source. + + The client should clean up and destroy this data source. + + + + + + + A wlr_data_control_offer represents a piece of data offered for transfer + by another client (the source client). The offer describes the different + MIME types that the data can be converted to and provides the mechanism + for transferring the data directly from the source client. + + + + + To transfer the offered data, the client issues this request and + indicates the MIME type it wants to receive. The transfer happens + through the passed file descriptor (typically created with the pipe + system call). The source client writes the data in the MIME type + representation requested and then closes the file descriptor. + + The receiving client reads from the read end of the pipe until EOF and + then closes its end, at which point the transfer is complete. + + This request may happen multiple times for different MIME types. + + + + + + + + Destroys the data offer object. + + + + + + Sent immediately after creating the wlr_data_control_offer object. + One event per offered MIME type. + + + + + diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 8167103f..4b03263b 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -29,6 +29,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/DataDeviceWlr.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -69,6 +70,7 @@ CProtocolManager::CProtocolManager() { PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); PROTO::presentation = std::make_unique(&wp_presentation_interface, 1, "Presentation"); PROTO::xdgShell = std::make_unique(&xdg_wm_base_interface, 6, "XDGShell"); + PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 76840bd3..a8505610 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -1,6 +1,7 @@ #include "SeatManager.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/DataDeviceWlr.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include @@ -446,6 +447,7 @@ void CSeatManager::setCurrentSelection(SP source) { if (source) { selection.destroySelection = source->events.destroy.registerListener([this](std::any d) { setCurrentSelection(nullptr); }); PROTO::data->setSelection(source); + PROTO::dataWlr->setSelection(source); } } diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp new file mode 100644 index 00000000..a518b0ae --- /dev/null +++ b/src/protocols/DataDeviceWlr.cpp @@ -0,0 +1,310 @@ +#include "DataDeviceWlr.hpp" +#include +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" + +#define LOGM PROTO::dataWlr->protoLog + +CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); + resource->setOnDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); + + resource->setReceive([this](CZwlrDataControlOfferV1* r, const char* mime, int32_t fd) { + if (!source) { + LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); + close(fd); + return; + } + + if (dead) { + LOGM(WARN, "Possible bug: Receive on an offer that's dead"); + close(fd); + return; + } + + LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); + + source->send(mime, fd); + }); +} + +bool CWLRDataOffer::good() { + return resource->resource(); +} + +void CWLRDataOffer::sendData() { + if (!source) + return; + + for (auto& m : source->mimes()) { + resource->sendOffer(m.c_str()); + } +} + +CWLRDataSource::CWLRDataSource(SP resource_, SP device_) : device(device_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CZwlrDataControlSourceV1* r) { + events.destroy.emit(); + PROTO::dataWlr->destroyResource(this); + }); + resource->setOnDestroy([this](CZwlrDataControlSourceV1* r) { + events.destroy.emit(); + PROTO::dataWlr->destroyResource(this); + }); + + resource->setOffer([this](CZwlrDataControlSourceV1* r, const char* mime) { mimeTypes.push_back(mime); }); +} + +CWLRDataSource::~CWLRDataSource() { + events.destroy.emit(); +} + +SP CWLRDataSource::fromResource(wl_resource* res) { + auto data = (CWLRDataSource*)(((CZwlrDataControlSourceV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLRDataSource::good() { + return resource->resource(); +} + +std::vector CWLRDataSource::mimes() { + return mimeTypes; +} + +void CWLRDataSource::send(const std::string& mime, uint32_t fd) { + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { + LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); + close(fd); + return; + } + + resource->sendSend(mime.c_str(), fd); + close(fd); +} + +void CWLRDataSource::accepted(const std::string& mime) { + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) + LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAccepted with non-existent mime"); + + // wlr has no accepted +} + +void CWLRDataSource::cancelled() { + resource->sendCancelled(); +} + +void CWLRDataSource::error(uint32_t code, const std::string& msg) { + resource->error(code, msg); +} + +CWLRDataDevice::CWLRDataDevice(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CZwlrDataControlDeviceV1* r) { PROTO::dataWlr->destroyResource(this); }); + resource->setOnDestroy([this](CZwlrDataControlDeviceV1* r) { PROTO::dataWlr->destroyResource(this); }); + + resource->setSetSelection([this](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { + auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; + if (!source) { + LOGM(LOG, "wlr reset selection received"); + g_pSeatManager->setCurrentSelection(nullptr); + return; + } + + if (source && source->used()) + LOGM(WARN, "setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this."); + + source->markUsed(); + + LOGM(LOG, "wlr manager requests selection to {:x}", (uintptr_t)source.get()); + g_pSeatManager->setCurrentSelection(source); + }); + + resource->setSetPrimarySelection([this](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { + auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; + if (!source) { + LOGM(LOG, "wlr reset primary selection received"); + g_pSeatManager->setCurrentSelection(nullptr); + return; + } + + if (source && source->used()) + LOGM(WARN, "setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this."); + + source->markUsed(); + + LOGM(LOG, "wlr manager requests primary selection to {:x}", (uintptr_t)source.get()); + g_pSeatManager->setCurrentSelection(source); + }); +} + +bool CWLRDataDevice::good() { + return resource->resource(); +} + +wl_client* CWLRDataDevice::client() { + return pClient; +} + +void CWLRDataDevice::sendInitialSelections() { + PROTO::dataWlr->sendSelectionToDevice(self.lock(), g_pSeatManager->selection.currentSelection.lock(), false); + PROTO::dataWlr->sendSelectionToDevice(self.lock(), g_pSeatManager->selection.currentPrimarySelection.lock(), true); +} + +void CWLRDataDevice::sendDataOffer(SP offer) { + resource->sendDataOffer(offer->resource.get()); +} + +void CWLRDataDevice::sendSelection(SP selection) { + resource->sendSelection(selection->resource.get()); +} + +CWLRDataControlManagerResource::CWLRDataControlManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwlrDataControlManagerV1* r) { PROTO::dataWlr->destroyResource(this); }); + resource->setOnDestroy([this](CZwlrDataControlManagerV1* r) { PROTO::dataWlr->destroyResource(this); }); + + resource->setGetDataDevice([this](CZwlrDataControlManagerV1* r, uint32_t id, wl_resource* seat) { + const auto RESOURCE = PROTO::dataWlr->m_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::dataWlr->m_vDevices.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + device = RESOURCE; + + for (auto& s : sources) { + if (!s) + continue; + s->device = RESOURCE; + } + + RESOURCE->sendInitialSelections(); + + LOGM(LOG, "New wlr data device bound at {:x}", (uintptr_t)RESOURCE.get()); + }); + + resource->setCreateDataSource([this](CZwlrDataControlManagerV1* r, uint32_t id) { + std::erase_if(sources, [](const auto& e) { return e.expired(); }); + + const auto RESOURCE = + PROTO::dataWlr->m_vSources.emplace_back(makeShared(makeShared(r->client(), r->version(), id), device.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::dataWlr->m_vSources.pop_back(); + return; + } + + if (!device) + LOGM(WARN, "New data source before a device was created"); + + RESOURCE->self = RESOURCE; + + sources.push_back(RESOURCE); + + LOGM(LOG, "New wlr data source bound at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CWLRDataControlManagerResource::good() { + return resource->resource(); +} + +CDataDeviceWLRProtocol::CDataDeviceWLRProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CDataDeviceWLRProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New wlr_data_control_manager at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CDataDeviceWLRProtocol::destroyResource(CWLRDataControlManagerResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CDataDeviceWLRProtocol::destroyResource(CWLRDataSource* resource) { + std::erase_if(m_vSources, [&](const auto& other) { return other.get() == resource; }); +} + +void CDataDeviceWLRProtocol::destroyResource(CWLRDataDevice* resource) { + std::erase_if(m_vDevices, [&](const auto& other) { return other.get() == resource; }); +} + +void CDataDeviceWLRProtocol::destroyResource(CWLRDataOffer* resource) { + std::erase_if(m_vOffers, [&](const auto& other) { return other.get() == resource; }); +} + +void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SP sel) { + if (!sel) + return; + + const auto OFFER = m_vOffers.emplace_back(makeShared(makeShared(dev->resource->client(), dev->resource->version(), 0), sel)); + + if (!OFFER->good()) { + dev->resource->noMemory(); + m_vOffers.pop_back(); + return; + } + + LOGM(LOG, "New offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)sel.get()); + + dev->sendDataOffer(OFFER); + OFFER->sendData(); + dev->sendSelection(OFFER); +} + +void CDataDeviceWLRProtocol::setSelection(SP source) { + for (auto& o : m_vOffers) { + if (o->source && o->source->hasDnd()) + continue; + o->dead = true; + } + + if (!source) { + LOGM(LOG, "resetting selection"); + + for (auto& d : m_vDevices) { + sendSelectionToDevice(d, nullptr); + } + + return; + } + + LOGM(LOG, "New selection for data source {:x}", (uintptr_t)source.get()); + + for (auto& d : m_vDevices) { + sendSelectionToDevice(d, source); + } +} + +SP CDataDeviceWLRProtocol::dataDeviceForClient(wl_client* c) { + auto it = std::find_if(m_vDevices.begin(), m_vDevices.end(), [c](const auto& e) { return e->client() == c; }); + if (it == m_vDevices.end()) + return nullptr; + return *it; +} diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp new file mode 100644 index 00000000..0b703347 --- /dev/null +++ b/src/protocols/DataDeviceWlr.hpp @@ -0,0 +1,121 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wlr-data-control-unstable-v1.hpp" +#include "types/DataDevice.hpp" + +class CWLRDataControlManagerResource; +class CWLRDataSource; +class CWLRDataDevice; +class CWLRDataOffer; + +class CWLRDataOffer { + public: + CWLRDataOffer(SP resource_, SP source); + + bool good(); + void sendData(); + + bool dead = false; + + WP source; + + private: + SP resource; + + friend class CWLRDataDevice; +}; + +class CWLRDataSource : public IDataSource { + public: + CWLRDataSource(SP resource_, SP device_); + ~CWLRDataSource(); + static SP fromResource(wl_resource*); + + bool good(); + + virtual std::vector mimes(); + virtual void send(const std::string& mime, uint32_t fd); + virtual void accepted(const std::string& mime); + virtual void cancelled(); + virtual void error(uint32_t code, const std::string& msg); + + std::vector mimeTypes; + WP self; + WP device; + + private: + SP resource; +}; + +class CWLRDataDevice { + public: + CWLRDataDevice(SP resource_); + + bool good(); + wl_client* client(); + void sendInitialSelections(); + + void sendDataOffer(SP offer); + void sendSelection(SP selection); + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CDataDeviceWLRProtocol; +}; + +class CWLRDataControlManagerResource { + public: + CWLRDataControlManagerResource(SP resource_); + + bool good(); + + WP device; + std::vector> sources; + + private: + SP resource; +}; + +class CDataDeviceWLRProtocol : public IWaylandProtocol { + public: + CDataDeviceWLRProtocol(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); + + private: + void destroyResource(CWLRDataControlManagerResource* resource); + void destroyResource(CWLRDataSource* resource); + void destroyResource(CWLRDataDevice* resource); + void destroyResource(CWLRDataOffer* resource); + + // + std::vector> m_vManagers; + std::vector> m_vSources; + std::vector> m_vDevices; + std::vector> m_vOffers; + + // + void setSelection(SP source); + void sendSelectionToDevice(SP dev, SP sel); + + // + SP dataDeviceForClient(wl_client*); + + friend class CSeatManager; + friend class CWLRDataControlManagerResource; + friend class CWLRDataSource; + friend class CWLRDataDevice; + friend class CWLRDataOffer; +}; + +namespace PROTO { + inline UP dataWlr; +}; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index d332a0be..2b9503b1 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -297,6 +297,8 @@ CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SPself = RESOURCE; + sources.push_back(RESOURCE); + LOGM(LOG, "New data source bound at {:x}", (uintptr_t)RESOURCE.get()); }); From 3eeaea5be9324121678774761c0226fe98bf7e5b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 12 May 2024 20:26:42 +0300 Subject: [PATCH 0086/2393] Meson: add wayland.xml proto --- protocols/meson.build | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index adedbf8e..d583c466 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -24,7 +24,6 @@ hyprwayland_scanner = find_program( ) 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-screencopy-unstable-v1.xml'], @@ -99,12 +98,27 @@ foreach p : new_protocols ) endforeach -wayland_server = dependency('wayland-server', version: '>=1.20.0') +wayland_server_dep = dependency('wayland-server', version: '>=1.20.0') +wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir') + +wl_server_protos = [ + wayland_server_dir / 'wayland.xml' +] +wl_server_protos_gen = [] +foreach p : wl_server_protos + wl_server_protos_gen += custom_target( + p.underscorify(), + input: p, + install: false, + output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], + command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], + ) +endforeach lib_server_protos = static_library( 'server_protos', - wl_protos_src + wl_protos_headers + new_wl_protos, - dependencies: wayland_server.partial_dependency(compile_args: true), + wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen, + dependencies: wayland_server_dep.partial_dependency(compile_args: true), ) server_protos = declare_dependency( From 94c20a186372aace78b188842848b873eb3ebbd7 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 13 May 2024 21:47:59 +0100 Subject: [PATCH 0087/2393] primary-selection: move to hyprland impl --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/config/ConfigManager.cpp | 1 + src/managers/ProtocolManager.cpp | 2 + src/managers/SeatManager.cpp | 26 ++- src/managers/SeatManager.hpp | 3 + src/protocols/DataDeviceWlr.cpp | 36 ++- src/protocols/DataDeviceWlr.hpp | 8 +- src/protocols/PrimarySelection.cpp | 338 +++++++++++++++++++++++++++++ src/protocols/PrimarySelection.hpp | 127 +++++++++++ 10 files changed, 529 insertions(+), 14 deletions(-) create mode 100644 src/protocols/PrimarySelection.cpp create mode 100644 src/protocols/PrimarySelection.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cdae161..9897185f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,6 +293,7 @@ protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) +protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false) protocolWayland() diff --git a/protocols/meson.build b/protocols/meson.build index d583c466..6b0b4d18 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -62,6 +62,7 @@ new_protocols = [ [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], ] wl_protos_src = [] diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 15d5ae81..bec651b2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -346,6 +346,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); + m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 4b03263b..c43e4c56 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -30,6 +30,7 @@ #include "../protocols/PresentationTime.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/DataDeviceWlr.hpp" +#include "../protocols/PrimarySelection.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -71,6 +72,7 @@ CProtocolManager::CProtocolManager() { PROTO::presentation = std::make_unique(&wp_presentation_interface, 1, "Presentation"); PROTO::xdgShell = std::make_unique(&xdg_wm_base_interface, 6, "XDGShell"); PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); + PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index a8505610..3e2d595f 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -2,6 +2,7 @@ #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" #include "../protocols/DataDeviceWlr.hpp" +#include "../protocols/PrimarySelection.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include @@ -447,7 +448,30 @@ void CSeatManager::setCurrentSelection(SP source) { if (source) { selection.destroySelection = source->events.destroy.registerListener([this](std::any d) { setCurrentSelection(nullptr); }); PROTO::data->setSelection(source); - PROTO::dataWlr->setSelection(source); + PROTO::dataWlr->setSelection(source, false); + } +} + +void CSeatManager::setCurrentPrimarySelection(SP source) { + if (source == selection.currentPrimarySelection) { + Debug::log(WARN, "[seat] duplicated setCurrentPrimarySelection?"); + return; + } + + selection.destroyPrimarySelection.reset(); + + if (selection.currentPrimarySelection) + selection.currentPrimarySelection->cancelled(); + + if (!source) + PROTO::primarySelection->setSelection(nullptr); + + selection.currentPrimarySelection = source; + + if (source) { + selection.destroyPrimarySelection = source->events.destroy.registerListener([this](std::any d) { setCurrentPrimarySelection(nullptr); }); + PROTO::primarySelection->setSelection(source); + PROTO::dataWlr->setSelection(source, true); } } diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 81ca663d..f4efda70 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -109,9 +109,12 @@ class CSeatManager { struct { WP currentSelection; CHyprSignalListener destroySelection; + WP currentPrimarySelection; + CHyprSignalListener destroyPrimarySelection; } selection; void setCurrentSelection(SP source); + void setCurrentPrimarySelection(SP source); // do not write to directly, use set... WP mouse; diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index a518b0ae..c039d3b4 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -145,7 +145,7 @@ CWLRDataDevice::CWLRDataDevice(SP resource_) : resourc source->markUsed(); LOGM(LOG, "wlr manager requests primary selection to {:x}", (uintptr_t)source.get()); - g_pSeatManager->setCurrentSelection(source); + g_pSeatManager->setCurrentPrimarySelection(source); }); } @@ -170,6 +170,10 @@ void CWLRDataDevice::sendSelection(SP selection) { resource->sendSelection(selection->resource.get()); } +void CWLRDataDevice::sendPrimarySelection(SP selection) { + resource->sendPrimarySelection(selection->resource.get()); +} + CWLRDataControlManagerResource::CWLRDataControlManagerResource(SP resource_) : resource(resource_) { if (!good()) return; @@ -259,9 +263,14 @@ void CDataDeviceWLRProtocol::destroyResource(CWLRDataOffer* resource) { std::erase_if(m_vOffers, [&](const auto& other) { return other.get() == resource; }); } -void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SP sel) { - if (!sel) +void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SP sel, bool primary) { + if (!sel) { + if (primary) + dev->resource->sendPrimarySelectionRaw(nullptr); + else + dev->resource->sendSelectionRaw(nullptr); return; + } const auto OFFER = m_vOffers.emplace_back(makeShared(makeShared(dev->resource->client(), dev->resource->version(), 0), sel)); @@ -271,34 +280,41 @@ void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SPprimary = primary; + + LOGM(LOG, "New {}offer {:x} for data source {:x}", primary ? "primary " : " ", (uintptr_t)OFFER.get(), (uintptr_t)sel.get()); dev->sendDataOffer(OFFER); OFFER->sendData(); - dev->sendSelection(OFFER); + if (primary) + dev->sendPrimarySelection(OFFER); + else + dev->sendSelection(OFFER); } -void CDataDeviceWLRProtocol::setSelection(SP source) { +void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) { for (auto& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; + if (o->primary != primary) + continue; o->dead = true; } if (!source) { - LOGM(LOG, "resetting selection"); + LOGM(LOG, "resetting {}selection", primary ? "primary " : " "); for (auto& d : m_vDevices) { - sendSelectionToDevice(d, nullptr); + sendSelectionToDevice(d, nullptr, primary); } return; } - LOGM(LOG, "New selection for data source {:x}", (uintptr_t)source.get()); + LOGM(LOG, "New {}selection for data source {:x}", primary ? "primary" : "", (uintptr_t)source.get()); for (auto& d : m_vDevices) { - sendSelectionToDevice(d, source); + sendSelectionToDevice(d, source, primary); } } diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 0b703347..193e918c 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -19,7 +19,8 @@ class CWLRDataOffer { bool good(); void sendData(); - bool dead = false; + bool dead = false; + bool primary = false; WP source; @@ -61,6 +62,7 @@ class CWLRDataDevice { void sendDataOffer(SP offer); void sendSelection(SP selection); + void sendPrimarySelection(SP selection); WP self; @@ -103,8 +105,8 @@ class CDataDeviceWLRProtocol : public IWaylandProtocol { std::vector> m_vOffers; // - void setSelection(SP source); - void sendSelectionToDevice(SP dev, SP sel); + void setSelection(SP source, bool primary); + void sendSelectionToDevice(SP dev, SP sel, bool primary); // SP dataDeviceForClient(wl_client*); diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp new file mode 100644 index 00000000..78eb8d63 --- /dev/null +++ b/src/protocols/PrimarySelection.cpp @@ -0,0 +1,338 @@ +#include "PrimarySelection.hpp" +#include +#include "../managers/SeatManager.hpp" +#include "core/Seat.hpp" +#include "../config/ConfigValue.hpp" + +#define LOGM PROTO::primarySelection->protoLog + +CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); + resource->setOnDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); + + resource->setReceive([this](CZwpPrimarySelectionOfferV1* r, const char* mime, int32_t fd) { + if (!source) { + LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); + close(fd); + return; + } + + if (dead) { + LOGM(WARN, "Possible bug: Receive on an offer that's dead"); + close(fd); + return; + } + + LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); + + source->send(mime, fd); + }); +} + +bool CPrimarySelectionOffer::good() { + return resource->resource(); +} + +void CPrimarySelectionOffer::sendData() { + if (!source) + return; + + for (auto& m : source->mimes()) { + resource->sendOffer(m.c_str()); + } +} + +CPrimarySelectionSource::CPrimarySelectionSource(SP resource_, SP device_) : device(device_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CZwpPrimarySelectionSourceV1* r) { + events.destroy.emit(); + PROTO::primarySelection->destroyResource(this); + }); + resource->setOnDestroy([this](CZwpPrimarySelectionSourceV1* r) { + events.destroy.emit(); + PROTO::primarySelection->destroyResource(this); + }); + + resource->setOffer([this](CZwpPrimarySelectionSourceV1* r, const char* mime) { mimeTypes.push_back(mime); }); +} + +CPrimarySelectionSource::~CPrimarySelectionSource() { + events.destroy.emit(); +} + +SP CPrimarySelectionSource::fromResource(wl_resource* res) { + auto data = (CPrimarySelectionSource*)(((CZwpPrimarySelectionSourceV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CPrimarySelectionSource::good() { + return resource->resource(); +} + +std::vector CPrimarySelectionSource::mimes() { + return mimeTypes; +} + +void CPrimarySelectionSource::send(const std::string& mime, uint32_t fd) { + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { + LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); + close(fd); + return; + } + + resource->sendSend(mime.c_str(), fd); + close(fd); +} + +void CPrimarySelectionSource::accepted(const std::string& mime) { + if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) + LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAccepted with non-existent mime"); + + // primary sel has no accepted +} + +void CPrimarySelectionSource::cancelled() { + resource->sendCancelled(); +} + +void CPrimarySelectionSource::error(uint32_t code, const std::string& msg) { + resource->error(code, msg); +} + +CPrimarySelectionDevice::CPrimarySelectionDevice(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CZwpPrimarySelectionDeviceV1* r) { PROTO::primarySelection->destroyResource(this); }); + resource->setOnDestroy([this](CZwpPrimarySelectionDeviceV1* r) { PROTO::primarySelection->destroyResource(this); }); + + resource->setSetSelection([this](CZwpPrimarySelectionDeviceV1* r, wl_resource* sourceR, uint32_t serial) { + static auto PPRIMARYSEL = CConfigValue("misc:middle_click_paste"); + + if (!*PPRIMARYSEL) { + LOGM(LOG, "Ignoring primary selection: disabled in config"); + g_pSeatManager->setCurrentPrimarySelection(nullptr); + return; + } + + auto source = sourceR ? CPrimarySelectionSource::fromResource(sourceR) : CSharedPointer{}; + if (!source) { + LOGM(LOG, "wlr reset selection received"); + g_pSeatManager->setCurrentPrimarySelection(nullptr); + return; + } + + if (source && source->used()) + LOGM(WARN, "setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this."); + + source->markUsed(); + + LOGM(LOG, "wlr manager requests selection to {:x}", (uintptr_t)source.get()); + g_pSeatManager->setCurrentPrimarySelection(source); + }); +} + +bool CPrimarySelectionDevice::good() { + return resource->resource(); +} + +wl_client* CPrimarySelectionDevice::client() { + return pClient; +} + +void CPrimarySelectionDevice::sendDataOffer(SP offer) { + resource->sendDataOffer(offer->resource.get()); +} + +void CPrimarySelectionDevice::sendSelection(SP selection) { + if (!selection) + resource->sendSelectionRaw(nullptr); + else + resource->sendSelection(selection->resource.get()); +} + +CPrimarySelectionManager::CPrimarySelectionManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpPrimarySelectionDeviceManagerV1* r) { PROTO::primarySelection->destroyResource(this); }); + + resource->setGetDevice([this](CZwpPrimarySelectionDeviceManagerV1* r, uint32_t id, wl_resource* seat) { + const auto RESOURCE = + PROTO::primarySelection->m_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::primarySelection->m_vDevices.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + device = RESOURCE; + + for (auto& s : sources) { + if (!s) + continue; + s->device = RESOURCE; + } + + LOGM(LOG, "New primary selection data device bound at {:x}", (uintptr_t)RESOURCE.get()); + }); + + resource->setCreateSource([this](CZwpPrimarySelectionDeviceManagerV1* r, uint32_t id) { + std::erase_if(sources, [](const auto& e) { return e.expired(); }); + + const auto RESOURCE = PROTO::primarySelection->m_vSources.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), device.lock())); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::primarySelection->m_vSources.pop_back(); + return; + } + + if (!device) + LOGM(WARN, "New data source before a device was created"); + + RESOURCE->self = RESOURCE; + + sources.push_back(RESOURCE); + + LOGM(LOG, "New primary selection data source bound at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CPrimarySelectionManager::good() { + return resource->resource(); +} + +CPrimarySelectionProtocol::CPrimarySelectionProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CPrimarySelectionProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New primary_seletion_manager at {:x}", (uintptr_t)RESOURCE.get()); + + // we need to do it here because protocols come before seatMgr + if (!listeners.onPointerFocusChange) + listeners.onPointerFocusChange = g_pSeatManager->events.pointerFocusChange.registerListener([this](std::any d) { this->onPointerFocus(); }); +} + +void CPrimarySelectionProtocol::destroyResource(CPrimarySelectionManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CPrimarySelectionProtocol::destroyResource(CPrimarySelectionSource* resource) { + std::erase_if(m_vSources, [&](const auto& other) { return other.get() == resource; }); +} + +void CPrimarySelectionProtocol::destroyResource(CPrimarySelectionDevice* resource) { + std::erase_if(m_vDevices, [&](const auto& other) { return other.get() == resource; }); +} + +void CPrimarySelectionProtocol::destroyResource(CPrimarySelectionOffer* resource) { + std::erase_if(m_vOffers, [&](const auto& other) { return other.get() == resource; }); +} + +void CPrimarySelectionProtocol::sendSelectionToDevice(SP dev, SP sel) { + if (!sel) { + dev->sendSelection(nullptr); + return; + } + + const auto OFFER = + m_vOffers.emplace_back(makeShared(makeShared(dev->resource->client(), dev->resource->version(), 0), sel)); + + if (!OFFER->good()) { + dev->resource->noMemory(); + m_vOffers.pop_back(); + return; + } + + LOGM(LOG, "New offer {:x} for data source {:x}", (uintptr_t)OFFER.get(), (uintptr_t)sel.get()); + + dev->sendDataOffer(OFFER); + OFFER->sendData(); + dev->sendSelection(OFFER); +} + +void CPrimarySelectionProtocol::setSelection(SP source) { + for (auto& o : m_vOffers) { + if (o->source && o->source->hasDnd()) + continue; + o->dead = true; + } + + if (!source) { + LOGM(LOG, "resetting selection"); + + if (!g_pSeatManager->state.pointerFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.pointerFocusResource->client()); + if (DESTDEVICE) + sendSelectionToDevice(DESTDEVICE, nullptr); + + return; + } + + LOGM(LOG, "New selection for data source {:x}", (uintptr_t)source.get()); + + if (!g_pSeatManager->state.pointerFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.pointerFocusResource->client()); + + if (!DESTDEVICE) { + LOGM(LOG, "CWLDataDeviceProtocol::setSelection: cannot send selection to a client without a data_device"); + return; + } + + sendSelectionToDevice(DESTDEVICE, source); +} + +void CPrimarySelectionProtocol::updateSelection() { + if (!g_pSeatManager->state.pointerFocusResource) + return; + + auto DESTDEVICE = dataDeviceForClient(g_pSeatManager->state.pointerFocusResource->client()); + + if (!DESTDEVICE) { + LOGM(LOG, "CPrimarySelectionProtocol::updateSelection: cannot send selection to a client without a data_device"); + return; + } + + sendSelectionToDevice(DESTDEVICE, g_pSeatManager->selection.currentPrimarySelection.lock()); +} + +void CPrimarySelectionProtocol::onPointerFocus() { + for (auto& o : m_vOffers) { + o->dead = true; + } + + updateSelection(); +} + +SP CPrimarySelectionProtocol::dataDeviceForClient(wl_client* c) { + auto it = std::find_if(m_vDevices.begin(), m_vDevices.end(), [c](const auto& e) { return e->client() == c; }); + if (it == m_vDevices.end()) + return nullptr; + return *it; +} diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp new file mode 100644 index 00000000..c33a00e8 --- /dev/null +++ b/src/protocols/PrimarySelection.hpp @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "primary-selection-unstable-v1.hpp" +#include "types/DataDevice.hpp" + +class CPrimarySelectionOffer; +class CPrimarySelectionSource; +class CPrimarySelectionDevice; +class CPrimarySelectionManager; + +class CPrimarySelectionOffer { + public: + CPrimarySelectionOffer(SP resource_, SP source_); + + bool good(); + void sendData(); + + bool dead = false; + + WP source; + + private: + SP resource; + + friend class CPrimarySelectionDevice; +}; + +class CPrimarySelectionSource : public IDataSource { + public: + CPrimarySelectionSource(SP resource_, SP device_); + ~CPrimarySelectionSource(); + + static SP fromResource(wl_resource*); + + bool good(); + + virtual std::vector mimes(); + virtual void send(const std::string& mime, uint32_t fd); + virtual void accepted(const std::string& mime); + virtual void cancelled(); + virtual void error(uint32_t code, const std::string& msg); + + std::vector mimeTypes; + WP self; + WP device; + + private: + SP resource; +}; + +class CPrimarySelectionDevice { + public: + CPrimarySelectionDevice(SP resource_); + + bool good(); + wl_client* client(); + + void sendDataOffer(SP offer); + void sendSelection(SP selection); + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CPrimarySelectionProtocol; +}; + +class CPrimarySelectionManager { + public: + CPrimarySelectionManager(SP resource_); + + bool good(); + + WP device; + std::vector> sources; + + private: + SP resource; +}; + +class CPrimarySelectionProtocol : public IWaylandProtocol { + public: + CPrimarySelectionProtocol(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); + + private: + void destroyResource(CPrimarySelectionManager* resource); + void destroyResource(CPrimarySelectionDevice* resource); + void destroyResource(CPrimarySelectionSource* resource); + void destroyResource(CPrimarySelectionOffer* resource); + + // + std::vector> m_vManagers; + std::vector> m_vDevices; + std::vector> m_vSources; + std::vector> m_vOffers; + + // + void setSelection(SP source); + void sendSelectionToDevice(SP dev, SP sel); + void updateSelection(); + void onPointerFocus(); + + // + SP dataDeviceForClient(wl_client*); + + friend class CPrimarySelectionManager; + friend class CPrimarySelectionDevice; + friend class CPrimarySelectionSource; + friend class CPrimarySelectionOffer; + friend class CSeatManager; + + struct { + CHyprSignalListener onPointerFocusChange; + } listeners; +}; + +namespace PROTO { + inline UP primarySelection; +}; From 31890026ea9f3ce75dbcfdf060239fc8aa6c144c Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Wed, 15 May 2024 20:17:56 +0900 Subject: [PATCH 0088/2393] wl_seat: send frame event after pointer leave (#6074) --- src/managers/SeatManager.cpp | 17 ++++++++++++++++- src/managers/SeatManager.hpp | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 3e2d595f..b9590c42 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -186,10 +186,13 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { } } + auto lastPointerFocusResource = state.pointerFocusResource; + state.pointerFocusResource.reset(); state.pointerFocus = surf; if (!surf) { + sendPointerFrame(lastPointerFocusResource); events.pointerFocusChange.emit(); return; } @@ -209,6 +212,11 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { } } + if (state.pointerFocusResource != lastPointerFocusResource) + sendPointerFrame(lastPointerFocusResource); + + sendPointerFrame(); + hyprListener_pointerSurfaceDestroy.initCallback( &surf->events.destroy, [this](void* owner, void* data) { setPointerFocus(nullptr, {}); }, nullptr, "CSeatManager"); @@ -245,7 +253,14 @@ void CSeatManager::sendPointerFrame() { if (!state.pointerFocusResource) return; - for (auto& p : state.pointerFocusResource->pointers) { + sendPointerFrame(state.pointerFocusResource); +} + +void CSeatManager::sendPointerFrame(WP pResource) { + if (!pResource) + return; + + for (auto& p : pResource->pointers) { if (!p) continue; diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index f4efda70..cf5e9216 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -63,6 +63,7 @@ class CSeatManager { void sendPointerMotion(uint32_t timeMs, const Vector2D& local); void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state); void sendPointerFrame(); + void sendPointerFrame(WP pResource); void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative); void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local); From 7fbe05a250fb81b4a9cd531460b72b038f37e88f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 15 May 2024 16:22:45 +0100 Subject: [PATCH 0089/2393] inputmgr: send pointer motion on ffm != 1 fixes #6077 --- src/managers/input/InputManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index d74657d9..02072229 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -471,6 +471,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (FOLLOWMOUSE != 0 || pFoundWindow == g_pCompositor->m_pLastWindow) g_pSeatManager->setPointerFocus(foundSurface, surfaceLocal); + if (g_pSeatManager->state.pointerFocus == foundSurface) + g_pSeatManager->sendPointerMotion(time, surfaceLocal); + m_bLastFocusOnLS = false; return; // don't enter any new surfaces } else { From 3381e2b55b9eaf8d30344c301aacfc664519688b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 15 May 2024 16:25:56 +0100 Subject: [PATCH 0090/2393] datadevice: guard surface in dnd for null fixes #6076 --- src/protocols/core/DataDevice.cpp | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 2b9503b1..354259fe 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -233,7 +233,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : reso source->dnd = true; - PROTO::data->initiateDrag(source, wlr_surface_from_resource(icon), wlr_surface_from_resource(origin)); + PROTO::data->initiateDrag(source, icon ? wlr_surface_from_resource(icon) : nullptr, wlr_surface_from_resource(origin)); }); } @@ -471,22 +471,24 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.currentSource = currentSource; dnd.originSurface = origin; dnd.dndSurface = dragSurface; - dnd.hyprListener_dndSurfaceDestroy.initCallback( - &dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag"); - dnd.hyprListener_dndSurfaceCommit.initCallback( - &dragSurface->events.commit, - [this](void* owner, void* data) { - if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) { - wlr_surface_map(dnd.dndSurface); - return; - } + if (dragSurface) { + dnd.hyprListener_dndSurfaceDestroy.initCallback( + &dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag"); + dnd.hyprListener_dndSurfaceCommit.initCallback( + &dragSurface->events.commit, + [this](void* owner, void* data) { + if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) { + wlr_surface_map(dnd.dndSurface); + return; + } - if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) { - wlr_surface_unmap(dnd.dndSurface); - return; - } - }, - nullptr, "CWLDataDeviceProtocol::drag"); + if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) { + wlr_surface_unmap(dnd.dndSurface); + return; + } + }, + nullptr, "CWLDataDeviceProtocol::drag"); + } dnd.mouseButton = g_pHookSystem->hookDynamic("mouseButton", [this](void* self, SCallbackInfo& info, std::any e) { auto E = std::any_cast(e); From 3fe5280ce93a7c216f47e8626e69ea015e875395 Mon Sep 17 00:00:00 2001 From: Raphael Tannous <107765121+rofe33@users.noreply.github.com> Date: Wed, 15 May 2024 18:54:23 +0300 Subject: [PATCH 0091/2393] hyprctl: return exitStatus in requestHyprpaper() and request() (#6083) --- hyprctl/main.cpp | 58 ++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 097ef5d8..e9d7583c 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -90,24 +90,24 @@ std::vector instances() { return result; } -void request(std::string arg, int minArgs = 0) { +int request(std::string arg, int minArgs = 0) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); const auto ARGS = std::count(arg.begin(), arg.end(), ' '); if (ARGS < minArgs) { std::cout << "Not enough arguments, expected at least " << minArgs; - return; + return -1; } if (SERVERSOCKET < 0) { std::cout << "Couldn't open a socket (1)"; - return; + return 1; } if (instanceSignature.empty()) { std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"; - return; + return 2; } const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid); @@ -121,14 +121,14 @@ void request(std::string arg, int minArgs = 0) { if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { std::cout << "Couldn't connect to " << socketPath << ". (3)"; - return; + return 3; } auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length()); if (sizeWritten < 0) { std::cout << "Couldn't write (4)"; - return; + return 4; } std::string reply = ""; @@ -138,7 +138,7 @@ void request(std::string arg, int minArgs = 0) { if (sizeWritten < 0) { std::cout << "Couldn't read (5)"; - return; + return 5; } reply += std::string(buffer, sizeWritten); @@ -147,7 +147,7 @@ void request(std::string arg, int minArgs = 0) { sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { std::cout << "Couldn't read (5)"; - return; + return 5; } reply += std::string(buffer, sizeWritten); } @@ -155,19 +155,21 @@ void request(std::string arg, int minArgs = 0) { close(SERVERSOCKET); std::cout << reply; + + return 0; } -void requestHyprpaper(std::string arg) { +int requestHyprpaper(std::string arg) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SERVERSOCKET < 0) { std::cout << "Couldn't open a socket (1)"; - return; + return 1; } if (instanceSignature.empty()) { std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"; - return; + return 2; } sockaddr_un serverAddress = {0}; @@ -181,7 +183,7 @@ void requestHyprpaper(std::string arg) { if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { std::cout << "Couldn't connect to " << socketPath << ". (3)"; - return; + return 3; } arg = arg.substr(arg.find_first_of('/') + 1); // strip flags @@ -191,7 +193,7 @@ void requestHyprpaper(std::string arg) { if (sizeWritten < 0) { std::cout << "Couldn't write (4)"; - return; + return 4; } char buffer[8192] = {0}; @@ -200,12 +202,14 @@ void requestHyprpaper(std::string arg) { if (sizeWritten < 0) { std::cout << "Couldn't read (5)"; - return; + return 5; } close(SERVERSOCKET); std::cout << std::string(buffer); + + return 0; } void batchRequest(std::string arg, bool json) { @@ -384,33 +388,33 @@ int main(int argc, char** argv) { if (fullRequest.contains("/--batch")) batchRequest(fullRequest, json); else if (fullRequest.contains("/hyprpaper")) - requestHyprpaper(fullRequest); + exitStatus = requestHyprpaper(fullRequest); else if (fullRequest.contains("/switchxkblayout")) - request(fullRequest, 2); + exitStatus = request(fullRequest, 2); else if (fullRequest.contains("/seterror")) - request(fullRequest, 1); + exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/setprop")) - request(fullRequest, 3); + exitStatus = request(fullRequest, 3); else if (fullRequest.contains("/plugin")) - request(fullRequest, 1); + exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/dismissnotify")) - request(fullRequest, 0); + exitStatus = request(fullRequest, 0); else if (fullRequest.contains("/notify")) - request(fullRequest, 2); + exitStatus = request(fullRequest, 2); else if (fullRequest.contains("/output")) - request(fullRequest, 2); + exitStatus = request(fullRequest, 2); else if (fullRequest.contains("/setcursor")) - request(fullRequest, 1); + exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/dispatch")) - request(fullRequest, 1); + exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/keyword")) - request(fullRequest, 2); + exitStatus = request(fullRequest, 2); else if (fullRequest.contains("/decorations")) - request(fullRequest, 1); + exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/--help")) std::cout << USAGE << std::endl; else { - request(fullRequest); + exitStatus = request(fullRequest); } std::cout << std::endl; From b9c58b6e75f7d0141d8ba88fb3f6f022fed0877a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 15 May 2024 17:38:02 +0100 Subject: [PATCH 0092/2393] seat: send enter/leave events to all bound wl_seats for a client fixes #6069 Will not send anything beyond enter/leave. If you depend on multiple seats sending you motion, button, etc, events, fix your app. --- src/managers/SeatManager.cpp | 96 ++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index b9590c42..360b5088 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include +#include CSeatManager::CSeatManager() { listeners.newSeatResource = PROTO::seat->events.newSeatResource.registerListener([this](std::any res) { onNewSeatResource(std::any_cast>(res)); }); @@ -104,11 +105,23 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { hyprListener_keyboardSurfaceDestroy.removeCallback(); if (state.keyboardFocusResource) { - for (auto& k : state.keyboardFocusResource->keyboards) { - if (!k) + // we will iterate over all bound wl_seat + // resources here, because some idiotic apps (e.g. those based on smithay) + // tend to bind wl_seat twice. + // I can't be arsed to actually pass all events to all seat resources, so we will + // only pass enter and leave. + // If you have an issue with that, fix your app. + auto client = state.keyboardFocusResource->client(); + for (auto& s : seatResources) { + if (s->resource->client() != client) continue; - k->sendLeave(); + for (auto& k : s->resource->keyboards) { + if (!k) + continue; + + k->sendLeave(); + } } } @@ -121,18 +134,17 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { } auto client = wl_resource_get_client(surf->resource); - for (auto& r : seatResources) { - if (r->resource->client() == client) { - state.keyboardFocusResource = r->resource; - for (auto& k : state.keyboardFocusResource->keyboards) { - if (!k) - continue; + for (auto& r : seatResources | std::views::reverse) { + if (r->resource->client() != client) + continue; - k->sendEnter(surf); - k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); - } + state.keyboardFocusResource = r->resource; + for (auto& k : r->resource->keyboards) { + if (!k) + continue; - break; + k->sendEnter(surf); + k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); } } @@ -178,11 +190,17 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { hyprListener_pointerSurfaceDestroy.removeCallback(); if (state.pointerFocusResource) { - for (auto& p : state.pointerFocusResource->pointers) { - if (!p) + auto client = state.pointerFocusResource->client(); + for (auto& s : seatResources) { + if (s->resource->client() != client) continue; - p->sendLeave(); + for (auto& p : s->resource->pointers) { + if (!p) + continue; + + p->sendLeave(); + } } } @@ -198,17 +216,16 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { } auto client = wl_resource_get_client(surf->resource); - for (auto& r : seatResources) { - if (r->resource->client() == client) { - state.pointerFocusResource = r->resource; - for (auto& p : state.pointerFocusResource->pointers) { - if (!p) - continue; + for (auto& r : seatResources | std::views::reverse) { + if (r->resource->client() != client) + continue; - p->sendEnter(surf, local); - } + state.pointerFocusResource = r->resource; + for (auto& p : r->resource->pointers) { + if (!p) + continue; - break; + p->sendEnter(surf, local); } } @@ -290,11 +307,17 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, hyprListener_touchSurfaceDestroy.removeCallback(); if (state.touchFocusResource) { - for (auto& t : state.touchFocusResource->touches) { - if (!t) + auto client = state.touchFocusResource->client(); + for (auto& s : seatResources) { + if (s->resource->client() != client) continue; - t->sendUp(timeMs, id); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendUp(timeMs, id); + } } } @@ -307,17 +330,16 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, } auto client = wl_resource_get_client(surf->resource); - for (auto& r : seatResources) { - if (r->resource->client() == client) { - state.touchFocusResource = r->resource; - for (auto& t : state.touchFocusResource->touches) { - if (!t) - continue; + for (auto& r : seatResources | std::views::reverse) { + if (r->resource->client() != client) + continue; - t->sendDown(surf, timeMs, id, local); - } + state.touchFocusResource = r->resource; + for (auto& t : r->resource->touches) { + if (!t) + continue; - break; + t->sendDown(surf, timeMs, id, local); } } From a8522db683ae260f16f8e7778561d8a54906beb1 Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Wed, 15 May 2024 21:03:51 +0100 Subject: [PATCH 0093/2393] keybinds: fix empty on monitor for new workspaces (#6089) --- src/helpers/MiscFunctions.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 4855553a..7382d24c 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -284,16 +284,24 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { } else if (in.starts_with("empty")) { const bool same_mon = in.substr(5).contains("m"); const bool next = in.substr(5).contains("n"); - if (same_mon || next) { - if (!g_pCompositor->m_pLastMonitor) { - Debug::log(ERR, "Empty monitor workspace on monitor null!"); - return WORKSPACE_INVALID; + if ((same_mon || next) && !g_pCompositor->m_pLastMonitor) { + Debug::log(ERR, "Empty monitor workspace on monitor null!"); + return WORKSPACE_INVALID; + } + + std::set invalidWSes; + if (same_mon) { + for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { + const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); + if (PMONITOR && (PMONITOR->ID != g_pCompositor->m_pLastMonitor->ID)) + invalidWSes.insert(rule.workspaceId); } } + int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; while (++id < INT_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); - if (!PWORKSPACE || (g_pCompositor->getWindowsOnWorkspace(id) == 0 && (!same_mon || PWORKSPACE->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID))) + if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) return id; } } else if (in.starts_with("prev")) { From 9eec4cb670f815c794a56005fd77020d34b6899d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 15 May 2024 23:01:48 +0100 Subject: [PATCH 0094/2393] sysd: add missing header ref #6094 --- src/helpers/SdDaemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index d5df3121..497101e4 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace Systemd { int SdBooted(void) { From 7e8c0b7f30817e0fc217ef769d4be7d406fa2374 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 15 May 2024 23:13:45 +0100 Subject: [PATCH 0095/2393] seat: send axis_stop events after axis events fixes #6090 --- src/managers/SeatManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 360b5088..2c7bfe39 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -297,6 +297,9 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double p->sendAxis(timeMs, axis, value); p->sendAxisSource(source); p->sendAxisRelativeDirection(axis, relative); + + if (value == 0) + p->sendAxisStop(timeMs, axis); } } From de9798fcf9494eb082bd168175390c0d47b8478b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 16 May 2024 00:55:55 +0100 Subject: [PATCH 0096/2393] configmgr: shadow exec rules when window is unmapped fixes #6091 --- src/config/ConfigManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bec651b2..9d8a538c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1041,6 +1041,9 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo if (!valid(pWindow)) return std::vector(); + // if the window is unmapped, don't process exec rules yet. + shadowExec = shadowExec || !pWindow->m_bIsMapped; + std::vector returns; std::string title = pWindow->m_szTitle; From ca0833c9ed6d6034b360d0ea83f3ac942ffb45b5 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Thu, 16 May 2024 06:38:10 -0400 Subject: [PATCH 0097/2393] decoration: Stacked group tabs (#5886) * Stacked group tabs * Fix index when creating groupbar title textures * Changes for stacked dnd * formatting * Don't remove internal horizontal padding when calculating stacked bar width --- src/config/ConfigManager.cpp | 1 + .../decorations/CHyprGroupBarDecoration.cpp | 86 +++++++++++++------ .../decorations/CHyprGroupBarDecoration.hpp | 1 + 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 9d8a538c..b0c44408 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -359,6 +359,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:render_titles", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:scrolling", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:text_color", Hyprlang::INT{0xffffffff}); + m_pConfig->addConfigValue("group:groupbar:stacked", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:int", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:log_damage", Hyprlang::INT{0}); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 451701b4..318999ed 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -1,6 +1,7 @@ #include "CHyprGroupBarDecoration.hpp" #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" +#include "managers/LayoutManager.hpp" #include #include @@ -12,6 +13,7 @@ static CTexture m_tGradientLockedInactive; constexpr int BAR_INDICATOR_HEIGHT = 3; constexpr int BAR_PADDING_OUTER_VERT = 2; +constexpr int BAR_PADDING_OUTER_HORZ = 2; constexpr int BAR_TEXT_PAD = 2; constexpr int BAR_HORIZONTAL_PADDING = 2; @@ -32,6 +34,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); static auto PPRIORITY = CConfigValue("group:groupbar:priority"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); SDecorationPositioningInfo info; info.policy = DECORATION_POSITION_STICKY; @@ -39,16 +42,20 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { info.priority = *PPRIORITY; info.reserved = true; - if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate) - info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; - else + if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate) { + if (*PSTACKED) { + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT}, {0, 0}}; + } else + info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; + } else info.desiredExtents = {{0, 0}, {0, 0}}; - return info; } void CHyprGroupBarDecoration::onPositioningReply(const SDecorationPositioningReply& reply) { m_bAssignedBox = reply.assignedGeometry; + g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_pWindow.lock()); } eDecorationType CHyprGroupBarDecoration::getDecorationType() { @@ -96,24 +103,31 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); static auto PHEIGHT = CConfigValue("group:groupbar:height"); static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate) return; const auto ASSIGNEDBOX = assignedBoxGlobal(); - m_fBarWidth = (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + m_fBarHeight = *PSTACKED ? ((ASSIGNEDBOX.h - 2 - BAR_PADDING_OUTER_VERT) - BAR_PADDING_OUTER_VERT * (barsToDraw)) / barsToDraw : ASSIGNEDBOX.h - BAR_PADDING_OUTER_VERT; - const auto DESIREDHEIGHT = BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2; - if (DESIREDHEIGHT != ASSIGNEDBOX.h) + const auto DESIREDHEIGHT = *PSTACKED ? (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT : BAR_PADDING_OUTER_VERT * 2 + ONEBARHEIGHT; + if (DESIREDHEIGHT != ASSIGNEDBOX.h) { g_pDecorationPositioner->repositionDeco(this); + } int xoff = 0; + int yoff = 0; for (int i = 0; i < barsToDraw; ++i) { - CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, - BAR_INDICATOR_HEIGHT}; + const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i; + + CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, + BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -133,38 +147,43 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; - CColor color = m_dwGroupMembers[i].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; + CColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y + BAR_PADDING_OUTER_VERT, m_fBarWidth, - ASSIGNEDBOX.h - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT * 2}; + ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}; rect.scale(pMonitor->scale); if (*PGRADIENTS) { - const auto& GRADIENTTEX = (m_dwGroupMembers[i].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + const auto& GRADIENTTEX = + (m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); if (GRADIENTTEX.m_iTexID != 0) g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0); } if (*PRENDERTITLES) { - CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[i]->m_szTitle); + CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); if (!pTitleTex) - pTitleTex = m_sTitleTexs.titleTexs - .emplace_back(std::make_unique( - m_dwGroupMembers[i].lock(), Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) - .get(); + pTitleTex = + m_sTitleTexs.titleTexs + .emplace_back(std::make_unique(m_dwGroupMembers[WINDOWINDEX].lock(), + Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) + .get(); - rect.y += (ASSIGNEDBOX.h / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; + rect.y += (*PHEIGHT / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale; g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); } - xoff += BAR_HORIZONTAL_PADDING + m_fBarWidth; + if (*PSTACKED) + yoff += ONEBARHEIGHT; + else + xoff += BAR_HORIZONTAL_PADDING + m_fBarWidth; } if (*PRENDERTITLES) @@ -335,13 +354,18 @@ void refreshGroupBarGradients() { } bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); if (m_pWindow.lock() == m_pWindow->m_sGroupData.pNextWindow.lock()) return false; const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; - const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + const float BARRELATIVEY = pos.y - assignedBoxGlobal().y; + const int WINDOWINDEX = *PSTACKED ? (BARRELATIVEY / (m_fBarHeight + BAR_PADDING_OUTER_VERT)) : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); - if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) + if (!*PSTACKED && (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth)) + return false; + + if (*PSTACKED && (BARRELATIVEY - (m_fBarHeight + BAR_PADDING_OUTER_VERT) * WINDOWINDEX < BAR_PADDING_OUTER_VERT)) return false; PHLWINDOW pWindow = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); @@ -364,11 +388,13 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { } bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) { + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock())) return false; - const float BARRELATIVEX = pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; - const int WINDOWINDEX = BARRELATIVEX < 0 ? -1 : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; + const float BARSIZE = *PSTACKED ? m_fBarHeight + BAR_PADDING_OUTER_VERT : m_fBarWidth + BAR_HORIZONTAL_PADDING; + const int WINDOWINDEX = BARRELATIVE < 0 ? -1 : BARRELATIVE / BARSIZE; PHLWINDOW pWindowInsertAfter = m_pWindow->getGroupWindowByIndex(WINDOWINDEX); PHLWINDOW pWindowInsertEnd = pWindowInsertAfter->m_sGroupData.pNextWindow.lock(); @@ -423,11 +449,13 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND } bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPointer::SButtonEvent& e) { + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); if (m_pWindow->m_bIsFullscreen && m_pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) return true; const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; - const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); + const float BARRELATIVEY = pos.y - assignedBoxGlobal().y; + const int WINDOWINDEX = *PSTACKED ? (BARRELATIVEY / (m_fBarHeight + BAR_PADDING_OUTER_VERT)) : (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); // close window on middle click @@ -446,7 +474,9 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo return true; // click on padding - if (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth) { + const auto TABPAD = !*PSTACKED && (BARRELATIVEX - (m_fBarWidth + BAR_HORIZONTAL_PADDING) * WINDOWINDEX > m_fBarWidth); + const auto STACKPAD = *PSTACKED && (BARRELATIVEY - (m_fBarHeight + BAR_PADDING_OUTER_VERT) * WINDOWINDEX < BAR_PADDING_OUTER_VERT); + if (TABPAD || STACKPAD) { if (!g_pCompositor->isWindowActive(m_pWindow.lock())) g_pCompositor->focusWindow(m_pWindow.lock()); return true; diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 3fe653cc..e3f553c5 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -54,6 +54,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { std::deque m_dwGroupMembers; float m_fBarWidth; + float m_fBarHeight; CTitleTex* textureFromTitle(const std::string&); void invalidateTextures(); From d693c448366131de9e5729690a6d894fd1adff5e Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Thu, 16 May 2024 10:48:30 +0000 Subject: [PATCH 0098/2393] keybinds: add keybind combos and add Left and Right mod distinction. (#5966) --- src/config/ConfigManager.cpp | 24 ++++++++-- src/managers/KeybindManager.cpp | 84 ++++++++++++++++++++++++++------- src/managers/KeybindManager.hpp | 43 +++++++++++------ 3 files changed, 117 insertions(+), 34 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b0c44408..ac5c101e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -6,6 +6,7 @@ #include "helpers/VarList.hpp" #include "../protocols/LayerShell.hpp" +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include extern "C" char** environ; @@ -1908,6 +1910,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool nonConsuming = false; bool transparent = false; bool ignoreMods = false; + bool multiKey = false; const auto BINDARGS = command.substr(4); for (auto& arg : BINDARGS) { @@ -1925,6 +1928,8 @@ std::optional CConfigManager::handleBind(const std::string& command transparent = true; } else if (arg == 'i') { ignoreMods = true; + } else if (arg == 's') { + multiKey = true; } else { return "bind: invalid flag"; } @@ -1943,10 +1948,21 @@ std::optional CConfigManager::handleBind(const std::string& command else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) return "bind: too many args"; + std::set KEYSYMS; + std::set MODS; + + if (multiKey) { + for (auto splitKey : CVarList(ARGS[1], 8, '&')) { + KEYSYMS.insert(xkb_keysym_from_name(splitKey.c_str(), XKB_KEYSYM_CASE_INSENSITIVE)); + } + for (auto splitMod : CVarList(ARGS[0], 8, '&')) { + MODS.insert(xkb_keysym_from_name(splitMod.c_str(), XKB_KEYSYM_CASE_INSENSITIVE)); + } + } const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); const auto MODSTR = ARGS[0]; - const auto KEY = ARGS[1]; + const auto KEY = multiKey ? "" : ARGS[1]; auto HANDLER = ARGS[2]; @@ -1970,7 +1986,7 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod."; } - if (KEY != "") { + if ((KEY != "") || multiKey) { SParsedKey parsedKey = parseKey(KEY); if (parsedKey.catchAll && m_szCurrentSubmap == "") { @@ -1978,8 +1994,8 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, parsedKey.keycode, parsedKey.catchAll, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, - nonConsuming, transparent, ignoreMods}); + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, + repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey}); } return {}; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ead83fa8..ea064031 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -8,7 +8,9 @@ #include "../devices/IKeyboard.hpp" #include "../managers/SeatManager.hpp" +#include #include +#include #include #include @@ -536,8 +538,48 @@ int repeatKeyHandler(void* data) { return 0; } +eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set keybindKeysyms, const std::set pressedKeysyms) { + // Returns whether two sets of keysyms are equal, partially equal, or not + // matching. (Partially matching means that pressed is a subset of bound) + + std::set boundKeysNotPressed; + std::set pressedKeysNotBound; + + std::set_difference(keybindKeysyms.begin(), keybindKeysyms.end(), pressedKeysyms.begin(), pressedKeysyms.end(), + std::inserter(boundKeysNotPressed, boundKeysNotPressed.begin())); + std::set_difference(pressedKeysyms.begin(), pressedKeysyms.end(), keybindKeysyms.begin(), keybindKeysyms.end(), + std::inserter(pressedKeysNotBound, pressedKeysNotBound.begin())); + + if (boundKeysNotPressed.empty() && pressedKeysNotBound.empty()) + return MK_FULL_MATCH; + + if (boundKeysNotPressed.size() && pressedKeysNotBound.empty()) + return MK_PARTIAL_MATCH; + + return MK_NO_MATCH; +} + +eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { + if (mkKeysymSetMatches(keybind.sMkMods, m_sMkMods) != MK_FULL_MATCH) + return MK_NO_MATCH; + + return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); +} + bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { - bool found = false; + bool found = false; + + if (pressed) { + if (keycodeToModifier(key.keycode)) + m_sMkMods.insert(key.keysym); + else + m_sMkKeys.insert(key.keysym); + } else { + if (keycodeToModifier(key.keycode)) + m_sMkMods.erase(key.keysym); + else + m_sMkKeys.erase(key.keysym); + } static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); @@ -559,7 +601,13 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) continue; - if (!key.keyName.empty()) { + if (k.multiKey) { + switch (mkBindMatches(k)) { + case MK_NO_MATCH: continue; + case MK_PARTIAL_MATCH: found = true; continue; + case MK_FULL_MATCH: found = true; + } + } else if (!key.keyName.empty()) { if (key.keyName != k.key) continue; } else if (k.keycode != 0) { @@ -672,25 +720,29 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 if (k.handler == "global" || k.transparent) continue; // can't be shadowed - const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); - const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); + if (k.multiKey && (mkBindMatches(k) == MK_FULL_MATCH)) + shadow = true; + else { + const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - for (auto& pk : m_dPressedKeys) { - if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { - shadow = true; + for (auto& pk : m_dPressedKeys) { + if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { + shadow = true; - if (pk.keysym == doesntHave && doesntHave != 0) { - shadow = false; - break; + if (pk.keysym == doesntHave && doesntHave != 0) { + shadow = false; + break; + } } - } - if (pk.keycode != 0 && pk.keycode == k.keycode) { - shadow = true; + if (pk.keycode != 0 && pk.keycode == k.keycode) { + shadow = true; - if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { - shadow = false; - break; + if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { + shadow = false; + break; + } } } } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index da98a749..a2025bb0 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include +#include #include "../Compositor.hpp" #include #include @@ -13,20 +14,23 @@ class CPluginSystem; class IKeyboard; struct SKeybind { - std::string key = ""; - uint32_t keycode = 0; - bool catchAll = false; - uint32_t modmask = 0; - std::string handler = ""; - std::string arg = ""; - bool locked = false; - std::string submap = ""; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; + std::string key = ""; + std::set sMkKeys = {}; + uint32_t keycode = 0; + bool catchAll = false; + uint32_t modmask = 0; + std::set sMkMods = {}; + std::string handler = ""; + std::string arg = ""; + bool locked = false; + std::string submap = ""; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; // DO NOT INITIALIZE bool shadowed = false; @@ -57,6 +61,12 @@ struct SParsedKey { bool catchAll = false; }; +enum eMultiKeyCase { + MK_NO_MATCH = 0, + MK_PARTIAL_MATCH, + MK_FULL_MATCH +}; + class CKeybindManager { public: CKeybindManager(); @@ -105,6 +115,11 @@ class CKeybindManager { bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); + std::set m_sMkKeys = {}; + std::set m_sMkMods = {}; + eMultiKeyCase mkBindMatches(const SKeybind); + eMultiKeyCase mkKeysymSetMatches(const std::set, const std::set); + bool handleInternalKeybinds(xkb_keysym_t); bool handleVT(xkb_keysym_t); From 3ac0e7ead1434c172f276a12f81da1eeb0dc4491 Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Thu, 16 May 2024 08:30:55 -0400 Subject: [PATCH 0099/2393] seat: Send discrete event when axis source is scroll wheel (#6103) modified: src/managers/SeatManager.cpp modified: src/managers/input/InputManager.cpp Co-authored-by: Agent_00Ming --- src/managers/SeatManager.cpp | 3 +++ src/managers/input/InputManager.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 2c7bfe39..2087122a 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -298,6 +298,9 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double p->sendAxisSource(source); p->sendAxisRelativeDirection(axis, relative); + if (source == 0) + p->sendAxisDiscrete(axis, discrete); + if (value == 0) p->sendAxisStop(timeMs, axis); } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 02072229..58e5ad17 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -774,7 +774,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { } } - g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete / 120), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { From a2643e11a0a0e5e01ffb51b8ae41cf1ef458102e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 16 May 2024 18:35:48 +0100 Subject: [PATCH 0100/2393] build: bump hw-s dep to 0.3.8 --- CMakeLists.txt | 2 +- protocols/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9897185f..ab3576c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.7 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) file(GLOB_RECURSE SRCFILES "src/*.cpp") diff --git a/protocols/meson.build b/protocols/meson.build index 6b0b4d18..2c331e4b 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -17,7 +17,7 @@ wayland_scanner = find_program( wayland_scanner_dep.get_variable('wayland_scanner'), native: true, ) -hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.5', native: true) +hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, From abbe71d26dd0299071e7a86a287c49d7fb185677 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 16 May 2024 19:34:36 +0100 Subject: [PATCH 0101/2393] pointer: don't update hw cursors on disabled displays --- src/managers/PointerManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 6a0fb984..d565ad6d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -309,6 +309,11 @@ void CPointerManager::resetCursorImage(bool apply) { return; for (auto& ms : monitorStates) { + if (!ms->monitor || !ms->monitor->m_bEnabled || !ms->monitor->dpmsStatus) { + Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); + continue; + } + if (ms->cursorFrontBuffer) { if (ms->monitor->output->impl->set_cursor) ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0); @@ -324,6 +329,11 @@ void CPointerManager::updateCursorBackend() { for (auto& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); + if (!m->m_bEnabled || !m->dpmsStatus) { + Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); + continue; + } + if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); From 7173f0c9e722b52eebcc231a118df738c8e32013 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 17 May 2024 00:03:23 +0300 Subject: [PATCH 0102/2393] flake.lock: update nix/overlays: remove merged wayland-protocols overlay Fixes #6061 --- flake.lock | 30 +++++++++++++++--------------- nix/overlays.nix | 11 ----------- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/flake.lock b/flake.lock index 98dda5bd..ca05387b 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1713612213, - "narHash": "sha256-zJboXgWNpNhKyNF8H/3UYzWkx7w00TOCGKi3cwi+tsw=", + "lastModified": 1715791817, + "narHash": "sha256-J069Uhv/gCMFLX1dSh2f+9ZTM09r1Nv3oUfocCnWKow=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "cab4746180f210a3c1dd3d53e45c510e309e90e1", + "rev": "7c3aa03dffb53921e583ade3d4ae3f487e390e7e", "type": "github" }, "original": { @@ -61,11 +61,11 @@ ] }, "locked": { - "lastModified": 1713121246, - "narHash": "sha256-502X0Q0fhN6tJK7iEUA8CghONKSatW/Mqj4Wappd++0=", + "lastModified": 1715791527, + "narHash": "sha256-HhQ4zvGHrRjR63ltySSeg+x+0jb0lepiutWdnFhLRoo=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "78fcaa27ae9e1d782faa3ff06c8ea55ddce63706", + "rev": "969cb076e5b76f2e823aeca1937a3e1f159812ee", "type": "github" }, "original": { @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715608589, - "narHash": "sha256-vimNaLjLcoNIvBhF37GaB6PRYEvKMamY3UnDE9M5MW8=", + "lastModified": 1715879663, + "narHash": "sha256-/DwglRvj4XF4ECdNtrCIbthleszAZBwOiXG5A6r0K/c=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "65c2636484e5cb00583b8a7446c3fb657f568883", + "rev": "f5181a068c1b06f2db51f6222e50a0c665a2b0c3", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1715534503, - "narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=", + "lastModified": 1715787315, + "narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2057814051972fa1453ddfb0d98badbea9b83c06", + "rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5", "type": "github" }, "original": { @@ -152,11 +152,11 @@ ] }, "locked": { - "lastModified": 1714662532, - "narHash": "sha256-Pj2xGSYhapYbXL7sk7TTlOtCZcTfPQoL3fPbZeg7L4Y=", + "lastModified": 1715788457, + "narHash": "sha256-32HOkjSIyANphV0p5gIwP4ONU/CcinhwOyVFB+tL/d0=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "1f228ba2f1f254195c0b571302b37482861abee3", + "rev": "af7c87a32f5d67eb2ada908a6a700f4e74831943", "type": "github" }, "original": { diff --git a/nix/overlays.nix b/nix/overlays.nix index 50d9f9d9..fbd7e9fc 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -24,7 +24,6 @@ in { inputs.hyprcursor.overlays.default inputs.hyprlang.overlays.default inputs.hyprwayland-scanner.overlays.default - self.overlays.wayland-protocols self.overlays.xwayland # Hyprland packages themselves @@ -73,14 +72,4 @@ in { ''; }); }; - - wayland-protocols = final: prev: { - wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: { - version = "1.35"; - src = prev.fetchurl { - url = "https://gitlab.freedesktop.org/wayland/${super.pname}/-/releases/${self.version}/downloads/${super.pname}-${self.version}.tar.xz"; - hash = "sha256-N6JxaigTPcgZNBxWiinSHoy3ITDlwSah/PyfQsI9las="; - }; - }); - }; } From a66cfe0fbed7fb4dc69383e107c2bf3b1e7cd80a Mon Sep 17 00:00:00 2001 From: Yaroslav Date: Fri, 17 May 2024 03:34:03 +0500 Subject: [PATCH 0103/2393] CMake: use add_custom_command for generating protocols (#6104) This fixes an issue with build error in case of e.g. $ rm protocols/*.{c,h} $ cmake --build build The workaround was to touch CMakeLists.txt. With this PR, protocol files are properly regenerated with no extra efforts. Also, resolve hyprwayland-scanner dependency via cmake instead ofpkg-config. --- CMakeLists.txt | 118 ++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ab3576c1..b30591d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,9 +110,11 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprlang>=0.3.2 hyprcursor>=0.1.7 ) +find_package(hyprwayland-scanner 0.3.8 REQUIRED) + file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") @@ -210,42 +212,48 @@ target_link_libraries(Hyprland rt PkgConfig::deps) function(protocol protoPath protoName external) if (external) - execute_process( - COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) else() - execute_process( - COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() + + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c + COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) + target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) endfunction() function(protocolNew protoPath protoName external) if (external) - execute_process( - COMMAND hyprwayland-scanner ${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) else() - execute_process( - COMMAND hyprwayland-scanner ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + target_sources(Hyprland PRIVATE protocols/${protoName}.hpp) endfunction() function(protocolWayland) - execute_process( + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) target_sources(Hyprland PRIVATE protocols/wayland.cpp) + target_sources(Hyprland PRIVATE protocols/wayland.hpp) endfunction() target_link_libraries(Hyprland @@ -263,37 +271,37 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.x protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) 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("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) -protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) -protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) -protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) -protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-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) -protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) -protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) -protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) -protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) -protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false) +protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) +protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) +protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) +protocolNew("protocols" "virtual-keyboard-unstable-v1" true) +protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) +protocolNew("protocols" "input-method-unstable-v2" true) +protocolNew("protocols" "wlr-output-management-unstable-v1" true) +protocolNew("protocols" "kde-server-decoration" true) +protocolNew("protocols" "wlr-data-control-unstable-v1" true) +protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) +protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolNew("staging/tearing-control" "tearing-control-v1" false) +protocolNew("staging/fractional-scale" "fractional-scale-v1" false) +protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) +protocolNew("staging/cursor-shape" "cursor-shape-v1" false) +protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) +protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) +protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) +protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) +protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) +protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) +protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolNew("unstable/text-input" "text-input-unstable-v3" false) +protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) +protocolNew("staging/xdg-activation" "xdg-activation-v1" false) +protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) +protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) +protocolNew("stable/tablet" "tablet-v2" false) +protocolNew("stable/presentation-time" "presentation-time" false) +protocolNew("stable/xdg-shell" "xdg-shell" false) +protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolWayland() From f91431465b910b1acfc352d2425310beb34b7598 Mon Sep 17 00:00:00 2001 From: Yaroslav Date: Fri, 17 May 2024 15:06:31 +0500 Subject: [PATCH 0104/2393] cmake: make gprof optional for debug builds (#6120) This fixes the debug build on musl systems, as -pg option is specific to glibc. Now we can build the project on such systems with -DUSE_GPROF=OFF --- CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b30591d9..43927fbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -126,6 +126,8 @@ endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) add_dependencies(Hyprland wlroots-hyprland) +set(USE_GPROF ON) + if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Setting debug flags") @@ -151,8 +153,12 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) endif() endif() - add_compile_options(-pg -no-pie -fno-builtin) - add_link_options(-pg -no-pie -fno-builtin) + add_compile_options(-fno-pie -fno-builtin) + add_link_options(-no-pie -fno-builtin) + if(USE_GPROF) + add_compile_options(-pg) + add_link_options(-pg) + endif() endif() check_include_file("execinfo.h" EXECINFOH) From f21b6fe576b1068598d6c19fbbfd3f0659d5498d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 14:51:06 +0100 Subject: [PATCH 0105/2393] tablet: avoid null deref on an empty cursor set fixes#6116 --- src/protocols/Tablet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 7c54a116..54c55176 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -164,7 +164,7 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP< if (!g_pSeatManager->state.pointerFocusResource || g_pSeatManager->state.pointerFocusResource->client() != r->client()) return; - g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{wlr_surface_from_resource(surf), {hot_x, hot_y}}); + g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? wlr_surface_from_resource(surf) : nullptr, {hot_x, hot_y}}); }); } From 0cb8fbe18e45936ef3e3c6f82fcd200affc9fb13 Mon Sep 17 00:00:00 2001 From: Tuur Vanhoutte <4633209+zjeffer@users.noreply.github.com> Date: Fri, 17 May 2024 20:06:51 +0200 Subject: [PATCH 0106/2393] error: Add option to change position of HyprError bar (#3241) (#6111) --- src/config/ConfigManager.cpp | 1 + src/hyprerror/HyprError.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ac5c101e..3dc36899 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -374,6 +374,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("debug:manual_crash", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:suppress_errors", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:error_limit", Hyprlang::INT{5}); + m_pConfig->addConfigValue("debug:error_position", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:watchdog_timeout", Hyprlang::INT{5}); m_pConfig->addConfigValue("debug:disable_scale_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:colored_stdout_logs", Hyprlang::INT{1}); diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 4c7b6731..e7e2ff0d 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -58,8 +58,11 @@ void CHyprError::createQueued() { cairo_paint(CAIRO); cairo_restore(CAIRO); - const auto LINECOUNT = Hyprlang::INT{1} + std::count(m_szQueued.begin(), m_szQueued.end(), '\n'); - static auto LINELIMIT = CConfigValue("debug:error_limit"); + const auto LINECOUNT = Hyprlang::INT{1} + std::count(m_szQueued.begin(), m_szQueued.end(), '\n'); + static auto LINELIMIT = CConfigValue("debug:error_limit"); + static auto BAR_POSITION = CConfigValue("debug:error_position"); + + const bool TOPBAR = *BAR_POSITION == 0; const auto VISLINECOUNT = std::min(LINECOUNT, *LINELIMIT); const auto EXTRALINES = (VISLINECOUNT < LINECOUNT) ? 1 : 0; @@ -68,11 +71,11 @@ void CHyprError::createQueued() { const double PAD = 10 * SCALE; - const double X = PAD; - const double Y = PAD; const double WIDTH = PMONITOR->vecPixelSize.x - PAD * 2; const double HEIGHT = (FONTSIZE + 2 * (FONTSIZE / 10.0)) * (VISLINECOUNT + EXTRALINES) + 3; const double RADIUS = PAD > HEIGHT / 2 ? HEIGHT / 2 - 1 : PAD; + const double X = PAD; + const double Y = TOPBAR ? PAD : PMONITOR->vecPixelSize.y - HEIGHT - PAD; m_bDamageBox = {0, 0, (int)PMONITOR->vecPixelSize.x, (int)HEIGHT + (int)PAD * 2}; @@ -96,9 +99,9 @@ void CHyprError::createQueued() { cairo_set_font_size(CAIRO, FONTSIZE); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); - float yoffset = FONTSIZE; + float yoffset = TOPBAR ? FONTSIZE : Y - PAD + FONTSIZE; int renderedcnt = 0; - while (m_szQueued != "" && renderedcnt < VISLINECOUNT) { + while (!m_szQueued.empty() && renderedcnt < VISLINECOUNT) { std::string current = m_szQueued.substr(0, m_szQueued.find('\n')); if (const auto NEWLPOS = m_szQueued.find('\n'); NEWLPOS != std::string::npos) m_szQueued = m_szQueued.substr(NEWLPOS + 1); From 23cd4c7998cc4308e5db9b64994ebd6b27c38877 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 19:28:33 +0100 Subject: [PATCH 0107/2393] seat: update keymap/repeat info on keymap events from keebs fixes #6114 --- src/managers/SeatManager.cpp | 11 ++++++++--- src/managers/SeatManager.hpp | 1 + src/managers/input/InputManager.cpp | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 2087122a..bbbe01d4 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -86,10 +86,15 @@ void CSeatManager::setKeyboard(SP KEEB) { keyboard->active = false; keyboard = KEEB; - if (KEEB) { + if (KEEB) KEEB->active = true; - PROTO::seat->updateRepeatInfo(KEEB->wlr()->repeat_info.rate, KEEB->wlr()->repeat_info.delay); - } + + updateActiveKeyboardData(); +} + +void CSeatManager::updateActiveKeyboardData() { + if (keyboard) + PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); PROTO::seat->updateKeymap(); } diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index cf5e9216..fee3efa9 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -54,6 +54,7 @@ class CSeatManager { void setMouse(SP mouse); void setKeyboard(SP keeb); + void updateActiveKeyboardData(); // updates the clients with the keymap and repeat info void setKeyboardFocus(wlr_surface* surf); void sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 58e5ad17..e05520f4 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -839,6 +839,9 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); const auto LAYOUT = PKEEB->getActiveLayout(); + if (PKEEB == g_pSeatManager->keyboard) + g_pSeatManager->updateActiveKeyboardData(); + g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEEB->hlName + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector{PKEEB, LAYOUT})); }, From 9518cec833606166f6901fae0e68503a64938fce Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 19:43:56 +0100 Subject: [PATCH 0108/2393] popup: clip input region to surface size fixes #6125 --- src/desktop/Popup.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index c652d298..03acfff9 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -301,7 +301,9 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { return p; } else { const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input}.translate(p->coordsGlobal() + offset); + const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input} + .intersect(CBox{{}, {p->m_sWLSurface.wlr()->current.width, p->m_sWLSurface.wlr()->current.height}}) + .translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; } From fe23d2b639f13db852adb5f10812f308b38d7e9b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 19:54:05 +0100 Subject: [PATCH 0109/2393] window: verify suppress flags in onUpdateState ref #6108 --- src/desktop/Window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index c11a714b..56003eca 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1337,7 +1337,7 @@ void CWindow::onUpdateState() { if (!m_pXDGSurface) return; - if (m_pXDGSurface->toplevel->state.requestsFullscreen) { + if (m_pXDGSurface->toplevel->state.requestsFullscreen && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value(); if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) @@ -1347,7 +1347,7 @@ void CWindow::onUpdateState() { m_bWantsInitialFullscreen = fs; } - if (m_pXDGSurface->toplevel->state.requestsMaximize) { + if (m_pXDGSurface->toplevel->state.requestsMaximize && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value(); if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) From 49485ba36a2d246c6fd3b32e3d4ad94f5c115ed5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 20:04:17 +0100 Subject: [PATCH 0110/2393] pointer: damage in software mode on cursor image changes fixes #6126 --- src/managers/PointerManager.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index d565ad6d..4be91b80 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -169,11 +169,13 @@ SP CPointerManager::stateFor(SP } void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { + damageIfSoftware(); if (buf == currentCursorImage.pBuffer) { if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { currentCursorImage.hotspot = hotspot; currentCursorImage.scale = scale; updateCursorBackend(); + damageIfSoftware(); } return; @@ -193,14 +195,18 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, currentCursorImage.scale = scale; updateCursorBackend(); + damageIfSoftware(); } void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { + damageIfSoftware(); + if (surf == currentCursorImage.surface) { if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) { currentCursorImage.hotspot = hotspot; currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F; updateCursorBackend(); + damageIfSoftware(); } return; @@ -217,10 +223,12 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot currentCursorImage.hyprListener_commitSurface.initCallback( &surf->wlr()->events.commit, [this](void* owner, void* data) { + damageIfSoftware(); currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height}; currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F; recheckEnteredOutputs(); updateCursorBackend(); + damageIfSoftware(); }, nullptr, "CPointerManager"); @@ -235,6 +243,7 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot recheckEnteredOutputs(); updateCursorBackend(); + damageIfSoftware(); } void CPointerManager::recheckEnteredOutputs() { @@ -276,6 +285,8 @@ void CPointerManager::recheckEnteredOutputs() { } void CPointerManager::resetCursorImage(bool apply) { + damageIfSoftware(); + if (currentCursorImage.surface) { for (auto& m : g_pCompositor->m_vMonitors) { wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output); From 2ead1fd22103ce065661555513bace5897083ded Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 17 May 2024 20:07:33 +0100 Subject: [PATCH 0111/2393] virtual-keyboard: emit event before finishing keyboard ref #6123 --- src/protocols/VirtualKeyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 7325f7cd..89b14c32 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -87,8 +87,8 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP } CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() { - wlr_keyboard_finish(&keyboard); events.destroy.emit(); + wlr_keyboard_finish(&keyboard); } bool CVirtualKeyboardV1Resource::good() { From c21a5a934061c248ff1cdd459a74a05b621fb427 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 18 May 2024 18:28:48 +0000 Subject: [PATCH 0112/2393] layout: Fix shrinking pseudotile windows. (#6143) --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index a31180e1..ffd9ddea 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -523,7 +523,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; wb.round(); - if (DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && + if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) { wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}}; } From f8857e6072bd85b95393499688872aaf7f088b5b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 18 May 2024 21:20:01 +0100 Subject: [PATCH 0113/2393] input: find surface pos correctly when mouse drag is active fixes #6144 --- src/managers/input/InputManager.cpp | 35 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e05520f4..f4f97236 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -222,26 +222,29 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { - foundSurface = g_pSeatManager->state.pointerFocus; - pFoundLayerSurface = g_pCompositor->getLayerSurfaceFromSurface(foundSurface); - if (pFoundLayerSurface) { - surfacePos = pFoundLayerSurface->position; + foundSurface = g_pSeatManager->state.pointerFocus; + + // IME popups aren't desktop-like elements + // TODO: make them. + CInputPopup* foundPopup = m_sIMERelay.popupFromSurface(foundSurface); + if (foundPopup) { + surfacePos = foundPopup->globalBox().pos(); m_bFocusHeldByButtons = true; m_bRefocusHeldByButtons = refocus; } else { - CInputPopup* foundPopup = m_sIMERelay.popupFromSurface(foundSurface); - if (foundPopup) { - surfacePos = foundPopup->globalBox().pos(); - m_bFocusHeldByButtons = true; - m_bRefocusHeldByButtons = refocus; - } else if (!g_pCompositor->m_pLastWindow.expired()) { - foundSurface = g_pSeatManager->state.pointerFocus; - pFoundWindow = g_pCompositor->m_pLastWindow.lock(); + auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); - surfaceCoords = g_pCompositor->vectorToSurfaceLocal(mouseCoords, pFoundWindow, foundSurface); - m_bFocusHeldByButtons = true; - m_bRefocusHeldByButtons = refocus; - } + if (HLSurface) { + const auto BOX = HLSurface->getSurfaceBoxGlobal(); + + if (BOX) { + surfacePos = BOX->pos(); + pFoundLayerSurface = HLSurface->getLayer(); + pFoundWindow = HLSurface->getWindow(); + } else // reset foundSurface, find one normally + foundSurface = nullptr; + } else // reset foundSurface, find one normally + foundSurface = nullptr; } } From baef55da1ddccf8ca1b831214bb96e523b600a28 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 21 May 2024 14:50:33 +0200 Subject: [PATCH 0114/2393] xdg-shell: fixup positioner behavior with slide and resize if sliding and resizing, include the slide in the resize to avoid off-screen surfaces. fixes #6150 --- src/protocols/XDGShell.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9777281f..cbb93de9 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -550,6 +550,14 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa return test.translate(-parentCoord - constraint.pos()); } + // if flips fail, we will slide and remember. + // if the positioner is allowed to resize, then resize the slid thing. + CBox test = predictedBox; + + // for slide and resize, defines the padding around the edge for the positioned + // surface. + constexpr int EDGE_PADDING = 4; + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) { // attempt to slide const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; @@ -563,17 +571,15 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; - CBox test = predictedBox; - // TODO: this isn't truly conformant. if (leftEdgeOut && slideX) - test.x = constraint.x; + test.x = constraint.x + EDGE_PADDING; if (rightEdgeOut && slideX) - test.x = constraint.x + constraint.w - predictedBox.w; + test.x = constraint.x + constraint.w - predictedBox.w - EDGE_PADDING; if (topEdgeOut && slideY) - test.y = constraint.y; + test.y = constraint.y + EDGE_PADDING; if (bottomEdgeOut && slideY) - test.y = constraint.y + constraint.h - predictedBox.y; + test.y = constraint.y + constraint.h - predictedBox.y - EDGE_PADDING; success = test.copy().expand(-1).inside(constraint); @@ -590,21 +596,19 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; - CBox test = predictedBox; - // TODO: this isn't truly conformant. if (leftEdgeOut && resizeX) { - test.w = test.x + test.w - constraint.x; - test.x = constraint.x; + test.w = test.x + test.w - constraint.x - EDGE_PADDING; + test.x = constraint.x + EDGE_PADDING; } if (rightEdgeOut && resizeX) - test.w = -(constraint.w + constraint.x - test.w - test.x); + test.w = -(constraint.w + constraint.x - test.w - test.x + EDGE_PADDING); if (topEdgeOut && resizeY) { - test.h = test.y + test.h - constraint.y; - test.y = constraint.y; + test.h = test.y + test.h - constraint.y - EDGE_PADDING; + test.y = constraint.y + EDGE_PADDING; } if (bottomEdgeOut && resizeY) - test.h = -(constraint.h + constraint.y - test.h - test.y); + test.h = -(constraint.h + constraint.y - test.h - test.y + EDGE_PADDING); success = test.copy().expand(-1).inside(constraint); @@ -614,7 +618,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); - return predictedBox.translate(-parentCoord - constraint.pos()); + return test.translate(-parentCoord - constraint.pos()); } CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { From 4daa5c06587390c5c6835275ccbfc645bacc0052 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 20 May 2024 17:29:35 +0300 Subject: [PATCH 0115/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index ca05387b..eba1996a 100644 --- a/flake.lock +++ b/flake.lock @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1715879663, - "narHash": "sha256-/DwglRvj4XF4ECdNtrCIbthleszAZBwOiXG5A6r0K/c=", + "lastModified": 1716058375, + "narHash": "sha256-CwjWoVnBZE5SBpRx9dgSQGCr4Goxyfcyv3zZbOhVqzk=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "f5181a068c1b06f2db51f6222e50a0c665a2b0c3", + "rev": "3afed4364790aebe0426077631af1e164a9650cc", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1715787315, - "narHash": "sha256-cYApT0NXJfqBkKcci7D9Kr4CBYZKOQKDYA23q8XNuWg=", + "lastModified": 1716137900, + "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "33d1e753c82ffc557b4a585c77de43d4c922ebb5", + "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1", "type": "github" }, "original": { @@ -152,11 +152,11 @@ ] }, "locked": { - "lastModified": 1715788457, - "narHash": "sha256-32HOkjSIyANphV0p5gIwP4ONU/CcinhwOyVFB+tL/d0=", + "lastModified": 1716290197, + "narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "af7c87a32f5d67eb2ada908a6a700f4e74831943", + "rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", "type": "github" }, "original": { From 3c907f783027328cf90fae45ff51978c1f123418 Mon Sep 17 00:00:00 2001 From: giskard Date: Thu, 16 May 2024 00:13:56 +0800 Subject: [PATCH 0116/2393] build: update meson, cmake setup - meson . fix run_command() check warning . drop lines for compatability, as it's already using c++23 - cmake . generate `compile_commands.json` by default . position independent build: __FILE__ --- CMakeLists.txt | 7 +++++-- meson.build | 21 ++++++--------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 43927fbe..858502cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project(Hyprland set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) -configure_file(hyprland.pc.in hyprland.pc @ONLY) +configure_file(hyprland.pc.in hyprland.pc @ONLY) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") @@ -90,9 +90,12 @@ include_directories( "protocols/") set(CMAKE_CXX_STANDARD 23) add_compile_definitions(WLR_USE_UNSTABLE) -add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith) +add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value + -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith + -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) message(STATUS "Checking deps...") diff --git a/meson.build b/meson.build index 9b278198..b7b23470 100644 --- a/meson.build +++ b/meson.build @@ -5,20 +5,9 @@ project('Hyprland', 'cpp', 'c', 'default_library=static', 'optimization=3', 'buildtype=release', - 'debug=false' - # 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0 - ]) - -# clang v14.0.6 uses C++2b instead of C++23, so we've gotta account for that -# replace the following with a project default option once meson gets support for C++23 -cpp_compiler = meson.get_compiler('cpp') -if cpp_compiler.has_argument('-std=c++23') - add_global_arguments('-std=c++23', language: 'cpp') -elif cpp_compiler.has_argument('-std=c++2b') - add_global_arguments('-std=c++2b', language: 'cpp') -else - error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)') -endif + 'debug=false', + 'cpp_std=c++23', + ]) add_project_arguments( [ @@ -26,9 +15,11 @@ add_project_arguments( '-Wno-unused-value', '-Wno-missing-field-initializers', '-Wno-narrowing', + '-Wno-pointer-arith', ], language: 'cpp') +cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif @@ -65,7 +56,7 @@ if get_option('buildtype') == 'debug' add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') endif -version_h = run_command('sh', '-c', 'scripts/generateVersion.sh') +version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) globber = run_command('find', 'src', '-name', '*.h*', check: true) headers = globber.stdout().strip().split('\n') From e419ef1873de01b0762f7f1a411994170a4d8cab Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 21 May 2024 21:29:56 +0300 Subject: [PATCH 0117/2393] Revert "CMake: use add_custom_command for generating protocols (#6104)" Fixes https://github.com/hyprwm/Hyprland/issues/6115. --- CMakeLists.txt | 118 +++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 858502cc..40e0f32a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,11 +113,9 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7 ) -find_package(hyprwayland-scanner 0.3.8 REQUIRED) - file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") @@ -221,48 +219,42 @@ target_link_libraries(Hyprland rt PkgConfig::deps) function(protocol protoPath protoName external) if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + execute_process( + COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + execute_process( + COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + execute_process( + COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + execute_process( + COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) endif() - - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) endfunction() function(protocolNew protoPath protoName external) if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + execute_process( + COMMAND hyprwayland-scanner ${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + execute_process( + COMMAND hyprwayland-scanner ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp - ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp - COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) - target_sources(Hyprland PRIVATE protocols/${protoName}.hpp) endfunction() function(protocolWayland) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp - ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + execute_process( COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) target_sources(Hyprland PRIVATE protocols/wayland.cpp) - target_sources(Hyprland PRIVATE protocols/wayland.hpp) endfunction() target_link_libraries(Hyprland @@ -280,37 +272,37 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.x protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) -protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) -protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) -protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols" "input-method-unstable-v2" true) -protocolNew("protocols" "wlr-output-management-unstable-v1" true) -protocolNew("protocols" "kde-server-decoration" true) -protocolNew("protocols" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) -protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) -protocolNew("staging/tearing-control" "tearing-control-v1" false) -protocolNew("staging/fractional-scale" "fractional-scale-v1" false) -protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) -protocolNew("staging/cursor-shape" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) -protocolNew("stable/tablet" "tablet-v2" false) -protocolNew("stable/presentation-time" "presentation-time" false) -protocolNew("stable/xdg-shell" "xdg-shell" false) -protocolNew("unstable/primary-selection" "primary-selection-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("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) +protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) +protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) +protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) +protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) +protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) +protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true) +protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) +protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-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) +protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) +protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false) +protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false) +protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false) +protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false) +protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false) +protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false) +protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false) +protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false) +protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) +protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) +protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) +protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) +protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) +protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) +protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false) protocolWayland() From 93fea890433ec11d7a915f5e0466b2e8b513e895 Mon Sep 17 00:00:00 2001 From: giskard Date: Wed, 22 May 2024 16:09:36 +0800 Subject: [PATCH 0118/2393] renderer: render fonts with pango, add global `font_family` config option (#6138) --- src/config/ConfigManager.cpp | 5 +- src/debug/HyprDebugOverlay.cpp | 107 ++++++++--------- src/debug/HyprNotificationOverlay.cpp | 109 +++++++++--------- src/debug/HyprNotificationOverlay.hpp | 3 - src/hyprerror/HyprError.cpp | 25 +++- src/render/OpenGL.cpp | 37 +++--- .../decorations/CHyprGroupBarDecoration.cpp | 7 +- 7 files changed, 157 insertions(+), 136 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3dc36899..14a326bb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -324,7 +324,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:col.splash", Hyprlang::INT{0x55ffffff}); - m_pConfig->addConfigValue("misc:splash_font_family", {"Sans"}); + m_pConfig->addConfigValue("misc:splash_font_family", {STRVAL_EMPTY}); + m_pConfig->addConfigValue("misc:font_family", {"Sans"}); m_pConfig->addConfigValue("misc:force_default_wallpaper", Hyprlang::INT{-1}); m_pConfig->addConfigValue("misc:vfr", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:vrr", Hyprlang::INT{0}); @@ -353,7 +354,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); - m_pConfig->addConfigValue("group:groupbar:font_family", {"Sans"}); + m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:height", Hyprlang::INT{14}); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 37ccc67a..6d3ec907 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -1,4 +1,6 @@ +#include #include "HyprDebugOverlay.hpp" +#include "config/ConfigValue.hpp" #include "../Compositor.hpp" void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { @@ -47,11 +49,6 @@ int CHyprMonitorDebugOverlay::draw(int offset) { if (!m_pMonitor) return 0; - int yOffset = offset; - cairo_text_extents_t cairoExtents; - float maxX = 0; - std::string text = ""; - // get avg fps float avgFrametime = 0; float maxFrametime = 0; @@ -105,23 +102,49 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick; avgAnimMgrTick /= m_dLastAnimationTicks.size() == 0 ? 1 : m_dLastAnimationTicks.size(); - const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms - const float idealFPS = m_dLastFrametimes.size(); + const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms + const float idealFPS = m_dLastFrametimes.size(); - cairo_select_font_face(g_pDebugOverlay->m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + static auto fontFamily = CConfigValue("misc:font_family"); + PangoLayout* layoutText = pango_cairo_create_layout(g_pDebugOverlay->m_pCairo); + PangoFontDescription* pangoFD = pango_font_description_new(); - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + + float maxTextW = 0; + int fontSize = 0; + auto cr = g_pDebugOverlay->m_pCairo; + + auto showText = [cr, layoutText, pangoFD, &maxTextW, &fontSize](const char* text, int size) { + if (fontSize != size) { + pango_font_description_set_absolute_size(pangoFD, size * PANGO_SCALE); + pango_layout_set_font_description(layoutText, pangoFD); + fontSize = size; + } + + pango_layout_set_text(layoutText, text, -1); + pango_cairo_show_layout(cr, layoutText); + + int textW = 0, textH = 0; + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; + if (textW > maxTextW) + maxTextW = textW; + + // move to next line + cairo_rel_move_to(cr, 0, fontSize + 1); + }; + + const int MARGIN_TOP = 8; + const int MARGIN_LEFT = 4; + cairo_move_to(cr, MARGIN_LEFT, MARGIN_TOP + offset); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); - yOffset += 10; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); - text = m_pMonitor->szName; - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; - - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 16); + std::string text; + showText(m_pMonitor->szName.c_str(), 10); if (FPS > idealFPS * 0.95f) cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 0.2f, 1.f, 0.2f, 1.f); @@ -130,57 +153,35 @@ int CHyprMonitorDebugOverlay::draw(int offset) { else cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 0.2f, 0.2f, 1.f); - yOffset += 17; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("{} FPS", (int)FPS); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 16); - cairo_set_font_size(g_pDebugOverlay->m_pCairo, 10); cairo_set_source_rgba(g_pDebugOverlay->m_pCairo, 1.f, 1.f, 1.f, 1.f); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Frametime: {:.2f}ms (var {:.2f}ms)", avgFrametime, varFrametime); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Rendertime: {:.2f}ms (var {:.2f}ms)", avgRenderTime, varRenderTime); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Rendertime (No Overlay): {:.2f}ms (var {:.2f}ms)", avgRenderTimeNoOverlay, varRenderTimeNoOverlay); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; - cairo_move_to(g_pDebugOverlay->m_pCairo, 0, yOffset); text = std::format("Avg Anim Tick: {:.2f}ms (var {:.2f}ms) ({:.2f} TPS)", avgAnimMgrTick, varAnimMgrTick, 1.0 / (avgAnimMgrTick / 1000.0)); - cairo_show_text(g_pDebugOverlay->m_pCairo, text.c_str()); - cairo_text_extents(g_pDebugOverlay->m_pCairo, text.c_str(), &cairoExtents); - if (cairoExtents.width > maxX) - maxX = cairoExtents.width; + showText(text.c_str(), 10); - yOffset += 11; + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + + double posX = 0, posY = 0; + cairo_get_current_point(cr, &posX, &posY); g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); - m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset - 1, (int)maxX + 2, - yOffset - offset + 2}; + m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1, + (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); - return yOffset - offset; + return posY - offset; } void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 80c80601..e1fc810b 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -1,6 +1,20 @@ +#include +#include #include "HyprNotificationOverlay.hpp" #include "../Compositor.hpp" -#include +#include "../config/ConfigValue.hpp" + +inline auto iconBackendFromLayout(PangoLayout* layout) { + // preference: Nerd > FontAwesome > text + auto eIconBackendChecks = std::array{ICONS_BACKEND_NF, ICONS_BACKEND_FA}; + for (auto iconID : eIconBackendChecks) { + auto iconsText = std::accumulate(ICONS_ARRAY[iconID].begin(), ICONS_ARRAY[iconID].end(), std::string()); + pango_layout_set_text(layout, iconsText.c_str(), -1); + if (pango_layout_get_unknown_glyphs_count(layout) == 0) + return iconID; + } + return ICONS_BACKEND_NONE; +} CHyprNotificationOverlay::CHyprNotificationOverlay() { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { @@ -9,31 +23,6 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { g_pHyprRenderer->damageBox(&m_bLastDamage); }); - - // check for the icon backend - std::string fonts = execAndGet("fc-list"); - std::string fontsLower = fonts; - std::transform(fontsLower.begin(), fontsLower.end(), fontsLower.begin(), [&](char& i) { return std::tolower(i); }); - - size_t index = 0; - - if (index = fontsLower.find("nerd"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_NF; - } else if (index = fontsLower.find("font awesome"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_FA; - } else if (index = fontsLower.find("fontawesome"); index != std::string::npos) { - m_eIconBackend = ICONS_BACKEND_FA; - } else { - return; - } - - const auto LASTNEWLINE = fonts.find_last_of('\n', index); - const auto COLON = fonts.find(':', LASTNEWLINE); - const auto COMMA = fonts.find(',', COLON); - const auto NEWLINE = fonts.find('\n', COLON); - const auto LASTCHAR = COMMA < NEWLINE ? COMMA : NEWLINE; - - m_szIconFontName = fonts.substr(COLON + 2, LASTCHAR - (COLON + 2)); } CHyprNotificationOverlay::~CHyprNotificationOverlay() { @@ -81,25 +70,24 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { float offsetY = 10; float maxWidth = 0; - const auto SCALE = pMonitor->scale; - + const auto SCALE = pMonitor->scale; const auto MONSIZE = pMonitor->vecTransformedSize; - cairo_text_extents_t cairoExtents; - int iconW = 0, iconH = 0; + static auto fontFamily = CConfigValue("misc:font_family"); - cairo_select_font_face(m_pCairo, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + PangoLayout* layout = pango_cairo_create_layout(m_pCairo); + PangoFontDescription* pangoFD = pango_font_description_new(); - const auto PBEZIER = g_pAnimationManager->getBezier("default"); + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + + const auto iconBackendID = iconBackendFromLayout(layout); + const auto PBEZIER = g_pAnimationManager->getBezier("default"); for (auto& notif : m_dNotifications) { - const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; - const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); - - PangoLayout* pangoLayout = pango_cairo_create_layout(m_pCairo); - PangoFontDescription* pangoFD = pango_font_description_from_string(("Sans " + std::to_string(FONTSIZE * ICON_SCALE)).c_str()); - pango_layout_set_font_description(pangoLayout, pangoFD); - cairo_set_font_size(m_pCairo, FONTSIZE); + const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; + const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); // first rect (bg, col) const float FIRSTRECTANIMP = @@ -122,31 +110,37 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { const float THIRDRECTPERC = notif->started.getMillis() / notif->timeMs; // get text size - cairo_text_extents(m_pCairo, notif->text.c_str(), &cairoExtents); - const auto ICON = ICONS_ARRAY[m_eIconBackend][notif->icon]; + const auto ICON = ICONS_ARRAY[iconBackendID][notif->icon]; const auto ICONCOLOR = ICONS_COLORS[notif->icon]; - pango_layout_set_text(pangoLayout, ICON.c_str(), -1); - pango_layout_set_font_description(pangoLayout, pangoFD); - pango_cairo_update_layout(m_pCairo, pangoLayout); - pango_layout_get_size(pangoLayout, &iconW, &iconH); + + int iconW = 0, iconH = 0; + pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE * ICON_SCALE); + pango_layout_set_font_description(layout, pangoFD); + pango_layout_set_text(layout, ICON.c_str(), -1); + pango_layout_get_size(layout, &iconW, &iconH); iconW /= PANGO_SCALE; iconH /= PANGO_SCALE; - cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); + int textW = 0, textH = 0; + pango_font_description_set_absolute_size(pangoFD, PANGO_SCALE * FONTSIZE); + pango_layout_set_font_description(layout, pangoFD); + pango_layout_set_text(layout, notif->text.c_str(), -1); + pango_layout_get_size(layout, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; - const auto NOTIFSIZE = Vector2D{cairoExtents.width + 20 + iconW + 2 * ICONPADFORNOTIF, cairoExtents.height + 10}; + const auto NOTIFSIZE = Vector2D{textW + 20 + iconW + 2 * ICONPADFORNOTIF, textH + 10}; // draw rects + cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); cairo_rectangle(m_pCairo, MONSIZE.x - (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, offsetY, (NOTIFSIZE.x + NOTIF_LEFTBAR_SIZE) * FIRSTRECTPERC, NOTIFSIZE.y); cairo_fill(m_pCairo); cairo_set_source_rgb(m_pCairo, 0.f, 0.f, 0.f); - cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC, offsetY, NOTIFSIZE.x * SECONDRECTPERC, NOTIFSIZE.y); cairo_fill(m_pCairo); cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); - cairo_rectangle(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + 3, offsetY + NOTIFSIZE.y - 4, THIRDRECTPERC * (NOTIFSIZE.x - 6), 2); cairo_fill(m_pCairo); @@ -164,26 +158,27 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { // draw icon cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); - cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY + std::round((NOTIFSIZE.y - iconH - 4) / 2.0)); - pango_cairo_show_layout(m_pCairo, pangoLayout); + cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + ICONPADFORNOTIF - 1, offsetY - 2 + std::round((NOTIFSIZE.y - iconH) / 2.0)); + pango_layout_set_text(layout, ICON.c_str(), -1); + pango_cairo_show_layout(m_pCairo, layout); } // draw text - cairo_set_font_size(m_pCairo, FONTSIZE); cairo_set_source_rgb(m_pCairo, 1.f, 1.f, 1.f); - cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY + FONTSIZE + (FONTSIZE / 10.0)); - cairo_show_text(m_pCairo, notif->text.c_str()); + cairo_move_to(m_pCairo, MONSIZE.x - NOTIFSIZE.x * SECONDRECTPERC + NOTIF_LEFTBAR_SIZE + iconW + 2 * ICONPADFORNOTIF, offsetY - 2 + std::round((NOTIFSIZE.y - textH) / 2.0)); + pango_layout_set_text(layout, notif->text.c_str(), -1); + pango_cairo_show_layout(m_pCairo, layout); // adjust offset and move on offsetY += NOTIFSIZE.y + 10; if (maxWidth < NOTIFSIZE.x) maxWidth = NOTIFSIZE.x; - - pango_font_description_free(pangoFD); - g_object_unref(pangoLayout); } + pango_font_description_free(pangoFD); + g_object_unref(layout); + // cleanup notifs std::erase_if(m_dNotifications, [](const auto& notif) { return notif->started.getMillis() > notif->timeMs; }); diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index d086ada9..5c978089 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -59,9 +59,6 @@ class CHyprNotificationOverlay { Vector2D m_vecLastSize = Vector2D(-1, -1); CTexture m_tTexture; - - eIconBackend m_eIconBackend = ICONS_BACKEND_NONE; - std::string m_szIconFontName = "Sans"; }; inline std::unique_ptr g_pHyprNotificationOverlay; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index e7e2ff0d..d147a6bb 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -1,3 +1,4 @@ +#include #include "HyprError.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" @@ -94,12 +95,19 @@ void CHyprError::createQueued() { // draw the text with a common font const CColor textColor = m_cQueued.r + m_cQueued.g + m_cQueued.b < 0.2f ? CColor(1.0, 1.0, 1.0, 1.0) : CColor(0, 0, 0, 1.0); - - cairo_select_font_face(CAIRO, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(CAIRO, FONTSIZE); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); - float yoffset = TOPBAR ? FONTSIZE : Y - PAD + FONTSIZE; + static auto fontFamily = CConfigValue("misc:font_family"); + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); + + pango_font_description_set_family(pangoFD, (*fontFamily).c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + + float yoffset = TOPBAR ? 0 : Y - PAD; int renderedcnt = 0; while (!m_szQueued.empty() && renderedcnt < VISLINECOUNT) { std::string current = m_szQueued.substr(0, m_szQueued.find('\n')); @@ -108,17 +116,22 @@ void CHyprError::createQueued() { else m_szQueued = ""; cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1); - cairo_show_text(CAIRO, current.c_str()); + pango_layout_set_text(layoutText, current.c_str(), -1); + pango_cairo_show_layout(CAIRO, layoutText); yoffset += FONTSIZE + (FONTSIZE / 10.f); renderedcnt++; } if (VISLINECOUNT < LINECOUNT) { std::string moreString = std::format("({} more...)", LINECOUNT - VISLINECOUNT); cairo_move_to(CAIRO, PAD + 1 + RADIUS, yoffset + PAD + 1); - cairo_show_text(CAIRO, moreString.c_str()); + pango_layout_set_text(layoutText, moreString.c_str(), -1); + pango_cairo_show_layout(CAIRO, layoutText); } m_szQueued = ""; + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + cairo_surface_flush(CAIROSURFACE); // copy the data to an OpenGL texture we have diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a8a20f30..a1e6f73e 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1,9 +1,9 @@ +#include +#include #include "Shaders.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" #include "../helpers/MiscFunctions.hpp" -#include "Shaders.hpp" -#include #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" @@ -2097,25 +2097,36 @@ void CHyprOpenGLImpl::renderMirrored() { } void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) { - static auto PSPLASHCOLOR = CConfigValue("misc:col.splash"); + static auto PSPLASHCOLOR = CConfigValue("misc:col.splash"); + static auto PSPLASHFONT = CConfigValue("misc:splash_font_family"); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); - static auto PSPLASHFONT = CConfigValue("misc:splash_font_family"); + const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT; + const auto FONTSIZE = (int)(size.y / 76); + const auto COLOR = CColor(*PSPLASHCOLOR); - cairo_select_font_face(CAIRO, (*PSPLASHFONT).c_str(), CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); - const auto FONTSIZE = (int)(size.y / 76); - cairo_set_font_size(CAIRO, FONTSIZE); - - const auto COLOR = CColor(*PSPLASHCOLOR); + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); - cairo_text_extents_t textExtents; - cairo_text_extents(CAIRO, g_pCompositor->m_szCurrentSplash.c_str(), &textExtents); + int textW = 0, textH = 0; + pango_layout_set_text(layoutText, g_pCompositor->m_szCurrentSplash.c_str(), -1); + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; - cairo_move_to(CAIRO, (size.x - textExtents.width) / 2.0, size.y - textExtents.height + offsetY); + cairo_move_to(CAIRO, (size.x - textW) / 2.0, size.y - textH * 2 + offsetY); + pango_cairo_show_layout(CAIRO, layoutText); - cairo_show_text(CAIRO, g_pCompositor->m_szCurrentSplash.c_str()); + pango_font_description_free(pangoFD); + g_object_unref(layoutText); cairo_surface_flush(CAIROSURFACE); } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 318999ed..04f69aaa 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -209,11 +209,13 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); const auto CAIRO = cairo_create(CAIROSURFACE); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); - const CColor COLOR = CColor(*PTEXTCOLOR); + const CColor COLOR = CColor(*PTEXTCOLOR); + const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; // clear the pixmap cairo_save(CAIRO); @@ -225,7 +227,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float PangoLayout* layout = pango_cairo_create_layout(CAIRO); pango_layout_set_text(layout, szContent.c_str(), -1); - PangoFontDescription* fontDesc = pango_font_description_from_string((*PTITLEFONTFAMILY).c_str()); + PangoFontDescription* fontDesc = pango_font_description_new(); + pango_font_description_set_family_static(fontDesc, FONTFAMILY.c_str()); pango_font_description_set_size(fontDesc, *PTITLEFONTSIZE * PANGO_SCALE * monitorScale); pango_layout_set_font_description(layout, fontDesc); pango_font_description_free(fontDesc); From 155ae3721c5ef57321a7ef010369f0e03a358612 Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Wed, 22 May 2024 13:51:46 -0600 Subject: [PATCH 0119/2393] keybinds: Add option to disable window direction monitor fallback (#6182) * add monitor fallback option * format --- src/Compositor.cpp | 9 ++++++++- src/config/ConfigManager.cpp | 1 + src/managers/KeybindManager.cpp | 17 +++++++++++++---- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index efbd997f..5c9cfbad 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1386,7 +1386,8 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { return nullptr; // 0 -> history, 1 -> shared length - static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); + static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); @@ -1416,6 +1417,9 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) continue; + if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + continue; + const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y); @@ -1505,6 +1509,9 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) continue; + if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + continue; + const auto DIST = w->middle().distance(pWindow->middle()); const auto ANGLE = vectorAngles(Vector2D{w->middle() - pWindow->middle()}, VECTORS.at(dir)); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 14a326bb..77aa2fb3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -495,6 +495,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0}); + m_pConfig->addConfigValue("binds:window_direction_monitor_fallback", Hyprlang::INT{1}); m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ea064031..925a7fb7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1220,8 +1220,9 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { } void CKeybindManager::moveFocusTo(std::string args) { - static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); - char arg = args[0]; + static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); + char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); @@ -1230,7 +1231,9 @@ void CKeybindManager::moveFocusTo(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW) { - tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); + if (*PMONITORFALLBACK) + tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); + return; } @@ -1246,7 +1249,7 @@ void CKeybindManager::moveFocusTo(std::string args) { Debug::log(LOG, "No window found in direction {}, looking for a monitor", arg); - if (tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) + if (*PMONITORFALLBACK && tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) return; static auto PNOFALLBACK = CConfigValue("general:no_focus_fallback"); @@ -1317,6 +1320,8 @@ void CKeybindManager::moveActiveTo(std::string args) { moveActiveToWorkspaceSilent(PNEWMONITOR->activeWorkspace->getConfigName()); else moveActiveToWorkspace(PNEWMONITOR->activeWorkspace->getConfigName()); + + return; } if (!isDirection(args)) { @@ -1356,6 +1361,10 @@ void CKeybindManager::moveActiveTo(std::string args) { return; } + static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); + if (!*PMONITORFALLBACK) + return; + // Otherwise, we always want to move to the next monitor in that direction const auto PMONITORTOCHANGETO = g_pCompositor->getMonitorInDirection(arg); if (!PMONITORTOCHANGETO) From 3775776a07dc54347dd0859c7b6fc63aa3a4c7fd Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 22 May 2024 22:37:02 +0200 Subject: [PATCH 0120/2393] window: guard monitor in bounding box calculations fixes #6190 --- src/desktop/Window.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 56003eca..7987c9d6 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -87,9 +87,9 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { const int BORDERSIZE = getRealBorderSize(); if (m_sAdditionalConfigData.dimAround) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, - {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, + {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; } SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; @@ -147,8 +147,8 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { CBox CWindow::getFullWindowBoundingBox() { if (m_sAdditionalConfigData.dimAround) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } auto maxExtents = getFullWindowExtents(); From 62401d5b3f278d502f18999c3218e1c769846e29 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 23 May 2024 00:42:16 +0200 Subject: [PATCH 0121/2393] screencopy: use a simple renderer for frame passing --- src/protocols/Screencopy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 7c25ed3f..622d9d68 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -494,7 +494,7 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* CFramebuffer fb; fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat); - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb)) { + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { wlr_texture_destroy(sourceTex); wlr_buffer_end_data_ptr_access(frame->buffer); return false; @@ -557,7 +557,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer, nullptr, true)) return false; CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} From 7ad9116de8d0b7dac27eaf080bd92998a8fb40e5 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 22 May 2024 22:43:47 +0000 Subject: [PATCH 0122/2393] [gha] Nix: update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index eba1996a..f285fe8f 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1715791817, - "narHash": "sha256-J069Uhv/gCMFLX1dSh2f+9ZTM09r1Nv3oUfocCnWKow=", + "lastModified": 1716327911, + "narHash": "sha256-PI+wygItS/TKzi4gEAROvKTUzTx9GT+PGBttS/IOA/Q=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "7c3aa03dffb53921e583ade3d4ae3f487e390e7e", + "rev": "27ca640abeef2d425b5dbecf804f5eb622cef56d", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716137900, - "narHash": "sha256-sowPU+tLQv8GlqtVtsXioTKeaQvlMz/pefcdwg8MvfM=", + "lastModified": 1716330097, + "narHash": "sha256-8BO3B7e3BiyIDsaKA0tY8O88rClYRTjvAp66y+VBUeU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "6c0b7a92c30122196a761b440ac0d46d3d9954f1", + "rev": "5710852ba686cc1fd0d3b8e22b3117d43ba374c2", "type": "github" }, "original": { From 25b9446949bf12a2bfc1b9a38b4ccac78a06b32d Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Thu, 23 May 2024 05:01:12 -0600 Subject: [PATCH 0123/2393] internal: save previous workspace before change (#6202) --- src/managers/KeybindManager.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 925a7fb7..e23cb500 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1071,6 +1071,14 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER); + if (BISWORKSPACECURRENT) { + if (*PALLOWWORKSPACECYCLES) + pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); + else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH) + pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr); + } else + pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); + PMONITORWORKSPACEOWNER->changeWorkspace(pWorkspaceToChangeTo, false, true); if (PMONITOR != PMONITORWORKSPACEOWNER) { @@ -1083,14 +1091,6 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->warpCursorTo(middle); } - if (BISWORKSPACECURRENT) { - if (*PALLOWWORKSPACECYCLES) - pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); - else if (!EXPLICITPREVIOUS && !*PBACKANDFORTH) - pWorkspaceToChangeTo->rememberPrevWorkspace(nullptr); - } else - pWorkspaceToChangeTo->rememberPrevWorkspace(PCURRENTWORKSPACE); - if (!g_pInputManager->m_bLastFocusOnLS) { if (g_pCompositor->m_pLastFocus) g_pInputManager->sendMotionEventsToFocused(); @@ -1163,13 +1163,13 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { else if (POLDWS->m_bIsSpecialWorkspace) g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr); + if (*PALLOWWORKSPACECYCLES) + pWorkspace->rememberPrevWorkspace(POLDWS); + pMonitor->changeWorkspace(pWorkspace); g_pCompositor->focusWindow(PWINDOW); g_pCompositor->warpCursorTo(PWINDOW->middle()); - - if (*PALLOWWORKSPACECYCLES) - pWorkspace->rememberPrevWorkspace(POLDWS); } void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { From df80fbf70650dfb0d96381a1d86d30811cf516f4 Mon Sep 17 00:00:00 2001 From: Ming-Chuan <10496191+sifmelcara@users.noreply.github.com> Date: Thu, 23 May 2024 04:52:32 -0700 Subject: [PATCH 0124/2393] tablet: fix mapping when mapped region is specified (#6206) When `region_size` is set in the config (non-empty `boundBox`), cursor is mapped to wrong coordinate because `CBox::translate` mutates `TAB->boundBox`, making all subsequent coordinate calculations wrong. This also fixes the edge case where user sets `region_position` but not `region_size`. --- src/managers/PointerManager.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 4be91b80..ae17c6d6 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -696,8 +696,11 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { } } - if (!TAB->boundBox.empty()) - mappedArea = TAB->boundBox.translate(currentMonitor->vecPosition); + mappedArea.translate(TAB->boundBox.pos()); + if (!TAB->boundBox.empty()) { + mappedArea.w = TAB->boundBox.w; + mappedArea.h = TAB->boundBox.h; + } break; } case HID_TYPE_TOUCH: { From 255272ea18a1bd899168b2d2063b6f153edda919 Mon Sep 17 00:00:00 2001 From: System64 <72354122+System64fumo@users.noreply.github.com> Date: Thu, 23 May 2024 19:04:39 +0300 Subject: [PATCH 0125/2393] debug: Add ARM GPU info (#6212) Added a simple way to get basic info about the GPU on ARM based systems --- src/debug/HyprCtl.cpp | 2 ++ src/helpers/MiscFunctions.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 51071533..dc5fa742 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -883,6 +883,8 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); +#elif defined(__arm__) || defined(__aarch64__) + const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 7382d24c..a520c9d4 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -649,6 +649,8 @@ void logSystemInfo() { #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); +#elif defined(__arm__) || defined(__aarch64__) + const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif From eea0a6a70412574baabea2b83d2c52003c98d46f Mon Sep 17 00:00:00 2001 From: Alessio Molinari Date: Thu, 23 May 2024 21:15:31 +0200 Subject: [PATCH 0126/2393] internal: Replace monitor rule when disabling head. (#6136) Closes #5978 --- src/config/ConfigManager.cpp | 12 ++++++++++++ src/config/ConfigManager.hpp | 1 + src/protocols/OutputManagement.cpp | 9 ++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 77aa2fb3..fd70da77 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1264,6 +1264,18 @@ void CConfigManager::appendMonitorRule(const SMonitorRule& r) { m_dMonitorRules.emplace_back(r); } +bool CConfigManager::replaceMonitorRule(const SMonitorRule& newrule) { + // Looks for an existing monitor rule (compared by name). + // If the rule exists, it is replaced with the input rule. + for (auto& r : m_dMonitorRules) { + if (r.name == newrule.name) { + r = newrule; + return true; + } + } + return false; +} + void CConfigManager::performMonitorReload() { bool overAgain = false; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 7fc132c6..45b100ee 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -128,6 +128,7 @@ class CConfigManager { void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); + bool replaceMonitorRule(const SMonitorRule&); bool m_bWantsMonitorReload = false; bool m_bForceReload = false; bool m_bNoMonitorReload = false; diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index e7779726..68c50193 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -106,6 +106,9 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : } pMonitor = nullptr; + for (auto& m : PROTO::outputManagement->m_vManagers) { + m->sendDone(); + } }); listeners.monitorModeChange = pMonitor->events.modeChanged.registerListener([this](std::any d) { updateMode(); }); @@ -305,6 +308,8 @@ COutputConfiguration::COutputConfiguration(SP resour LOGM(LOG, "disableHead on {}", PMONITOR->szName); PMONITOR->activeMonitorRule.disabled = true; + if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule)) + g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule); g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false); }); @@ -356,6 +361,7 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { SMonitorRule newRule = PMONITOR->activeMonitorRule; newRule.name = PMONITOR->szName; + newRule.disabled = false; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; @@ -380,7 +386,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { // reset properties for next set. head->committedProperties = 0; - g_pConfigManager->appendMonitorRule(newRule); + if (!g_pConfigManager->replaceMonitorRule(newRule)) + g_pConfigManager->appendMonitorRule(newRule); g_pConfigManager->m_bWantsMonitorReload = true; } From 4e42107d25dc47ee94da282db233f85f1e4c6bd0 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 23 May 2024 21:19:14 +0200 Subject: [PATCH 0127/2393] pointermgr: ensure compositor exist on destroy (#6216) on exit of hyprland the CMonitor destroy signal comes after the compositor has been destructed, causing a heap use after free. add if check to ensure compositor exist and isnt shutting down when its triggered. --- src/managers/PointerManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ae17c6d6..636eab1d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -131,7 +131,11 @@ CPointerManager::CPointerManager() { PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); PMONITOR->events.destroy.registerStaticListener( - [this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr); + [this](void* owner, std::any data) { + if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) + std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); + }, + nullptr); }); } From 52684b7d90de509c66f4f9a81c54a985123315b6 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 24 May 2024 20:40:15 +0200 Subject: [PATCH 0128/2393] window: fix invalid env buffer size in getEnv --- src/desktop/Window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7987c9d6..7a06aa61 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1296,9 +1296,12 @@ std::unordered_map CWindow::getEnv() { needle += 512; } + if (needle <= 1) + return {}; + std::replace(buffer.begin(), buffer.end() - 1, '\0', '\n'); - CVarList envs(std::string{buffer.data(), needle - 1}, 0, '\n', true); + CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true); for (auto& e : envs) { if (!e.contains('=')) From 0d6eae052352dfa39a2442f252133988ecfb28ba Mon Sep 17 00:00:00 2001 From: thejch <66577496+thejch@users.noreply.github.com> Date: Fri, 24 May 2024 11:50:22 -0700 Subject: [PATCH 0129/2393] pointer: add back nvidia hardware cursor quirks (#6220) --- src/managers/PointerManager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 636eab1d..b199881e 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -119,7 +119,17 @@ static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_ } } - return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888); + // Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797 + // If this fails to find a shared modifier try to use a linear + // modifier. This avoids a scenario where the hardware cannot render to + // linear textures but only linear textures are supported for cursors, + // as is the case with Nvidia and VmWare GPUs + if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) { + // Clear the format as output_pick_format doesn't zero it + memset(format, 0, sizeof(*format)); + return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888); + } + return true; } CPointerManager::CPointerManager() { From 6d67b84469d5c12c5bbc4880f327ca8eb7a2ed2d Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 24 May 2024 20:56:42 +0200 Subject: [PATCH 0130/2393] monitor: avoid UB on undefined auto dir ref #6217 --- src/Compositor.cpp | 1 + src/helpers/Monitor.hpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5c9cfbad..529a3b3d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2666,6 +2666,7 @@ void CCompositor::arrangeMonitors() { maxXOffsetLeft = newPosition.x; break; case eAutoDirs::DIR_AUTO_RIGHT: + case eAutoDirs::DIR_AUTO_NONE: newPosition.x = maxXOffsetRight; maxXOffsetRight += m->vecSize.x; break; diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7aa07a86..e4456084 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -13,7 +13,8 @@ #include "signal/Signal.hpp" // Enum for the different types of auto directions, e.g. auto-left, auto-up. -enum class eAutoDirs { +enum eAutoDirs { + DIR_AUTO_NONE = 0, /* None will be treated as right. */ DIR_AUTO_UP, DIR_AUTO_DOWN, DIR_AUTO_LEFT, @@ -21,7 +22,7 @@ enum class eAutoDirs { }; struct SMonitorRule { - eAutoDirs autoDir; + eAutoDirs autoDir = DIR_AUTO_NONE; std::string name = ""; Vector2D resolution = Vector2D(1280, 720); Vector2D offset = Vector2D(0, 0); From ce17961aad6f9164e5d026d19efd42b07b123bff Mon Sep 17 00:00:00 2001 From: Can <45462997+yungcxn@users.noreply.github.com> Date: Fri, 24 May 2024 20:58:26 +0200 Subject: [PATCH 0131/2393] keybinds: Added new dispatcher (sendshortcut) (#6174) --- hyprctl/hyprctl.bash | 6 +- hyprctl/hyprctl.fish | 6 +- hyprctl/hyprctl.usage | 1 + hyprctl/hyprctl.zsh | 5 +- src/managers/KeybindManager.cpp | 154 +++++++++++++++++++++++++++- src/managers/KeybindManager.hpp | 7 ++ src/managers/input/InputManager.cpp | 4 +- 7 files changed, 174 insertions(+), 9 deletions(-) diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index 279ee518..0b4e6b86 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -23,12 +23,12 @@ _hyprctl () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") declare -A literal_transitions - literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)" + literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)" literal_transitions[3]="([72]=18 [13]=2 [32]=18 [54]=18 [55]=18 [89]=18 [104]=2 [120]=2 [76]=1 [16]=2 [123]=18 [3]=1 [5]=2 [63]=18 [127]=2 [129]=18 [80]=18 [130]=18 [83]=18 [31]=18 [48]=2 [12]=2 [85]=18 [10]=18 [86]=18 [137]=18)" - literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)" + literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)" literal_transitions[8]="([128]=2 [131]=2 [0]=2 [73]=2 [35]=2 [106]=2 [37]=2 [107]=2 [4]=2 [78]=2 [39]=2 [79]=2 [110]=2 [6]=2 [41]=2 [42]=2 [81]=2 [82]=2 [46]=2 [47]=2 [9]=2 [109]=2 [50]=2 [52]=2 [11]=2 [115]=2 [87]=2 [49]=2 [56]=2 [90]=2 [57]=2 [91]=2 [92]=2 [60]=2 [61]=2 [125]=2 [93]=2 [62]=2 [20]=2 [95]=2 [22]=2 [23]=2 [64]=2 [65]=2 [24]=2 [132]=2 [26]=2 [68]=2 [98]=2 [69]=2 [29]=2 [136]=2 [70]=2 [99]=2)" literal_transitions[9]="([114]=15 [111]=16)" literal_transitions[11]="([101]=2)" diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index 5d8d12cb..6d31b25a 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -29,7 +29,7 @@ function _hyprctl set COMP_CWORD (count $COMP_WORDS) end - set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" + set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut" set --local descriptions set descriptions[1] "Focus the next window on a workspace" @@ -130,12 +130,14 @@ function _hyprctl set descriptions[133] "Move the cursor to the corner of the active window" set descriptions[136] "INFO" set descriptions[137] "Resize a selected window" + set descriptions[138] "On shortcut X sends shortcut Y to a specified window" + set --local literal_transitions set literal_transitions[1] "set inputs 104 75 34 2 3 78 106 37 109 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 97 98 28 29 101 103; set tos 2 3 4 3 3 3 5 3 6 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 6 3 3 15 3 6" set literal_transitions[4] "set inputs 73 14 33 55 56 90 105 121 77 17 124 4 6 64 128 130 81 131 84 32 49 13 86 11 87 138; set tos 19 3 19 19 19 19 3 3 2 3 19 2 3 19 3 19 19 19 19 19 3 3 19 19 19 19" set literal_transitions[8] "set inputs 104 75 34 2 3 78 106 37 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 98 28 29 101; set tos 2 3 4 3 3 3 5 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" - set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100 138; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" set literal_transitions[10] "set inputs 115 112; set tos 16 17" set literal_transitions[12] "set inputs 102; set tos 3" set literal_transitions[14] "set inputs 22 117 31 136 119 44 72; set tos 2 2 2 2 2 2 2" diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index a98541dd..8e75917e 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -94,6 +94,7 @@ hyprctl []... ::= (exec) "Execute a shell command" | (execr) "Execute a raw shell command" | (pass) "Pass the key to a specified window" + | (sendshortcut) "On shortcut X sends shortcut Y to a specified window" | (killactive) "Close the active window" | (closewindow) "Close a specified window" | (workspace) "Change the workspace" diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index 5e2a475b..82276778 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -17,7 +17,7 @@ _hyprctl_cmd_3 () { } _hyprctl () { - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") local -A descriptions descriptions[1]="Focus the next window on a workspace" @@ -118,12 +118,13 @@ _hyprctl () { descriptions[133]="Move the cursor to the corner of the active window" descriptions[136]="INFO" descriptions[137]="Resize a selected window" + descriptions[138]="On shortcut X sends shortcut Y to a specified window" local -A literal_transitions literal_transitions[1]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [109]=6 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [97]=6 [98]=3 [28]=3 [29]=15 [101]=3 [103]=6)" literal_transitions[4]="([73]=19 [14]=3 [33]=19 [55]=19 [56]=19 [90]=19 [105]=3 [121]=3 [77]=2 [17]=3 [124]=19 [4]=2 [6]=3 [64]=19 [128]=3 [130]=19 [81]=19 [131]=19 [84]=19 [32]=19 [49]=3 [13]=3 [86]=19 [11]=19 [87]=19 [138]=19)" literal_transitions[8]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [98]=3 [28]=3 [29]=15 [101]=3)" - literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3)" + literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3 [138]=3)" literal_transitions[10]="([115]=16 [112]=17)" literal_transitions[12]="([102]=3)" literal_transitions[14]="([22]=2 [117]=2 [31]=2 [136]=2 [119]=2 [44]=2 [72]=2)" diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e23cb500..41b82d10 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -89,6 +89,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["submap"] = setSubmap; m_mDispatchers["pass"] = pass; + m_mDispatchers["sendshortcut"] = sendshortcut; m_mDispatchers["layoutmsg"] = layoutmsg; m_mDispatchers["toggleopaque"] = toggleOpaque; m_mDispatchers["dpms"] = dpms; @@ -589,7 +590,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi } for (auto& k : m_lKeybinds) { - const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "mouse"; + const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; const bool SPECIALTRIGGERED = std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == &k; }) != m_vPressedSpecialBinds.end(); const bool IGNORECONDITIONS = @@ -2022,6 +2023,157 @@ void CKeybindManager::pass(std::string regexp) { g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL); } +void CKeybindManager::sendshortcut(std::string args) { + // args=[,WINDOW_RULES] + const auto ARGS = CVarList(args, 3); + if (ARGS.size() != 3) { + Debug::log(ERR, "sendshortcut: invalid args"); + return; + } + + const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); + const auto KEY = ARGS[1]; + uint32_t keycode = 0; + bool isMouse = 0; + + // similar to parseKey in ConfigManager + if (isNumber(KEY) && std::stoi(KEY) > 9) + keycode = std::stoi(KEY); + else if (KEY.compare(0, 5, "code:") == 0 && isNumber(KEY.substr(5))) + keycode = std::stoi(KEY.substr(5)); + else if (KEY.compare(0, 6, "mouse:") == 0 && isNumber(KEY.substr(6))) { + keycode = std::stoi(KEY.substr(6)); + isMouse = 1; + if (keycode < 272) { + Debug::log(ERR, "sendshortcut: invalid mouse button"); + return; + } + } else { + + // here, we need to find the keycode from the key name + // this is not possible through xkb's lib, so we need to iterate through all keycodes + // once found, we save it to the cache + + const auto KEYSYM = xkb_keysym_from_name(KEY.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + keycode = 0; + + const auto KB = g_pSeatManager->keyboard; + + if (!KB) { + Debug::log(ERR, "sendshortcut: no kb"); + return; + } + + const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); + + if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) { + xkb_keymap* km = KB->wlr()->keymap; + xkb_state* ks = KB->xkbTranslationState; + + xkb_keycode_t keycode_min, keycode_max; + keycode_min = xkb_keymap_min_keycode(km); + keycode_max = xkb_keymap_max_keycode(km); + + for (xkb_keycode_t kc = keycode_min; kc <= keycode_max; ++kc) { + xkb_keysym_t sym = xkb_state_key_get_one_sym(ks, kc); + + if (sym == KEYSYM) { + keycode = kc; + g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING] = keycode; + } + } + + if (!keycode) { + Debug::log(ERR, "sendshortcut: key not found"); + return; + } + + } else + keycode = g_pKeybindManager->m_mKeyToCodeCache[KEYPAIRSTRING]; + } + + if (!keycode) { + Debug::log(ERR, "sendshortcut: invalid key"); + return; + } + + const std::string regexp = ARGS[2]; + PHLWINDOW PWINDOW = nullptr; + const auto LASTSURFACE = g_pCompositor->m_pLastFocus; + + //if regexp is not empty, send shortcut to current window + //else, dont change focus + if (regexp != "") { + PWINDOW = g_pCompositor->getWindowByRegex(regexp); + + if (!PWINDOW) { + Debug::log(ERR, "sendshortcut: window not found"); + return; + } + + if (!g_pSeatManager->keyboard) { + Debug::log(ERR, "No kb in sendshortcut?"); + return; + } + + if (!isMouse) + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + else + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + } + + //copied the rest from pass and modified it + // if wl -> xwl, activate destination + if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11) + g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface.wlr(), true); + // if xwl -> xwl, send to current. Timing issues make this not work. + if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) + PWINDOW = nullptr; + + g_pSeatManager->sendKeyboardMods(MOD, 0, 0, 0); + + if (g_pKeybindManager->m_iPassPressed == 1) { + if (!isMouse) + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); + else + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED); + } else if (g_pKeybindManager->m_iPassPressed == 0) { + if (!isMouse) + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); + else + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED); + } else { + // dynamic call of the dispatcher + if (!isMouse) { + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_PRESSED); + g_pSeatManager->sendKeyboardKey(g_pKeybindManager->m_uTimeLastMs, keycode - 8, WL_KEYBOARD_KEY_STATE_RELEASED); + } else { + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_PRESSED); + g_pSeatManager->sendPointerButton(g_pKeybindManager->m_uTimeLastMs, keycode, WL_POINTER_BUTTON_STATE_RELEASED); + } + } + + if (!PWINDOW) + return; + + if (PWINDOW->m_bIsX11) { //xwayland hack, see pass + if (!isMouse) { + g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocusResource.reset(); + } else { + g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocusResource.reset(); + } + } + + const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + + if (!isMouse) + g_pSeatManager->setKeyboardFocus(LASTSURFACE); + else + g_pSeatManager->setPointerFocus(LASTSURFACE, SL); +} + void CKeybindManager::layoutmsg(std::string msg) { SLayoutMessageHeader hd = {g_pCompositor->m_pLastWindow.lock()}; g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index a2025bb0..a5499987 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -95,6 +95,12 @@ class CKeybindManager { std::list m_lKeybinds; + //since we cant find keycode through keyname in xkb: + //on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42) + //and cache it in this map to make sendshortcut calls faster + //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) + std::unordered_map m_mKeyToCodeCache; + private: std::deque m_dPressedKeys; @@ -177,6 +183,7 @@ class CKeybindManager { static void focusWindow(std::string); static void setSubmap(std::string); static void pass(std::string); + static void sendshortcut(std::string); static void layoutmsg(std::string); static void toggleOpaque(std::string); static void dpms(std::string); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f4f97236..52927d95 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -842,8 +842,10 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); const auto LAYOUT = PKEEB->getActiveLayout(); - if (PKEEB == g_pSeatManager->keyboard) + if (PKEEB == g_pSeatManager->keyboard) { g_pSeatManager->updateActiveKeyboardData(); + g_pKeybindManager->m_mKeyToCodeCache.clear(); + } g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", PKEEB->hlName + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector{PKEEB, LAYOUT})); From 2ff95bba3fec58b9f1a127fe72dda84b1420a7af Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 24 May 2024 23:51:08 +0300 Subject: [PATCH 0132/2393] flake.lock: update --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index f285fe8f..8fc80b1d 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1716327911, - "narHash": "sha256-PI+wygItS/TKzi4gEAROvKTUzTx9GT+PGBttS/IOA/Q=", + "lastModified": 1716576411, + "narHash": "sha256-FIN1wMoyePBTtibCbaeJaoKNLuAYIGwLCWAYC1DJanw=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "27ca640abeef2d425b5dbecf804f5eb622cef56d", + "rev": "57298fc4f13c807e50ada2c986a3114b7fc2e621", "type": "github" }, "original": { @@ -61,11 +61,11 @@ ] }, "locked": { - "lastModified": 1715791527, - "narHash": "sha256-HhQ4zvGHrRjR63ltySSeg+x+0jb0lepiutWdnFhLRoo=", + "lastModified": 1716473782, + "narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "969cb076e5b76f2e823aeca1937a3e1f159812ee", + "rev": "87d5d984109c839482b88b4795db073eb9ed446f", "type": "github" }, "original": { From 90f262aada21af9be1c5ccf89b8dc5e0d28478f1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 25 May 2024 20:43:29 +0200 Subject: [PATCH 0133/2393] pointer: remove dividing hotspot by scale fixes #6117 --- src/managers/PointerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index b199881e..7df2d6f4 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -574,7 +574,7 @@ CBox CPointerManager::getCursorBoxLogicalForMonitor(SP pMonitor) { } CBox CPointerManager::getCursorBoxGlobal() { - return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot / currentCursorImage.scale); + return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot); } Vector2D CPointerManager::closestValid(const Vector2D& pos) { From 71c2ff3105942fb5d698225012d2082219e868de Mon Sep 17 00:00:00 2001 From: zjeffer <4633209+zjeffer@users.noreply.github.com> Date: Tue, 21 May 2024 23:25:45 +0200 Subject: [PATCH 0134/2393] Reapply "CMake: use add_custom_command for generating protocols (#6104)" This reverts commit e419ef1873de01b0762f7f1a411994170a4d8cab. --- CMakeLists.txt | 118 ++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 55 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40e0f32a..858502cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,9 +113,11 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprwayland-scanner>=0.3.8 hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprlang>=0.3.2 hyprcursor>=0.1.7 ) +find_package(hyprwayland-scanner 0.3.8 REQUIRED) + file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") @@ -219,42 +221,48 @@ target_link_libraries(Hyprland rt PkgConfig::deps) function(protocol protoPath protoName external) if (external) - execute_process( - COMMAND ${WaylandScanner} server-header ${protoPath} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${protoPath} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) else() - execute_process( - COMMAND ${WaylandScanner} server-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - execute_process( - COMMAND ${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}-protocol.c) + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() + + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c + COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) + target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) endfunction() function(protocolNew protoPath protoName external) if (external) - execute_process( - COMMAND hyprwayland-scanner ${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) else() - execute_process( - COMMAND hyprwayland-scanner ${WAYLAND_PROTOCOLS_DIR}/${protoPath} ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) + target_sources(Hyprland PRIVATE protocols/${protoName}.hpp) endfunction() function(protocolWayland) - execute_process( + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) target_sources(Hyprland PRIVATE protocols/wayland.cpp) + target_sources(Hyprland PRIVATE protocols/wayland.hpp) endfunction() target_link_libraries(Hyprland @@ -272,37 +280,37 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.x protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) 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("protocols/wlr-output-power-management-unstable-v1.xml" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols/virtual-keyboard-unstable-v1.xml" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols/wlr-virtual-pointer-unstable-v1.xml" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols/input-method-unstable-v2.xml" "input-method-unstable-v2" true) -protocolNew("protocols/wlr-output-management-unstable-v1.xml" "wlr-output-management-unstable-v1" true) -protocolNew("protocols/kde-server-decoration.xml" "kde-server-decoration" true) -protocolNew("protocols/wlr-data-control-unstable-v1.xml" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols/hyprland-focus-grab-v1.xml" "hyprland-focus-grab-v1" true) -protocolNew("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-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) -protocolNew("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer/relative-pointer-unstable-v1.xml" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier/alpha-modifier-v1.xml" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) -protocolNew("stable/tablet/tablet-v2.xml" "tablet-v2" false) -protocolNew("stable/presentation-time/presentation-time.xml" "presentation-time" false) -protocolNew("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) -protocolNew("unstable/primary-selection/primary-selection-unstable-v1.xml" "primary-selection-unstable-v1" false) +protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) +protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) +protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) +protocolNew("protocols" "virtual-keyboard-unstable-v1" true) +protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) +protocolNew("protocols" "input-method-unstable-v2" true) +protocolNew("protocols" "wlr-output-management-unstable-v1" true) +protocolNew("protocols" "kde-server-decoration" true) +protocolNew("protocols" "wlr-data-control-unstable-v1" true) +protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) +protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolNew("staging/tearing-control" "tearing-control-v1" false) +protocolNew("staging/fractional-scale" "fractional-scale-v1" false) +protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) +protocolNew("staging/cursor-shape" "cursor-shape-v1" false) +protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) +protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) +protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) +protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) +protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) +protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) +protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolNew("unstable/text-input" "text-input-unstable-v3" false) +protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) +protocolNew("staging/xdg-activation" "xdg-activation-v1" false) +protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) +protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) +protocolNew("stable/tablet" "tablet-v2" false) +protocolNew("stable/presentation-time" "presentation-time" false) +protocolNew("stable/xdg-shell" "xdg-shell" false) +protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolWayland() From a71207434c0bc2c8e05e94b1619e68059a002879 Mon Sep 17 00:00:00 2001 From: zjeffer <4633209+zjeffer@users.noreply.github.com> Date: Wed, 22 May 2024 00:02:01 +0200 Subject: [PATCH 0135/2393] Add custom cmake target for installheaders This will ensure the correct headers are generated before trying to install them. --- CMakeLists.txt | 16 ++++++++++------ Makefile | 2 ++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 858502cc..adc9a5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,9 @@ message(STATUS "Setting link libraries") target_link_libraries(Hyprland rt PkgConfig::deps) +# used by `make installheaders`, to ensure the headers are generated +add_custom_target(generate-protocol-headers) + function(protocol protoPath protoName external) if (external) set(path ${CMAKE_SOURCE_DIR}/${protoPath}) @@ -236,9 +239,10 @@ function(protocol protoPath protoName external) COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) + target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) + target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) endfunction() + function(protocolNew protoPath protoName external) if (external) set(path ${CMAKE_SOURCE_DIR}/${protoPath}) @@ -251,8 +255,8 @@ function(protocolNew protoPath protoName external) COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp) - target_sources(Hyprland PRIVATE protocols/${protoName}.hpp) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp) + target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) endfunction() function(protocolWayland) add_custom_command( @@ -261,8 +265,8 @@ function(protocolWayland) COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) - target_sources(Hyprland PRIVATE protocols/wayland.cpp) - target_sources(Hyprland PRIVATE protocols/wayland.hpp) + target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) + target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) endfunction() target_link_libraries(Hyprland diff --git a/Makefile b/Makefile index e7b9c1b6..a33f4cb7 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,8 @@ installheaders: mkdir -p ${PREFIX}/include/hyprland/wlr mkdir -p ${PREFIX}/share/pkgconfig + cmake --build ./build --config Release --target generate-protocol-headers + find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. From addd3e7f1aeb670dd91d26005aaeccce3efb1ae7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 25 May 2024 22:43:51 +0200 Subject: [PATCH 0136/2393] xwayland: move to hyprland impl (#6086) --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 28 +- src/Compositor.hpp | 18 - src/desktop/Window.cpp | 164 +++- src/desktop/Window.hpp | 40 +- src/events/Events.hpp | 3 - src/events/Misc.cpp | 44 - src/events/Windows.cpp | 270 +----- src/helpers/XWaylandStubs.hpp | 172 ---- src/includes.hpp | 5 - src/layout/IHyprLayout.cpp | 9 +- src/managers/CursorManager.cpp | 11 +- src/managers/CursorManager.hpp | 3 +- src/managers/ProtocolManager.cpp | 2 + src/managers/SeatManager.cpp | 4 + src/managers/SeatManager.hpp | 2 + src/managers/XWaylandManager.cpp | 134 +-- src/managers/XWaylandManager.hpp | 29 +- src/managers/input/InputManager.cpp | 18 +- src/protocols/XDGOutput.cpp | 3 +- src/protocols/XWaylandShell.cpp | 84 ++ src/protocols/XWaylandShell.hpp | 66 ++ src/protocols/types/DataDevice.cpp | 4 + src/protocols/types/DataDevice.hpp | 6 + src/render/Renderer.cpp | 10 +- src/xwayland/Server.cpp | 427 ++++++++++ src/xwayland/Server.hpp | 48 ++ src/xwayland/XDataSource.cpp | 97 +++ src/xwayland/XDataSource.hpp | 22 + src/xwayland/XSurface.cpp | 291 +++++++ src/xwayland/XSurface.hpp | 120 +++ src/xwayland/XWM.cpp | 1210 +++++++++++++++++++++++++++ src/xwayland/XWM.hpp | 160 ++++ src/xwayland/XWayland.cpp | 28 + src/xwayland/XWayland.hpp | 129 +++ 36 files changed, 2956 insertions(+), 707 deletions(-) delete mode 100644 src/helpers/XWaylandStubs.hpp create mode 100644 src/protocols/XWaylandShell.cpp create mode 100644 src/protocols/XWaylandShell.hpp create mode 100644 src/xwayland/Server.cpp create mode 100644 src/xwayland/Server.hpp create mode 100644 src/xwayland/XDataSource.cpp create mode 100644 src/xwayland/XDataSource.hpp create mode 100644 src/xwayland/XSurface.cpp create mode 100644 src/xwayland/XSurface.hpp create mode 100644 src/xwayland/XWM.cpp create mode 100644 src/xwayland/XWM.hpp create mode 100644 src/xwayland/XWayland.cpp create mode 100644 src/xwayland/XWayland.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index adc9a5a2..3e780ac0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,6 +315,7 @@ protocolNew("stable/tablet" "tablet-v2" false) protocolNew("stable/presentation-time" "presentation-time" false) protocolNew("stable/xdg-shell" "xdg-shell" false) protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) +protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) protocolWayland() diff --git a/protocols/meson.build b/protocols/meson.build index 2c331e4b..f491bb09 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -63,6 +63,7 @@ new_protocols = [ [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], + [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 529a3b3d..a14e91fd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -20,6 +20,7 @@ #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" #include "desktop/LayerSurface.hpp" +#include "xwayland/XWayland.hpp" #include #include @@ -332,12 +333,9 @@ void CCompositor::cleanup() { m->state.commit(); } - m_vMonitors.clear(); + g_pXWayland.reset(); - if (g_pXWaylandManager->m_sWLRXWayland) { - wlr_xwayland_destroy(g_pXWaylandManager->m_sWLRXWayland); - g_pXWaylandManager->m_sWLRXWayland = nullptr; - } + m_vMonitors.clear(); wl_display_destroy_clients(g_pCompositor->m_sWLDisplay); removeAllSignals(); @@ -462,6 +460,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the CursorManager!"); g_pCursorManager = std::make_unique(); + + Debug::log(LOG, "Starting XWayland"); + g_pXWayland = std::make_unique(); } break; default: UNREACHABLE(); } @@ -669,7 +670,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; + CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) return w; @@ -698,7 +699,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA}; + CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent @@ -707,7 +708,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (box.containsPoint(g_pPointerManager->position())) { - if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) { + if (w->m_bIsX11 && w->m_iX11Type == 2 && !w->m_pXWaylandSurface->wantsFocus()) { // Override Redirect return g_pCompositor->m_pLastWindow.lock(); // we kinda trick everything here. // TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases. @@ -892,7 +893,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { return; } - if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(pWindow->m_uSurface.xwayland)) + if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !pWindow->m_pXWaylandSurface->wantsFocus()) return; g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow); @@ -1273,10 +1274,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { if (top) pWindow->m_bCreatedOverFullscreen = true; - if (!pWindow->m_bIsX11) { + if (!pWindow->m_bIsX11) moveToZ(pWindow, top); - return; - } else { + else { // move X11 window stack std::deque toMove; @@ -1288,7 +1288,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { toMove.emplace_front(pw); for (auto& w : m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw) { + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) { x11Stack(w, top, x11Stack); } } @@ -2226,7 +2226,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { if (!w->m_bIsX11) continue; - if (w->m_uSurface.xwayland == pWindow->m_uSurface.xwayland->parent) + if (w->m_pXWaylandSurface == pWindow->m_pXWaylandSurface->parent) return w; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 574889bc..94d9e4d0 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -189,21 +189,3 @@ class CCompositor { }; inline std::unique_ptr g_pCompositor; - -// For XWayland -inline std::map HYPRATOMS = {HYPRATOM("_NET_WM_WINDOW_TYPE"), - HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"), - HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"), - HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"), - HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"), - HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"), - HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"), - HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"), - HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"), - HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"), - HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"), - HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"), - HYPRATOM("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"), - HYPRATOM("_NET_SUPPORTING_WM_CHECK"), - HYPRATOM("_NET_WM_NAME"), - HYPRATOM("UTF8_STRING")}; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7a06aa61..093cab5e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -7,11 +7,14 @@ #include #include "../managers/TokenManager.hpp" #include "../protocols/XDGShell.hpp" +#include "../xwayland/XWayland.hpp" -PHLWINDOW CWindow::create() { - PHLWINDOW pWindow = SP(new CWindow); +PHLWINDOW CWindow::create(SP surface) { + PHLWINDOW pWindow = SP(new CWindow(surface)); - pWindow->m_pSelf = pWindow; + pWindow->m_pSelf = pWindow; + pWindow->m_bIsX11 = true; + pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1; pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); @@ -61,8 +64,19 @@ CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { listeners.updateMetadata = m_pXDGSurface->toplevel->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); } -CWindow::CWindow() { - ; +CWindow::CWindow(SP surface) : m_pXWaylandSurface(surface) { + listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); + listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); + listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); + listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); + listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast(d)); }); + listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); + listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); + listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); + listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); }); + + if (m_pXWaylandSurface->overrideRedirect) + listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); }); } CWindow::~CWindow() { @@ -300,10 +314,10 @@ pid_t CWindow::getPID() { wl_client_get_credentials(m_pXDGSurface->owner->client(), &PID, nullptr, nullptr); } else { - if (!m_uSurface.xwayland) + if (!m_pXWaylandSurface) return -1; - PID = m_uSurface.xwayland->pid; + PID = m_pXWaylandSurface->pid; } return PID; @@ -426,22 +440,23 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } PHLWINDOW CWindow::X11TransientFor() { - if (!m_bIsX11) + if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) return nullptr; - if (!m_uSurface.xwayland->parent) - return nullptr; - - auto PPARENT = g_pCompositor->getWindowFromSurface(m_uSurface.xwayland->parent->surface); - - while (validMapped(PPARENT) && PPARENT->m_uSurface.xwayland->parent) { - PPARENT = g_pCompositor->getWindowFromSurface(PPARENT->m_uSurface.xwayland->parent->surface); + auto s = m_pXWaylandSurface->parent; + while (s) { + if (!s->parent) + break; + s = s->parent; } - if (!validMapped(PPARENT)) - return nullptr; + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_pXWaylandSurface != s) + continue; + return w; + } - return PPARENT; + return nullptr; } void CWindow::removeDecorationByType(eDecorationType type) { @@ -494,8 +509,6 @@ void CWindow::onUnmap() { std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); - hyprListener_unmapWindow.removeCallback(); - if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) @@ -548,9 +561,6 @@ void CWindow::onMap() { g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); - if (m_bIsX11) - hyprListener_unmapWindow.initCallback(&m_uSurface.xwayland->surface->events.unmap, &Events::listener_unmapWindow, this, "CWindow"); - m_vReportedSize = m_vPendingReportedSize; m_bAnimatingIn = true; @@ -1119,9 +1129,9 @@ bool CWindow::opaque() { return false; if (m_bIsX11) - return !m_uSurface.xwayland->has_alpha; + return false; - if (m_pXDGSurface->surface->opaque) + if (m_pXDGSurface && m_pXDGSurface->surface->opaque) return true; const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region); @@ -1337,23 +1347,23 @@ void CWindow::activate(bool force) { } void CWindow::onUpdateState() { - if (!m_pXDGSurface) - return; + std::optional requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen; + std::optional requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize; - if (m_pXDGSurface->toplevel->state.requestsFullscreen && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { - bool fs = m_pXDGSurface->toplevel->state.requestsFullscreen.value(); + if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { + bool fs = requestsFS.value(); - if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) + if (fs != m_bIsFullscreen && m_bIsMapped) g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL); - if (!m_pXDGSurface->mapped) + if (!m_bIsMapped) m_bWantsInitialFullscreen = fs; } - if (m_pXDGSurface->toplevel->state.requestsMaximize && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { - bool fs = m_pXDGSurface->toplevel->state.requestsMaximize.value(); + if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { + bool fs = requestsMX.value(); - if (fs != m_bIsFullscreen && m_pXDGSurface->mapped) + if (fs != m_bIsFullscreen && m_bIsMapped) g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED); } } @@ -1402,8 +1412,8 @@ std::string CWindow::fetchTitle() { if (m_pXDGSurface && m_pXDGSurface->toplevel) return m_pXDGSurface->toplevel->state.title; } else { - if (m_uSurface.xwayland && m_uSurface.xwayland->title) - return m_uSurface.xwayland->title; + if (m_pXWaylandSurface) + return m_pXWaylandSurface->state.title; } return ""; @@ -1414,8 +1424,8 @@ std::string CWindow::fetchClass() { if (m_pXDGSurface && m_pXDGSurface->toplevel) return m_pXDGSurface->toplevel->state.appid; } else { - if (m_uSurface.xwayland && m_uSurface.xwayland->_class) - return m_uSurface.xwayland->_class; + if (m_pXWaylandSurface) + return m_pXWaylandSurface->state.appid; } return ""; @@ -1429,4 +1439,80 @@ void CWindow::onAck(uint32_t serial) { m_pPendingSizeAck = *SERIAL; std::erase_if(m_vPendingSizeAcks, [&](const auto& el) { return el.first <= SERIAL->first; }); -} \ No newline at end of file +} + +void CWindow::onResourceChangeX11() { + if (m_pXWaylandSurface->surface && !m_pWLSurface.wlr()) + m_pWLSurface.assign(m_pXWaylandSurface->surface, m_pSelf.lock()); + else if (!m_pXWaylandSurface->surface && m_pWLSurface.wlr()) + m_pWLSurface.unassign(); + + // update metadata as well, + // could be first assoc and we need to catch the class + onUpdateMeta(); + + Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface.wlr()); +} + +void CWindow::onX11Configure(CBox box) { + + if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) { + m_pXWaylandSurface->configure(box); + m_vPendingReportedSize = box.size(); + m_vReportedSize = box.size(); + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + m_fX11SurfaceScaledBy = PMONITOR->scale; + return; + } + + g_pHyprRenderer->damageWindow(m_pSelf.lock()); + + if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) { + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); + g_pInputManager->refocus(); + g_pHyprRenderer->damageWindow(m_pSelf.lock()); + return; + } + + if (box.size() > Vector2D{1, 1}) + setHidden(false); + else + setHidden(true); + + const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos()); + + m_vRealPosition.setValueAndWarp(LOGICALPOS); + m_vRealSize.setValueAndWarp(box.size()); + + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + if (*PXWLFORCESCALEZERO) { + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) { + m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); + m_fX11SurfaceScaledBy = PMONITOR->scale; + } + } + + m_vPosition = m_vRealPosition.value(); + m_vSize = m_vRealSize.value(); + + m_pXWaylandSurface->configure(box); + + m_vPendingReportedSize = box.size(); + m_vReportedSize = box.size(); + + updateWindowDecos(); + + if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace)) + return; // further things are only for visible windows + + m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; + + g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); + + m_bCreatedOverFullscreen = true; + + if (!m_sAdditionalConfigData.windowDanceCompat) + g_pInputManager->refocus(); + + g_pHyprRenderer->damageWindow(m_pSelf.lock()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 24d9562b..473ce361 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -15,6 +15,7 @@ #include "../helpers/signal/Signal.hpp" class CXDGSurfaceResource; +class CXWaylandSurface; enum eIdleInhibitMode { IDLEINHIBIT_NONE = 0, @@ -199,48 +200,23 @@ struct SInitialWorkspaceToken { class CWindow { public: static PHLWINDOW create(SP); - // xwl - static PHLWINDOW create(); + static PHLWINDOW create(SP); private: CWindow(SP resource); - CWindow(); + CWindow(SP surface); public: ~CWindow(); - DYNLISTENER(commitWindow); - DYNLISTENER(mapWindow); - DYNLISTENER(unmapWindow); - DYNLISTENER(destroyWindow); - DYNLISTENER(setTitleWindow); - DYNLISTENER(setGeometryX11U); - DYNLISTENER(fullscreenWindow); - DYNLISTENER(requestMove); - DYNLISTENER(requestMinimize); - DYNLISTENER(requestMaximize); - DYNLISTENER(requestResize); - DYNLISTENER(activateX11); - DYNLISTENER(configureX11); - DYNLISTENER(toplevelClose); - DYNLISTENER(toplevelActivate); - DYNLISTENER(toplevelFullscreen); - DYNLISTENER(setOverrideRedirect); - DYNLISTENER(associateX11); - DYNLISTENER(dissociateX11); - DYNLISTENER(ackConfigure); - // DYNLISTENER(newSubsurfaceWindow); - CWLSurface m_pWLSurface; struct { CSignal destroy; } events; - union { - wlr_xwayland_surface* xwayland; - } m_uSurface; WP m_pXDGSurface; + WP m_pXWaylandSurface; // this is the position and size of the "bounding box" Vector2D m_vPosition = Vector2D(0, 0); @@ -391,7 +367,7 @@ class CWindow { // For the list lookup bool operator==(const CWindow& rhs) { - return m_pXDGSurface == rhs.m_pXDGSurface && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && + return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; } @@ -459,6 +435,8 @@ class CWindow { void onWorkspaceAnimUpdate(); void onUpdateState(); void onUpdateMeta(); + void onX11Configure(CBox box); + void onResourceChangeX11(); std::string fetchTitle(); std::string fetchClass(); @@ -478,8 +456,12 @@ class CWindow { CHyprSignalListener unmap; CHyprSignalListener commit; CHyprSignalListener destroy; + CHyprSignalListener activate; + CHyprSignalListener configure; + CHyprSignalListener setGeometry; CHyprSignalListener updateState; CHyprSignalListener updateMetadata; + CHyprSignalListener resourceChange; } listeners; private: diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 0b757842..f8eb9d2f 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -33,8 +33,6 @@ namespace Events { DYNLISTENFUNC(requestMinimize); DYNLISTENFUNC(requestMaximize); DYNLISTENFUNC(setOverrideRedirect); - DYNLISTENFUNC(associateX11); - DYNLISTENFUNC(dissociateX11); DYNLISTENFUNC(ackConfigure); LISTENER(newInput); @@ -56,7 +54,6 @@ namespace Events { DYNLISTENFUNC(monitorBind); // XWayland - LISTENER(readyXWayland); LISTENER(surfaceXWayland); // Renderer destroy diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index 7152730e..6580d93e 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -25,50 +25,6 @@ void Events::listener_leaseRequest(wl_listener* listener, void* data) { } } -void Events::listener_readyXWayland(wl_listener* listener, void* data) { -#ifndef NO_XWAYLAND - const auto XCBCONNECTION = xcb_connect(g_pXWaylandManager->m_sWLRXWayland->display_name, NULL); - const auto ERR = xcb_connection_has_error(XCBCONNECTION); - if (ERR) { - Debug::log(LogLevel::ERR, "XWayland -> xcb_connection_has_error failed with {}", ERR); - return; - } - - for (auto& ATOM : HYPRATOMS) { - xcb_intern_atom_cookie_t cookie = xcb_intern_atom(XCBCONNECTION, 0, ATOM.first.length(), ATOM.first.c_str()); - xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(XCBCONNECTION, cookie, NULL); - - if (!reply) { - Debug::log(LogLevel::ERR, "XWayland -> Atom failed: {}", ATOM.first); - continue; - } - - ATOM.second = reply->atom; - - free(reply); - } - - //wlr_xwayland_set_seat(g_pXWaylandManager->m_sWLRXWayland, g_pCompositor->m_sSeat.seat); - - g_pCursorManager->setXWaylandCursor(g_pXWaylandManager->m_sWLRXWayland); - - const auto ROOT = xcb_setup_roots_iterator(xcb_get_setup(XCBCONNECTION)).data->root; - auto cookie = xcb_get_property(XCBCONNECTION, 0, ROOT, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_ANY, 0, 2048); - auto reply = xcb_get_property_reply(XCBCONNECTION, cookie, nullptr); - - const auto XWMWINDOW = *(xcb_window_t*)xcb_get_property_value(reply); - const char* name = "Hyprland"; - - xcb_change_property(wlr_xwayland_get_xwm_connection(g_pXWaylandManager->m_sWLRXWayland), XCB_PROP_MODE_REPLACE, XWMWINDOW, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"], - 8, // format - strlen(name), name); - - free(reply); - - xcb_disconnect(XCBCONNECTION); -#endif -} - void Events::listener_RendererDestroy(wl_listener* listener, void* data) { Debug::log(LOG, "!!Renderer destroyed!!"); } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 384ea9ed..9044bc61 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -9,6 +9,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" +#include "../xwayland/XSurface.hpp" // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -20,19 +21,6 @@ // // // ------------------------------------------------------------ // -void addViewCoords(void* pWindow, int* x, int* y) { - const auto PWINDOW = (CWindow*)pWindow; - *x += PWINDOW->m_vRealPosition.goal().x; - *y += PWINDOW->m_vRealPosition.goal().y; - - if (!PWINDOW->m_bIsX11 && PWINDOW->m_bIsMapped) { - Vector2D pos = PWINDOW->m_pXDGSurface->current.geometry.pos(); - - *x -= pos.x; - *y -= pos.y; - } -} - void setAnimToMove(void* data) { auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); @@ -68,7 +56,6 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bReadyToDelete = false; PWINDOW->m_bFadingOut = false; PWINDOW->m_szTitle = PWINDOW->fetchTitle(); - PWINDOW->m_iX11Type = PWINDOW->m_bIsX11 ? (PWINDOW->m_uSurface.xwayland->override_redirect ? 2 : 1) : 1; PWINDOW->m_bFirstMap = true; PWINDOW->m_szInitialTitle = PWINDOW->m_szTitle; PWINDOW->m_szInitialClass = PWINDOW->fetchClass(); @@ -129,8 +116,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bRequestsFloat = true; } - PWINDOW->m_bX11ShouldntFocus = - PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland)); + PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !PWINDOW->m_pXWaylandSurface->wantsFocus()); if (PWORKSPACE->m_bDefaultFloating) PWINDOW->m_bIsFloating = true; @@ -144,7 +130,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // window rules PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); - bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->fullscreen); + bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen); bool requestsFakeFullscreen = false; bool requestsMaximize = false; bool overridingNoFullscreen = false; @@ -492,9 +478,8 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus && - (PWINDOW->m_iX11Type != 2 || - (PWINDOW->m_bIsX11 && PWINDOW->m_uSurface.xwayland->window_type_len > 0 && wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland))) && - !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { + (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && + !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH); @@ -503,22 +488,6 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_fDimPercent.setValueAndWarp(0); } - if (PWINDOW->m_bIsX11) { - PWINDOW->hyprListener_fullscreenWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_fullscreen, &Events::listener_fullscreenWindow, PWINDOW.get(), - "XWayland Window Late"); - PWINDOW->hyprListener_activateX11.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_activate, &Events::listener_activateX11, PWINDOW.get(), - "XWayland Window Late"); - PWINDOW->hyprListener_setTitleWindow.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_title, &Events::listener_setTitleWindow, PWINDOW.get(), "XWayland Window Late"); - PWINDOW->hyprListener_requestMinimize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_minimize, &Events::listener_requestMinimize, PWINDOW.get(), - "Xwayland Window Late"); - PWINDOW->hyprListener_requestMaximize.initCallback(&PWINDOW->m_uSurface.xwayland->events.request_maximize, &Events::listener_requestMaximize, PWINDOW.get(), - "Xwayland Window Late"); - - if (PWINDOW->m_iX11Type == 2) - PWINDOW->hyprListener_setGeometryX11U.initCallback(&PWINDOW->m_uSurface.xwayland->events.set_geometry, &Events::listener_unmanagedSetGeometry, PWINDOW.get(), - "XWayland Window Late"); - } - if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) || (requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) { // fix fullscreen on requested (basically do a switcheroo) @@ -687,16 +656,6 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW); - if (!PWINDOW->m_bIsX11) { - Debug::log(LOG, "Unregistered late callbacks XWL"); - PWINDOW->hyprListener_fullscreenWindow.removeCallback(); - PWINDOW->hyprListener_activateX11.removeCallback(); - PWINDOW->hyprListener_setTitleWindow.removeCallback(); - PWINDOW->hyprListener_setGeometryX11U.removeCallback(); - PWINDOW->hyprListener_requestMaximize.removeCallback(); - PWINDOW->hyprListener_requestMinimize.removeCallback(); - } - if (PWINDOW->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); @@ -859,9 +818,6 @@ void Events::listener_destroyWindow(void* owner, void* data) { Debug::log(LOG, "{:c} destroyed, queueing.", PWINDOW); - if (PWINDOW->m_bIsX11) - Debug::log(LOG, "XWayland class raw: {}", PWINDOW->m_uSurface.xwayland->_class ? PWINDOW->m_uSurface.xwayland->_class : "null"); - if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { g_pCompositor->m_pLastWindow.reset(); g_pCompositor->m_pLastFocus = nullptr; @@ -869,15 +825,6 @@ void Events::listener_destroyWindow(void* owner, void* data) { PWINDOW->m_pWLSurface.unassign(); - PWINDOW->hyprListener_commitWindow.removeCallback(); - PWINDOW->hyprListener_mapWindow.removeCallback(); - PWINDOW->hyprListener_unmapWindow.removeCallback(); - PWINDOW->hyprListener_destroyWindow.removeCallback(); - PWINDOW->hyprListener_configureX11.removeCallback(); - PWINDOW->hyprListener_setOverrideRedirect.removeCallback(); - PWINDOW->hyprListener_associateX11.removeCallback(); - PWINDOW->hyprListener_dissociateX11.removeCallback(); - PWINDOW->listeners = {}; g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); @@ -901,39 +848,6 @@ void Events::listener_setTitleWindow(void* owner, void* data) { PWINDOW->onUpdateMeta(); } -void Events::listener_fullscreenWindow(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - // x11 only - - if (!PWINDOW->m_bIsMapped) { - PWINDOW->m_bWantsInitialFullscreen = true; - return; - } - - if (PWINDOW->isHidden() || (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) - return; - - bool requestedFullState = false; - - if (!PWINDOW->m_uSurface.xwayland->surface->mapped) - return; - - if (!PWINDOW->m_bFakeFullscreenState) - g_pCompositor->setWindowFullscreen(PWINDOW, PWINDOW->m_uSurface.xwayland->fullscreen, FULLSCREEN_FULL); - - requestedFullState = PWINDOW->m_uSurface.xwayland->fullscreen; - - if (!requestedFullState && PWINDOW->m_bFakeFullscreenState) { - g_pXWaylandManager->setWindowFullscreen(PWINDOW, false); // fixes for apps expecting a de-fullscreen (e.g. ff) - g_pXWaylandManager->setWindowFullscreen(PWINDOW, true); - } - - PWINDOW->updateToplevel(); - - Debug::log(LOG, "{} fullscreen to {}", PWINDOW, PWINDOW->m_bIsFullscreen); -} - void Events::listener_activateX11(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); @@ -946,7 +860,7 @@ void Events::listener_activateX11(void* owner, void* data) { if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->getPID() != PWINDOW->getPID()) return; - if (!wlr_xwayland_or_surface_wants_focus(PWINDOW->m_uSurface.xwayland)) + if (!PWINDOW->m_pXWaylandSurface->wantsFocus()) return; g_pCompositor->focusWindow(PWINDOW); @@ -959,82 +873,16 @@ void Events::listener_activateX11(void* owner, void* data) { PWINDOW->activate(); } -void Events::listener_configureX11(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - const auto E = (wlr_xwayland_surface_configure_event*)data; - - if (!PWINDOW->m_uSurface.xwayland->surface || !PWINDOW->m_uSurface.xwayland->surface->mapped || !PWINDOW->m_bIsMapped) { - wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height); - PWINDOW->m_vPendingReportedSize = {E->width, E->height}; - PWINDOW->m_vReportedSize = {E->width, E->height}; - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) - PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; - return; - } - - g_pHyprRenderer->damageWindow(PWINDOW); - - if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow.lock() == PWINDOW) { - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); - g_pInputManager->refocus(); - g_pHyprRenderer->damageWindow(PWINDOW); - return; - } - - if (E->width > 1 && E->height > 1) - PWINDOW->setHidden(false); - else - PWINDOW->setHidden(true); - - const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({E->x, E->y}); - - PWINDOW->m_vRealPosition.setValueAndWarp(LOGICALPOS); - PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(E->width, E->height)); - - static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (*PXWLFORCESCALEZERO) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { - PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); - PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; - } - } - - PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.value(); - PWINDOW->m_vSize = PWINDOW->m_vRealSize.value(); - - wlr_xwayland_surface_configure(PWINDOW->m_uSurface.xwayland, E->x, E->y, E->width, E->height); - - PWINDOW->m_vPendingReportedSize = {E->width, E->height}; - PWINDOW->m_vReportedSize = {E->width, E->height}; - - PWINDOW->updateWindowDecos(); - - if (!g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace)) - return; // further things are only for visible windows - - PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace; - - g_pCompositor->changeWindowZOrder(PWINDOW, true); - - PWINDOW->m_bCreatedOverFullscreen = true; - - if (!PWINDOW->m_sAdditionalConfigData.windowDanceCompat) - g_pInputManager->refocus(); - - g_pHyprRenderer->damageWindow(PWINDOW); -} - void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - if (!PWINDOW->m_bIsMapped) + if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect) return; const auto POS = PWINDOW->m_vRealPosition.goal(); const auto SIZ = PWINDOW->m_vRealSize.goal(); - if (PWINDOW->m_uSurface.xwayland->width > 1 && PWINDOW->m_uSurface.xwayland->height > 1) + if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1}) PWINDOW->setHidden(false); else PWINDOW->setHidden(true); @@ -1047,18 +895,17 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords({PWINDOW->m_uSurface.xwayland->x, PWINDOW->m_uSurface.xwayland->y}); + const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(PWINDOW->m_pXWaylandSurface->geometry.pos()); - if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || - abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) { - Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {} {}", PWINDOW, LOGICALPOS, (int)PWINDOW->m_uSurface.xwayland->width, - (int)PWINDOW->m_uSurface.xwayland->height); + if (abs(std::floor(POS.x) - LOGICALPOS.x) > 2 || abs(std::floor(POS.y) - LOGICALPOS.y) > 2 || abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.width) > 2 || + abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.height) > 2) { + Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size()); g_pHyprRenderer->damageWindow(PWINDOW); PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); - if (abs(std::floor(SIZ.x) - PWINDOW->m_uSurface.xwayland->width) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_uSurface.xwayland->height) > 2) - PWINDOW->m_vRealSize.setValueAndWarp(Vector2D(PWINDOW->m_uSurface.xwayland->width, PWINDOW->m_uSurface.xwayland->height)); + if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2) + PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { @@ -1079,92 +926,3 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal(); } } - -void Events::listener_setOverrideRedirect(void* owner, void* data) { - // const auto PWINDOW = (CWindow*)owner; - - //if (!PWINDOW->m_bIsMapped && PWINDOW->m_uSurface.xwayland->mapped) { - // Events::listener_mapWindow(PWINDOW, nullptr); - //} -} - -void Events::listener_associateX11(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - PWINDOW->hyprListener_mapWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.map, &Events::listener_mapWindow, PWINDOW.get(), "XWayland Window"); - PWINDOW->hyprListener_commitWindow.initCallback(&PWINDOW->m_uSurface.xwayland->surface->events.commit, &Events::listener_commitWindow, PWINDOW.get(), "XWayland Window"); - - PWINDOW->m_pWLSurface.assign(PWINDOW->m_uSurface.xwayland->surface, PWINDOW); -} - -void Events::listener_dissociateX11(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - PWINDOW->m_pWLSurface.unassign(); - - PWINDOW->hyprListener_mapWindow.removeCallback(); - PWINDOW->hyprListener_commitWindow.removeCallback(); -} - -void Events::listener_surfaceXWayland(wl_listener* listener, void* data) { - const auto XWSURFACE = (wlr_xwayland_surface*)data; - - Debug::log(LOG, "New XWayland Surface created (class {}).", XWSURFACE->_class ? XWSURFACE->_class : "null"); - if (XWSURFACE->parent) - Debug::log(LOG, "Window parent data: {} at {:x}", XWSURFACE->parent->_class ? XWSURFACE->parent->_class : "null", (uintptr_t)XWSURFACE->parent); - - const auto PNEWWINDOW = g_pCompositor->m_vWindows.emplace_back(CWindow::create()); - - PNEWWINDOW->m_uSurface.xwayland = XWSURFACE; - PNEWWINDOW->m_iX11Type = XWSURFACE->override_redirect ? 2 : 1; - PNEWWINDOW->m_bIsX11 = true; - - PNEWWINDOW->m_pX11Parent = g_pCompositor->getX11Parent(PNEWWINDOW); - - PNEWWINDOW->hyprListener_associateX11.initCallback(&XWSURFACE->events.associate, &Events::listener_associateX11, PNEWWINDOW.get(), "XWayland Window"); - PNEWWINDOW->hyprListener_dissociateX11.initCallback(&XWSURFACE->events.dissociate, &Events::listener_dissociateX11, PNEWWINDOW.get(), "XWayland Window"); - PNEWWINDOW->hyprListener_destroyWindow.initCallback(&XWSURFACE->events.destroy, &Events::listener_destroyWindow, PNEWWINDOW.get(), "XWayland Window"); - PNEWWINDOW->hyprListener_setOverrideRedirect.initCallback(&XWSURFACE->events.set_override_redirect, &Events::listener_setOverrideRedirect, PNEWWINDOW.get(), "XWayland Window"); - PNEWWINDOW->hyprListener_configureX11.initCallback(&XWSURFACE->events.request_configure, &Events::listener_configureX11, PNEWWINDOW.get(), "XWayland Window"); -} - -void Events::listener_requestMaximize(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) - return; - - Debug::log(LOG, "Maximize request for {}", PWINDOW); - if (!PWINDOW->m_bIsX11) { - - g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, - FULLSCREEN_MAXIMIZED); // this will be rejected if there already is a fullscreen window - - } else { - if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1) - return; - - g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, FULLSCREEN_MAXIMIZED); - } -} - -void Events::listener_requestMinimize(void* owner, void* data) { - PHLWINDOW PWINDOW = ((CWindow*)owner)->m_pSelf.lock(); - - Debug::log(LOG, "Minimize request for {}", PWINDOW); - - if (PWINDOW->m_bIsX11) { - if (!PWINDOW->m_bIsMapped || PWINDOW->m_iX11Type != 1) - return; - - const auto E = (wlr_xwayland_minimize_event*)data; - - g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), (int)E->minimize)}); - EMIT_HOOK_EVENT("minimize", (std::vector{PWINDOW, E->minimize})); - - wlr_xwayland_surface_set_minimized(PWINDOW->m_uSurface.xwayland, E->minimize && g_pCompositor->m_pLastWindow.lock() != PWINDOW); // fucking DXVK - } else { - g_pEventManager->postEvent({"minimize", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), 1)}); - EMIT_HOOK_EVENT("minimize", (std::vector{PWINDOW, (int64_t)(1)})); - } -} diff --git a/src/helpers/XWaylandStubs.hpp b/src/helpers/XWaylandStubs.hpp deleted file mode 100644 index c21041cd..00000000 --- a/src/helpers/XWaylandStubs.hpp +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once - -#include - -typedef unsigned int xcb_atom_t; -struct xcb_icccm_wm_hints_t; -typedef struct { - /** User specified flags */ - uint32_t flags; - /** User-specified position */ - int32_t x, y; - /** User-specified size */ - int32_t width, height; - /** Program-specified minimum size */ - int32_t min_width, min_height; - /** Program-specified maximum size */ - int32_t max_width, max_height; - /** Program-specified resize increments */ - int32_t width_inc, height_inc; - /** Program-specified minimum aspect ratios */ - int32_t min_aspect_num, min_aspect_den; - /** Program-specified maximum aspect ratios */ - int32_t max_aspect_num, max_aspect_den; - /** Program-specified base size */ - int32_t base_width, base_height; - /** Program-specified window gravity */ - uint32_t win_gravity; -} xcb_size_hints_t; -typedef unsigned int xcb_window_t; - -typedef enum xcb_stack_mode_t { - XCB_STACK_MODE_ABOVE = 0, - XCB_STACK_MODE_BELOW = 1, - XCB_STACK_MODE_TOP_IF = 2, - XCB_STACK_MODE_BOTTOM_IF = 3, - XCB_STACK_MODE_OPPOSITE = 4 -} xcb_stack_mode_t; - -struct wlr_xwayland { - struct wlr_xwayland_server* server; - struct wlr_xwm* xwm; - struct wlr_xwayland_cursor* cursor; - - const char* display_name; - - struct wl_display* wl_display; - struct wlr_compositor* compositor; - struct wlr_seat* seat; - - void* data; -}; - -struct wlr_xwayland_surface { - xcb_window_t window_id; - struct wlr_xwm* xwm; - uint32_t surface_id; - - struct wl_list link; - struct wl_list stack_link; - struct wl_list unpaired_link; - - struct wlr_surface* surface; - int16_t x, y; - uint16_t width, height; - uint16_t saved_width, saved_height; - bool override_redirect; - bool mapped; - - char* title; - char* _class; - char* instance; - char* role; - char* startup_id; - pid_t pid; - bool has_utf8_title; - - struct wl_list children; // wlr_xwayland_surface::parent_link - struct wlr_xwayland_surface* parent; - struct wl_list parent_link; // wlr_xwayland_surface::children - - xcb_atom_t* window_type; - size_t window_type_len; - - xcb_atom_t* protocols; - size_t protocols_len; - - uint32_t decorations; - xcb_icccm_wm_hints_t* hints; - xcb_size_hints_t* size_hints; - - bool pinging; - struct wl_event_source* ping_timer; - - // _NET_WM_STATE - bool modal; - bool fullscreen; - bool maximized_vert, maximized_horz; - bool minimized; - - bool has_alpha; - - struct { - struct wl_signal destroy; - struct wl_signal request_configure; - struct wl_signal request_move; - struct wl_signal request_resize; - struct wl_signal request_minimize; - struct wl_signal request_maximize; - struct wl_signal request_fullscreen; - struct wl_signal request_activate; - - struct wl_signal map; - struct wl_signal unmap; - struct wl_signal associate; - struct wl_signal dissociate; - struct wl_signal set_title; - struct wl_signal set_class; - struct wl_signal set_role; - struct wl_signal set_parent; - struct wl_signal set_startup_id; - struct wl_signal set_window_type; - struct wl_signal set_hints; - struct wl_signal set_decorations; - struct wl_signal set_override_redirect; - struct wl_signal set_geometry; - struct wl_signal ping_timeout; - } events; -}; - -struct wlr_xwayland_surface_configure_event { - struct wlr_xwayland_surface* surface; - int16_t x, y; - uint16_t width, height; - uint16_t mask; // xcb_config_window_t -}; - -struct wlr_xwayland_minimize_event { - struct wlr_xwayland_surface* surface; - bool minimize; -}; - -inline void wlr_xwayland_destroy(wlr_xwayland*) {} - -inline void wlr_xwayland_surface_configure(wlr_xwayland_surface*, int, int, int, int) {} - -inline bool wlr_surface_is_xwayland_surface(void*) { - return false; -} - -inline void wlr_xwayland_surface_activate(wlr_xwayland_surface*, bool) {} - -inline void wlr_xwayland_surface_restack(wlr_xwayland_surface*, void*, xcb_stack_mode_t) {} - -inline wlr_xwayland_surface* wlr_xwayland_surface_from_wlr_surface(void*) { - return nullptr; -} - -inline void wlr_xwayland_surface_close(wlr_xwayland_surface*) {} - -inline void wlr_xwayland_surface_set_fullscreen(wlr_xwayland_surface*, bool) {} - -inline void wlr_xwayland_surface_set_minimized(wlr_xwayland_surface*, bool) {} - -inline wlr_xwayland_surface* wlr_xwayland_surface_try_from_wlr_surface(wlr_surface*) { - return nullptr; -} - -inline bool wlr_xwayland_or_surface_wants_focus(const wlr_xwayland_surface*) { - return false; -} - -inline void wlr_xwayland_set_cursor(wlr_xwayland* wlr_xwayland, uint8_t* pixels, uint32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, int32_t hotspot_y) {} \ No newline at end of file diff --git a/src/includes.hpp b/src/includes.hpp index dfbe0221..dbae7635 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -82,10 +82,6 @@ extern "C" { #if WLR_HAS_X11_BACKEND #include #endif - -#ifndef NO_XWAYLAND -#include -#endif } #undef delete @@ -110,7 +106,6 @@ extern "C" { #ifdef NO_XWAYLAND #define XWAYLAND false -#include "helpers/XWaylandStubs.hpp" #else #define XWAYLAND true #endif diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index ffd9ddea..108f9039 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -5,6 +5,7 @@ #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" #include "../protocols/XDGShell.hpp" +#include "../xwayland/XSurface.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { if (pWindow->m_bIsFloating) { @@ -111,10 +112,10 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5) pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; - if (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect) { + if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { - if (pWindow->m_uSurface.xwayland->x != 0 && pWindow->m_uSurface.xwayland->y != 0) - pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords({pWindow->m_uSurface.xwayland->x, pWindow->m_uSurface.xwayland->y}); + if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0) + pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); else pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f, PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f); @@ -161,7 +162,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale; - if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_uSurface.xwayland->override_redirect)) { + if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2)) { pWindow->m_vRealPosition.warp(); pWindow->m_vRealSize.warp(); } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index ea36b9b2..c9783844 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -2,6 +2,7 @@ #include "Compositor.hpp" #include "../config/ConfigValue.hpp" #include "PointerManager.hpp" +#include "../xwayland/XWayland.hpp" extern "C" { #include @@ -246,14 +247,14 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) { return IMAGES.images[0]; } -void CCursorManager::setXWaylandCursor(wlr_xwayland* xwayland) { +void CCursorManager::setXWaylandCursor() { const auto CURSOR = dataFor("left_ptr"); if (CURSOR.surface) { - wlr_xwayland_set_cursor(xwayland, cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), CURSOR.size, CURSOR.size, CURSOR.hotspotX, - CURSOR.hotspotY); + g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, + {CURSOR.hotspotX, CURSOR.hotspotY}); } else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) { - wlr_xwayland_set_cursor(xwayland, XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, XCURSOR->images[0]->width, XCURSOR->images[0]->height, - XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y); + g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {XCURSOR->images[0]->width, XCURSOR->images[0]->height}, + {XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y}); } else Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index b4c5232a..4ff9adeb 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -8,7 +8,6 @@ struct wlr_buffer; struct wlr_xcursor_manager; -struct wlr_xwayland; class CWLSurface; class CCursorManager { @@ -25,7 +24,7 @@ class CCursorManager { void changeTheme(const std::string& name, const int size); void updateTheme(); SCursorImageData dataFor(const std::string& name); // for xwayland - void setXWaylandCursor(wlr_xwayland* xwayland); + void setXWaylandCursor(); void tickAnimatedCursor(); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index c43e4c56..feff69e0 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -31,6 +31,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" +#include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -73,6 +74,7 @@ CProtocolManager::CProtocolManager() { PROTO::xdgShell = std::make_unique(&xdg_wm_base_interface, 6, "XDGShell"); PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); + PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index bbbe01d4..ce40650d 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -498,6 +498,8 @@ void CSeatManager::setCurrentSelection(SP source) { PROTO::data->setSelection(source); PROTO::dataWlr->setSelection(source, false); } + + events.setSelection.emit(); } void CSeatManager::setCurrentPrimarySelection(SP source) { @@ -521,6 +523,8 @@ void CSeatManager::setCurrentPrimarySelection(SP source) { PROTO::primarySelection->setSelection(source); PROTO::dataWlr->setSelection(source, true); } + + events.setPrimarySelection.emit(); } void CSeatManager::setGrab(SP grab) { diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index fee3efa9..b88058a8 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -106,6 +106,8 @@ class CSeatManager { CSignal pointerFocusChange; CSignal touchFocusChange; CSignal setCursor; // SSetCursorEvent + CSignal setSelection; + CSignal setPrimarySelection; } events; struct { diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 390c6ece..4aebefcb 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -3,29 +3,14 @@ #include "../events/Events.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/XDGShell.hpp" +#include "../xwayland/XWayland.hpp" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 #define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3 CHyprXWaylandManager::CHyprXWaylandManager() { -#ifndef NO_XWAYLAND - m_sWLRXWayland = wlr_xwayland_create(g_pCompositor->m_sWLDisplay, g_pCompositor->m_sWLRCompositor, 1); - - if (!m_sWLRXWayland) { - Debug::log(ERR, "Couldn't start up the XWaylandManager because wlr_xwayland_create returned a nullptr!"); - return; - } - - addWLSignal(&m_sWLRXWayland->events.ready, &Events::listen_readyXWayland, m_sWLRXWayland, "XWayland Manager"); - addWLSignal(&m_sWLRXWayland->events.new_surface, &Events::listen_surfaceXWayland, m_sWLRXWayland, "XWayland Manager"); - - setenv("DISPLAY", m_sWLRXWayland->display_name, 1); - - Debug::log(LOG, "CHyprXWaylandManager started on display {}", m_sWLRXWayland->display_name); -#else - unsetenv("DISPLAY"); // unset DISPLAY so that X11 apps do not try to start on a different/invalid DISPLAY -#endif + ; } CHyprXWaylandManager::~CHyprXWaylandManager() { @@ -42,24 +27,23 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) if (!pSurface) return; - if (wlr_xwayland_surface_try_from_wlr_surface(pSurface)) { - const auto XSURF = wlr_xwayland_surface_try_from_wlr_surface(pSurface); - wlr_xwayland_surface_activate(XSURF, activate); - - if (activate && !XSURF->override_redirect) - wlr_xwayland_surface_restack(XSURF, nullptr, XCB_STACK_MODE_ABOVE); - } - // TODO: // this cannot be nicely done until we rewrite wlr_surface for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_bIsX11 || !w->m_bIsMapped) + if (!w->m_bIsMapped) continue; if (w->m_pWLSurface.wlr() != pSurface) continue; - w->m_pXDGSurface->toplevel->setActive(activate); + if (w->m_bIsX11) { + if (activate) { + w->m_pXWaylandSurface->setMinimized(false); + w->m_pXWaylandSurface->restackToTop(); + } + w->m_pXWaylandSurface->activate(activate); + } else + w->m_pXDGSurface->toplevel->setActive(activate); } } @@ -68,12 +52,12 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos if (activate) { - wlr_xwayland_surface_set_minimized(pWindow->m_uSurface.xwayland, false); - if (!pWindow->m_uSurface.xwayland->override_redirect) - wlr_xwayland_surface_restack(pWindow->m_uSurface.xwayland, nullptr, XCB_STACK_MODE_ABOVE); + pWindow->m_pXWaylandSurface->setMinimized(false); + if (pWindow->m_iX11Type != 2) + pWindow->m_pXWaylandSurface->restackToTop(); } - wlr_xwayland_surface_activate(pWindow->m_uSurface.xwayland, activate); + pWindow->m_pXWaylandSurface->activate(activate); } else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) pWindow->m_pXDGSurface->toplevel->setActive(activate); @@ -88,7 +72,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { if (pWindow->m_bIsX11) { - const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints; + const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); if (SIZEHINTS && pWindow->m_iX11Type != 2) { pbox->x = SIZEHINTS->x; @@ -96,10 +80,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { pbox->width = SIZEHINTS->width; pbox->height = SIZEHINTS->height; } else { - pbox->x = pWindow->m_uSurface.xwayland->x; - pbox->y = pWindow->m_uSurface.xwayland->y; - pbox->width = pWindow->m_uSurface.xwayland->width; - pbox->height = pWindow->m_uSurface.xwayland->height; + *pbox = pWindow->m_pXWaylandSurface->geometry; } } else if (pWindow->m_pXDGSurface) *pbox = pWindow->m_pXDGSurface->current.geometry; @@ -107,7 +88,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) { if (pWindow->m_bIsX11) - wlr_xwayland_surface_close(pWindow->m_uSurface.xwayland); + pWindow->m_pXWaylandSurface->close(); else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) pWindow->m_pXDGSurface->toplevel->close(); } @@ -145,7 +126,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool } if (pWindow->m_bIsX11) - wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, windowPos.x, windowPos.y, size.x, size.y); + pWindow->m_pXWaylandSurface->configure({windowPos, size}); else if (pWindow->m_pXDGSurface->toplevel) pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); } @@ -156,45 +137,36 @@ wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { - for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++) - if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) { + for (auto& a : pWindow->m_pXWaylandSurface->atoms) + if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || + a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || + a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || + a == HYPRATOMS["_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"]) { - if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"]) + if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"]) pWindow->m_bX11ShouldntFocus = true; pWindow->m_bNoInitialFocus = true; return true; } - if (pWindow->m_uSurface.xwayland->role) { - try { - std::string winrole = std::string(pWindow->m_uSurface.xwayland->role); - if (winrole.contains("pop-up") || winrole.contains("task_dialog")) { - return true; - } - } catch (std::exception& e) { Debug::log(ERR, "Error in shouldBeFloated, winrole threw {}", e.what()); } - } - - if (pWindow->m_uSurface.xwayland->modal) { + if (pWindow->m_pXWaylandSurface->modal) { pWindow->m_bIsModal = true; return true; } - if (pWindow->m_iX11Type == 2) - return true; // override_redirect + if (pWindow->m_pXWaylandSurface->transient) + return true; - const auto SIZEHINTS = pWindow->m_uSurface.xwayland->size_hints; - if (SIZEHINTS && (pWindow->m_uSurface.xwayland->parent || ((SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height)))) + if (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up")) + return true; + + if (pWindow->m_pXWaylandSurface->overrideRedirect) + return true; + + const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); + if (pWindow->m_pXWaylandSurface->transient || pWindow->m_pXWaylandSurface->parent || + (SIZEHINTS && (SIZEHINTS->min_width == SIZEHINTS->max_width) && (SIZEHINTS->min_height == SIZEHINTS->max_height))) return true; } else { const auto PSTATE = pending ? &pWindow->m_pXDGSurface->toplevel->pending : &pWindow->m_pXDGSurface->toplevel->current; @@ -207,28 +179,14 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { return false; } -void CHyprXWaylandManager::moveXWaylandWindow(PHLWINDOW pWindow, const Vector2D& pos) { - if (!validMapped(pWindow)) - return; - - if (!pWindow->m_bIsX11) - return; - - wlr_xwayland_surface_configure(pWindow->m_uSurface.xwayland, pos.x, pos.y, pWindow->m_vRealSize.value().x, pWindow->m_vRealSize.value().y); -} - void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { if (!pWindow->m_bIsX11) return; - for (size_t i = 0; i < pWindow->m_uSurface.xwayland->window_type_len; i++) { - if (pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || - pWindow->m_uSurface.xwayland->window_type[i] == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) { + for (auto& a : pWindow->m_pXWaylandSurface->atoms) { + if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || + a == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || + a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) { pWindow->m_bX11DoesntWantBorders = true; return; @@ -242,7 +200,7 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { if (pWindow->m_bIsX11) - wlr_xwayland_surface_set_fullscreen(pWindow->m_uSurface.xwayland, fullscreen); + pWindow->m_pXWaylandSurface->setFullscreen(fullscreen); else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen); } @@ -251,10 +209,10 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return Vector2D(99999, 99999); - if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize) + if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize) return Vector2D(99999, 99999); - auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->max_width, pWindow->m_uSurface.xwayland->size_hints->max_height) : + auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : pWindow->m_pXDGSurface->toplevel->current.maxSize; if (MAXSIZE.x < 5) @@ -269,10 +227,10 @@ Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return Vector2D(0, 0); - if ((pWindow->m_bIsX11 && !pWindow->m_uSurface.xwayland->size_hints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel)) + if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel)) return Vector2D(0, 0); - auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_uSurface.xwayland->size_hints->min_width, pWindow->m_uSurface.xwayland->size_hints->min_height) : + auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : pWindow->m_pXDGSurface->toplevel->current.minSize; MINSIZE = MINSIZE.clamp({1, 1}); diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 8889eb61..5bbab802 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -11,22 +11,19 @@ class CHyprXWaylandManager { CHyprXWaylandManager(); ~CHyprXWaylandManager(); - wlr_xwayland* m_sWLRXWayland = nullptr; - - wlr_surface* getWindowSurface(PHLWINDOW); - void activateSurface(wlr_surface*, bool); - void activateWindow(PHLWINDOW, bool); - void getGeometryForWindow(PHLWINDOW, CBox*); - void sendCloseWindow(PHLWINDOW); - void setWindowSize(PHLWINDOW, Vector2D, bool force = false); - void setWindowFullscreen(PHLWINDOW, bool); - wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&); - bool shouldBeFloated(PHLWINDOW, bool pending = false); - void moveXWaylandWindow(PHLWINDOW, const Vector2D&); - void checkBorders(PHLWINDOW); - Vector2D getMaxSizeForWindow(PHLWINDOW); - Vector2D getMinSizeForWindow(PHLWINDOW); - Vector2D xwaylandToWaylandCoords(const Vector2D&); + wlr_surface* getWindowSurface(PHLWINDOW); + void activateSurface(wlr_surface*, bool); + void activateWindow(PHLWINDOW, bool); + void getGeometryForWindow(PHLWINDOW, CBox*); + void sendCloseWindow(PHLWINDOW); + void setWindowSize(PHLWINDOW, Vector2D, bool force = false); + void setWindowFullscreen(PHLWINDOW, bool); + wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&); + bool shouldBeFloated(PHLWINDOW, bool pending = false); + void checkBorders(PHLWINDOW); + Vector2D getMaxSizeForWindow(PHLWINDOW); + Vector2D getMinSizeForWindow(PHLWINDOW); + Vector2D xwaylandToWaylandCoords(const Vector2D&); }; inline std::unique_ptr g_pXWaylandManager; \ No newline at end of file diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 52927d95..5a7688cd 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -661,7 +661,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // clicking on border triggers resize // TODO detect click on LS properly - if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) { if (w && !w->m_bIsFullscreen) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; @@ -674,7 +674,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { } switch (e.state) { - case WL_POINTER_BUTTON_STATE_PRESSED: + case WL_POINTER_BUTTON_STATE_PRESSED: { if (*PFOLLOWMOUSE == 3) // don't refocus on full loose break; @@ -692,10 +692,16 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { } // if clicked on a floating window make it top - if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) - g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true); + if (!g_pSeatManager->state.pointerFocus) + break; + + auto HLSurf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); + + if (HLSurf && HLSurf->getWindow()) + g_pCompositor->changeWindowZOrder(HLSurf->getWindow(), true); break; + } case WL_POINTER_BUTTON_STATE_RELEASED: break; } @@ -1677,6 +1683,10 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { return; } + // ignore X11 OR windows, they shouldn't be touched + if (w->m_bIsX11 && w->m_iX11Type == 2) + return; + static auto PEXTENDBORDERGRAB = CConfigValue("general:extend_border_grab_area"); const int BORDERSIZE = w->getRealBorderSize(); const int ROUNDING = w->rounding(); diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 9d3e2ac9..771f5f78 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -1,6 +1,7 @@ #include "XDGOutput.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "../xwayland/XWayland.hpp" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 @@ -55,7 +56,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); #ifndef NO_XWAYLAND - if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == CLIENT) + if (g_pXWayland && g_pXWayland->pServer && g_pXWayland->pServer->xwaylandClient == CLIENT) pXDGOutput->isXWayland = true; #endif pXDGOutput->client = CLIENT; diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp new file mode 100644 index 00000000..8b9905f8 --- /dev/null +++ b/src/protocols/XWaylandShell.cpp @@ -0,0 +1,84 @@ +#include "XWaylandShell.hpp" +#include + +#define LOGM PROTO::xwaylandShell->protoLog + +CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, wlr_surface* surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CXwaylandSurfaceV1* r) { + events.destroy.emit(); + PROTO::xwaylandShell->destroyResource(this); + }); + resource->setOnDestroy([this](CXwaylandSurfaceV1* r) { + events.destroy.emit(); + PROTO::xwaylandShell->destroyResource(this); + }); + + pClient = resource->client(); + + resource->setSetSerial([this](CXwaylandSurfaceV1* r, uint32_t lo, uint32_t hi) { + serial = (((uint64_t)hi) << 32) + lo; + PROTO::xwaylandShell->events.newSurface.emit(self.lock()); + }); +} + +CXWaylandSurfaceResource::~CXWaylandSurfaceResource() { + events.destroy.emit(); +} + +bool CXWaylandSurfaceResource::good() { + return resource->resource(); +} + +wl_client* CXWaylandSurfaceResource::client() { + return pClient; +} + +CXWaylandShellResource::CXWaylandShellResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CXwaylandShellV1* r) { PROTO::xwaylandShell->destroyResource(this); }); + resource->setOnDestroy([this](CXwaylandShellV1* r) { PROTO::xwaylandShell->destroyResource(this); }); + + resource->setGetXwaylandSurface([this](CXwaylandShellV1* r, uint32_t id, wl_resource* surface) { + const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), wlr_surface_from_resource(surface))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::xwaylandShell->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); +} + +bool CXWaylandShellResource::good() { + return resource->resource(); +} + +CXWaylandShellProtocol::CXWaylandShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CXWaylandShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CXWaylandShellProtocol::destroyResource(CXWaylandShellResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CXWaylandShellProtocol::destroyResource(CXWaylandSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/XWaylandShell.hpp b/src/protocols/XWaylandShell.hpp new file mode 100644 index 00000000..2c03d172 --- /dev/null +++ b/src/protocols/XWaylandShell.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xwayland-shell-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CXWaylandSurfaceResource { + public: + CXWaylandSurfaceResource(SP resource_, wlr_surface* surface_); + ~CXWaylandSurfaceResource(); + + bool good(); + wl_client* client(); + + struct { + CSignal destroy; + } events; + + uint64_t serial = 0; + wlr_surface* surface = nullptr; + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CXWaylandShellResource { + public: + CXWaylandShellResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CXWaylandShellProtocol : public IWaylandProtocol { + public: + CXWaylandShellProtocol(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); + + struct { + CSignal newSurface; // SP. Fired when it sets a serial, otherwise it's useless + } events; + + private: + void destroyResource(CXWaylandSurfaceResource* resource); + void destroyResource(CXWaylandShellResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vSurfaces; + + friend class CXWaylandSurfaceResource; + friend class CXWaylandShellResource; +}; + +namespace PROTO { + inline UP xwaylandShell; +}; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp index 47cbda8b..eb6969cc 100644 --- a/src/protocols/types/DataDevice.cpp +++ b/src/protocols/types/DataDevice.cpp @@ -15,3 +15,7 @@ bool IDataSource::used() { void IDataSource::markUsed() { wasUsed = true; } + +eDataSourceType IDataSource::type() { + return DATA_SOURCE_TYPE_WAYLAND; +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 98a97c14..948f47a0 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -5,6 +5,11 @@ #include #include "../../helpers/signal/Signal.hpp" +enum eDataSourceType { + DATA_SOURCE_TYPE_WAYLAND = 0, + DATA_SOURCE_TYPE_X11, +}; + class IDataSource { public: IDataSource() {} @@ -19,6 +24,7 @@ class IDataSource { virtual bool used(); virtual void markUsed(); virtual void error(uint32_t code, const std::string& msg) = 0; + virtual eDataSourceType type(); struct { CSignal destroy; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c5c87ea1..40ae953e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -192,14 +192,10 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) g_pHyprOpenGL->blend(true); if (RDATA->surface && surface == RDATA->surface) { - if (wlr_xwayland_surface_try_from_wlr_surface(surface) && !wlr_xwayland_surface_try_from_wlr_surface(surface)->has_alpha && ALPHA == 1.f) { + if (RDATA->blur) + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); + else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); - } else { - if (RDATA->blur) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); - else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); - } } else { if (RDATA->blur && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp new file mode 100644 index 00000000..510ad737 --- /dev/null +++ b/src/xwayland/Server.cpp @@ -0,0 +1,427 @@ +#ifndef NO_XWAYLAND + +#include "Server.hpp" +#include "../defines.hpp" +#include "../Compositor.hpp" +#include "../managers/CursorManager.hpp" +#include "XWayland.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO: cleanup +static bool set_cloexec(int fd, bool cloexec) { + int flags = fcntl(fd, F_GETFD); + if (flags == -1) { + wlr_log_errno(WLR_ERROR, "fcntl failed"); + return false; + } + if (cloexec) { + flags = flags | FD_CLOEXEC; + } else { + flags = flags & ~FD_CLOEXEC; + } + if (fcntl(fd, F_SETFD, flags) == -1) { + wlr_log_errno(WLR_ERROR, "fcntl failed"); + return false; + } + return true; +} + +static int openSocket(struct sockaddr_un* addr, size_t path_size) { + int fd, rc; + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + wlr_log_errno(WLR_ERROR, "Failed to create socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + return -1; + } + if (!set_cloexec(fd, true)) { + close(fd); + return -1; + } + + if (addr->sun_path[0]) { + unlink(addr->sun_path); + } + if (bind(fd, (struct sockaddr*)addr, size) < 0) { + rc = errno; + wlr_log_errno(WLR_ERROR, "Failed to bind socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + goto cleanup; + } + if (listen(fd, 1) < 0) { + rc = errno; + wlr_log_errno(WLR_ERROR, "Failed to listen to socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + goto cleanup; + } + + return fd; + +cleanup: + close(fd); + if (addr->sun_path[0]) { + unlink(addr->sun_path); + } + errno = rc; + return -1; +} + +static bool checkPermissionsForSocketDir(void) { + struct stat buf; + + if (lstat("/tmp/.X11-unix", &buf)) { + Debug::log(ERR, "Failed statting X11 socket dir"); + return false; + } + + if (!(buf.st_mode & S_IFDIR)) { + Debug::log(ERR, "X11 socket dir is not a dir"); + return false; + } + + if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) { + Debug::log(ERR, "X11 socket dir is not ours"); + return false; + } + + if (!(buf.st_mode & S_ISVTX)) { + if ((buf.st_mode & (S_IWGRP | S_IWOTH))) { + Debug::log(ERR, "X11 socket dir is sticky by others"); + return false; + } + } + + return true; +} + +static bool openSockets(std::array& sockets, int display) { + auto ret = mkdir("/tmp/.X11-unix", 755); + + if (ret != 0) { + if (errno == EEXIST) { + if (!checkPermissionsForSocketDir()) + return false; + } else { + Debug::log(ERR, "XWayland: couldn't create socket dir"); + return false; + } + } + + std::string path; + sockaddr_un addr = {.sun_family = AF_UNIX}; + +#ifdef __linux__ + // cursed... + addr.sun_path[0] = 0; + path = std::format("/tmp/.X11-unix/X{}", display); + strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1); +#else + path = std::format("/tmp/.X11-unix/X{}_", display); + strncpy(addr.sun_path, path.c_str(), path.length() + 1); +#endif + sockets[0] = openSocket(&addr, path.length()); + if (sockets[0] < 0) + return false; + + path = std::format("/tmp/.X11-unix/X{}", display); + strncpy(addr.sun_path, path.c_str(), path.length() + 1); + sockets[1] = openSocket(&addr, path.length()); + if (sockets[1] < 0) { + close(sockets[0]); + sockets[0] = -1; + return false; + } + + return true; +} + +static void startServer(void* data) { + if (!g_pXWayland->pServer->start()) + Debug::log(ERR, "The XWayland server could not start! XWayland will not work..."); +} + +static int xwaylandReady(int fd, uint32_t mask, void* data) { + return g_pXWayland->pServer->ready(fd, mask); +} + +bool CXWaylandServer::tryOpenSockets() { + for (size_t i = 0; i <= 32; ++i) { + auto LOCK = std::format("/tmp/.X{}-lock", i); + + if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { + // we managed to open the lock + if (!openSockets(xFDs, i)) { + std::filesystem::remove(LOCK); + close(fd); + continue; + } + + const auto PIDSTR = std::format("{}", getpid()); + + if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { + std::filesystem::remove(LOCK); + close(fd); + continue; + } + + close(fd); + + display = i; + displayName = std::format(":{}", display); + break; + } + + int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC); + + if (fd < 0) + continue; + + char pidstr[12] = {0}; + read(fd, pidstr, sizeof(pidstr) - 1); + close(fd); + + uint64_t pid = 0; + try { + pid = std::stoi(std::string{pidstr, 11}); + } catch (...) { continue; } + + if (kill(pid, 0) != 0 && errno == ESRCH) { + if (!std::filesystem::remove(LOCK)) + continue; + + i--; + } + } + + if (display < 0) { + Debug::log(ERR, "Failed to find a suitable socket for xwayland"); + return false; + } + + Debug::log(LOG, "XWayland found a suitable display socket at DISPLAY: {}", displayName); + return true; +} + +CXWaylandServer::CXWaylandServer() { + ; +} + +CXWaylandServer::~CXWaylandServer() { + die(); + if (display < 0) + return; + + if (xFDs[0]) + close(xFDs[0]); + if (xFDs[1]) + close(xFDs[1]); + + auto LOCK = std::format("/tmp/.X{}-lock", display); + std::filesystem::remove(LOCK); + + std::string path; +#ifdef __linux__ + path = std::format("/tmp/.X11-unix/X{}", display); +#else + path = std::format("/tmp/.X11-unix/X{}_", display); +#endif + std::filesystem::remove(path); +} + +void CXWaylandServer::die() { + if (display < 0) + return; + + if (xFDReadEvents[0]) { + wl_event_source_remove(xFDReadEvents[0]); + wl_event_source_remove(xFDReadEvents[1]); + + xFDReadEvents = {nullptr, nullptr}; + } + + if (pipeSource) + wl_event_source_remove(pipeSource); + + if (waylandFDs[0]) + close(waylandFDs[0]); + if (waylandFDs[1]) + close(waylandFDs[1]); + if (xwmFDs[0]) + close(xwmFDs[0]); + if (xwmFDs[1]) + close(xwmFDs[1]); + + if (xwaylandClient) + wl_client_destroy(xwaylandClient); + + xwaylandClient = nullptr; + waylandFDs = {-1, -1}; + xwmFDs = {-1, -1}; +} + +bool CXWaylandServer::create() { + if (!tryOpenSockets()) + return false; + + setenv("DISPLAY", displayName.c_str(), true); + + // TODO: lazy mode + + idleSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::startServer, nullptr); + + return true; +} + +void CXWaylandServer::runXWayland(int notifyFD) { + if (!set_cloexec(xFDs[0], false) || !set_cloexec(xFDs[1], false) || !set_cloexec(waylandFDs[1], false) || !set_cloexec(xwmFDs[1], false)) { + Debug::log(ERR, "Failed to unset cloexec on fds"); + _exit(EXIT_FAILURE); + } + + auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]); + + auto waylandSocket = std::format("{}", waylandFDs[1]); + setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true); + + Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd); + + execl("/bin/sh", "/bin/sh", "-c", cmd.c_str(), nullptr); + + Debug::log(ERR, "XWayland failed to open"); + _exit(1); +} + +bool CXWaylandServer::start() { + idleSource = nullptr; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) { + Debug::log(ERR, "socketpair failed (1)"); + die(); + return false; + } + + if (!set_cloexec(waylandFDs[0], true) || !set_cloexec(waylandFDs[1], true)) { + Debug::log(ERR, "set_cloexec failed (1)"); + die(); + return false; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) { + Debug::log(ERR, "socketpair failed (2)"); + die(); + return false; + } + + if (!set_cloexec(xwmFDs[0], true) || !set_cloexec(xwmFDs[1], true)) { + Debug::log(ERR, "set_cloexec failed (2)"); + die(); + return false; + } + + xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]); + if (!xwaylandClient) { + Debug::log(ERR, "wl_client_create failed"); + die(); + return false; + } + + waylandFDs[0] = -1; + + int notify[2] = {-1, -1}; + if (pipe(notify) < 0) { + Debug::log(ERR, "pipe failed"); + die(); + return false; + } + + if (!set_cloexec(notify[0], true)) { + Debug::log(ERR, "set_cloexec failed (3)"); + close(notify[0]); + close(notify[1]); + die(); + return false; + } + + pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); + + serverPID = fork(); + if (serverPID < 0) { + Debug::log(ERR, "fork failed"); + close(notify[0]); + close(notify[1]); + die(); + return false; + } else if (serverPID == 0) { + pid_t pid = fork(); + if (pid < 0) { + Debug::log(ERR, "second fork failed"); + _exit(1); + } else if (pid == 0) { + runXWayland(notify[1]); + } + + _exit(0); + } + + close(notify[1]); + close(waylandFDs[1]); + close(xwmFDs[1]); + waylandFDs[1] = -1; + xwmFDs[1] = -1; + + return true; +} + +int CXWaylandServer::ready(int fd, uint32_t mask) { + if (mask & WL_EVENT_READABLE) { + // xwayland writes twice + char buf[64]; + ssize_t n = read(fd, buf, sizeof(buf)); + if (n < 0 && errno != EINTR) { + Debug::log(ERR, "Xwayland: read from displayFd failed"); + mask = 0; + } else if (n <= 0 || buf[n - 1] != '\n') + return 1; + } + + while (waitpid(serverPID, nullptr, 0) < 0) { + if (errno == EINTR) + continue; + Debug::log(ERR, "Xwayland: waitpid for fork failed"); + g_pXWayland->pServer.reset(); + return 1; + } + + // if we don't have readable here, it failed + if (!(mask & WL_EVENT_READABLE)) { + Debug::log(ERR, "Xwayland: startup failed, not setting up xwm"); + g_pXWayland->pServer.reset(); + return 1; + } + + Debug::log(LOG, "XWayland is ready"); + + close(fd); + wl_event_source_remove(pipeSource); + pipeSource = nullptr; + + // start the wm + g_pXWayland->pWM = std::make_unique(); + + g_pCursorManager->setXWaylandCursor(); + + return 0; +} + +#endif diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp new file mode 100644 index 00000000..0c06a56c --- /dev/null +++ b/src/xwayland/Server.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include "../helpers/signal/Signal.hpp" + +struct wl_event_source; +struct wl_client; + +// TODO: add lazy mode +class CXWaylandServer { + public: + CXWaylandServer(); + ~CXWaylandServer(); + + // create the server. + bool create(); + + // starts the server, meant to be called by CXWaylandServer. + bool start(); + + // called on ready + int ready(int fd, uint32_t mask); + + void die(); + + struct { + CSignal ready; + } events; + + wl_client* xwaylandClient = nullptr; + + private: + bool tryOpenSockets(); + void runXWayland(int notifyFD); + + pid_t serverPID = 0; + + std::string displayName; + int display = -1; + std::array xFDs = {-1, -1}; + std::array xFDReadEvents = {nullptr, nullptr}; + wl_event_source* idleSource = nullptr; + wl_event_source* pipeSource = nullptr; + std::array xwmFDs = {-1, -1}; + std::array waylandFDs = {-1, -1}; + + friend class CXWM; +}; diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp new file mode 100644 index 00000000..98e0701b --- /dev/null +++ b/src/xwayland/XDataSource.cpp @@ -0,0 +1,97 @@ +#ifndef NO_XWAYLAND + +#include "XDataSource.hpp" +#include "XWayland.hpp" +#include "../defines.hpp" + +#include + +CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { + xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, + 1, // delete + selection.window, HYPRATOMS["_WL_SELECTION"], XCB_GET_PROPERTY_TYPE_ANY, 0, 4096); + + xcb_get_property_reply_t* reply = xcb_get_property_reply(g_pXWayland->pWM->connection, cookie, NULL); + if (!reply) + return; + + if (reply->type != XCB_ATOM_ATOM) { + free(reply); + return; + } + + auto value = (xcb_atom_t*)xcb_get_property_value(reply); + for (uint32_t i = 0; i < reply->value_len; i++) { + if (value[i] == HYPRATOMS["UTF8_STRING"]) + mimeTypes.push_back("text/plain;charset=utf-8"); + else if (value[i] == HYPRATOMS["TEXT"]) + mimeTypes.push_back("text/plain"); + else if (value[i] != HYPRATOMS["TARGETS"] && value[i] != HYPRATOMS["TIMESTAMP"]) { + + auto type = g_pXWayland->pWM->mimeFromAtom(value[i]); + + if (type == "INVALID") + continue; + + mimeTypes.push_back(type); + } + + mimeAtoms.push_back(value[i]); + } + + free(reply); +} + +std::vector CXDataSource::mimes() { + return mimeTypes; +} + +void CXDataSource::send(const std::string& mime, uint32_t fd) { + xcb_atom_t mimeAtom = 0; + + for (size_t i = 0; i < mimeTypes.size(); ++i) { + if (mimeTypes.at(i) == mime) { + mimeAtom = mimeAtoms.at(i); + break; + } + } + + if (!mimeAtom) { + Debug::log(ERR, "[XDataSource] mime atom not found"); + close(fd); + return; + } + + Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); + + selection.transfer = std::make_unique(selection); + selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); + const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, selection.transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK); + + xcb_convert_selection(g_pXWayland->pWM->connection, selection.transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME); + + xcb_flush(g_pXWayland->pWM->connection); + + fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); + selection.transfer->wlFD = fd; +} + +void CXDataSource::accepted(const std::string& mime) { + Debug::log(LOG, "[XDataSource] accepted is a stub"); +} + +void CXDataSource::cancelled() { + Debug::log(LOG, "[XDataSource] cancelled is a stub"); +} + +void CXDataSource::error(uint32_t code, const std::string& msg) { + Debug::log(LOG, "[XDataSource] error is a stub: err {}: {}", code, msg); +} + +eDataSourceType CXDataSource::type() { + return DATA_SOURCE_TYPE_X11; +} + +#endif \ No newline at end of file diff --git a/src/xwayland/XDataSource.hpp b/src/xwayland/XDataSource.hpp new file mode 100644 index 00000000..c629aa2a --- /dev/null +++ b/src/xwayland/XDataSource.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "../protocols/types/DataDevice.hpp" + +struct SXSelection; + +class CXDataSource : public IDataSource { + public: + CXDataSource(SXSelection&); + + virtual std::vector mimes(); + virtual void send(const std::string& mime, uint32_t fd); + virtual void accepted(const std::string& mime); + virtual void cancelled(); + virtual void error(uint32_t code, const std::string& msg); + virtual eDataSourceType type(); + + private: + SXSelection& selection; + std::vector mimeTypes; // these two have shared idx + std::vector mimeAtoms; // +}; \ No newline at end of file diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp new file mode 100644 index 00000000..8994e975 --- /dev/null +++ b/src/xwayland/XSurface.cpp @@ -0,0 +1,291 @@ +#include "XSurface.hpp" +#include "XWayland.hpp" +#include "../protocols/XWaylandShell.hpp" + +#ifndef NO_XWAYLAND + +#include "../Compositor.hpp" +#include + +CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { + xcb_res_query_client_ids_cookie_t client_id_cookie = {0}; + if (g_pXWayland->pWM->xres) { + xcb_res_client_id_spec_t spec = {.client = xID, .mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID}; + client_id_cookie = xcb_res_query_client_ids(g_pXWayland->pWM->connection, 1, &spec); + } + + uint32_t values[1]; + values[0] = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_change_window_attributes(g_pXWayland->pWM->connection, xID, XCB_CW_EVENT_MASK, values); + + if (g_pXWayland->pWM->xres) { + xcb_res_query_client_ids_reply_t* reply = xcb_res_query_client_ids_reply(g_pXWayland->pWM->connection, client_id_cookie, nullptr); + if (!reply) + return; + + uint32_t* ppid = nullptr; + xcb_res_client_id_value_iterator_t iter = xcb_res_query_client_ids_ids_iterator(reply); + while (iter.rem > 0) { + if (iter.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID && xcb_res_client_id_value_value_length(iter.data) > 0) { + ppid = xcb_res_client_id_value_value(iter.data); + break; + } + xcb_res_client_id_value_next(&iter); + } + if (ppid == NULL) { + free(reply); + return; + } + pid = *ppid; + free(reply); + } + + events.resourceChange.registerStaticListener([this](void* data, std::any d) { ensureListeners(); }, nullptr); +} + +void CXWaylandSurface::ensureListeners() { + bool connected = hyprListener_surfaceDestroy.isConnected(); + + if (connected && !surface) { + hyprListener_surfaceDestroy.removeCallback(); + hyprListener_surfaceCommit.removeCallback(); + } else if (!connected && surface) { + hyprListener_surfaceDestroy.initCallback( + &surface->events.destroy, + [this](void* owner, void* data) { + if (mapped) + unmap(); + + surface = nullptr; + hyprListener_surfaceDestroy.removeCallback(); + hyprListener_surfaceCommit.removeCallback(); + events.resourceChange.emit(); + }, + nullptr, "CXWaylandSurface"); + hyprListener_surfaceCommit.initCallback( + &surface->events.commit, + [this](void* owner, void* data) { + if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { + map(); + return; + } + + if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { + unmap(); + return; + } + + events.commit.emit(); + }, + nullptr, "CXWaylandSurface"); + } + + if (resource) { + listeners.destroyResource = resource->events.destroy.registerListener([this](std::any d) { + unmap(); + surface = nullptr; + events.resourceChange.emit(); + }); + } +} + +void CXWaylandSurface::map() { + if (mapped) + return; + + ASSERT(surface); + + g_pXWayland->pWM->mappedSurfaces.emplace_back(self); + g_pXWayland->pWM->mappedSurfacesStacking.emplace_back(self); + + mapped = true; + wlr_surface_map(surface); + + Debug::log(LOG, "XWayland surface {:x} mapping", (uintptr_t)this); + + events.map.emit(); + + g_pXWayland->pWM->updateClientList(); +} + +void CXWaylandSurface::unmap() { + if (!mapped) + return; + + ASSERT(surface); + + std::erase(g_pXWayland->pWM->mappedSurfaces, self); + std::erase(g_pXWayland->pWM->mappedSurfacesStacking, self); + + mapped = false; + wlr_surface_unmap(surface); + + Debug::log(LOG, "XWayland surface {:x} unmapping", (uintptr_t)this); + + events.unmap.emit(); + + g_pXWayland->pWM->updateClientList(); +} + +void CXWaylandSurface::considerMap() { + if (mapped) + return; + + if (!surface) { + Debug::log(LOG, "XWayland surface: considerMap, nope, no surface"); + return; + } + + if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { + Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer"); + map(); + return; + } + + Debug::log(LOG, "XWayland surface: considerMap, nope, we don't have a buffer"); +} + +bool CXWaylandSurface::wantsFocus() { + if (atoms.empty()) + return true; + + const std::array search = { + HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DND"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"], + HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"], HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"], HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"], + HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"], HYPRATOMS["_NET_WM_WINDOW_TYPE_DESKTOP"], HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"], + HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"], + }; + + for (auto& searched : search) { + for (auto& a : atoms) { + if (a == searched) + return false; + } + } + + return true; +} + +void CXWaylandSurface::configure(const CBox& box) { + Vector2D oldSize = geometry.size(); + + geometry = box; + + uint32_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT | XCB_CONFIG_WINDOW_BORDER_WIDTH; + uint32_t values[] = {box.x, box.y, box.width, box.height, 0}; + xcb_configure_window(g_pXWayland->pWM->connection, xID, mask, values); + + g_pXWayland->pWM->updateClientList(); + + xcb_flush(g_pXWayland->pWM->connection); +} + +void CXWaylandSurface::activate(bool activate) { + if (overrideRedirect && !activate) + return; + g_pXWayland->pWM->activateSurface(self.lock()); +} + +void CXWaylandSurface::setFullscreen(bool fs) { + fullscreen = fs; + g_pXWayland->pWM->sendState(self.lock()); +} + +void CXWaylandSurface::setMinimized(bool mz) { + minimized = mz; + g_pXWayland->pWM->sendState(self.lock()); +} + +void CXWaylandSurface::restackToTop() { + uint32_t values[1] = {XCB_STACK_MODE_ABOVE}; + + xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values); + + for (auto it = g_pXWayland->pWM->mappedSurfacesStacking.begin(); it != g_pXWayland->pWM->mappedSurfacesStacking.end(); ++it) { + if (*it == self) { + std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end()); + break; + } + } + + g_pXWayland->pWM->updateClientList(); + + xcb_flush(g_pXWayland->pWM->connection); +} + +void CXWaylandSurface::close() { + xcb_client_message_data_t msg = {0}; + msg.data32[0] = HYPRATOMS["WM_DELETE_WINDOW"]; + msg.data32[1] = XCB_CURRENT_TIME; + g_pXWayland->pWM->sendWMMessage(self.lock(), &msg, XCB_EVENT_MASK_NO_EVENT); +} + +void CXWaylandSurface::setWithdrawn(bool withdrawn_) { + withdrawn = withdrawn_; + std::vector props = {XCB_ICCCM_WM_STATE_NORMAL, XCB_WINDOW_NONE}; + + if (withdrawn) + props[0] = XCB_ICCCM_WM_STATE_WITHDRAWN; + else if (minimized) + props[0] = XCB_ICCCM_WM_STATE_ICONIC; + else + props[0] = XCB_ICCCM_WM_STATE_NORMAL; + + xcb_change_property(g_pXWayland->pWM->connection, XCB_PROP_MODE_REPLACE, xID, HYPRATOMS["WM_STATE"], HYPRATOMS["WM_STATE"], 32, props.size(), props.data()); +} + +#else + +CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { + ; +} + +void CXWaylandSurface::ensureListeners() { + ; +} + +void CXWaylandSurface::map() { + ; +} + +void CXWaylandSurface::unmap() { + ; +} + +bool CXWaylandSurface::wantsFocus() { + return false; +} + +void CXWaylandSurface::configure(const CBox& box) { + ; +} + +void CXWaylandSurface::activate(bool activate) { + ; +} + +void CXWaylandSurface::setFullscreen(bool fs) { + ; +} + +void CXWaylandSurface::setMinimized(bool mz) { + ; +} + +void CXWaylandSurface::restackToTop() { + ; +} + +void CXWaylandSurface::close() { + ; +} + +void CXWaylandSurface::considerMap() { + ; +} + +void CXWaylandSurface::setWithdrawn(bool withdrawn) { + ; +} + +#endif diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp new file mode 100644 index 00000000..73cb89a5 --- /dev/null +++ b/src/xwayland/XSurface.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include "../helpers/WLListener.hpp" +#include "../helpers/signal/Signal.hpp" +#include "../helpers/Box.hpp" +#include + +struct wlr_surface; +class CXWaylandSurfaceResource; + +#ifdef NO_XWAYLAND +typedef uint32_t xcb_pixmap_t; +typedef uint32_t xcb_window_t; +typedef struct { + int32_t flags; + uint32_t input; + int32_t initial_state; + xcb_pixmap_t icon_pixmap; + xcb_window_t icon_window; + int32_t icon_x, icon_y; + xcb_pixmap_t icon_mask; + xcb_window_t window_group; +} xcb_icccm_wm_hints_t; +typedef struct { + uint32_t flags; + int32_t x, y; + int32_t width, height; + int32_t min_width, min_height; + int32_t max_width, max_height; + int32_t width_inc, height_inc; + int32_t min_aspect_num, min_aspect_den; + int32_t max_aspect_num, max_aspect_den; + int32_t base_width, base_height; + uint32_t win_gravity; +} xcb_size_hints_t; +#else +#include +#endif + +class CXWaylandSurface { + public: + wlr_surface* surface = nullptr; + WP resource; + + struct { + CSignal stateChanged; // maximized, fs, minimized, etc. + CSignal metadataChanged; // title, appid + CSignal destroy; + + CSignal resourceChange; // associated / dissociated + + CSignal setGeometry; + CSignal configure; // CBox + + CSignal map; + CSignal unmap; + CSignal commit; + + CSignal activate; + } events; + + struct { + std::string title; + std::string appid; + + // volatile state: is reset after the stateChanged signal fires + std::optional requestsMaximize; + std::optional requestsFullscreen; + std::optional requestsMinimize; + } state; + + uint32_t xID = 0; + uint64_t wlID = 0; + uint64_t wlSerial = 0; + pid_t pid = 0; + CBox geometry; + bool overrideRedirect = false; + bool withdrawn = false; + bool fullscreen = false; + bool maximized = false; + bool minimized = false; + bool mapped = false; + bool modal = false; + + WP parent; + WP self; + std::vector> children; + + UP hints; + UP sizeHints; + std::vector atoms; + std::string role = ""; + bool transient = false; + + bool wantsFocus(); + void configure(const CBox& box); + void activate(bool activate); + void setFullscreen(bool fs); + void setMinimized(bool mz); + void restackToTop(); + void close(); + + private: + CXWaylandSurface(uint32_t xID, CBox geometry, bool OR); + + void ensureListeners(); + void map(); + void unmap(); + void considerMap(); + void setWithdrawn(bool withdrawn); + + DYNLISTENER(surfaceDestroy); + DYNLISTENER(surfaceCommit); + + struct { + CHyprSignalListener destroyResource; + } listeners; + + friend class CXWM; +}; \ No newline at end of file diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp new file mode 100644 index 00000000..9e308314 --- /dev/null +++ b/src/xwayland/XWM.cpp @@ -0,0 +1,1210 @@ +#include "helpers/Vector2D.hpp" +#ifndef NO_XWAYLAND + +#include "XWayland.hpp" +#include "../defines.hpp" +#include +#include "../Compositor.hpp" +#include "../protocols/XWaylandShell.hpp" +#include "../managers/SeatManager.hpp" +#include "../protocols/core/Seat.hpp" +#include +#include +#include +#include + +#include + +#define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f +#define INCR_CHUNK_SIZE (64 * 1024) + +static int onX11Event(int fd, uint32_t mask, void* data) { + return g_pXWayland->pWM->onEvent(fd, mask); +} + +SP CXWM::windowForXID(xcb_window_t wid) { + for (auto& s : surfaces) { + if (s->xID == wid) + return s; + } + + return nullptr; +} + +void CXWM::handleCreate(xcb_create_notify_event_t* e) { + if (isWMWindow(e->window)) + return; + + const auto XSURF = surfaces.emplace_back(SP(new CXWaylandSurface(e->window, CBox{e->x, e->y, e->width, e->height}, e->override_redirect))); + XSURF->self = XSURF; + Debug::log(LOG, "[xwm] New XSurface at {:x} with xid of {}", (uintptr_t)XSURF.get(), e->window); + + const auto WINDOW = CWindow::create(XSURF); + g_pCompositor->m_vWindows.emplace_back(WINDOW); + WINDOW->m_pSelf = WINDOW; + Debug::log(LOG, "[xwm] New XWayland window at {:x} for surf {:x}", (uintptr_t)WINDOW.get(), (uintptr_t)XSURF.get()); +} + +void CXWM::handleDestroy(xcb_destroy_notify_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + XSURF->events.destroy.emit(); + std::erase_if(surfaces, [XSURF](const auto& other) { return XSURF == other; }); +} + +void CXWM::handleConfigure(xcb_configure_request_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + const uint16_t MASK = e->value_mask; + constexpr uint16_t GEOMETRY = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + if (!(MASK & GEOMETRY)) + return; + + XSURF->events.configure.emit(CBox{MASK & XCB_CONFIG_WINDOW_X ? e->x : XSURF->geometry.x, MASK & XCB_CONFIG_WINDOW_Y ? e->y : XSURF->geometry.y, + MASK & XCB_CONFIG_WINDOW_WIDTH ? e->width : XSURF->geometry.width, MASK & XCB_CONFIG_WINDOW_HEIGHT ? e->height : XSURF->geometry.height}); +} + +void CXWM::handleConfigureNotify(xcb_configure_notify_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + if (XSURF->geometry == CBox{e->x, e->y, e->width, e->height}) + return; + + XSURF->geometry = {e->x, e->y, e->width, e->height}; + XSURF->events.setGeometry.emit(); +} + +void CXWM::handleMapRequest(xcb_map_request_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + xcb_map_window(connection, e->window); + + XSURF->restackToTop(); + + const bool SMALL = + XSURF->geometry.size() < Vector2D{2, 2} || (XSURF->sizeHints && XSURF->geometry.size() < Vector2D{XSURF->sizeHints->min_width, XSURF->sizeHints->min_height}); + const bool HAS_HINTS = XSURF->sizeHints && Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} > Vector2D{5, 5}; + const auto DESIREDSIZE = HAS_HINTS ? Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} : Vector2D{800, 800}; + + // if it's too small, or its base size is set, configure it. + if ((SMALL || HAS_HINTS) && !XSURF->overrideRedirect) // default to 800 x 800 + XSURF->configure({XSURF->geometry.pos(), DESIREDSIZE}); + + Debug::log(LOG, "[xwm] Mapping window {} in X (geometry {}x{} at {}x{}))", e->window, XSURF->geometry.width, XSURF->geometry.height, XSURF->geometry.x, XSURF->geometry.y); + + // read data again. Some apps for some reason fail to send WINDOW_TYPE + // this shouldn't happen but does, I prolly fucked up somewhere, this is a band-aid + readWindowData(XSURF); + + XSURF->considerMap(); +} + +void CXWM::handleMapNotify(xcb_map_notify_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF || XSURF->overrideRedirect) + return; + + XSURF->setWithdrawn(false); + sendState(XSURF); + xcb_flush(connection); + + XSURF->considerMap(); +} + +void CXWM::handleUnmapNotify(xcb_unmap_notify_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + XSURF->unmap(); + dissociate(XSURF); + + if (XSURF->overrideRedirect) + return; + + XSURF->setWithdrawn(true); + sendState(XSURF); + xcb_flush(connection); +} + +static bool lookupParentExists(SP XSURF, SP prospectiveChild) { + while (XSURF->parent) { + if (XSURF->parent == prospectiveChild) + return true; + XSURF = XSURF->parent.lock(); + } + + return false; +} + +void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply) { + std::string propName = "?"; + for (auto& ha : HYPRATOMS) { + if (ha.second != atom) + continue; + + propName = ha.first; + break; + } + + if (atom == XCB_ATOM_WM_CLASS) { + size_t len = xcb_get_property_value_length(reply); + char* string = (char*)xcb_get_property_value(reply); + XSURF->state.appid = std::string{string, len}; + if (std::count(XSURF->state.appid.begin(), XSURF->state.appid.end(), '\000') == 2) + XSURF->state.appid = XSURF->state.appid.substr(XSURF->state.appid.find_first_of('\000') + 1); // fuck you X + if (!XSURF->state.appid.empty()) + XSURF->state.appid.pop_back(); + XSURF->events.metadataChanged.emit(); + } else if (atom == XCB_ATOM_WM_NAME || atom == HYPRATOMS["_NET_WM_NAME"]) { + size_t len = xcb_get_property_value_length(reply); + char* string = (char*)xcb_get_property_value(reply); + XSURF->state.title = std::string{string, len}; + XSURF->events.metadataChanged.emit(); + } else if (atom == HYPRATOMS["_NET_WM_WINDOW_TYPE"]) { + xcb_atom_t* atomsArr = (xcb_atom_t*)xcb_get_property_value(reply); + size_t atomsNo = reply->value_len; + XSURF->atoms.clear(); + for (size_t i = 0; i < atomsNo; ++i) { + XSURF->atoms.push_back(atomsArr[i]); + } + } else if (atom == HYPRATOMS["_NET_WM_STATE"]) { + xcb_atom_t* atoms = (xcb_atom_t*)xcb_get_property_value(reply); + for (uint32_t i = 0; i < reply->value_len; i++) { + if (atoms[i] == HYPRATOMS["_NET_WM_STATE_MODAL"]) + XSURF->modal = true; + } + } else if (atom == HYPRATOMS["WM_HINTS"]) { + if (reply->value_len != 0) { + XSURF->hints = std::make_unique(); + xcb_icccm_get_wm_hints_from_reply(XSURF->hints.get(), reply); + + if (!(XSURF->hints->flags & XCB_ICCCM_WM_HINT_INPUT)) + XSURF->hints->input = true; + } + } else if (atom == HYPRATOMS["WM_WINDOW_ROLE"]) { + size_t len = xcb_get_property_value_length(reply); + + if (len <= 0) + XSURF->role = ""; + else { + XSURF->role = std::string{(char*)xcb_get_property_value(reply), len}; + XSURF->role = XSURF->role.substr(0, XSURF->role.find_first_of('\000')); + } + } else if (atom == XCB_ATOM_WM_TRANSIENT_FOR) { + if (reply->type == XCB_ATOM_WINDOW) { + const auto XID = (xcb_window_t*)xcb_get_property_value(reply); + XSURF->transient = XID; + if (XID) { + if (const auto NEWXSURF = windowForXID(*XID); !lookupParentExists(XSURF, NEWXSURF)) { + XSURF->parent = NEWXSURF; + NEWXSURF->children.push_back(XSURF); + } else + Debug::log(LOG, "[xwm] Denying transient because it would create a loop"); + } + } + } else if (atom == HYPRATOMS["WM_NORMAL_HINTS"]) { + if (reply->type == HYPRATOMS["WM_SIZE_HINTS"] && reply->value_len > 0) { + XSURF->sizeHints = std::make_unique(); + std::memset(XSURF->sizeHints.get(), 0, sizeof(xcb_size_hints_t)); + + xcb_icccm_get_wm_size_hints_from_reply(XSURF->sizeHints.get(), reply); + + const int32_t FLAGS = XSURF->sizeHints->flags; + const bool HASMIN = (FLAGS & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE); + const bool HASBASE = (FLAGS & XCB_ICCCM_SIZE_HINT_BASE_SIZE); + + if (!HASMIN && !HASBASE) { + XSURF->sizeHints->min_width = -1; + XSURF->sizeHints->min_height = -1; + XSURF->sizeHints->base_width = -1; + XSURF->sizeHints->base_height = -1; + } else if (!HASBASE) { + XSURF->sizeHints->base_width = XSURF->sizeHints->min_width; + XSURF->sizeHints->base_height = XSURF->sizeHints->min_height; + } else if (!HASMIN) { + XSURF->sizeHints->min_width = XSURF->sizeHints->base_width; + XSURF->sizeHints->min_height = XSURF->sizeHints->base_height; + } + + if (!(FLAGS & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) { + XSURF->sizeHints->max_width = -1; + XSURF->sizeHints->max_height = -1; + } + } + } else { + Debug::log(LOG, "[xwm] Unhandled prop {} -> {}", atom, propName); + return; + } + + Debug::log(LOG, "[xwm] Handled prop {} -> {}", atom, propName); +} + +void CXWM::handlePropertyNotify(xcb_property_notify_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, XSURF->xID, e->atom, XCB_ATOM_ANY, 0, 2048); + xcb_get_property_reply_t* reply = xcb_get_property_reply(connection, cookie, nullptr); + if (!reply) { + Debug::log(ERR, "[xwm] Failed to read property notify cookie"); + return; + } + + readProp(XSURF, e->atom, reply); + + free(reply); +} + +void CXWM::handleClientMessage(xcb_client_message_event_t* e) { + const auto XSURF = windowForXID(e->window); + + if (!XSURF) + return; + + std::string propName = "?"; + for (auto& ha : HYPRATOMS) { + if (ha.second != e->type) + continue; + + propName = ha.first; + break; + } + + if (e->type == HYPRATOMS["WL_SURFACE_ID"]) { + if (XSURF->surface) { + Debug::log(WARN, "[xwm] Re-assignment of WL_SURFACE_ID"); + dissociate(XSURF); + } + + auto id = e->data.data32[0]; + auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id); + if (resource) { + auto wlrSurface = wlr_surface_from_resource(resource); + associate(XSURF, wlrSurface); + } + } else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) { + if (XSURF->wlSerial) { + Debug::log(WARN, "[xwm] Re-assignment of WL_SURFACE_SERIAL"); + dissociate(XSURF); + } + + uint32_t serialLow = e->data.data32[0]; + uint32_t serialHigh = e->data.data32[1]; + XSURF->wlSerial = ((uint64_t)serialHigh << 32) | serialLow; + + Debug::log(LOG, "[xwm] surface {:x} requests serial {:x}", (uintptr_t)XSURF.get(), XSURF->wlSerial); + + for (auto& res : shellResources) { + if (!res) + continue; + + if (res->serial != XSURF->wlSerial || !XSURF->wlSerial) + continue; + + associate(XSURF, res->surface); + break; + } + + } else if (e->type == HYPRATOMS["_NET_WM_STATE"]) { + if (e->format == 32) { + uint32_t action = e->data.data32[0]; + for (size_t i = 0; i < 2; ++i) { + xcb_atom_t prop = e->data.data32[1 + i]; + + auto updateState = [XSURF](int action, bool current) -> bool { + switch (action) { + case 0: + /* remove */ + return false; + case 1: + /* add */ + return true; + case 2: + /* toggle */ + return !current; + default: return false; + } + return false; + }; + + if (prop == HYPRATOMS["_NET_WM_STATE_FULLSCREEN"]) + XSURF->state.requestsFullscreen = updateState(action, XSURF->fullscreen); + } + + XSURF->events.stateChanged.emit(); + } + } else if (e->type == HYPRATOMS["_NET_ACTIVE_WINDOW"]) { + XSURF->events.activate.emit(); + } else { + Debug::log(LOG, "[xwm] Unhandled message prop {} -> {}", e->type, propName); + return; + } + + Debug::log(LOG, "[xwm] Handled message prop {} -> {}", e->type, propName); +} + +void CXWM::handleFocusIn(xcb_focus_in_event_t* e) { + if (e->mode == XCB_NOTIFY_MODE_GRAB || e->mode == XCB_NOTIFY_MODE_UNGRAB || e->detail == XCB_NOTIFY_DETAIL_POINTER) + return; + + const auto XSURF = windowForXID(e->event); + + if (!XSURF) + return; + + if (focusedSurface && focusedSurface->pid == XSURF->pid && e->sequence - lastFocusSeq <= 255) + focusWindow(XSURF); + else + focusWindow(focusedSurface.lock()); +} + +void CXWM::sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask) { + xcb_client_message_event_t event = { + .response_type = XCB_CLIENT_MESSAGE, + .format = 32, + .sequence = 0, + .window = surf->xID, + .type = HYPRATOMS["WM_PROTOCOLS"], + .data = *data, + }; + + xcb_send_event(connection, 0, surf->xID, mask, (const char*)&event); + xcb_flush(connection); +} + +void CXWM::focusWindow(SP surf) { + if (surf == focusedSurface) + return; + + auto oldSurf = focusedSurface.lock(); + focusedSurface = surf; + + if (oldSurf) + sendState(oldSurf); + + if (!surf) { + xcb_set_input_focus_checked(connection, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_NONE, XCB_CURRENT_TIME); + return; + } + + if (surf->overrideRedirect) + return; + + xcb_client_message_data_t msg = {0}; + msg.data32[0] = HYPRATOMS["WM_TAKE_FOCUS"]; + msg.data32[1] = XCB_TIME_CURRENT_TIME; + + if (surf->hints && !surf->hints->input) + sendWMMessage(surf, &msg, XCB_EVENT_MASK_NO_EVENT); + else { + sendWMMessage(surf, &msg, XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT); + + xcb_void_cookie_t cookie = xcb_set_input_focus(connection, XCB_INPUT_FOCUS_POINTER_ROOT, surf->xID, XCB_CURRENT_TIME); + lastFocusSeq = cookie.sequence; + } +} + +void CXWM::handleError(xcb_value_error_t* e) { + const char* major_name = xcb_errors_get_name_for_major_code(errors, e->major_opcode); + if (!major_name) { + Debug::log(ERR, "xcb error happened, but could not get major name"); + return; + } + + const char* minor_name = xcb_errors_get_name_for_minor_code(errors, e->major_opcode, e->minor_opcode); + + const char* extension; + const char* error_name = xcb_errors_get_name_for_error(errors, e->error_code, &extension); + if (!error_name) { + Debug::log(ERR, "xcb error happened, but could not get error name"); + return; + } + + Debug::log(ERR, "[xwm] xcb error: {} ({}), code {} ({}), seq {}, val {}", major_name, minor_name ? minor_name : "no minor", error_name, extension ? extension : "no extension", + e->sequence, e->bad_value); +} + +void CXWM::selectionSendNotify(xcb_selection_request_event_t* e, bool success) { + xcb_selection_notify_event_t selection_notify = { + .response_type = XCB_SELECTION_NOTIFY, + .sequence = 0, + .time = e->time, + .requestor = e->requestor, + .selection = e->selection, + .target = e->target, + .property = success ? e->property : (uint32_t)XCB_ATOM_NONE, + }; + + xcb_send_event(connection, 0, e->requestor, XCB_EVENT_MASK_NO_EVENT, (const char*)&selection_notify); + xcb_flush(connection); +} + +xcb_atom_t CXWM::mimeToAtom(const std::string& mime) { + if (mime == "text/plain;charset=utf-8") + return HYPRATOMS["UTF8_STRING"]; + if (mime == "text/plain") + return HYPRATOMS["TEXT"]; + + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 0, mime.length(), mime.c_str()); + xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(connection, cookie, nullptr); + if (!reply) + return XCB_ATOM_NONE; + xcb_atom_t atom = reply->atom; + free(reply); + return atom; +} + +std::string CXWM::mimeFromAtom(xcb_atom_t atom) { + if (atom == HYPRATOMS["UTF8_STRING"]) + return "text/plain;charset=utf-8"; + if (atom == HYPRATOMS["TEXT"]) + return "text/plain"; + + xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(connection, atom); + xcb_get_atom_name_reply_t* reply = xcb_get_atom_name_reply(connection, cookie, nullptr); + if (!reply) + return "INVALID"; + size_t len = xcb_get_atom_name_name_length(reply); + char* buf = xcb_get_atom_name_name(reply); // not a C string + std::string SZNAME{buf, len}; + free(reply); + return SZNAME; +} + +void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { + Debug::log(LOG, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target); + + SXSelection& sel = clipboard; + + if (e->property == XCB_ATOM_NONE) { + if (sel.transfer) { + Debug::log(ERR, "[xwm] converting selection failed"); + sel.transfer.reset(); + } + } else if (e->target == HYPRATOMS["TARGETS"]) { + if (!focusedSurface) { + Debug::log(LOG, "[xwm] denying access to write to clipboard because no X client is in focus"); + return; + } + + setClipboardToWayland(sel); + } else if (sel.transfer) + getTransferData(sel); +} + +bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { + // Debug::log(LOG, "[xwm] Selection property notify for {} target {}", e->atom, e->window); + + // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); + + return true; +} + +void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { + Debug::log(LOG, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor, + e->selection); + + SXSelection& sel = clipboard; + + if (!g_pSeatManager->selection.currentSelection) { + Debug::log(ERR, "[xwm] No selection"); + selectionSendNotify(e, false); + return; + } + + if (e->selection == HYPRATOMS["CLIPBOARD_MANAGER"]) { + selectionSendNotify(e, true); + return; + } + + if (sel.window != e->owner && e->time != XCB_CURRENT_TIME && e->time < sel.timestamp) { + Debug::log(ERR, "[xwm] outdated selection request. Time {} < {}", e->time, sel.timestamp); + selectionSendNotify(e, false); + return; + } + + if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient) { + Debug::log(LOG, "[xwm] Ignoring clipboard access: xwayland not in focus"); + selectionSendNotify(e, false); + return; + } + + if (e->target == HYPRATOMS["TARGETS"]) { + // send mime types + auto mimes = g_pSeatManager->selection.currentSelection->mimes(); + + std::vector atoms; + atoms.push_back(HYPRATOMS["TIMESTAMP"]); + atoms.push_back(HYPRATOMS["TARGETS"]); + + for (auto& m : mimes) { + atoms.push_back(mimeToAtom(m)); + } + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, e->requestor, e->property, XCB_ATOM_ATOM, 32, atoms.size(), atoms.data()); + selectionSendNotify(e, true); + } else if (e->target == HYPRATOMS["TIMESTAMP"]) { + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, e->requestor, e->property, XCB_ATOM_INTEGER, 32, 1, &sel.timestamp); + selectionSendNotify(e, true); + } else if (e->target == HYPRATOMS["DELETE"]) { + selectionSendNotify(e, true); + } else { + + std::string mime = mimeFromAtom(e->target); + + if (mime == "INVALID") { + Debug::log(LOG, "[xwm] Ignoring clipboard access: invalid mime atom {}", e->target); + selectionSendNotify(e, false); + return; + } + + if (!sel.sendData(e, mime)) { + Debug::log(LOG, "[xwm] Failed to send selection :("); + selectionSendNotify(e, false); + return; + } + } +} + +bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) { + Debug::log(LOG, "[xwm] Selection xfixes notify for {}", e->selection); + + // IMPORTANT: mind the g_pSeatManager below + SXSelection& sel = clipboard; + + if (e->owner == XCB_WINDOW_NONE) { + if (sel.owner != sel.window) + g_pSeatManager->setCurrentSelection(nullptr); + + sel.owner = 0; + return true; + } + + sel.owner = e->owner; + + if (sel.owner == sel.window) { + sel.timestamp = e->timestamp; + return true; + } + + xcb_convert_selection(connection, sel.window, HYPRATOMS["CLIPBOARD"], HYPRATOMS["TARGETS"], HYPRATOMS["_WL_SELECTION"], e->timestamp); + xcb_flush(connection); + + return true; +} + +bool CXWM::handleSelectionEvent(xcb_generic_event_t* e) { + switch (e->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { + case XCB_SELECTION_NOTIFY: { + handleSelectionNotify((xcb_selection_notify_event_t*)e); + return true; + } + case XCB_PROPERTY_NOTIFY: { + return handleSelectionPropertyNotify((xcb_property_notify_event_t*)e); + } + case XCB_SELECTION_REQUEST: { + handleSelectionRequest((xcb_selection_request_event_t*)e); + return true; + } + } + + if (e->response_type - xfixes->first_event == XCB_XFIXES_SELECTION_NOTIFY) + return handleSelectionXFixesNotify((xcb_xfixes_selection_notify_event_t*)e); + + return 0; +} + +int CXWM::onEvent(int fd, uint32_t mask) { + + if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) { + Debug::log(ERR, "XWayland has yeeten the xwm off?!"); + Debug::log(CRIT, "XWayland has yeeten the xwm off?!"); + g_pXWayland->pWM.reset(); + g_pXWayland->pServer.reset(); + return 0; + } + + int count = 0; + + while (42069) { + xcb_generic_event_t* event = xcb_poll_for_event(connection); + if (!event) + break; + + count++; + + if (handleSelectionEvent(event)) { + free(event); + continue; + } + + switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { + case XCB_CREATE_NOTIFY: handleCreate((xcb_create_notify_event_t*)event); break; + case XCB_DESTROY_NOTIFY: handleDestroy((xcb_destroy_notify_event_t*)event); break; + case XCB_CONFIGURE_REQUEST: handleConfigure((xcb_configure_request_event_t*)event); break; + case XCB_CONFIGURE_NOTIFY: handleConfigureNotify((xcb_configure_notify_event_t*)event); break; + case XCB_MAP_REQUEST: handleMapRequest((xcb_map_request_event_t*)event); break; + case XCB_MAP_NOTIFY: handleMapNotify((xcb_map_notify_event_t*)event); break; + case XCB_UNMAP_NOTIFY: handleUnmapNotify((xcb_unmap_notify_event_t*)event); break; + case XCB_PROPERTY_NOTIFY: handlePropertyNotify((xcb_property_notify_event_t*)event); break; + case XCB_CLIENT_MESSAGE: handleClientMessage((xcb_client_message_event_t*)event); break; + case XCB_FOCUS_IN: handleFocusIn((xcb_focus_in_event_t*)event); break; + case 0: handleError((xcb_value_error_t*)event); break; + default: { + ; + } + } + free(event); + } + + if (count) + xcb_flush(connection); + + return count; +} + +void CXWM::gatherResources() { + xcb_prefetch_extension_data(connection, &xcb_xfixes_id); + xcb_prefetch_extension_data(connection, &xcb_composite_id); + xcb_prefetch_extension_data(connection, &xcb_res_id); + + for (auto& ATOM : HYPRATOMS) { + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 0, ATOM.first.length(), ATOM.first.c_str()); + xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(connection, cookie, nullptr); + + if (!reply) { + Debug::log(ERR, "[xwm] Atom failed: {}", ATOM.first); + continue; + } + + ATOM.second = reply->atom; + free(reply); + } + + xfixes = xcb_get_extension_data(connection, &xcb_xfixes_id); + + if (!xfixes || !xfixes->present) + Debug::log(WARN, "XFixes not available"); + + xcb_xfixes_query_version_cookie_t xfixes_cookie; + xcb_xfixes_query_version_reply_t* xfixes_reply; + xfixes_cookie = xcb_xfixes_query_version(connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION); + xfixes_reply = xcb_xfixes_query_version_reply(connection, xfixes_cookie, NULL); + + Debug::log(LOG, "xfixes version: {}.{}", xfixes_reply->major_version, xfixes_reply->minor_version); + xfixesMajor = xfixes_reply->major_version; + + free(xfixes_reply); + + const xcb_query_extension_reply_t* xresReply1 = xcb_get_extension_data(connection, &xcb_res_id); + if (!xresReply1 || !xresReply1->present) + return; + + xcb_res_query_version_cookie_t xres_cookie = xcb_res_query_version(connection, XCB_RES_MAJOR_VERSION, XCB_RES_MINOR_VERSION); + xcb_res_query_version_reply_t* xres_reply = xcb_res_query_version_reply(connection, xres_cookie, NULL); + if (xres_reply == NULL) + return; + + Debug::log(LOG, "xres version: {}.{}", xres_reply->server_major, xres_reply->server_minor); + if (xres_reply->server_major > 1 || (xres_reply->server_major == 1 && xres_reply->server_minor >= 2)) { + xres = xresReply1; + } + free(xres_reply); +} + +void CXWM::getVisual() { + xcb_depth_iterator_t d_iter; + xcb_visualtype_iterator_t vt_iter; + xcb_visualtype_t* visualtype; + + d_iter = xcb_screen_allowed_depths_iterator(screen); + visualtype = NULL; + while (d_iter.rem > 0) { + if (d_iter.data->depth == 32) { + vt_iter = xcb_depth_visuals_iterator(d_iter.data); + visualtype = vt_iter.data; + break; + } + + xcb_depth_next(&d_iter); + } + + if (visualtype == NULL) { + wlr_log(WLR_DEBUG, "No 32 bit visualtype\n"); + return; + } + + visual_id = visualtype->visual_id; + colormap = xcb_generate_id(connection); + xcb_create_colormap(connection, XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, visual_id); +} + +void CXWM::getRenderFormat() { + xcb_render_query_pict_formats_cookie_t cookie = xcb_render_query_pict_formats(connection); + xcb_render_query_pict_formats_reply_t* reply = xcb_render_query_pict_formats_reply(connection, cookie, NULL); + if (!reply) { + wlr_log(WLR_ERROR, "Did not get any reply from xcb_render_query_pict_formats"); + return; + } + xcb_render_pictforminfo_iterator_t iter = xcb_render_query_pict_formats_formats_iterator(reply); + xcb_render_pictforminfo_t* format = NULL; + while (iter.rem > 0) { + if (iter.data->depth == 32) { + format = iter.data; + break; + } + + xcb_render_pictforminfo_next(&iter); + } + + if (format == NULL) { + wlr_log(WLR_DEBUG, "No 32 bit render format"); + free(reply); + return; + } + + render_format_id = format->id; + free(reply); +} + +CXWM::CXWM() { + connection = xcb_connect_to_fd(g_pXWayland->pServer->xwmFDs[0], nullptr); + + if (int ret = xcb_connection_has_error(connection); ret) { + Debug::log(ERR, "[xwm] Couldn't start, error {}", ret); + return; + } + + if (xcb_errors_context_new(connection, &errors)) { + Debug::log(ERR, "[xwm] Couldn't allocate errors context"); + return; + } + + xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(connection)); + screen = screen_iterator.data; + + eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0], WL_EVENT_READABLE, ::onX11Event, nullptr); + wl_event_source_check(eventSource); + + gatherResources(); + getVisual(); + getRenderFormat(); + + uint32_t values[] = { + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_PROPERTY_CHANGE, + }; + xcb_change_window_attributes(connection, screen->root, XCB_CW_EVENT_MASK, values); + + xcb_composite_redirect_subwindows(connection, screen->root, XCB_COMPOSITE_REDIRECT_MANUAL); + + xcb_atom_t supported[] = { + HYPRATOMS["_NET_WM_STATE"], HYPRATOMS["_NET_ACTIVE_WINDOW"], HYPRATOMS["_NET_WM_MOVERESIZE"], HYPRATOMS["_NET_WM_STATE_FOCUSED"], + HYPRATOMS["_NET_WM_STATE_MODAL"], HYPRATOMS["_NET_WM_STATE_FULLSCREEN"], HYPRATOMS["_NET_WM_STATE_MAXIMIZED_VERT"], HYPRATOMS["_NET_WM_STATE_MAXIMIZED_HORZ"], + HYPRATOMS["_NET_WM_STATE_HIDDEN"], HYPRATOMS["_NET_CLIENT_LIST"], HYPRATOMS["_NET_CLIENT_LIST_STACKING"], + }; + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTED"], XCB_ATOM_ATOM, 32, sizeof(supported) / sizeof(*supported), supported); + + xcb_flush(connection); + + setActiveWindow(XCB_WINDOW_NONE); + + initSelection(); + + hyprListener_newSurface.initCallback( + &g_pCompositor->m_sWLRCompositor->events.new_surface, [this](void* owner, void* data) { onNewSurface((wlr_surface*)data); }, nullptr, "XWM"); + + listeners.newXShellSurface = PROTO::xwaylandShell->events.newSurface.registerListener([this](std::any d) { onNewResource(std::any_cast>(d)); }); + + createWMWindow(); + + xcb_flush(connection); +} + +void CXWM::setActiveWindow(xcb_window_t window) { + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_ACTIVE_WINDOW"], HYPRATOMS["WINDOW"], 32, 1, &window); +} + +void CXWM::createWMWindow() { + constexpr const char* wmName = "Hyprland :D"; + wmWindow = xcb_generate_id(connection); + xcb_create_window(connection, XCB_COPY_FROM_PARENT, wmWindow, screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0, NULL); + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, wmWindow, HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["UTF8_STRING"], + 8, // format + strlen(wmName), wmName); + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_WINDOW, + 32, // format + 1, &wmWindow); + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, wmWindow, HYPRATOMS["_NET_SUPPORTING_WM_CHECK"], XCB_ATOM_WINDOW, + 32, // format + 1, &wmWindow); + xcb_set_selection_owner(connection, wmWindow, HYPRATOMS["WM_S0"], XCB_CURRENT_TIME); + xcb_set_selection_owner(connection, wmWindow, HYPRATOMS["_NET_WM_CM_S0"], XCB_CURRENT_TIME); +} + +void CXWM::activateSurface(SP surf) { + if (surf == focusedSurface || (surf && surf->overrideRedirect)) + return; + + setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE); + + focusWindow(surf); + + xcb_flush(connection); +} + +void CXWM::sendState(SP surf) { + if (surf->withdrawn) { + xcb_delete_property(connection, surf->xID, HYPRATOMS["_NET_WM_STATE"]); + return; + } + + std::vector props; + if (surf->modal) + props.push_back(HYPRATOMS["_NET_WM_STATE_MODAL"]); + if (surf->fullscreen) + props.push_back(HYPRATOMS["_NET_WM_STATE_FULLSCREEN"]); + if (surf->maximized) { + props.push_back(HYPRATOMS["NET_WM_STATE_MAXIMIZED_VERT"]); + props.push_back(HYPRATOMS["NET_WM_STATE_MAXIMIZED_HORZ"]); + } + if (surf->minimized) + props.push_back(HYPRATOMS["_NET_WM_STATE_HIDDEN"]); + if (surf == focusedSurface) + props.push_back(HYPRATOMS["_NET_WM_STATE_FOCUSED"]); + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, surf->xID, HYPRATOMS["_NET_WM_STATE"], XCB_ATOM_ATOM, 32, props.size(), props.data()); +} + +void CXWM::onNewSurface(wlr_surface* surf) { + if (wl_resource_get_client(surf->resource) != g_pXWayland->pServer->xwaylandClient) + return; + + Debug::log(LOG, "[xwm] New XWayland surface at {:x}", (uintptr_t)surf); + + const auto WLID = wl_resource_get_id(surf->resource); + + for (auto& sr : surfaces) { + if (sr->surface || sr->wlID != WLID) + continue; + + associate(sr, surf); + return; + } + + Debug::log(WARN, "[xwm] CXWM::onNewSurface: no matching xwaylandSurface"); +} + +void CXWM::onNewResource(SP resource) { + Debug::log(LOG, "[xwm] New XWayland resource at {:x}", (uintptr_t)resource.get()); + + std::erase_if(shellResources, [](const auto& e) { return e.expired(); }); + shellResources.push_back(resource); + + for (auto& surf : surfaces) { + if (surf->resource || surf->wlSerial != resource->serial) + continue; + + associate(surf, resource->surface); + break; + } +} + +void CXWM::readWindowData(SP surf) { + const std::array interestingProps = { + XCB_ATOM_WM_CLASS, XCB_ATOM_WM_NAME, XCB_ATOM_WM_TRANSIENT_FOR, HYPRATOMS["WM_HINTS"], + HYPRATOMS["_NET_WM_STATE"], HYPRATOMS["_NET_WM_NAME"], HYPRATOMS["_NET_WM_WINDOW_TYPE"], HYPRATOMS["WM_NORMAL_HINTS"], + }; + + for (size_t i = 0; i < interestingProps.size(); i++) { + xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, surf->xID, interestingProps.at(i), XCB_ATOM_ANY, 0, 2048); + xcb_get_property_reply_t* reply = xcb_get_property_reply(connection, cookie, nullptr); + if (!reply) { + Debug::log(ERR, "[xwm] Failed to get window property"); + continue; + } + readProp(surf, interestingProps.at(i), reply); + free(reply); + } +} + +void CXWM::associate(SP surf, wlr_surface* wlSurf) { + if (surf->surface) + return; + + auto existing = std::find_if(surfaces.begin(), surfaces.end(), [wlSurf](const auto& e) { return e->surface == wlSurf; }); + + if (existing != surfaces.end()) { + Debug::log(WARN, "[xwm] associate() called but surface is already associated to {:x}, ignoring...", (uintptr_t)surf.get()); + return; + } + + surf->surface = wlSurf; + surf->ensureListeners(); + + readWindowData(surf); + + surf->events.resourceChange.emit(); +} + +void CXWM::dissociate(SP surf) { + if (!surf->surface) + return; + + if (surf->mapped) + surf->unmap(); + + surf->surface = nullptr; + surf->events.resourceChange.emit(); + + Debug::log(LOG, "Dissociate for {:x}", (uintptr_t)surf.get()); +} + +void CXWM::updateClientList() { + std::erase_if(mappedSurfaces, [](const auto& e) { return e.expired() || !e->mapped; }); + std::erase_if(mappedSurfacesStacking, [](const auto& e) { return e.expired() || !e->mapped; }); + + std::vector windows; + for (auto& m : mappedSurfaces) { + windows.push_back(m->xID); + } + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_CLIENT_LIST"], XCB_ATOM_WINDOW, 32, windows.size(), windows.data()); + + windows.clear(); + + for (auto& m : mappedSurfacesStacking) { + windows.push_back(m->xID); + } + + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_CLIENT_LIST_STACKING"], XCB_ATOM_WINDOW, 32, windows.size(), windows.data()); +} + +bool CXWM::isWMWindow(xcb_window_t w) { + return w == wmWindow || w == clipboard.window; +} + +void CXWM::initSelection() { + clipboard.window = xcb_generate_id(connection); + uint32_t mask[1] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE}; + xcb_create_window(connection, XCB_COPY_FROM_PARENT, clipboard.window, screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, XCB_CW_EVENT_MASK, + mask); + xcb_set_selection_owner(connection, clipboard.window, HYPRATOMS["CLIPBOARD_MANAGER"], XCB_TIME_CURRENT_TIME); + + uint32_t mask2 = + XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; + xcb_xfixes_select_selection_input(connection, clipboard.window, HYPRATOMS["CLIPBOARD"], mask2); + + clipboard.listeners.setSelection = g_pSeatManager->events.setSelection.registerListener([this](std::any d) { clipboard.onSelection(); }); +} + +void CXWM::setClipboardToWayland(SXSelection& sel) { + sel.dataSource = makeShared(sel); + if (sel.dataSource->mimes().empty()) { + Debug::log(ERR, "[xwm] can't set clipboard: no MIMEs"); + sel.dataSource.reset(); + } + + if (sel.dataSource) { + Debug::log(LOG, "[xwm] X clipboard at {:x} takes clipboard", (uintptr_t)sel.dataSource.get()); + g_pSeatManager->setCurrentSelection(sel.dataSource); + } +} + +void CXWM::getTransferData(SXSelection& sel) { + Debug::log(LOG, "[xwm] getTransferData"); + + sel.transfer->getIncomingSelectionProp(true); + + if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { + Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); + close(sel.transfer->wlFD); + sel.transfer.reset(); + return; + } else { + char* property = (char*)xcb_get_property_value(sel.transfer->propertyReply); + int remainder = xcb_get_property_value_length(sel.transfer->propertyReply) - sel.transfer->propertyStart; + + ssize_t len = write(sel.transfer->wlFD, property + sel.transfer->propertyStart, remainder); + if (len == -1) { + Debug::log(ERR, "[xwm] write died in transfer get"); + close(sel.transfer->wlFD); + sel.transfer.reset(); + return; + } + + if (len < remainder) { + sel.transfer->propertyStart += len; + Debug::log(ERR, "[xwm] wl client read partially: len {}", len); + return; + } else { + Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); + close(sel.transfer->wlFD); + sel.transfer.reset(); + } + } +} + +void CXWM::setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot) { + if (!render_format_id) { + Debug::log(ERR, "[xwm] can't set cursor: no render format"); + return; + } + + if (cursorXID) + xcb_free_cursor(connection, cursorXID); + + constexpr int CURSOR_DEPTH = 32; + + xcb_pixmap_t pix = xcb_generate_id(connection); + xcb_create_pixmap(connection, CURSOR_DEPTH, pix, screen->root, size.x, size.y); + + xcb_render_picture_t pic = xcb_generate_id(connection); + xcb_render_create_picture(connection, pic, pix, render_format_id, 0, 0); + + xcb_gcontext_t gc = xcb_generate_id(connection); + xcb_create_gc(connection, gc, pix, 0, NULL); + + xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pix, gc, size.x, size.y, 0, 0, 0, CURSOR_DEPTH, stride * size.y * sizeof(uint8_t), pixData); + xcb_free_gc(connection, gc); + + cursorXID = xcb_generate_id(connection); + xcb_render_create_cursor(connection, cursorXID, pic, hotspot.x, hotspot.y); + xcb_free_pixmap(connection, pix); + xcb_render_free_picture(connection, pic); + + uint32_t values[] = {cursorXID}; + xcb_change_window_attributes(connection, screen->root, XCB_CW_CURSOR, values); + xcb_flush(connection); +} + +void SXSelection::onSelection() { + if (g_pSeatManager->selection.currentSelection && g_pSeatManager->selection.currentSelection->type() == DATA_SOURCE_TYPE_X11) + return; + + if (g_pSeatManager->selection.currentSelection) { + xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->clipboard.window, HYPRATOMS["CLIPBOARD"], XCB_TIME_CURRENT_TIME); + xcb_flush(g_pXWayland->pWM->connection); + } +} + +int SXSelection::onRead(int fd, uint32_t mask) { + // TODO: support INCR + + size_t pre = transfer->data.size(); + transfer->data.resize(INCR_CHUNK_SIZE + pre); + + auto len = read(fd, transfer->data.data() + pre, INCR_CHUNK_SIZE - 1); + if (len < 0) { + Debug::log(ERR, "[xwm] readDataSource died"); + g_pXWayland->pWM->selectionSendNotify(&transfer->request, false); + transfer.reset(); + return 0; + } + + transfer->data.resize(pre + len); + + if (len == 0) { + Debug::log(LOG, "[xwm] Received all the bytes, final length {}", transfer->data.size()); + xcb_change_property(g_pXWayland->pWM->connection, XCB_PROP_MODE_REPLACE, transfer->request.requestor, transfer->request.property, transfer->request.target, 8, + transfer->data.size(), transfer->data.data()); + xcb_flush(g_pXWayland->pWM->connection); + g_pXWayland->pWM->selectionSendNotify(&transfer->request, true); + transfer.reset(); + } else + Debug::log(LOG, "[xwm] Received {} bytes, waiting...", len); + + return 1; +} + +static int readDataSource(int fd, uint32_t mask, void* data) { + Debug::log(LOG, "[xwm] readDataSource on fd {}", fd); + + auto selection = (SXSelection*)data; + + return selection->onRead(fd, mask); +} + +bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { + WP selection = g_pSeatManager->selection.currentSelection; + + if (!selection) + return false; + + const auto MIMES = selection->mimes(); + + if (MIMES.empty()) + return false; + + if (std::find(MIMES.begin(), MIMES.end(), mime) == MIMES.end()) { + Debug::log(ERR, "[xwm] X Client asked for an invalid MIME, sending the first advertised. THIS SHIT MAY BREAK!"); + mime = *MIMES.begin(); + } + + transfer = std::make_unique(*this); + transfer->request = *e; + + int p[2]; + if (pipe(p) == -1) { + Debug::log(ERR, "[xwm] selection: pipe() failed"); + return false; + } + + fcntl(p[0], F_SETFD, FD_CLOEXEC); + fcntl(p[0], F_SETFL, O_NONBLOCK); + fcntl(p[1], F_SETFD, FD_CLOEXEC); + fcntl(p[1], F_SETFL, O_NONBLOCK); + + transfer->wlFD = p[0]; + + Debug::log(LOG, "[xwm] sending wayland selection to xwayland with mime {}, target {}, fds {} {}", mime, e->target, p[0], p[1]); + + selection->send(mime, p[1]); + + transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD, WL_EVENT_READABLE, ::readDataSource, this); + + return true; +} + +SXTransfer::~SXTransfer() { + if (wlFD) + close(wlFD); + if (eventSource) + wl_event_source_remove(eventSource); + if (incomingWindow) + xcb_destroy_window(g_pXWayland->pWM->connection, incomingWindow); + if (propertyReply) + free(propertyReply); +} + +bool SXTransfer::getIncomingSelectionProp(bool erase) { + xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, erase, incomingWindow, HYPRATOMS["_WL_SELECTION"], XCB_GET_PROPERTY_TYPE_ANY, 0, 0x1fffffff); + + propertyStart = 0; + propertyReply = xcb_get_property_reply(g_pXWayland->pWM->connection, cookie, nullptr); + + if (!propertyReply) { + Debug::log(ERR, "[SXTransfer] couldn't get a prop reply"); + return false; + } + + return true; +} + +#endif diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp new file mode 100644 index 00000000..b312f4a9 --- /dev/null +++ b/src/xwayland/XWM.hpp @@ -0,0 +1,160 @@ +#pragma once + +#include "../helpers/signal/Listener.hpp" +#include "../helpers/WLListener.hpp" +#include "../macros.hpp" + +#include "XDataSource.hpp" + +#include +#include +#include +#include +#include + +struct wl_event_source; +class CXWaylandSurfaceResource; +struct SXSelection; + +struct SXTransfer { + ~SXTransfer(); + + SXSelection& selection; + bool out = true; + + bool incremental = false; + bool flushOnDelete = false; + bool propertySet = false; + + int wlFD = -1; + wl_event_source* eventSource = nullptr; + + std::vector data; + + xcb_selection_request_event_t request; + + int propertyStart; + xcb_get_property_reply_t* propertyReply; + xcb_window_t incomingWindow; + + bool getIncomingSelectionProp(bool erase); +}; + +struct SXSelection { + xcb_window_t window = 0; + xcb_window_t owner = 0; + xcb_timestamp_t timestamp = 0; + SP dataSource; + + void onSelection(); + bool sendData(xcb_selection_request_event_t* e, std::string mime); + int onRead(int fd, uint32_t mask); + + struct { + CHyprSignalListener setSelection; + } listeners; + + std::unique_ptr transfer; +}; + +class CXWM { + public: + CXWM(); + + int onEvent(int fd, uint32_t mask); + + private: + void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot); + + void gatherResources(); + void getVisual(); + void getRenderFormat(); + void createWMWindow(); + void initSelection(); + + void onNewSurface(wlr_surface* surf); + void onNewResource(SP resource); + + void setActiveWindow(xcb_window_t window); + void sendState(SP surf); + void focusWindow(SP surf); + void activateSurface(SP surf); + bool isWMWindow(xcb_window_t w); + + void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); + + SP windowForXID(xcb_window_t wid); + + void readWindowData(SP surf); + void associate(SP surf, wlr_surface* wlSurf); + void dissociate(SP surf); + + void updateClientList(); + + // event handlers + void handleCreate(xcb_create_notify_event_t* e); + void handleDestroy(xcb_destroy_notify_event_t* e); + void handleConfigure(xcb_configure_request_event_t* e); + void handleConfigureNotify(xcb_configure_notify_event_t* e); + void handleMapRequest(xcb_map_request_event_t* e); + void handleMapNotify(xcb_map_notify_event_t* e); + void handleUnmapNotify(xcb_unmap_notify_event_t* e); + void handlePropertyNotify(xcb_property_notify_event_t* e); + void handleClientMessage(xcb_client_message_event_t* e); + void handleFocusIn(xcb_focus_in_event_t* e); + void handleError(xcb_value_error_t* e); + + bool handleSelectionEvent(xcb_generic_event_t* e); + void handleSelectionNotify(xcb_selection_notify_event_t* e); + bool handleSelectionPropertyNotify(xcb_property_notify_event_t* e); + void handleSelectionRequest(xcb_selection_request_event_t* e); + bool handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e); + + void selectionSendNotify(xcb_selection_request_event_t* e, bool success); + xcb_atom_t mimeToAtom(const std::string& mime); + std::string mimeFromAtom(xcb_atom_t atom); + void setClipboardToWayland(SXSelection& sel); + void getTransferData(SXSelection& sel); + void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); + + // + xcb_connection_t* connection = nullptr; + xcb_errors_context_t* errors = nullptr; + xcb_screen_t* screen = nullptr; + + xcb_window_t wmWindow; + + wl_event_source* eventSource = nullptr; + + const xcb_query_extension_reply_t* xfixes = nullptr; + const xcb_query_extension_reply_t* xres = nullptr; + int xfixesMajor = 0; + + xcb_visualid_t visual_id; + xcb_colormap_t colormap; + uint32_t cursorXID = 0; + + xcb_render_pictformat_t render_format_id; + + std::vector> shellResources; + std::vector> surfaces; + std::vector> mappedSurfaces; // ordered by map time + std::vector> mappedSurfacesStacking; // ordered by stacking + + WP focusedSurface; + uint64_t lastFocusSeq = 0; + + SXSelection clipboard; + + DYNLISTENER(newSurface); + + struct { + CHyprSignalListener newXShellSurface; + } listeners; + + friend class CXWaylandSurface; + friend class CXWayland; + friend class CXDataSource; + friend struct SXSelection; + friend struct SXTransfer; +}; diff --git a/src/xwayland/XWayland.cpp b/src/xwayland/XWayland.cpp new file mode 100644 index 00000000..8d45fa63 --- /dev/null +++ b/src/xwayland/XWayland.cpp @@ -0,0 +1,28 @@ +#include "XWayland.hpp" +#include "../debug/Log.hpp" + +CXWayland::CXWayland() { +#ifndef NO_XWAYLAND + Debug::log(LOG, "Starting up the XWayland server"); + + pServer = std::make_unique(); + + if (!pServer->create()) { + Debug::log(ERR, "XWayland failed to start: it will not work."); + return; + } +#else + Debug::log(LOG, "Not starting XWayland: disabled at compile time"); +#endif +} + +void CXWayland::setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot) { +#ifndef NO_XWAYLAND + if (!pWM) { + Debug::log(ERR, "Couldn't set XCursor: no XWM yet"); + return; + } + + pWM->setCursor(pixData, stride, size, hotspot); +#endif +} \ No newline at end of file diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp new file mode 100644 index 00000000..c7981251 --- /dev/null +++ b/src/xwayland/XWayland.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include +#include "../helpers/signal/Signal.hpp" + +#include "XSurface.hpp" + +#ifndef NO_XWAYLAND +#include "Server.hpp" +#include "XWM.hpp" +#else +class CXWaylandServer; +class CXWM; +#endif + +class CXWayland { + public: + CXWayland(); + +#ifndef NO_XWAYLAND + std::unique_ptr pServer; + std::unique_ptr pWM; +#endif + + void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot); + + struct { + CSignal newSurface; + } events; +}; + +inline std::unique_ptr g_pXWayland; + +#define HYPRATOM(name) \ + { name, 0 } +inline std::unordered_map HYPRATOMS = { + HYPRATOM("_NET_SUPPORTED"), + HYPRATOM("_NET_SUPPORTING_WM_CHECK"), + HYPRATOM("_NET_WM_NAME"), + HYPRATOM("_NET_WM_VISIBLE_NAME"), + HYPRATOM("_NET_WM_MOVERESIZE"), + HYPRATOM("_NET_WM_STATE_STICKY"), + HYPRATOM("_NET_WM_STATE_FULLSCREEN"), + HYPRATOM("_NET_WM_STATE_DEMANDS_ATTENTION"), + HYPRATOM("_NET_WM_STATE_MODAL"), + HYPRATOM("_NET_WM_STATE_HIDDEN"), + HYPRATOM("_NET_WM_STATE_FOCUSED"), + HYPRATOM("_NET_WM_STATE"), + HYPRATOM("_NET_WM_WINDOW_TYPE"), + HYPRATOM("_NET_WM_WINDOW_TYPE_NORMAL"), + HYPRATOM("_NET_WM_WINDOW_TYPE_DOCK"), + HYPRATOM("_NET_WM_WINDOW_TYPE_DIALOG"), + HYPRATOM("_NET_WM_WINDOW_TYPE_UTILITY"), + HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLBAR"), + HYPRATOM("_NET_WM_WINDOW_TYPE_SPLASH"), + HYPRATOM("_NET_WM_WINDOW_TYPE_MENU"), + HYPRATOM("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"), + HYPRATOM("_NET_WM_WINDOW_TYPE_POPUP_MENU"), + HYPRATOM("_NET_WM_WINDOW_TYPE_TOOLTIP"), + HYPRATOM("_NET_WM_WINDOW_TYPE_NOTIFICATION"), + HYPRATOM("_NET_WM_WINDOW_TYPE_COMBO"), + HYPRATOM("_NET_WM_WINDOW_TYPE_DND"), + HYPRATOM("_NET_WM_WINDOW_TYPE_DESKTOP"), + HYPRATOM("_NET_WM_STATE_MAXIMIZED_HORZ"), + HYPRATOM("_NET_WM_STATE_MAXIMIZED_VERT"), + HYPRATOM("_NET_WM_DESKTOP"), + HYPRATOM("_NET_WM_STRUT_PARTIAL"), + HYPRATOM("_NET_CLIENT_LIST"), + HYPRATOM("_NET_CLIENT_LIST_STACKING"), + HYPRATOM("_NET_CURRENT_DESKTOP"), + HYPRATOM("_NET_NUMBER_OF_DESKTOPS"), + HYPRATOM("_NET_DESKTOP_NAMES"), + HYPRATOM("_NET_DESKTOP_VIEWPORT"), + HYPRATOM("_NET_ACTIVE_WINDOW"), + HYPRATOM("_NET_CLOSE_WINDOW"), + HYPRATOM("_NET_MOVERESIZE_WINDOW"), + HYPRATOM("_NET_WM_USER_TIME"), + HYPRATOM("_NET_STARTUP_ID"), + HYPRATOM("_NET_WORKAREA"), + HYPRATOM("_NET_WM_ICON"), + HYPRATOM("_NET_WM_CM_S0"), + HYPRATOM("WM_PROTOCOLS"), + HYPRATOM("WM_HINTS"), + HYPRATOM("WM_DELETE_WINDOW"), + HYPRATOM("UTF8_STRING"), + HYPRATOM("WM_STATE"), + HYPRATOM("WM_CLIENT_LEADER"), + HYPRATOM("WM_TAKE_FOCUS"), + HYPRATOM("WM_NORMAL_HINTS"), + HYPRATOM("WM_SIZE_HINTS"), + HYPRATOM("WM_WINDOW_ROLE"), + HYPRATOM("_NET_REQUEST_FRAME_EXTENTS"), + HYPRATOM("_NET_FRAME_EXTENTS"), + HYPRATOM("_MOTIF_WM_HINTS"), + HYPRATOM("WM_CHANGE_STATE"), + HYPRATOM("_NET_SYSTEM_TRAY_OPCODE"), + HYPRATOM("_NET_SYSTEM_TRAY_COLORS"), + HYPRATOM("_NET_SYSTEM_TRAY_VISUAL"), + HYPRATOM("_NET_SYSTEM_TRAY_ORIENTATION"), + HYPRATOM("_XEMBED_INFO"), + HYPRATOM("MANAGER"), + HYPRATOM("XdndSelection"), + HYPRATOM("XdndAware"), + HYPRATOM("XdndStatus"), + HYPRATOM("XdndPosition"), + HYPRATOM("XdndEnter"), + HYPRATOM("XdndLeave"), + HYPRATOM("XdndDrop"), + HYPRATOM("XdndFinished"), + HYPRATOM("XdndProxy"), + HYPRATOM("XdndTypeList"), + HYPRATOM("XdndActionMove"), + HYPRATOM("XdndActionCopy"), + HYPRATOM("XdndActionAsk"), + HYPRATOM("XdndActionPrivate"), + HYPRATOM("CLIPBOARD"), + HYPRATOM("PRIMARY"), + HYPRATOM("_WL_SELECTION"), + HYPRATOM("CLIPBOARD_MANAGER"), + HYPRATOM("WINDOW"), + HYPRATOM("WM_S0"), + HYPRATOM("WL_SURFACE_ID"), + HYPRATOM("WL_SURFACE_SERIAL"), + HYPRATOM("TARGETS"), + HYPRATOM("TIMESTAMP"), + HYPRATOM("DELETE"), + HYPRATOM("TEXT"), + HYPRATOM("INCR"), +}; \ No newline at end of file From 553232a3e4c112c8511309e6b685cb614895e714 Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Sat, 25 May 2024 20:46:07 +0000 Subject: [PATCH 0137/2393] hyprctl: Add Config Flag to `hyprctl systeminfo` (#6160) --- .github/ISSUE_TEMPLATE/bug.yml | 8 ++++++-- hyprctl/main.cpp | 2 ++ src/config/ConfigManager.cpp | 19 +++++++++++++++++++ src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 9 +++++++++ src/debug/HyprCtl.hpp | 5 +++-- 6 files changed, 40 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 08a9ad9c..66ce5fa9 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -12,8 +12,12 @@ body: - type: textarea id: ver attributes: - label: Hyprland Version - description: "Paste the output of `hyprctl systeminfo` here." + label: System Info and Version + description: | + Paste the output of `hyprctl systeminfo -c` here (If you are on a + version that shows you help menu, omit the `-c` and attach config files + to the issue). If you have configs outside of the main config shown + here, please attach. value: "
System/Version info diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index e9d7583c..bdf354e7 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -297,6 +297,8 @@ int main(int argc, char** argv) { fullArgs += "r"; } else if (ARGS[i] == "-a" && !fullArgs.contains("a")) { fullArgs += "a"; + } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) { + fullArgs += "c"; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fd70da77..f65b5abb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -633,6 +633,25 @@ std::string CConfigManager::getMainConfigPath() { return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); } +const std::string CConfigManager::getConfigString() { + std::string configString; + std::string currFileContent; + + for (auto path : configPaths) { + std::ifstream configFile(path); + configString += ("\n\nConfig File: " + path + ": "); + if (!configFile.is_open()) { + Debug::log(LOG, "Config file not readable/found!"); + configString += "Read Failed\n"; + continue; + } + configString += "Read Succeeded\n"; + currFileContent.assign(std::istreambuf_iterator(configFile), std::istreambuf_iterator()); + configString.append(currFileContent); + } + return configString; +} + std::string CConfigManager::getErrors() { return m_szConfigErrors; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 45b100ee..ca22904d 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -103,6 +103,7 @@ class CConfigManager { void onPluginLoadUnload(const std::string& name, bool load); static std::string getConfigDir(); static std::string getMainConfigPath(); + const std::string getConfigString(); SMonitorRule getMonitorRuleFor(const CMonitor&); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index dc5fa742..1faea41c 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -23,6 +23,7 @@ #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "config/ConfigManager.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -897,6 +898,12 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } + if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + result += "\n======Config-Start======\n"; + result += g_pConfigManager->getConfigString(); + result += "\n======Config-End========\n"; + } + return result; } @@ -1640,6 +1647,8 @@ std::string CHyprCtl::getReply(std::string request) { reloadAll = true; else if (c == 'a') m_sCurrentRequestParams.all = true; + else if (c == 'c') + m_sCurrentRequestParams.sysInfoConfig = true; } if (sepIndex < request.size()) diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index ebcb87cf..b48ea26a 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -17,7 +17,8 @@ class CHyprCtl { int m_iSocketFD = -1; struct { - bool all = false; + bool all = false; + bool sysInfoConfig = false; } m_sCurrentRequestParams; private: @@ -26,4 +27,4 @@ class CHyprCtl { std::vector> m_vCommands; }; -inline std::unique_ptr g_pHyprCtl; \ No newline at end of file +inline std::unique_ptr g_pHyprCtl; From db5d39a66f1285f78321d953eac398feaedfc63d Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sun, 26 May 2024 20:11:09 +0200 Subject: [PATCH 0138/2393] meson: add more xcb-* dependencies after addd3e7f1aeb ld: error: undefined symbol: xcb_icccm_get_wm_hints_from_reply >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::readProp(CSharedPointer, unsigned int, xcb_get_property_reply_t*)) ld: error: undefined symbol: xcb_icccm_get_wm_size_hints_from_reply >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::readProp(CSharedPointer, unsigned int, xcb_get_property_reply_t*)) ld: error: undefined symbol: xcb_errors_get_name_for_major_code >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::handleError(xcb_value_error_t*)) ld: error: undefined symbol: xcb_errors_get_name_for_minor_code >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::handleError(xcb_value_error_t*)) ld: error: undefined symbol: xcb_errors_get_name_for_error >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::handleError(xcb_value_error_t*)) ld: error: undefined symbol: xcb_xfixes_id >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_composite_id >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_res_id >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_xfixes_query_version >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_xfixes_query_version_reply >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_res_query_version >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_res_query_version_reply >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::gatherResources()) ld: error: undefined symbol: xcb_render_query_pict_formats >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::getRenderFormat()) ld: error: undefined symbol: xcb_render_query_pict_formats_reply >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::getRenderFormat()) ld: error: undefined symbol: xcb_render_query_pict_formats_formats_iterator >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::getRenderFormat()) ld: error: undefined symbol: xcb_render_pictforminfo_next >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::getRenderFormat()) ld: error: undefined symbol: xcb_errors_context_new >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::CXWM()) ld: error: undefined symbol: xcb_composite_redirect_subwindows >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::CXWM()) ld: error: undefined symbol: xcb_xfixes_select_selection_input >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::initSelection()) ld: error: undefined symbol: xcb_render_create_picture >>> referenced by XWM.cpp >>> src/Hyprland.p/xwayland_XWM.cpp.o:(CXWM::setCursor(unsigned char*, unsigned int, Vector2D const&, Vector2D const&)) ld: error: too many errors emitted, stopping now (use --error-limit=0 to see all errors) --- meson.build | 6 ++++++ src/meson.build | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/meson.build b/meson.build index b7b23470..49c48c6c 100644 --- a/meson.build +++ b/meson.build @@ -27,6 +27,12 @@ endif wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2']) have_xwlr = wlroots.get_variable('features').get('xwayland') xcb_dep = dependency('xcb', required: get_option('xwayland')) +xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) +xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) +xcb_icccm_dep = dependency('xcb-icccm', required: get_option('xwayland')) +xcb_render_dep = dependency('xcb-render', required: get_option('xwayland')) +xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) +xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) cmake = import('cmake') udis = cmake.subproject('udis86') diff --git a/src/meson.build b/src/meson.build index 7a00a5ff..ef00d4e0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,12 @@ executable('Hyprland', src, dependency('xkbcommon'), dependency('libinput'), xcb_dep, + xcb_composite_dep, + xcb_errors_dep, + xcb_icccm_dep, + xcb_render_dep, + xcb_res_dep, + xcb_xfixes_dep, backtrace_dep, epoll_dep, udis86, From 546a486bab56af06fd95b23fb2ce231d00f671c9 Mon Sep 17 00:00:00 2001 From: Flafy Date: Mon, 27 May 2024 23:31:35 +0300 Subject: [PATCH 0139/2393] hyprctl: add delimiter to hyprctl batch command (#6261) adds a delimiter of 3 newlines to separate different command outputs --- src/debug/HyprCtl.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 1faea41c..795272cc 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1045,13 +1045,15 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { nextItem(); + const std::string DELIMITER = "\n\n\n"; + while (curitem != "" || request != "") { - reply += g_pHyprCtl->getReply(curitem); + reply += g_pHyprCtl->getReply(curitem) + DELIMITER; nextItem(); } - return reply; + return reply.substr(0, std::max(static_cast(reply.size() - DELIMITER.size()), 0)); } std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) { From 506d0c06e6fb280275311ea4baff8af73a84dbd2 Mon Sep 17 00:00:00 2001 From: AERDU Date: Mon, 27 May 2024 20:45:14 +0000 Subject: [PATCH 0140/2393] compositor: change monitor focus when no_warps is enabled (#6260) fixes focus between monitors when moving using directions with no_warps = true --- src/Compositor.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a14e91fd..254abd92 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2366,8 +2366,12 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { static auto PNOWARPS = CConfigValue("cursor:no_warps"); - if (*PNOWARPS && !force) + if (*PNOWARPS && !force) { + const auto PMONITORNEW = getMonitorFromVector(pos); + if (PMONITORNEW != m_pLastMonitor.get()) + setActiveMonitor(PMONITORNEW); return; + } g_pPointerManager->warpTo(pos); From 722d537a91a9beacf9c12fc1317ff1fbe10ffac5 Mon Sep 17 00:00:00 2001 From: Connor Wong Date: Mon, 27 May 2024 13:45:32 -0700 Subject: [PATCH 0141/2393] windows: make new_window_takes_over_fullscreen use the new window's workspace (#6263) * fix new_window_takes_over_fullscreen behavior * missed a few things --- src/events/Windows.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 9044bc61..5372a105 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -466,12 +466,12 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; - if (PWORKSPACE->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { + if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { if (*PNEWTAKESOVERFS == 0) PWINDOW->m_bNoInitialFocus = true; else if (*PNEWTAKESOVERFS == 2) - g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false, FULLSCREEN_INVALID); - else if (PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) + g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); + else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) requestsMaximize = true; else requestsFullscreen = true; @@ -491,8 +491,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) || (requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) { // fix fullscreen on requested (basically do a switcheroo) - if (PWORKSPACE->m_bHasFullscreenWindow) { - const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) { + const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID); g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL); } From 73b133d0155d376f35833cd992f821399a42f76b Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 28 May 2024 16:35:18 -0500 Subject: [PATCH 0142/2393] hyprctl: Make setcursor better (support XCursor themes, give fail message) (#6097) * add support for changing to X cursor themes * use new hyprcursor abi for options * remove unneeded struct --- src/debug/HyprCtl.cpp | 3 +- src/managers/CursorManager.cpp | 54 ++++++++++++++++++++++++++++------ src/managers/CursorManager.hpp | 2 +- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 795272cc..d1975279 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1074,7 +1074,8 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) if (size <= 0) return "size not positive"; - g_pCursorManager->changeTheme(theme, size); + if (!g_pCursorManager->changeTheme(theme, size)) + return "failed to set cursor"; return "ok"; } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index c9783844..cb43f0b9 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -267,9 +267,6 @@ void CCursorManager::updateTheme() { highestScale = m->scale; } - if (std::round(highestScale * m_iSize) == m_sCurrentStyleInfo.size) - return; - if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid()) m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); @@ -287,13 +284,52 @@ void CCursorManager::updateTheme() { } } -void CCursorManager::changeTheme(const std::string& name, const int size) { - m_pHyprcursor = std::make_unique(name.empty() ? "" : name.c_str(), hcLogger); - m_szTheme = name; - m_iSize = size; +bool CCursorManager::changeTheme(const std::string& name, const int size) { + auto options = Hyprcursor::SManagerOptions(); + options.logFn = hcLogger; + options.allowDefaultFallback = false; - if (!m_pHyprcursor->valid()) - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme); + m_pHyprcursor = std::make_unique(name.empty() ? "" : name.c_str(), options); + if (m_pHyprcursor->valid()) { + m_szTheme = name; + m_iSize = size; + updateTheme(); + return true; + } + + Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); + + if (m_pWLRXCursorMgr) + wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); + + m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size); + bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1; + + // this basically checks if xcursor changed used theme to default but better + bool diffTheme = false; + wlr_xcursor_manager_theme* theme; + wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) { + if (std::string{theme->theme->name} != name) { + diffTheme = true; + break; + } + } + + if (xSuccess && !diffTheme) { + m_szTheme = name; + m_iSize = size; + updateTheme(); + return true; + } + + Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name); + + m_pHyprcursor = std::make_unique(m_szTheme.c_str(), hcLogger); + + wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); + m_pWLRXCursorMgr = wlr_xcursor_manager_create(m_szTheme.c_str(), m_iSize); + wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0); updateTheme(); + return false; } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 4ff9adeb..e76b6829 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -21,7 +21,7 @@ class CCursorManager { void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot); void setXCursor(const std::string& name); - void changeTheme(const std::string& name, const int size); + bool changeTheme(const std::string& name, const int size); void updateTheme(); SCursorImageData dataFor(const std::string& name); // for xwayland void setXWaylandCursor(); From ebf258788e46cd0320fb17138ba413f719180418 Mon Sep 17 00:00:00 2001 From: giskard Date: Wed, 29 May 2024 05:37:24 +0800 Subject: [PATCH 0143/2393] config: add tag dispacther and window rule (#6211) --- hyprctl/hyprctl.usage | 1 + src/config/ConfigManager.cpp | 76 +++++++++++++++++++++++---------- src/debug/HyprCtl.cpp | 25 ++++++++--- src/desktop/Window.cpp | 26 ++++++++--- src/desktop/Window.hpp | 21 ++++++--- src/helpers/TagKeeper.cpp | 40 +++++++++++++++++ src/helpers/TagKeeper.hpp | 18 ++++++++ src/managers/KeybindManager.cpp | 33 ++++++++++---- src/managers/KeybindManager.hpp | 1 + 9 files changed, 190 insertions(+), 51 deletions(-) create mode 100644 src/helpers/TagKeeper.cpp create mode 100644 src/helpers/TagKeeper.hpp diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index 8e75917e..334eefe7 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -117,6 +117,7 @@ hyprctl []... | (movewindowpixel) "Move a selected window" | (cyclenext) "Focus the next window on a workspace" | (swapnext) "Swap the focused window with the next window" + | (tagwindow) "Apply a tag to the window" | (focuswindow) "Focus the first window matching" | (focusmonitor) "Focus a monitor" | (splitratio) "Change the split ratio" diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f65b5abb..b1c5951d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include extern "C" char** environ; @@ -994,7 +995,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); for (auto& r : m_dMonitorRules) { - if (r.name == "") { + if (r.name.empty()) { return r; } } @@ -1080,12 +1081,17 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo bool hasFloating = pWindow->m_bIsFloating; bool hasFullscreen = pWindow->m_bIsFullscreen; + // local tags for dynamic tag rule match + auto tags = pWindow->m_tags; + for (auto& rule : m_dWindowRules) { // check if we have a matching rule if (!rule.v2) { try { + if (rule.szValue.starts_with("tag:") && !tags.isTagged(rule.szValue.substr(4))) + continue; + if (rule.szValue.starts_with("title:")) { - // we have a title rule. std::regex RULECHECK(rule.szValue.substr(6)); if (!std::regex_search(title, RULECHECK)) @@ -1102,28 +1108,31 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo } } else { try { - if (rule.szClass != "") { + if (!rule.szTag.empty() && !tags.isTagged(rule.szTag)) + continue; + + if (!rule.szClass.empty()) { std::regex RULECHECK(rule.szClass); if (!std::regex_search(appidclass, RULECHECK)) continue; } - if (rule.szTitle != "") { + if (!rule.szTitle.empty()) { std::regex RULECHECK(rule.szTitle); if (!std::regex_search(title, RULECHECK)) continue; } - if (rule.szInitialTitle != "") { + if (!rule.szInitialTitle.empty()) { std::regex RULECHECK(rule.szInitialTitle); if (!std::regex_search(pWindow->m_szInitialTitle, RULECHECK)) continue; } - if (rule.szInitialClass != "") { + if (!rule.szInitialClass.empty()) { std::regex RULECHECK(rule.szInitialClass); if (!std::regex_search(pWindow->m_szInitialClass, RULECHECK)) @@ -1192,6 +1201,13 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo returns.push_back(rule); + // apply tag with local tags + if (rule.szRule.starts_with("tag")) { + CVarList vars{rule.szRule, 0, 's', true}; + if (vars.size() == 2 && vars[0] == "tag") + tags.applyTag(vars[1], true); + } + if (dynamic) continue; @@ -1696,7 +1712,7 @@ std::optional CConfigManager::handleMonitor(const std::string& comm newrule.resolution = Vector2D(-1, -2); } else if (parseModeLine(ARGS[1], newrule.drmMode)) { newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay); - newrule.refreshRate = newrule.drmMode.vrefresh / 1000; + newrule.refreshRate = float(newrule.drmMode.vrefresh) / 1000; } else { if (!ARGS[1].contains("x")) { @@ -2023,7 +2039,7 @@ std::optional CConfigManager::handleBind(const std::string& command if ((KEY != "") || multiKey) { SParsedKey parsedKey = parseKey(KEY); - if (parsedKey.catchAll && m_szCurrentSubmap == "") { + if (parsedKey.catchAll && m_szCurrentSubmap.empty()) { Debug::log(ERR, "Catchall not allowed outside of submap!"); return "Invalid catchall, catchall keybinds are only allowed in submaps."; } @@ -2048,18 +2064,24 @@ std::optional CConfigManager::handleUnbind(const std::string& comma } bool windowRuleValid(const std::string& RULE) { - return RULE == "float" || RULE == "tile" || RULE.starts_with("opacity") || RULE.starts_with("move") || RULE.starts_with("size") || RULE.starts_with("minsize") || - RULE.starts_with("maxsize") || RULE.starts_with("pseudo") || RULE.starts_with("monitor") || RULE.starts_with("idleinhibit") || RULE == "nofocus" || RULE == "noblur" || - RULE == "noshadow" || RULE == "nodim" || RULE == "noborder" || RULE == "opaque" || RULE == "forceinput" || RULE == "fullscreen" || RULE == "fakefullscreen" || - RULE == "nomaxsize" || RULE == "pin" || RULE == "noanim" || RULE == "dimaround" || RULE == "windowdance" || RULE == "maximize" || RULE == "keepaspectratio" || - RULE == "focusonactivate" || RULE.starts_with("animation") || RULE.starts_with("rounding") || RULE.starts_with("workspace") || RULE.starts_with("bordercolor") || - RULE == "forcergbx" || RULE == "noinitialfocus" || RULE == "stayfocused" || RULE.starts_with("bordersize") || RULE.starts_with("xray") || RULE.starts_with("center") || - RULE.starts_with("group") || RULE == "immediate" || RULE == "nearestneighbor" || RULE.starts_with("suppressevent") || RULE.starts_with("plugin:"); + static const auto rules = std::unordered_set{ + "dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate", + "keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus", + "noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance", + }; + static const auto rulesPrefix = std::vector{ + "animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", + "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", + }; + + return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); } bool layerRuleValid(const std::string& RULE) { - return RULE == "noanim" || RULE == "blur" || RULE == "blurpopups" || RULE.starts_with("ignorealpha") || RULE.starts_with("ignorezero") || RULE == "dimaround" || - RULE.starts_with("xray") || RULE.starts_with("animation"); + static const auto rules = std::unordered_set{"noanim", "blur", "blurpopups", "dimaround"}; + static const auto rulesPrefix = std::vector{"ignorealpha", "ignorezero", "xray", "animation"}; + + return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); } std::optional CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { @@ -2067,7 +2089,7 @@ std::optional CConfigManager::handleWindowRule(const std::string& c const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); // check rule and value - if (RULE == "" || VALUE == "") + if (RULE.empty() || VALUE.empty()) return "empty rule?"; if (RULE == "unset") { @@ -2094,7 +2116,7 @@ std::optional CConfigManager::handleLayerRule(const std::string& co const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); // check rule and value - if (RULE == "" || VALUE == "") + if (RULE.empty() || VALUE.empty()) return "empty rule?"; if (RULE == "unset") { @@ -2132,6 +2154,7 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& rule.szRule = RULE; rule.szValue = VALUE; + const auto TAGPOS = VALUE.find("tag:"); const auto TITLEPOS = VALUE.find("title:"); const auto CLASSPOS = VALUE.find("class:"); const auto INITIALTITLEPOS = VALUE.find("initialTitle:"); @@ -2154,9 +2177,10 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& currentPos = VALUE.find("workspace:", currentPos + 1); } - if (TITLEPOS == std::string::npos && CLASSPOS == std::string::npos && INITIALTITLEPOS == std::string::npos && INITIALCLASSPOS == std::string::npos && - X11POS == std::string::npos && FLOATPOS == std::string::npos && FULLSCREENPOS == std::string::npos && PINNEDPOS == std::string::npos && WORKSPACEPOS == std::string::npos && - FOCUSPOS == std::string::npos && ONWORKSPACEPOS == std::string::npos) { + const auto checkPos = std::unordered_set{ + TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, PINNEDPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, + }; + if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; } @@ -2166,6 +2190,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& result = VALUE.substr(pos); size_t min = 999999; + if (TAGPOS > pos && TAGPOS < min) + min = TAGPOS; if (TITLEPOS > pos && TITLEPOS < min) min = TITLEPOS; if (CLASSPOS > pos && CLASSPOS < min) @@ -2199,6 +2225,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& return result; }; + if (TAGPOS != std::string::npos) + rule.szTag = extract(TAGPOS + 4); + if (CLASSPOS != std::string::npos) rule.szClass = extract(CLASSPOS + 6); @@ -2237,6 +2266,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (!other.v2) { return other.szClass == rule.szClass && !rule.szClass.empty(); } else { + if (!rule.szTag.empty() && rule.szTag != other.szTag) + return false; + if (!rule.szClass.empty() && rule.szClass != other.szClass) return false; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d1975279..bbe5019a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "../config/ConfigDataValues.hpp" #include "../config/ConfigValue.hpp" @@ -131,10 +132,9 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { continue; result += std::format( - "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\tspecial " - "workspace: {} ({})\n\treserved: {} " - "{} {} {}\n\tscale: {:.2f}\n\ttransform: " - "{}\n\tfocused: {}\n\tdpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), @@ -147,6 +147,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { return result; } +static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) { + const auto tags = w->m_tags.getTags(); + + if (format == eHyprCtlOutputFormat::FORMAT_JSON) + return std::accumulate(tags.begin(), tags.end(), std::string(), + [](const std::string& a, const std::string& b) { return a.empty() ? std::format("\"{}\"", b) : std::format("{}, \"{}\"", a, b); }); + else + return std::accumulate(tags.begin(), tags.end(), std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; }); +} + static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) { const bool isJson = format == eHyprCtlOutputFormat::FORMAT_JSON; if (w->m_sGroupData.pNextWindow.expired()) @@ -205,6 +215,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "fullscreenMode": {}, "fakeFullscreen": {}, "grouped": [{}], + "tags": [{}], "swallowing": "0x{:x}", "focusHistoryID": {} }},)#", @@ -214,18 +225,18 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), - (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } else { return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\txwayland: {}\n\tpinned: " - "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", + "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format), - (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } } diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 093cab5e..60592452 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1,10 +1,12 @@ +#include +#include +#include #include "Window.hpp" #include "../Compositor.hpp" #include "../render/decorations/CHyprDropShadowDecoration.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../render/decorations/CHyprBorderDecoration.hpp" #include "../config/ConfigValue.hpp" -#include #include "../managers/TokenManager.hpp" #include "../protocols/XDGShell.hpp" #include "../xwayland/XWayland.hpp" @@ -619,6 +621,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { m_sAdditionalConfigData.forceTearing = true; } else if (r.szRule == "nearestneighbor") { m_sAdditionalConfigData.nearestNeighbor = true; + } else if (r.szRule.starts_with("tag")) { + CVarList vars{r.szRule, 0, 's', true}; + + if (vars.size() == 2 && vars[0] == "tag") + m_tags.applyTag(vars[1], true); + else + Debug::log(ERR, "Tag rule invalid: {}", r.szRule); } else if (r.szRule.starts_with("rounding")) { try { m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); @@ -800,6 +809,8 @@ void CWindow::updateDynamicRules() { m_sAdditionalConfigData.nearestNeighbor = false; m_eIdleInhibitMode = IDLEINHIBIT_NONE; + m_tags.removeDynamicTags(); + m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock()); for (auto& r : m_vMatchedRules) { applyDynamicRule(r); @@ -1370,6 +1381,7 @@ void CWindow::onUpdateState() { void CWindow::onUpdateMeta() { const auto NEWTITLE = fetchTitle(); + bool doUpdate = false; if (m_szTitle != NEWTITLE) { m_szTitle = NEWTITLE; @@ -1382,11 +1394,8 @@ void CWindow::onUpdateMeta() { EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock()); } - updateDynamicRules(); - g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock()); - updateToplevel(); - Debug::log(LOG, "Window {:x} set title to {}", (uintptr_t)this, m_szTitle); + doUpdate = true; } const auto NEWCLASS = fetchClass(); @@ -1399,11 +1408,14 @@ void CWindow::onUpdateMeta() { EMIT_HOOK_EVENT("activeWindow", m_pSelf.lock()); } + Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass); + doUpdate = true; + } + + if (doUpdate) { updateDynamicRules(); g_pCompositor->updateWindowAnimatedDecorationValues(m_pSelf.lock()); updateToplevel(); - - Debug::log(LOG, "Window {:x} set class to {}", (uintptr_t)this, m_szClass); } } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 473ce361..d4e26d5d 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -1,18 +1,21 @@ #pragma once -#include "../defines.hpp" -#include "Subsurface.hpp" -#include "../helpers/AnimatedVariable.hpp" -#include "../render/decorations/IHyprWindowDecoration.hpp" #include +#include + #include "../config/ConfigDataValues.hpp" +#include "../defines.hpp" +#include "../helpers/AnimatedVariable.hpp" #include "../helpers/Vector2D.hpp" -#include "WLSurface.hpp" -#include "Popup.hpp" +#include "../helpers/signal/Signal.hpp" +#include "../helpers/TagKeeper.hpp" #include "../macros.hpp" #include "../managers/XWaylandManager.hpp" +#include "../render/decorations/IHyprWindowDecoration.hpp" #include "DesktopTypes.hpp" -#include "../helpers/signal/Signal.hpp" +#include "Popup.hpp" +#include "Subsurface.hpp" +#include "WLSurface.hpp" class CXDGSurfaceResource; class CXWaylandSurface; @@ -183,6 +186,7 @@ struct SWindowRule { std::string szClass; std::string szInitialTitle; std::string szInitialClass; + std::string szTag; int bX11 = -1; // -1 means "ANY" int bFloating = -1; int bFullscreen = -1; @@ -365,6 +369,9 @@ class CWindow { // stores the currently matched window rules std::vector m_vMatchedRules; + // window tags + CTagKeeper m_tags; + // For the list lookup bool operator==(const CWindow& rhs) { return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && diff --git a/src/helpers/TagKeeper.cpp b/src/helpers/TagKeeper.cpp new file mode 100644 index 00000000..f960accb --- /dev/null +++ b/src/helpers/TagKeeper.cpp @@ -0,0 +1,40 @@ +#include "TagKeeper.hpp" + +bool CTagKeeper::isTagged(const std::string& tag, bool strict) { + return m_tags.contains(tag) || (!strict && m_tags.contains(tag + "*")); +} + +bool CTagKeeper::applyTag(const std::string& tag, bool dynamic) { + + std::string tagReal = tag; + + if (dynamic && !tag.ends_with("*")) + tagReal += "*"; + + bool changed = true; + bool setTag = true; + + if (tagReal.starts_with("-")) { // unset + tagReal = tagReal.substr(1); + changed = isTagged(tagReal, true); + setTag = false; + } else if (tagReal.starts_with("+")) { // set + tagReal = tagReal.substr(1); + changed = !isTagged(tagReal, true); + } else // toggle if without prefix + setTag = !isTagged(tagReal, true); + + if (!changed) + return false; + + if (setTag) + m_tags.emplace(tagReal); + else + m_tags.erase(tagReal); + + return true; +} + +bool CTagKeeper::removeDynamicTags() { + return std::erase_if(m_tags, [](const auto& tag) { return tag.ends_with("*"); }); +} diff --git a/src/helpers/TagKeeper.hpp b/src/helpers/TagKeeper.hpp new file mode 100644 index 00000000..deeabf48 --- /dev/null +++ b/src/helpers/TagKeeper.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +class CTagKeeper { + public: + bool isTagged(const std::string& tag, bool strict = false); + bool applyTag(const std::string& tag, bool dynamic = false); + bool removeDynamicTags(); + + inline const auto& getTags() { + return m_tags; + }; + + private: + std::set m_tags; +}; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 41b82d10..4f89315d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1,17 +1,16 @@ -#include "KeybindManager.hpp" -#include "../render/decorations/CHyprGroupBarDecoration.hpp" -#include "debug/Log.hpp" -#include "helpers/VarList.hpp" #include "../config/ConfigValue.hpp" -#include "TokenManager.hpp" -#include "../protocols/ShortcutsInhibit.hpp" #include "../devices/IKeyboard.hpp" #include "../managers/SeatManager.hpp" +#include "../protocols/ShortcutsInhibit.hpp" +#include "../render/decorations/CHyprGroupBarDecoration.hpp" +#include "KeybindManager.hpp" +#include "TokenManager.hpp" +#include "debug/Log.hpp" +#include "helpers/VarList.hpp" #include -#include #include -#include +#include #include #include @@ -87,6 +86,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["cyclenext"] = circleNext; m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["focuswindow"] = focusWindow; + m_mDispatchers["tagwindow"] = tagWindow; m_mDispatchers["submap"] = setSubmap; m_mDispatchers["pass"] = pass; m_mDispatchers["sendshortcut"] = sendshortcut; @@ -1928,6 +1928,23 @@ void CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->warpCursorTo(PWINDOW->middle()); } +void CKeybindManager::tagWindow(std::string args) { + PHLWINDOW PWINDOW = nullptr; + CVarList vars{args, 0, 's', true}; + + if (vars.size() == 1) + PWINDOW = g_pCompositor->m_pLastWindow.lock(); + else if (vars.size() == 2) + PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); + else + return; + + if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { + PWINDOW->updateDynamicRules(); + g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock()); + } +} + void CKeybindManager::setSubmap(std::string submap) { if (submap == "reset" || submap == "") { m_szCurrentSelectedSubmap = ""; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index a5499987..305e563f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -181,6 +181,7 @@ class CKeybindManager { static void resizeWindow(std::string); static void circleNext(std::string); static void focusWindow(std::string); + static void tagWindow(std::string); static void setSubmap(std::string); static void pass(std::string); static void sendshortcut(std::string); From a60c7283e677ed81a466d1c0c864c8a05e192cac Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 29 May 2024 09:34:18 +0200 Subject: [PATCH 0144/2393] xwayland: verify new xsurf is valid in prop reads fixes #6250 --- src/xwayland/XWM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 9e308314..b0f8d6aa 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -210,7 +210,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ const auto XID = (xcb_window_t*)xcb_get_property_value(reply); XSURF->transient = XID; if (XID) { - if (const auto NEWXSURF = windowForXID(*XID); !lookupParentExists(XSURF, NEWXSURF)) { + if (const auto NEWXSURF = windowForXID(*XID); NEWXSURF && !lookupParentExists(XSURF, NEWXSURF)) { XSURF->parent = NEWXSURF; NEWXSURF->children.push_back(XSURF); } else From df6ebe358b30ee7b49f296e05763e5e4b0edce98 Mon Sep 17 00:00:00 2001 From: obivan Date: Fri, 31 May 2024 10:38:52 +0000 Subject: [PATCH 0145/2393] pointer: Include monitor scaling in HW hotspot calculation (#6283) --- src/managers/PointerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 7df2d6f4..66d12076 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -564,7 +564,7 @@ Vector2D CPointerManager::transformedHotspot(SP pMonitor) { if (!pMonitor->output->cursor_swapchain) return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors - return CBox{currentCursorImage.hotspot, {0, 0}} + return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}} .transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) .pos(); } From a54ab301602e205f273969c093cf494d38ba4a98 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 31 May 2024 22:07:00 +0200 Subject: [PATCH 0146/2393] cmake: make xcb-errors required fixes #6290 --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e780ac0..e42a530a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,12 +192,8 @@ if(NO_XWAYLAND) add_compile_definitions(NO_XWAYLAND) else() message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") - pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh) - pkg_check_modules(xcb_errors IMPORTED_TARGET xcb-errors) + pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors) target_link_libraries(Hyprland PkgConfig::xdeps) - if(xcb_errors_FOUND) - target_link_libraries(Hyprland PkgConfig::xcb_errors) - endif() endif() if(NO_SYSTEMD) From 0ebb43c1a37e7321e5ed7223ea85ed555cc82735 Mon Sep 17 00:00:00 2001 From: shezdy <77217897+shezdy@users.noreply.github.com> Date: Sat, 1 Jun 2024 12:45:30 -0600 Subject: [PATCH 0147/2393] renderer: fix xwayland solitary rechecks (#6295) --- src/desktop/Window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 60592452..32f4d882 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1139,8 +1139,8 @@ bool CWindow::opaque() { if (PWORKSPACE->m_fAlpha.value() != 1.f) return false; - if (m_bIsX11) - return false; + if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface) + return m_pXWaylandSurface->surface->opaque; if (m_pXDGSurface && m_pXDGSurface->surface->opaque) return true; From 66acdfe2ad68527cc57f967ce9a05704cc0657e3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 2 Jun 2024 18:38:36 +0200 Subject: [PATCH 0148/2393] seat: don't send keymap on empty device --- src/protocols/core/Seat.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 489fced7..9d5cf496 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -213,6 +213,9 @@ bool CWLKeyboardResource::good() { } void CWLKeyboardResource::sendKeymap(SP keyboard) { + if (!keyboard) + return; + wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; int fd; uint32_t size; From e08195d240f54049745c503ba736cf99a9c09b25 Mon Sep 17 00:00:00 2001 From: "wouter@wouterbijlsma.nl" Date: Sun, 2 Jun 2024 15:14:20 +0200 Subject: [PATCH 0149/2393] Fix initial xdg-decoration toplevel decoration mode negotiation Clients using zxdg_decoration_manager_v1::get_toplevel_decoration may expect a receiving a zxdg_toplevel_decoration_v1::configure event to determine the initial decoration mode, without having to go through a zxdg_toplevel_decoration_v1::set_mode request. Hyprland was not sending this event, resulting in unwanted decorations being drawn. Specifically, clients using libdecor, e.g. applications using recent GLFW, would draw GTK decorations with artefacts. This change fixes these. --- src/protocols/XDGDecoration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index 5a4cf68d..021a1141 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -26,6 +26,8 @@ CXDGDecoration::CXDGDecoration(SP resource_, wl_resou LOGM(LOG, "unsetMode. Sending MODE_SERVER_SIDE."); resource->sendConfigure(ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); }); + + resource->sendConfigure(ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } bool CXDGDecoration::good() { From eaecf7db14cff793e46c432edf68fef58b43373b Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 2 Jun 2024 18:42:54 +0200 Subject: [PATCH 0150/2393] core: fix a few asan reported issues and a coredump on exit (#6285) * xwayland: add destructor to CXWM and free resource the wl_event_resource was running upon destruction of the compositor causing a null pointer segfault in onX11Event so ensure the event is removed upon destruction, also free the memory allocated by xcb_errors_context_new and finally call xcb_disconnect on the connection to free the fd and its memory. * hyprctl: dont leak the fd on destruction add a destructor and properly free the fd on destruction * eventloop: add destructor and free event source properly free the wl_event_source upon destruction. --- src/debug/HyprCtl.cpp | 7 ++++++- src/debug/HyprCtl.hpp | 2 ++ src/managers/eventLoop/EventLoopManager.cpp | 7 ++++++- src/managers/eventLoop/EventLoopManager.hpp | 6 ++++-- src/xwayland/XWM.cpp | 11 +++++++++++ src/xwayland/XWM.hpp | 1 + 6 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index bbe5019a..4563c5a1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1625,6 +1625,11 @@ CHyprCtl::CHyprCtl() { startHyprCtlSocket(); } +CHyprCtl::~CHyprCtl() { + if (m_eventSource) + wl_event_source_remove(m_eventSource); +} + SP CHyprCtl::registerCommand(SHyprCtlCommand cmd) { return m_vCommands.emplace_back(makeShared(cmd)); } @@ -1805,5 +1810,5 @@ void CHyprCtl::startHyprCtlSocket() { Debug::log(LOG, "Hypr socket started at {}", socketPath); - wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); + m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index b48ea26a..21a2c5f8 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -8,6 +8,7 @@ class CHyprCtl { public: CHyprCtl(); + ~CHyprCtl(); std::string makeDynamicCall(const std::string& input); SP registerCommand(SHyprCtlCommand cmd); @@ -25,6 +26,7 @@ class CHyprCtl { void startHyprCtlSocket(); std::vector> m_vCommands; + wl_event_source* m_eventSource = nullptr; }; inline std::unique_ptr g_pHyprCtl; diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 5910e71a..1193ffb8 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -13,6 +13,11 @@ CEventLoopManager::CEventLoopManager() { m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); } +CEventLoopManager::~CEventLoopManager() { + if (m_sWayland.eventSource) + wl_event_source_remove(m_sWayland.eventSource); +} + static int timerWrite(int fd, uint32_t mask, void* data) { g_pEventLoopManager->onTimerFire(); return 1; @@ -22,7 +27,7 @@ void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoo m_sWayland.loop = wlEventLoop; m_sWayland.display = display; - wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + m_sWayland.eventSource = wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); wl_display_run(display); diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index f2ba61a4..7a4fa19e 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -10,6 +10,7 @@ class CEventLoopManager { public: CEventLoopManager(); + ~CEventLoopManager(); void enterLoop(wl_display* display, wl_event_loop* wlEventLoop); @@ -24,8 +25,9 @@ class CEventLoopManager { private: struct { - wl_event_loop* loop = nullptr; - wl_display* display = nullptr; + wl_event_loop* loop = nullptr; + wl_display* display = nullptr; + wl_event_source* eventSource = nullptr; } m_sWayland; struct { diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b0f8d6aa..5dfd4839 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -837,6 +837,17 @@ CXWM::CXWM() { xcb_flush(connection); } +CXWM::~CXWM() { + if (errors) + xcb_errors_context_free(errors); + + if (connection) + xcb_disconnect(connection); + + if (eventSource) + wl_event_source_remove(eventSource); +} + void CXWM::setActiveWindow(xcb_window_t window) { xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_ACTIVE_WINDOW"], HYPRATOMS["WINDOW"], 32, 1, &window); } diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index b312f4a9..1d695a15 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -60,6 +60,7 @@ struct SXSelection { class CXWM { public: CXWM(); + ~CXWM(); int onEvent(int fd, uint32_t mask); From 3fd6c1b30e5397432c4640286efaf52a6891f71c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 2 Jun 2024 23:05:02 +0200 Subject: [PATCH 0151/2393] layout: fix centering of new floating windows ref #6154 --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 108f9039..7fadf188 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -147,7 +147,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() + pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F; else - pWindow->m_vRealPosition = PMONITOR->vecPosition + desiredGeometry.size() / 2.F; + pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F; } else { // if it is, we respect where it wants to put itself, but apply monitor offset if outside // most of these are popups From b30c7125d73f26b5919293e6743768d5f13cedc2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Jun 2024 21:09:18 +0200 Subject: [PATCH 0152/2393] window: avoid nullptr deref on monitor in box helpers fixes #6321 --- src/desktop/Window.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 32f4d882..9f5f9dd3 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -176,11 +176,13 @@ CBox CWindow::getFullWindowBoundingBox() { } CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - auto POS = m_vPosition; - auto SIZE = m_vSize; + if (!PMONITOR) + return {m_vPosition, m_vSize}; + + auto POS = m_vPosition; + auto SIZE = m_vSize; if (m_bIsFullscreen) { POS = PMONITOR->vecPosition; @@ -208,10 +210,10 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { } CBox CWindow::getWindowBoxUnified(uint64_t properties) { - if (m_sAdditionalConfigData.dimAround) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + if (PMONITOR) + return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}}; From 0ac0f32671b949b7bde276f1175bed035fb09fd9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Jun 2024 21:10:31 +0200 Subject: [PATCH 0153/2393] toplevelexport: avoid locking software cursors during render this may trigger a render begin/end and fuck up the pass fixes #6277 --- src/protocols/ToplevelExport.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index d3b71a9e..14629214 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -378,16 +378,16 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times CFramebuffer outFB; outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat); - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) { - wlr_buffer_end_data_ptr_access(frame->buffer); - return false; - } - if (frame->overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); g_pPointerManager->damageCursor(PMONITOR->self.lock()); } + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) { + wlr_buffer_end_data_ptr_access(frame->buffer); + return false; + } + g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); // render client at 0,0 From 5517cc506b2754cb2485b1bf3e46918ee638ea6d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Jun 2024 21:13:38 +0200 Subject: [PATCH 0154/2393] xwayland: don't destroy server client this potentially leaks, but avoids a UAF ref #6323 --- src/xwayland/Server.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 510ad737..26010cfb 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -262,8 +262,9 @@ void CXWaylandServer::die() { if (xwmFDs[1]) close(xwmFDs[1]); - if (xwaylandClient) - wl_client_destroy(xwaylandClient); + // possible crash. Better to leak a bit. + //if (xwaylandClient) + // wl_client_destroy(xwaylandClient); xwaylandClient = nullptr; waylandFDs = {-1, -1}; From d0a224a4915b5a90555818ed3f9e49e1a61b7cdb Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:47:02 -0400 Subject: [PATCH 0155/2393] seat: discrete round away from zero + high res scrolling (#6317) * Discrete scrolling round away from zero e.deltaDiscrete can be multiples of 30 instead of the usual 120 causing the rounded value to be 0 when too small causing erratic scrolling. * Send value120 alongside discrete Fixes sensitivity issues for clients that support value120 axis events --- src/managers/SeatManager.cpp | 6 ++++-- src/managers/SeatManager.hpp | 4 +++- src/managers/input/InputManager.cpp | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index ce40650d..5fa3d1ae 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -290,7 +290,7 @@ void CSeatManager::sendPointerFrame(WP pResource) { } } -void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, +void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative) { if (!state.pointerFocusResource) return; @@ -303,8 +303,10 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double p->sendAxisSource(source); p->sendAxisRelativeDirection(axis, relative); - if (source == 0) + if (source == 0) { + p->sendAxisValue120(axis, value120); p->sendAxisDiscrete(axis, discrete); + } if (value == 0) p->sendAxisStop(timeMs, axis); diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index b88058a8..35456cb3 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "../helpers/WLListener.hpp" #include "../macros.hpp" @@ -65,7 +66,8 @@ class CSeatManager { void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state); void sendPointerFrame(); void sendPointerFrame(WP pResource); - void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative); + void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source, + wl_pointer_axis_relative_direction relative); void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local); void sendTouchUp(uint32_t timeMs, int32_t id); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 5a7688cd..27d04699 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1,6 +1,7 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" #include "wlr/types/wlr_switch.h" +#include #include #include "../../config/ConfigValue.hpp" #include "../../desktop/Window.hpp" @@ -782,8 +783,9 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { } } } - - g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete / 120), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + double deltaDiscrete = factor * e.deltaDiscrete / std::abs(e.deltaDiscrete); + g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete), + std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { From 098ac916a6314a2b731532e0c85f357e3cf90d2f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 4 Jun 2024 15:57:39 +0200 Subject: [PATCH 0156/2393] deps: update wlroots closes #6328 --- subprojects/wlroots-hyprland | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland index a336b9b1..91de8da4 160000 --- a/subprojects/wlroots-hyprland +++ b/subprojects/wlroots-hyprland @@ -1 +1 @@ -Subproject commit a336b9b1fb415433e849de002df68c45034d0419 +Subproject commit 91de8da4b6b9b3c5630123d2446cd6de4e80071a From fefa55d406e38eda481ce75178cef3e43298762d Mon Sep 17 00:00:00 2001 From: memchr <118117622+memchr@users.noreply.github.com> Date: Wed, 5 Jun 2024 08:42:44 +0000 Subject: [PATCH 0157/2393] build: fix non-pch build (#6337) --- src/managers/KeybindManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4f89315d..905a9d48 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -9,6 +9,7 @@ #include "helpers/VarList.hpp" #include +#include #include #include From 155fe6f165f70ea69a44cbd6989fc01a473e6946 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 5 Jun 2024 16:53:06 +0200 Subject: [PATCH 0158/2393] popup: minor safety improvements --- src/desktop/Popup.cpp | 23 ++++++++++++++++++++--- src/desktop/Popup.hpp | 3 ++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 03acfff9..d42a0ef0 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -45,7 +45,7 @@ void CPopup::initAllSignals() { listeners.reposition = m_pResource->events.reposition.registerListener([this](std::any d) { this->onReposition(); }); listeners.map = m_pResource->surface->events.map.registerListener([this](std::any d) { this->onMap(); }); listeners.unmap = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); - listeners.dismissed = m_pResource->surface->events.unmap.registerListener([this](std::any d) { this->onUnmap(); }); + listeners.dismissed = m_pResource->events.dismissed.registerListener([this](std::any d) { this->onUnmap(); }); listeners.destroy = m_pResource->surface->events.destroy.registerListener([this](std::any d) { this->onDestroy(); }); listeners.commit = m_pResource->surface->events.commit.registerListener([this](std::any d) { this->onCommit(); }); listeners.newPopup = m_pResource->surface->events.newPopup.registerListener([this](std::any d) { this->onNewPopup(std::any_cast>(d)); }); @@ -66,6 +66,10 @@ void CPopup::onDestroy() { } void CPopup::onMap() { + if (m_bMapped) + return; + + m_bMapped = true; m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; const auto COORDS = coordsGlobal(); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); @@ -90,8 +94,15 @@ void CPopup::onMap() { } void CPopup::onUnmap() { - if (!m_pResource || !m_pResource->surface) + if (!m_bMapped) return; + + if (!m_pResource || !m_pResource->surface) { + Debug::log(ERR, "CPopup: orphaned (no surface/resource) and unmaps??"); + onDestroy(); + return; + } + m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; const auto COORDS = coordsGlobal(); @@ -109,7 +120,7 @@ void CPopup::onUnmap() { // damage all children breadthfirst( - [this](CPopup* p, void* data) { + [](CPopup* p, void* data) { if (!p->m_pResource) return; @@ -120,6 +131,12 @@ void CPopup::onUnmap() { } void CPopup::onCommit(bool ignoreSiblings) { + if (!m_pResource || !m_pResource->surface) { + Debug::log(ERR, "CPopup: orphaned (no surface/resource) and commits??"); + onDestroy(); + return; + } + if (m_pResource->surface->initialCommit) { m_pResource->surface->scheduleConfigure(); return; diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index ba6da55a..7fdabee6 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -56,7 +56,8 @@ class CPopup { bool m_bRequestedReposition = false; - bool m_bInert = false; + bool m_bInert = false; + bool m_bMapped = false; // std::vector> m_vChildren; From 82099fd1c0ab5b0bee022a45949556e7e1084835 Mon Sep 17 00:00:00 2001 From: phonetic112 <73647246+phonetic112@users.noreply.github.com> Date: Wed, 5 Jun 2024 12:26:38 -0400 Subject: [PATCH 0159/2393] hyprctl: Allow setting name for custom/headless outputs (#6319) --- src/debug/HyprCtl.cpp | 93 +++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 4563c5a1..bdb12e58 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1374,73 +1374,64 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) return result; } -void createOutputIter(wlr_backend* backend, void* data) { - const auto DATA = (std::pair*)data; +static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) { + wlr_output* output = nullptr; - if (DATA->second) + if (type.empty() || type == "auto") { + if (wlr_backend_is_wl(backend)) + output = wlr_wl_output_create(backend); + else if (wlr_backend_is_headless(backend)) + output = wlr_headless_add_output(backend, 1920, 1080); + } else { + if (wlr_backend_is_wl(backend) && type == "wayland") + output = wlr_wl_output_create(backend); + else if (wlr_backend_is_headless(backend) && type == "headless") + output = wlr_headless_add_output(backend, 1920, 1080); + } + + if (output && !name.empty()) + g_pCompositor->getMonitorFromOutput(output)->szName = name; + + return output != nullptr; +} + +struct outputData { + std::string type; + std::string name; + bool added; +}; + +void createOutputIter(wlr_backend* backend, void* data) { + const auto DATA = static_cast(data); + + if (DATA->added) return; - if (DATA->first.empty() || DATA->first == "auto") { - if (wlr_backend_is_wl(backend)) { - wlr_wl_output_create(backend); - DATA->second = true; - } else if (wlr_backend_is_x11(backend)) { - wlr_x11_output_create(backend); - DATA->second = true; - } else if (wlr_backend_is_headless(backend)) { - wlr_headless_add_output(backend, 1920, 1080); - DATA->second = true; - } - } else { - if (wlr_backend_is_wl(backend) && DATA->first == "wayland") { - wlr_wl_output_create(backend); - DATA->second = true; - } else if (wlr_backend_is_x11(backend) && DATA->first == "x11") { - wlr_x11_output_create(backend); - DATA->second = true; - } else if (wlr_backend_is_headless(backend) && DATA->first == "headless") { - wlr_headless_add_output(backend, 1920, 1080); - DATA->second = true; - } - } + if (addOutput(backend, DATA->type, DATA->name)) + DATA->added = true; } std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { - std::string curitem = ""; + CVarList vars(request, 0, ' '); - auto nextItem = [&]() { - auto idx = request.find_first_of(' '); + if (vars.size() < 2) + return "not enough args"; - if (idx != std::string::npos) { - curitem = request.substr(0, idx); - request = request.substr(idx + 1); - } else { - curitem = request; - request = ""; - } - - curitem = removeBeginEndSpacesTabs(curitem); - }; - - nextItem(); - nextItem(); - - const auto MODE = curitem; - - nextItem(); - - const auto NAME = curitem; + const auto MODE = vars[1]; if (MODE == "create" || MODE == "add") { - std::pair result = {NAME, false}; + if (g_pCompositor->getMonitorFromName(vars[3])) + return "A real monitor already uses that name."; + + outputData result{vars[2], vars[3], false}; wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result); - if (!result.second) + if (!result.added) return "no backend replied to the request"; } else if (MODE == "destroy" || MODE == "remove") { - const auto PMONITOR = g_pCompositor->getMonitorFromName(NAME); + const auto PMONITOR = g_pCompositor->getMonitorFromName(vars[2]); if (!PMONITOR) return "output not found"; From c95845b1488b4bd63e901cbdc4cb68c27a45971b Mon Sep 17 00:00:00 2001 From: giskard Date: Thu, 6 Jun 2024 00:30:46 +0800 Subject: [PATCH 0160/2393] log: log with local timezone (#6331) * log: log with local timezone * log: backward compatability for clang 17 with libc++ --- src/debug/Log.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index abf74065..e8cd80cf 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -49,11 +49,13 @@ namespace Debug { // print date and time to the ofs if (disableTime && !**disableTime) { #ifndef _LIBCPP_VERSION - logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}); + const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}; + const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; #else - auto c = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}; - logMsg += std::format("{:%H}:{:%M}:{:%S}", c.hours(), c.minutes(), c.subseconds()); + // TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready + const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}; #endif + logMsg += std::format("[{}] ", hms); } // no need for try {} catch {} because std::format_string ensures that vformat never throw std::format_error From af5f24929d83cc7a97a77de516bc665e38acfa12 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 6 Jun 2024 20:27:09 +0200 Subject: [PATCH 0161/2393] core: free more memory on destruction (#6348) * pointermgr: add destructor to state and free buf if the pointer has a buffer set it wont be freed upon destruction, make asan more happy by adding a destructor and wlr_buf_unlock it on exit. * cursormgr: free the animation timer event source properly free the animation timer event source on destruction. * compositor: free the critsig event source on exit properly free the critical signal event source on exit. * popup: clang format style clang format. --- src/Compositor.cpp | 5 ++++- src/Compositor.hpp | 15 ++++++++------- src/desktop/Popup.cpp | 2 +- src/managers/CursorManager.cpp | 3 +++ src/managers/PointerManager.hpp | 5 +++++ 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 254abd92..73708b1b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -147,7 +147,7 @@ void CCompositor::initServer() { m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay); // register crit signal handler - wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr); + m_critSigSource = wl_event_loop_add_signal(m_sWLEventLoop, SIGTERM, handleCritSignal, nullptr); if (!envEnabled("HYPRLAND_NO_CRASHREPORTER")) { signal(SIGSEGV, handleUnrecoverableSignal); @@ -373,6 +373,9 @@ void CCompositor::cleanup() { if (m_sWLRBackend) wlr_backend_destroy(m_sWLRBackend); + if (m_critSigSource) + wl_event_source_remove(m_critSigSource); + wl_display_terminate(m_sWLDisplay); m_sWLDisplay = nullptr; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 94d9e4d0..a297518d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -178,14 +178,15 @@ class CCompositor { std::string explicitConfigPath; private: - void initAllSignals(); - void removeAllSignals(); - void cleanEnvironment(); - void setRandomSplash(); - void initManagers(eManagersInitStage stage); - void prepareFallbackOutput(); + void initAllSignals(); + void removeAllSignals(); + void cleanEnvironment(); + void setRandomSplash(); + void initManagers(eManagersInitStage stage); + void prepareFallbackOutput(); - uint64_t m_iHyprlandPID = 0; + uint64_t m_iHyprlandPID = 0; + wl_event_source* m_critSigSource = nullptr; }; inline std::unique_ptr g_pCompositor; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index d42a0ef0..6bc76fc7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -136,7 +136,7 @@ void CPopup::onCommit(bool ignoreSiblings) { onDestroy(); return; } - + if (m_pResource->surface->initialCommit) { m_pResource->surface->scheduleConfigure(); return; diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index cb43f0b9..e3ebce80 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -58,6 +58,9 @@ CCursorManager::CCursorManager() { CCursorManager::~CCursorManager() { if (m_pWLRXCursorMgr) wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); + + if (m_pAnimationTimer) + wl_event_source_remove(m_pAnimationTimer); } void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index b6cb0c7a..db9f27e7 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -146,6 +146,11 @@ class CPointerManager { struct SMonitorPointerState { SMonitorPointerState(SP m) : monitor(m) {} + ~SMonitorPointerState() { + if (cursorFrontBuffer) + wlr_buffer_unlock(cursorFrontBuffer); + } + WP monitor; int softwareLocks = 0; From 429cff340de68b3bfa4790062734c23fcbf26088 Mon Sep 17 00:00:00 2001 From: "John M. Harris, Jr" Date: Fri, 7 Jun 2024 09:31:27 -0700 Subject: [PATCH 0162/2393] hookSystem: Make needsDeadCleanup volatile (#6356) The value of needsDeadCleanup would be clobbered after longjmp, having an undefined value. --- src/managers/HookSystemManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/HookSystemManager.cpp b/src/managers/HookSystemManager.cpp index a1920863..208c79ae 100644 --- a/src/managers/HookSystemManager.cpp +++ b/src/managers/HookSystemManager.cpp @@ -28,7 +28,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal return; std::vector faultyHandles; - bool needsDeadCleanup = false; + volatile bool needsDeadCleanup = false; for (auto& cb : *callbacks) { @@ -80,4 +80,4 @@ std::vector* CHookSystemManager::getVecForEvent(const std::strin Debug::log(LOG, "[hookSystem] New hook event registered: {}", event); return &m_mRegisteredHooks[event]; -} \ No newline at end of file +} From d6337146bb99a20c96c89b7693f4ad726455f6ba Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 7 Jun 2024 18:42:31 +0200 Subject: [PATCH 0163/2393] xdg_shell: improve xdg_positioner resize calculations ref #6240 --- src/protocols/XDGShell.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index cbb93de9..b192b43c 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -528,7 +528,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa bool success = predictedBox.inside(constraint); if (success) - return predictedBox.translate(-parentCoord - constraint.pos()); + return predictedBox; if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) { // attempt to flip @@ -547,7 +547,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa success = false; if (success) - return test.translate(-parentCoord - constraint.pos()); + return test; } // if flips fail, we will slide and remember. @@ -584,7 +584,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa success = test.copy().expand(-1).inside(constraint); if (success) - return test.translate(-parentCoord - constraint.pos()); + return test; } if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) { @@ -602,18 +602,18 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa test.x = constraint.x + EDGE_PADDING; } if (rightEdgeOut && resizeX) - test.w = -(constraint.w + constraint.x - test.w - test.x + EDGE_PADDING); + test.w = constraint.w - (test.x - constraint.w) - EDGE_PADDING; if (topEdgeOut && resizeY) { test.h = test.y + test.h - constraint.y - EDGE_PADDING; test.y = constraint.y + EDGE_PADDING; } if (bottomEdgeOut && resizeY) - test.h = -(constraint.h + constraint.y - test.h - test.y + EDGE_PADDING); + test.h = constraint.h - (test.y - constraint.y) - EDGE_PADDING; success = test.copy().expand(-1).inside(constraint); if (success) - return test.translate(parentCoord - constraint.pos()); + return test; } LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); From 9bc00897fcc896c49a83f55da9de2427e878401a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 7 Jun 2024 19:46:24 +0200 Subject: [PATCH 0164/2393] xdg_shell: improve xdg_positioner slide behavior ref #6240 --- src/protocols/XDGShell.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index b192b43c..23148fab 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -575,11 +575,11 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa if (leftEdgeOut && slideX) test.x = constraint.x + EDGE_PADDING; if (rightEdgeOut && slideX) - test.x = constraint.x + constraint.w - predictedBox.w - EDGE_PADDING; + test.x = std::clamp((double)(constraint.x + constraint.w - test.w), (double)(constraint.x + EDGE_PADDING), (double)INFINITY); if (topEdgeOut && slideY) test.y = constraint.y + EDGE_PADDING; if (bottomEdgeOut && slideY) - test.y = constraint.y + constraint.h - predictedBox.y - EDGE_PADDING; + test.y = std::clamp((double)(constraint.y + constraint.h - test.h), (double)(constraint.y + EDGE_PADDING), (double)INFINITY); success = test.copy().expand(-1).inside(constraint); From 41e1147dfc3319ccac0ed11bbbe8f3c77f8b635f Mon Sep 17 00:00:00 2001 From: memchr <118117622+memchr@users.noreply.github.com> Date: Fri, 7 Jun 2024 17:52:15 +0000 Subject: [PATCH 0165/2393] input: add cursor:persistent_warps to maintain relative position within a window (#6338) Allows the cursor to return to its last relative position within a window when the window is refocused. Allows the cursor to retain its relative position within a window when the window is swapped, moved, changed workspace, added to or removed from groups. controlled with cursor:persistent_warps --- src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 13 ++++++++- src/desktop/Window.hpp | 8 ++++-- src/managers/KeybindManager.cpp | 49 +++++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b1c5951d..6db920ea 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -521,6 +521,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY}); m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 9f5f9dd3..c478b766 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1356,7 +1356,7 @@ void CWindow::activate(bool force) { g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); g_pCompositor->focusWindow(m_pSelf.lock()); - g_pCompositor->warpCursorTo(middle()); + warpCursor(); } void CWindow::onUpdateState() { @@ -1530,3 +1530,14 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); } + +void CWindow::warpCursor() { + static auto PERSISTENTWARPS = CConfigValue("cursor:persistent_warps"); + const auto coords = m_vRelativeCursorCoordsOnLastWarp; + m_vRelativeCursorCoordsOnLastWarp.x = -1; // reset m_vRelativeCursorCoordsOnLastWarp + + if (*PERSISTENTWARPS && coords.x > 0 && coords.y > 0 && coords < m_vSize) // don't warp cursor outside the window + g_pCompositor->warpCursorTo(m_vPosition + coords); + else + g_pCompositor->warpCursorTo(middle()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d4e26d5d..151d9809 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -245,8 +245,11 @@ class CWindow { Vector2D m_vFloatingOffset = Vector2D(0, 0); // this is used for pseudotiling - bool m_bIsPseudotiled = false; - Vector2D m_vPseudoSize = Vector2D(1280, 720); + bool m_bIsPseudotiled = false; + Vector2D m_vPseudoSize = Vector2D(1280, 720); + + // for recovering relative cursor position + Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); bool m_bFirstMap = false; // for layouts bool m_bIsFloating = false; @@ -446,6 +449,7 @@ class CWindow { void onResourceChangeX11(); std::string fetchTitle(); std::string fetchClass(); + void warpCursor(); // listeners void onAck(uint32_t serial); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 905a9d48..f7009afb 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -257,6 +257,16 @@ bool CKeybindManager::ensureMouseBindState() { return false; } +void updateRelativeCursorCoords() { + static auto PNOWARPS = CConfigValue("cursor:no_warps"); + + if (*PNOWARPS) + return; + + if (g_pCompositor->m_pLastWindow) + g_pCompositor->m_pLastWindow->m_vRelativeCursorCoordsOnLastWarp = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vPosition; +} + bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { if (!monitor) return false; @@ -277,8 +287,9 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { const auto PNEWWINDOW = PNEWWORKSPACE->getLastFocusedWindow(); if (PNEWWINDOW) { + updateRelativeCursorCoords(); g_pCompositor->focusWindow(PNEWWINDOW); - g_pCompositor->warpCursorTo(PNEWWINDOW->middle()); + PNEWWINDOW->warpCursor(); g_pInputManager->m_pForcedFocus = PNEWWINDOW; g_pInputManager->simulateMouseMovement(); @@ -313,8 +324,9 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); } else { + updateRelativeCursorCoords(); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); - g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle()); + PWINDOWTOCHANGETO->warpCursor(); g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; g_pInputManager->simulateMouseMovement(); @@ -1146,6 +1158,8 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { const auto POLDWS = PWINDOW->m_pWorkspace; static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); + updateRelativeCursorCoords(); + g_pHyprRenderer->damageWindow(PWINDOW); if (pWorkspace) { @@ -1171,7 +1185,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { pMonitor->changeWorkspace(pWorkspace); g_pCompositor->focusWindow(PWINDOW); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->warpCursor(); } void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { @@ -1303,8 +1317,9 @@ void CKeybindManager::swapActive(std::string args) { if (!PWINDOWTOCHANGETO) return; + updateRelativeCursorCoords(); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO); - g_pCompositor->warpCursorTo(PLASTWINDOW->middle()); + PLASTWINDOW->warpCursor(); } void CKeybindManager::moveActiveTo(std::string args) { @@ -1357,9 +1372,11 @@ void CKeybindManager::moveActiveTo(std::string args) { // If the window to change to is on the same workspace, switch them const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); if (PWINDOWTOCHANGETO) { + updateRelativeCursorCoords(); + g_pLayoutManager->getCurrentLayout()->moveWindowTo(PLASTWINDOW, args, silent); if (!silent) - g_pCompositor->warpCursorTo(PLASTWINDOW->middle()); + PLASTWINDOW->warpCursor(); return; } @@ -1896,6 +1913,8 @@ void CKeybindManager::focusWindow(std::string regexp) { return; } + updateRelativeCursorCoords(); + if (g_pCompositor->m_pLastMonitor && g_pCompositor->m_pLastMonitor->activeWorkspace != PWINDOW->m_pWorkspace && g_pCompositor->m_pLastMonitor->activeSpecialWorkspace != PWINDOW->m_pWorkspace) { Debug::log(LOG, "Fake executing workspace to move focus"); @@ -1926,7 +1945,7 @@ void CKeybindManager::focusWindow(std::string regexp) { } else g_pCompositor->focusWindow(PWINDOW); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->warpCursor(); } void CKeybindManager::tagWindow(std::string args) { @@ -2445,6 +2464,8 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn if (pWindow->m_sGroupData.deny) return; + updateRelativeCursorCoords(); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! static auto USECURRPOS = CConfigValue("group:insert_after_current"); @@ -2455,7 +2476,7 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn pWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); g_pCompositor->focusWindow(pWindow); - g_pCompositor->warpCursorTo(pWindow->middle()); + pWindow->warpCursor(); if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -2478,6 +2499,8 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& default: direction = DIRECTION_DEFAULT; } + updateRelativeCursorCoords(); + if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow) { pWindow->destroyGroup(); } else { @@ -2493,10 +2516,10 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& if (*BFOCUSREMOVEDWINDOW) { g_pCompositor->focusWindow(pWindow); - g_pCompositor->warpCursorTo(pWindow->middle()); + pWindow->warpCursor(); } else { g_pCompositor->focusWindow(PWINDOWPREV); - g_pCompositor->warpCursorTo(PWINDOWPREV->middle()); + PWINDOWPREV->warpCursor(); } g_pEventManager->postEvent(SHyprIPCEvent{"moveoutofgroup", std::format("{:x}", (uintptr_t)pWindow.get())}); @@ -2576,24 +2599,26 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && PWINDOW->getGroupHead()->m_sGroupData.locked; const bool ISWINDOWGROUPSINGLE = ISWINDOWGROUP && PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW; + updateRelativeCursorCoords(); + // note: PWINDOWINDIR is not null implies !PWINDOW->m_bIsFloating if (PWINDOWINDIR && PWINDOWINDIR->m_sGroupData.pNextWindow) { // target is group if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || ISWINDOWGROUPLOCKED || PWINDOW->m_sGroupData.deny)) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->warpCursor(); } else moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); } else if (PWINDOWINDIR) { // target is regular window if ((!*PIGNOREGROUPLOCK && ISWINDOWGROUPLOCKED) || !ISWINDOWGROUP || (ISWINDOWGROUPSINGLE && PWINDOW->m_eGroupRules & GROUP_SET_ALWAYS)) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->warpCursor(); } else moveWindowOutOfGroup(PWINDOW, args); } else if ((*PIGNOREGROUPLOCK || !ISWINDOWGROUPLOCKED) && ISWINDOWGROUP) { // no target window moveWindowOutOfGroup(PWINDOW, args); } else if (!PWINDOWINDIR && !ISWINDOWGROUP) { // no target in dir and not in group g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - g_pCompositor->warpCursorTo(PWINDOW->middle()); + PWINDOW->warpCursor(); } g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); From 40ce17bbbd6b01c7d5061358e5ff318122759a9e Mon Sep 17 00:00:00 2001 From: "John M. Harris, Jr" Date: Fri, 7 Jun 2024 10:54:08 -0700 Subject: [PATCH 0166/2393] gestures: Add gestures:workspace_swipe_min_fingers option (#6342) When gestures:workspace_swipe_min_fingers is enabled, gestures:workspace_swipe_fingers is considered to be the minimum number of fingers required to swipe. This behavior is more similar to sway and macOS's default behavior. For example, this allows you to set workspace_swipe_fingers to 3, but swipe with 4 or more fingers instead of 3. --- src/config/ConfigManager.cpp | 1 + src/managers/input/Swipe.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6db920ea..e10522d9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -500,6 +500,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3}); + m_pConfig->addConfigValue("gestures:workspace_swipe_min_fingers", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_distance", Hyprlang::INT{300}); m_pConfig->addConfigValue("gestures:workspace_swipe_invert", Hyprlang::INT{1}); m_pConfig->addConfigValue("gestures:workspace_swipe_min_speed_to_force", Hyprlang::INT{30}); diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 44623671..a605fea7 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -3,13 +3,14 @@ #include "../../config/ConfigValue.hpp" void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { - static auto PSWIPE = CConfigValue("gestures:workspace_swipe"); - static auto PSWIPEFINGERS = CConfigValue("gestures:workspace_swipe_fingers"); - static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); + static auto PSWIPE = CConfigValue("gestures:workspace_swipe"); + static auto PSWIPEFINGERS = CConfigValue("gestures:workspace_swipe_fingers"); + static auto PSWIPEMINFINGERS = CConfigValue("gestures:workspace_swipe_min_fingers"); + static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e); - if (e.fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) + if ((!*PSWIPEMINFINGERS && e.fingers != *PSWIPEFINGERS) || (*PSWIPEMINFINGERS && e.fingers < *PSWIPEFINGERS) || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) return; int onMonitor = 0; From 6b6b02c27a21a6a4fe3d66937c709c32e21a9078 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 7 Jun 2024 20:16:26 +0200 Subject: [PATCH 0167/2393] seat: send events to all bound seats for a client some apps are legitimately braindead and bind wl_seat a bazillion times and expect the events to be sent to all of them ref #6159 --- src/managers/SeatManager.cpp | 146 ++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 47 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 5fa3d1ae..7899386b 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -110,12 +110,6 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { hyprListener_keyboardSurfaceDestroy.removeCallback(); if (state.keyboardFocusResource) { - // we will iterate over all bound wl_seat - // resources here, because some idiotic apps (e.g. those based on smithay) - // tend to bind wl_seat twice. - // I can't be arsed to actually pass all events to all seat resources, so we will - // only pass enter and leave. - // If you have an issue with that, fix your app. auto client = state.keyboardFocusResource->client(); for (auto& s : seatResources) { if (s->resource->client() != client) @@ -163,11 +157,16 @@ void CSeatManager::sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_ke if (!state.keyboardFocusResource) return; - for (auto& k : state.keyboardFocusResource->keyboards) { - if (!k) + for (auto& s : seatResources) { + if (s->resource->client() != state.keyboardFocusResource->client()) continue; - k->sendKey(timeMs, key, state_); + for (auto& k : s->resource->keyboards) { + if (!k) + continue; + + k->sendKey(timeMs, key, state_); + } } } @@ -175,11 +174,16 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32 if (!state.keyboardFocusResource) return; - for (auto& k : state.keyboardFocusResource->keyboards) { - if (!k) + for (auto& s : seatResources) { + if (s->resource->client() != state.keyboardFocusResource->client()) continue; - k->sendMods(depressed, latched, locked, group); + for (auto& k : s->resource->keyboards) { + if (!k) + continue; + + k->sendMods(depressed, latched, locked, group); + } } } @@ -249,11 +253,16 @@ void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { if (!state.pointerFocusResource) return; - for (auto& p : state.pointerFocusResource->pointers) { - if (!p) + for (auto& s : seatResources) { + if (s->resource->client() != state.pointerFocusResource->client()) continue; - p->sendMotion(timeMs, local); + for (auto& p : s->resource->pointers) { + if (!p) + continue; + + p->sendMotion(timeMs, local); + } } lastLocalCoords = local; @@ -263,11 +272,16 @@ void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_b if (!state.pointerFocusResource) return; - for (auto& p : state.pointerFocusResource->pointers) { - if (!p) + for (auto& s : seatResources) { + if (s->resource->client() != state.pointerFocusResource->client()) continue; - p->sendButton(timeMs, key, state_); + for (auto& p : s->resource->pointers) { + if (!p) + continue; + + p->sendButton(timeMs, key, state_); + } } } @@ -282,11 +296,19 @@ void CSeatManager::sendPointerFrame(WP pResource) { if (!pResource) return; - for (auto& p : pResource->pointers) { - if (!p) + if (!state.pointerFocusResource) + return; + + for (auto& s : seatResources) { + if (s->resource->client() != state.pointerFocusResource->client()) continue; - p->sendFrame(); + for (auto& p : s->resource->pointers) { + if (!p) + continue; + + p->sendFrame(); + } } } @@ -295,21 +317,26 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double if (!state.pointerFocusResource) return; - for (auto& p : state.pointerFocusResource->pointers) { - if (!p) + for (auto& s : seatResources) { + if (s->resource->client() != state.pointerFocusResource->client()) continue; - p->sendAxis(timeMs, axis, value); - p->sendAxisSource(source); - p->sendAxisRelativeDirection(axis, relative); + for (auto& p : s->resource->pointers) { + if (!p) + continue; - if (source == 0) { - p->sendAxisValue120(axis, value120); - p->sendAxisDiscrete(axis, discrete); + p->sendAxis(timeMs, axis, value); + p->sendAxisSource(source); + p->sendAxisRelativeDirection(axis, relative); + + if (source == 0) { + p->sendAxisValue120(axis, value120); + p->sendAxisDiscrete(axis, discrete); + } + + if (value == 0) + p->sendAxisStop(timeMs, axis); } - - if (value == 0) - p->sendAxisStop(timeMs, axis); } } @@ -370,11 +397,16 @@ void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& if (!state.touchFocusResource) return; - for (auto& t : state.touchFocusResource->touches) { - if (!t) + for (auto& s : seatResources) { + if (s->resource->client() != state.touchFocusResource->client()) continue; - t->sendMotion(timeMs, id, local); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendMotion(timeMs, id, local); + } } } @@ -382,11 +414,16 @@ void CSeatManager::sendTouchFrame() { if (!state.touchFocusResource) return; - for (auto& t : state.touchFocusResource->touches) { - if (!t) + for (auto& s : seatResources) { + if (s->resource->client() != state.touchFocusResource->client()) continue; - t->sendFrame(); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendFrame(); + } } } @@ -394,11 +431,16 @@ void CSeatManager::sendTouchCancel() { if (!state.touchFocusResource) return; - for (auto& t : state.touchFocusResource->touches) { - if (!t) + for (auto& s : seatResources) { + if (s->resource->client() != state.touchFocusResource->client()) continue; - t->sendCancel(); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendCancel(); + } } } @@ -406,11 +448,16 @@ void CSeatManager::sendTouchShape(int32_t id, const Vector2D& shape) { if (!state.touchFocusResource) return; - for (auto& t : state.touchFocusResource->touches) { - if (!t) + for (auto& s : seatResources) { + if (s->resource->client() != state.touchFocusResource->client()) continue; - t->sendShape(id, shape); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendShape(id, shape); + } } } @@ -418,11 +465,16 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) { if (!state.touchFocusResource) return; - for (auto& t : state.touchFocusResource->touches) { - if (!t) + for (auto& s : seatResources) { + if (s->resource->client() != state.touchFocusResource->client()) continue; - t->sendOrientation(id, angle); + for (auto& t : s->resource->touches) { + if (!t) + continue; + + t->sendOrientation(id, angle); + } } } From c31d9ef4172452f6f219f91d9b87a24d91f0cf3a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 7 Jun 2024 20:23:35 +0200 Subject: [PATCH 0168/2393] xdg_shell: fix nested xdg_positioner calculations ref #6240 --- src/protocols/XDGShell.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 23148fab..80e3487d 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -528,7 +528,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa bool success = predictedBox.inside(constraint); if (success) - return predictedBox; + return predictedBox.translate(-parentCoord - constraint.pos()); if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) { // attempt to flip @@ -547,7 +547,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa success = false; if (success) - return test; + return test.translate(-parentCoord - constraint.pos()); } // if flips fail, we will slide and remember. @@ -584,7 +584,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa success = test.copy().expand(-1).inside(constraint); if (success) - return test; + return test.translate(-parentCoord - constraint.pos()); } if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) { @@ -613,7 +613,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa success = test.copy().expand(-1).inside(constraint); if (success) - return test; + return test.translate(-parentCoord - constraint.pos()); } LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); From 6967a31450441fc5605c05db6f65505dace4b263 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 8 Jun 2024 10:07:59 +0200 Subject: [PATCH 0169/2393] wayland/core: move to new impl (#6268) * wayland/core/dmabuf: move to new impl it's the final countdown --- CMakeLists.txt | 6 +- flake.lock | 18 +- protocols/meson.build | 4 +- protocols/wayland-drm.xml | 189 +++++++ src/Compositor.cpp | 182 +++---- src/Compositor.hpp | 163 +++--- src/debug/HyprDebugOverlay.cpp | 10 +- src/debug/HyprDebugOverlay.hpp | 3 +- src/debug/HyprNotificationOverlay.cpp | 8 +- src/debug/HyprNotificationOverlay.hpp | 2 +- src/desktop/LayerSurface.cpp | 57 ++- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 47 +- src/desktop/Popup.hpp | 2 +- src/desktop/Subsurface.cpp | 122 ++--- src/desktop/Subsurface.hpp | 25 +- src/desktop/WLSurface.cpp | 95 ++-- src/desktop/WLSurface.hpp | 77 +-- src/desktop/Window.cpp | 92 ++-- src/desktop/Window.hpp | 4 +- src/devices/Tablet.cpp | 26 +- src/devices/Tablet.hpp | 38 +- src/events/Windows.cpp | 24 +- src/helpers/Format.cpp | 271 ++++++++++ src/helpers/Format.hpp | 37 ++ src/helpers/MiscFunctions.cpp | 66 ++- src/helpers/MiscFunctions.hpp | 3 +- src/helpers/Monitor.cpp | 12 +- src/helpers/Monitor.hpp | 1 - src/helpers/Region.cpp | 7 + src/helpers/Region.hpp | 1 + src/helpers/WLClasses.hpp | 13 +- src/helpers/memory/SharedPtr.hpp | 4 +- src/helpers/memory/WeakPtr.hpp | 2 +- src/helpers/signal/Signal.cpp | 29 +- src/hyprerror/HyprError.cpp | 15 +- src/hyprerror/HyprError.hpp | 2 +- src/layout/IHyprLayout.cpp | 5 +- src/macros.hpp | 12 +- src/managers/CursorManager.cpp | 4 +- src/managers/CursorManager.hpp | 2 +- src/managers/KeybindManager.cpp | 24 +- src/managers/PointerManager.cpp | 66 +-- src/managers/PointerManager.hpp | 14 +- src/managers/ProtocolManager.cpp | 34 +- src/managers/SeatManager.cpp | 50 +- src/managers/SeatManager.hpp | 43 +- src/managers/SessionLockManager.cpp | 6 +- src/managers/SessionLockManager.hpp | 7 +- src/managers/XWaylandManager.cpp | 13 +- src/managers/XWaylandManager.hpp | 26 +- src/managers/input/IdleInhibitor.cpp | 4 +- src/managers/input/InputManager.cpp | 60 +-- src/managers/input/InputManager.hpp | 24 +- src/managers/input/InputMethodPopup.cpp | 22 +- src/managers/input/InputMethodPopup.hpp | 16 +- src/managers/input/InputMethodRelay.cpp | 20 +- src/managers/input/InputMethodRelay.hpp | 10 +- src/managers/input/Tablets.cpp | 6 +- src/managers/input/TextInput.cpp | 65 ++- src/managers/input/TextInput.hpp | 44 +- src/managers/input/Touch.cpp | 2 +- src/protocols/AlphaModifier.cpp | 43 +- src/protocols/AlphaModifier.hpp | 25 +- src/protocols/FocusGrab.cpp | 36 +- src/protocols/FocusGrab.hpp | 28 +- src/protocols/FractionalScale.cpp | 55 +-- src/protocols/FractionalScale.hpp | 37 +- src/protocols/GammaControl.cpp | 11 +- src/protocols/IdleInhibit.cpp | 25 +- src/protocols/IdleInhibit.hpp | 17 +- src/protocols/InputMethodV2.cpp | 65 ++- src/protocols/InputMethodV2.hpp | 16 +- src/protocols/LayerShell.cpp | 87 ++-- src/protocols/LayerShell.hpp | 21 +- src/protocols/LinuxDMABUF.cpp | 454 +++++++++++++++++ src/protocols/LinuxDMABUF.hpp | 138 ++++++ src/protocols/MesaDRM.cpp | 133 +++++ src/protocols/MesaDRM.hpp | 60 +++ src/protocols/OutputPower.cpp | 7 +- src/protocols/PointerConstraints.cpp | 31 +- src/protocols/PointerConstraints.hpp | 23 +- src/protocols/PointerGestures.cpp | 7 +- src/protocols/PresentationTime.cpp | 14 +- src/protocols/PresentationTime.hpp | 17 +- src/protocols/Screencopy.cpp | 84 ++-- src/protocols/Screencopy.hpp | 5 +- src/protocols/ServerDecorationKDE.cpp | 6 +- src/protocols/ServerDecorationKDE.hpp | 4 +- src/protocols/SessionLock.cpp | 81 ++- src/protocols/SessionLock.hpp | 18 +- src/protocols/ShortcutsInhibit.cpp | 11 +- src/protocols/ShortcutsInhibit.hpp | 10 +- src/protocols/Tablet.cpp | 17 +- src/protocols/Tablet.hpp | 23 +- src/protocols/TearingControl.cpp | 12 +- src/protocols/TearingControl.hpp | 5 +- src/protocols/TextInputV1.cpp | 3 +- src/protocols/TextInputV3.cpp | 9 +- src/protocols/TextInputV3.hpp | 6 +- src/protocols/ToplevelExport.cpp | 63 +-- src/protocols/ToplevelExportWlrFuncs.hpp | 243 --------- src/protocols/Viewporter.cpp | 126 +++++ src/protocols/Viewporter.hpp | 55 +++ src/protocols/WaylandProtocol.cpp | 6 + src/protocols/WaylandProtocol.hpp | 3 +- src/protocols/XDGActivation.cpp | 5 +- src/protocols/XDGOutput.cpp | 5 +- src/protocols/XDGShell.cpp | 96 ++-- src/protocols/XDGShell.hpp | 11 +- src/protocols/XWaylandShell.cpp | 5 +- src/protocols/XWaylandShell.hpp | 8 +- src/protocols/core/Compositor.cpp | 467 ++++++++++++++++++ src/protocols/core/Compositor.hpp | 175 +++++++ src/protocols/core/DataDevice.cpp | 61 ++- src/protocols/core/DataDevice.hpp | 13 +- src/protocols/core/Output.cpp | 107 ++++ src/protocols/core/Output.hpp | 61 +++ src/protocols/core/Seat.cpp | 54 +- src/protocols/core/Seat.hpp | 31 +- src/protocols/core/Shm.cpp | 214 ++++++++ src/protocols/core/Shm.hpp | 111 +++++ src/protocols/core/Subcompositor.cpp | 192 +++++++ src/protocols/core/Subcompositor.hpp | 82 +++ src/protocols/types/Buffer.cpp | 41 ++ src/protocols/types/Buffer.hpp | 74 +++ src/protocols/types/DMABuffer.cpp | 75 +++ src/protocols/types/DMABuffer.hpp | 28 ++ src/protocols/types/SurfaceRole.hpp | 14 + src/protocols/types/WLBuffer.cpp | 43 ++ src/protocols/types/WLBuffer.hpp | 31 ++ src/render/Framebuffer.cpp | 27 +- src/render/Framebuffer.hpp | 21 +- src/render/OpenGL.cpp | 453 +++++++++-------- src/render/OpenGL.hpp | 159 +++--- src/render/Renderbuffer.cpp | 24 + src/render/Renderbuffer.hpp | 3 + src/render/Renderer.cpp | 253 +++++----- src/render/Renderer.hpp | 19 +- src/render/Texture.cpp | 106 +++- src/render/Texture.hpp | 18 + .../decorations/CHyprGroupBarDecoration.cpp | 50 +- .../decorations/CHyprGroupBarDecoration.hpp | 2 +- src/xwayland/XSurface.cpp | 60 ++- src/xwayland/XSurface.hpp | 9 +- src/xwayland/XWM.cpp | 21 +- src/xwayland/XWM.hpp | 7 +- 147 files changed, 5388 insertions(+), 2226 deletions(-) create mode 100644 protocols/wayland-drm.xml create mode 100644 src/helpers/Format.cpp create mode 100644 src/helpers/Format.hpp create mode 100644 src/protocols/LinuxDMABUF.cpp create mode 100644 src/protocols/LinuxDMABUF.hpp create mode 100644 src/protocols/MesaDRM.cpp create mode 100644 src/protocols/MesaDRM.hpp delete mode 100644 src/protocols/ToplevelExportWlrFuncs.hpp create mode 100644 src/protocols/Viewporter.cpp create mode 100644 src/protocols/Viewporter.hpp create mode 100644 src/protocols/core/Compositor.cpp create mode 100644 src/protocols/core/Compositor.hpp create mode 100644 src/protocols/core/Output.cpp create mode 100644 src/protocols/core/Output.hpp create mode 100644 src/protocols/core/Shm.cpp create mode 100644 src/protocols/core/Shm.hpp create mode 100644 src/protocols/core/Subcompositor.cpp create mode 100644 src/protocols/core/Subcompositor.hpp create mode 100644 src/protocols/types/Buffer.cpp create mode 100644 src/protocols/types/Buffer.hpp create mode 100644 src/protocols/types/DMABuffer.cpp create mode 100644 src/protocols/types/DMABuffer.hpp create mode 100644 src/protocols/types/SurfaceRole.hpp create mode 100644 src/protocols/types/WLBuffer.cpp create mode 100644 src/protocols/types/WLBuffer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e42a530a..43cbb50c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprlang>=0.3.2 hyprcursor>=0.1.7 ) -find_package(hyprwayland-scanner 0.3.8 REQUIRED) +find_package(hyprwayland-scanner 0.3.10 REQUIRED) file(GLOB_RECURSE SRCFILES "src/*.cpp") @@ -277,7 +277,6 @@ target_link_libraries(Hyprland protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) -protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) @@ -291,6 +290,7 @@ protocolNew("protocols" "kde-server-decoration" true) protocolNew("protocols" "wlr-data-control-unstable-v1" true) protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolNew("protocols" "wayland-drm" true) protocolNew("staging/tearing-control" "tearing-control-v1" false) protocolNew("staging/fractional-scale" "fractional-scale-v1" false) protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) @@ -312,6 +312,8 @@ protocolNew("stable/presentation-time" "presentation-time" false) protocolNew("stable/xdg-shell" "xdg-shell" false) protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) +protocolNew("stable/viewporter" "viewporter" false) +protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolWayland() diff --git a/flake.lock b/flake.lock index 8fc80b1d..ab886a15 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1716576411, - "narHash": "sha256-FIN1wMoyePBTtibCbaeJaoKNLuAYIGwLCWAYC1DJanw=", + "lastModified": 1717181720, + "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "57298fc4f13c807e50ada2c986a3114b7fc2e621", + "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", "type": "github" }, "original": { @@ -84,11 +84,11 @@ ] }, "locked": { - "lastModified": 1716058375, - "narHash": "sha256-CwjWoVnBZE5SBpRx9dgSQGCr4Goxyfcyv3zZbOhVqzk=", + "lastModified": 1717784906, + "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "3afed4364790aebe0426077631af1e164a9650cc", + "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", "type": "github" }, "original": { @@ -99,11 +99,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1716330097, - "narHash": "sha256-8BO3B7e3BiyIDsaKA0tY8O88rClYRTjvAp66y+VBUeU=", + "lastModified": 1717602782, + "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5710852ba686cc1fd0d3b8e22b3117d43ba374c2", + "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index f491bb09..f4978c23 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -24,7 +24,6 @@ hyprwayland_scanner = find_program( ) protocols = [ - [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], @@ -41,6 +40,7 @@ new_protocols = [ ['wlr-output-management-unstable-v1.xml'], ['kde-server-decoration.xml'], ['wlr-layer-shell-unstable-v1.xml'], + ['wayland-drm.xml'], ['wlr-data-control-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], @@ -64,6 +64,8 @@ new_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], + [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], + [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], ] wl_protos_src = [] diff --git a/protocols/wayland-drm.xml b/protocols/wayland-drm.xml new file mode 100644 index 00000000..eaf2654a --- /dev/null +++ b/protocols/wayland-drm.xml @@ -0,0 +1,189 @@ + + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that\n the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bitmask of capabilities. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 73708b1b..b0456358 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -19,6 +19,8 @@ #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" +#include "protocols/core/Compositor.hpp" +#include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" #include "xwayland/XWayland.hpp" @@ -184,7 +186,7 @@ void CCompositor::initServer() { &isHeadlessOnly); if (isHeadlessOnly) { - m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); + m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now. } else { m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); if (m_iDRMFD < 0) { @@ -200,15 +202,6 @@ void CCompositor::initServer() { throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); } - wlr_renderer_init_wl_shm(m_sWLRRenderer, m_sWLDisplay); - - if (wlr_renderer_get_dmabuf_texture_formats(m_sWLRRenderer)) { - if (wlr_renderer_get_drm_fd(m_sWLRRenderer) >= 0) - wlr_drm_create(m_sWLDisplay, m_sWLRRenderer); - - m_sWLRLinuxDMABuf = wlr_linux_dmabuf_v1_create_with_renderer(m_sWLDisplay, 4, m_sWLRRenderer); - } - m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); if (!m_sWLRAllocator) { @@ -223,13 +216,7 @@ void CCompositor::initServer() { throwError("wlr_gles2_renderer_get_egl() failed!"); } - m_sWLRCompositor = wlr_compositor_create(m_sWLDisplay, 6, m_sWLRRenderer); - m_sWLRSubCompositor = wlr_subcompositor_create(m_sWLDisplay); - // m_sWLRDataDevMgr = wlr_data_device_manager_create(m_sWLDisplay); - - // wlr_data_control_manager_v1_create(m_sWLDisplay); - // wlr_primary_selection_v1_device_manager_create(m_sWLDisplay); - wlr_viewporter_create(m_sWLDisplay); + initManagers(STAGE_BASICINIT); m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend); if (!m_sWRLDRMLeaseMgr) { @@ -244,8 +231,6 @@ void CCompositor::initServer() { throwError("wlr_headless_backend_create() failed!"); } - wlr_single_pixel_buffer_manager_v1_create(m_sWLDisplay); - wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend); initManagers(STAGE_LATE); @@ -320,7 +305,7 @@ void CCompositor::cleanup() { // still in a normal working state. g_pPluginSystem->unloadAllPlugins(); - m_pLastFocus = nullptr; + m_pLastFocus.reset(); m_pLastWindow.reset(); m_vWorkspaces.clear(); @@ -393,12 +378,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the HookSystem!"); g_pHookSystem = std::make_unique(); - Debug::log(LOG, "Creating the ProtocolManager!"); - g_pProtocolManager = std::make_unique(); - - Debug::log(LOG, "Creating the SeatManager!"); - g_pSeatManager = std::make_unique(); - Debug::log(LOG, "Creating the KeybindManager!"); g_pKeybindManager = std::make_unique(); @@ -423,6 +402,13 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique(); } break; + case STAGE_BASICINIT: { + Debug::log(LOG, "Creating the ProtocolManager!"); + g_pProtocolManager = std::make_unique(); + + Debug::log(LOG, "Creating the SeatManager!"); + g_pSeatManager = std::make_unique(); + } break; case STAGE_LATE: { Debug::log(LOG, "Creating the ThreadManager!"); g_pThreadManager = std::make_unique(); @@ -574,6 +560,8 @@ void CCompositor::startCompositor() { createLockFile(); + EMIT_HOOK_EVENT("ready", nullptr); + // This blocks until we are done. Debug::log(LOG, "Hyprland is ready, running the event loop!"); g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop); @@ -789,47 +777,32 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper return windowForWorkspace(false); } -wlr_surface* CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) { +SP CCompositor::vectorWindowToSurface(const Vector2D& pos, PHLWINDOW pWindow, Vector2D& sl) { if (!validMapped(pWindow)) return nullptr; RASSERT(!pWindow->m_bIsX11, "Cannot call vectorWindowToSurface on an X11 window!"); - double subx, suby; - - CBox geom = pWindow->m_pXDGSurface->current.geometry; - // try popups first - const auto PPOPUP = pWindow->m_pPopupHead->at(pos); + const auto PPOPUP = pWindow->m_pPopupHead->at(pos); - wlr_surface* found = PPOPUP ? PPOPUP->m_sWLSurface.wlr() : nullptr; - - if (!PPOPUP) - found = wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), pos.x - pWindow->m_vRealPosition.value().x + geom.x, pos.y - pWindow->m_vRealPosition.value().y + geom.y, &subx, - &suby); - else { + if (PPOPUP) { const auto OFF = PPOPUP->coordsRelativeToParent(); - subx = pos.x - OFF.x + geom.x - pWindow->m_vRealPosition.goal().x; - suby = pos.y - OFF.y + geom.y - pWindow->m_vRealPosition.goal().y; + sl = pos - pWindow->m_vRealPosition.goal() - OFF; + return PPOPUP->m_pWLSurface->resource(); } - if (found) { - sl.x = subx; - sl.y = suby; - return found; + auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition.goal(), true); + if (surf) { + sl = local; + return surf; } - sl.x = pos.x - pWindow->m_vRealPosition.value().x; - sl.y = pos.y - pWindow->m_vRealPosition.value().y; - - sl.x += geom.x; - sl.y += geom.y; - - return pWindow->m_pWLSurface.wlr(); + return nullptr; } -Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, wlr_surface* pSurface) { +Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindow, SP pSurface) { if (!validMapped(pWindow)) return {}; @@ -840,25 +813,22 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo if (PPOPUP) return vec - PPOPUP->coordsGlobal(); - std::tuple iterData = {pSurface, -1337, -1337}; + std::tuple, Vector2D> iterData = {pSurface, {-1337, -1337}}; - wlr_surface_for_each_surface( - pWindow->m_pWLSurface.wlr(), - [](wlr_surface* surf, int x, int y, void* data) { - const auto PDATA = (std::tuple*)data; - if (surf == std::get<0>(*PDATA)) { - std::get<1>(*PDATA) = x; - std::get<2>(*PDATA) = y; - } + pWindow->m_pWLSurface->resource()->breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + const auto PDATA = (std::tuple, Vector2D>*)data; + if (surf == std::get<0>(*PDATA)) + std::get<1>(*PDATA) = offset; }, &iterData); CBox geom = pWindow->m_pXDGSurface->current.geometry; - if (std::get<1>(iterData) == -1337 && std::get<2>(iterData) == -1337) + if (std::get<1>(iterData) == Vector2D{-1337, -1337}) return vec - pWindow->m_vRealPosition.goal(); - return vec - pWindow->m_vRealPosition.goal() - Vector2D{std::get<1>(iterData), std::get<2>(iterData)} + Vector2D{geom.x, geom.y}; + return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { @@ -881,7 +851,7 @@ CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) { return nullptr; } -void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { +void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); @@ -924,7 +894,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr); - m_pLastFocus = nullptr; + m_pLastFocus.reset(); g_pInputManager->recheckIdleInhibitorStatus(); return; @@ -976,7 +946,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { m_pLastWindow = PLASTWINDOW; - const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface.wlr(); + const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow->m_pWLSurface->resource(); focusSurface(PWINDOWSURFACE, pWindow); @@ -1011,9 +981,9 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, wlr_surface* pSurface) { g_pInputManager->sendMotionEventsToFocused(); } -void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { +void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindowOwner) { - if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface.wlr())) + if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface->resource())) return; // Don't focus when already focused on this. if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) @@ -1024,18 +994,18 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { return; } - const auto PLASTSURF = m_pLastFocus; + const auto PLASTSURF = m_pLastFocus.lock(); // Unfocus last surface if should if (m_pLastFocus && !pWindowOwner) - g_pXWaylandManager->activateSurface(m_pLastFocus, false); + g_pXWaylandManager->activateSurface(m_pLastFocus.lock(), false); if (!pSurface) { g_pSeatManager->setKeyboardFocus(nullptr); g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); - EMIT_HOOK_EVENT("keyboardFocus", (wlr_surface*)nullptr); - m_pLastFocus = nullptr; + EMIT_HOOK_EVENT("keyboardFocus", (SP)nullptr); + m_pLastFocus.reset(); return; } @@ -1052,8 +1022,8 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { EMIT_HOOK_EVENT("keyboardFocus", pSurface); - const auto SURF = CWLSurface::surfaceFromWlr(pSurface); - const auto OLDSURF = CWLSurface::surfaceFromWlr(PLASTSURF); + const auto SURF = CWLSurface::fromResource(pSurface); + const auto OLDSURF = CWLSurface::fromResource(PLASTSURF); if (OLDSURF && OLDSURF->constraint()) OLDSURF->constraint()->deactivate(); @@ -1062,7 +1032,7 @@ void CCompositor::focusSurface(wlr_surface* pSurface, PHLWINDOW pWindowOwner) { SURF->constraint()->activate(); } -wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto& ls : lsl | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) @@ -1073,7 +1043,7 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito if (SURFACEAT) { *ppLayerSurfaceFound = ls.lock(); *sCoords = pos - SURFACEAT->coordsGlobal(); - return SURFACEAT->m_sWLSurface.wlr(); + return SURFACEAT->m_pWLSurface->resource(); } } } @@ -1081,31 +1051,34 @@ wlr_surface* CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonito return nullptr; } -wlr_surface* CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; - auto SURFACEAT = wlr_surface_surface_at(ls->layerSurface->surface, pos.x - ls->geometry.x, pos.y - ls->geometry.y, &sCoords->x, &sCoords->y); + auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos()); - if (SURFACEAT) { - if (!pixman_region32_not_empty(&SURFACEAT->input_region)) + if (surf) { + if (surf->current.input.empty()) continue; *ppLayerSurfaceFound = ls.lock(); - return SURFACEAT; + + *sCoords = local; + + return surf; } } return nullptr; } -PHLWINDOW CCompositor::getWindowFromSurface(wlr_surface* pSurface) { +PHLWINDOW CCompositor::getWindowFromSurface(SP pSurface) { for (auto& w : m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; - if (w->m_pWLSurface.wlr() == pSurface) + if (w->m_pWLSurface->resource() == pSurface) return w; } @@ -1244,7 +1217,7 @@ bool CCompositor::isWindowActive(PHLWINDOW pWindow) { if (!pWindow->m_bIsMapped) return false; - const auto PSURFACE = pWindow->m_pWLSurface.wlr(); + const auto PSURFACE = pWindow->m_pWLSurface->resource(); return PSURFACE == m_pLastFocus || pWindow == m_pLastWindow.lock(); } @@ -1646,11 +1619,6 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* p return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); } -void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) { - auto pair = (std::pair*)data; - pair->second = pair->second || pSurface == pair->first; -} - CMonitor* CCompositor::getMonitorInDirection(const char& dir) { return this->getMonitorInDirection(m_pLastMonitor.get(), dir); } @@ -2389,24 +2357,24 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { } } -PHLLS CCompositor::getLayerSurfaceFromSurface(wlr_surface* pSurface) { - std::pair result = {pSurface, false}; +PHLLS CCompositor::getLayerSurfaceFromSurface(SP pSurface) { + std::pair, bool> result = {pSurface, false}; for (auto& ls : m_vLayers) { if (ls->layerSurface && ls->layerSurface->surface == pSurface) return ls; - static auto iter = [](wlr_surface* surf, int x, int y, void* data) -> void { - if (surf == ((std::pair*)data)->first) { - *(bool*)data = true; - return; - } - }; - if (!ls->layerSurface || !ls->mapped) continue; - wlr_surface_for_each_surface(ls->layerSurface->surface, iter, &result); + ls->layerSurface->surface->breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + if (surf == ((std::pair, bool>*)data)->first) { + *(bool*)data = true; + return; + } + }, + &result); if (result.second) return ls; @@ -2738,13 +2706,13 @@ void CCompositor::leaveUnsafeState() { } } -void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) { +void CCompositor::setPreferredScaleForSurface(SP pSurface, double scale) { PROTO::fractional->sendScale(pSurface, scale); - wlr_surface_set_preferred_buffer_scale(pSurface, static_cast(std::ceil(scale))); + pSurface->sendPreferredScale(std::ceil(scale)); - const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface); + const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); return; } @@ -2752,12 +2720,12 @@ void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scal PSURFACE->m_iLastScale = static_cast(std::ceil(scale)); } -void CCompositor::setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform) { - wlr_surface_set_preferred_buffer_transform(pSurface, transform); +void CCompositor::setPreferredTransformForSurface(SP pSurface, wl_output_transform transform) { + pSurface->sendPreferredTransform(transform); - const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface); + const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned wlr_surface {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); return; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a297518d..793899ee 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -29,8 +29,11 @@ #include "plugins/PluginSystem.hpp" #include "helpers/Watchdog.hpp" +class CWLSurfaceResource; + enum eManagersInitStage { STAGE_PRIORITY = 0, + STAGE_BASICINIT, STAGE_LATE }; @@ -79,7 +82,7 @@ class CCompositor { void createLockFile(); void removeLockFile(); - wlr_surface* m_pLastFocus = nullptr; + WP m_pLastFocus; PHLWINDOWREF m_pLastWindow; WP m_pLastMonitor; @@ -96,86 +99,86 @@ class CCompositor { // ------------------------------------------------- // - CMonitor* getMonitorFromID(const int&); - CMonitor* getMonitorFromName(const std::string&); - CMonitor* getMonitorFromDesc(const std::string&); - CMonitor* getMonitorFromCursor(); - CMonitor* getMonitorFromVector(const Vector2D&); - void removeWindowFromVectorSafe(PHLWINDOW); - void focusWindow(PHLWINDOW, wlr_surface* pSurface = nullptr); - void focusSurface(wlr_surface*, PHLWINDOW pWindowOwner = nullptr); - bool monitorExists(CMonitor*); - PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); - wlr_surface* vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); - wlr_surface* vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); - wlr_surface* vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); - Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, wlr_surface*); - CMonitor* getMonitorFromOutput(wlr_output*); - CMonitor* getRealMonitorFromOutput(wlr_output*); - PHLWINDOW getWindowFromSurface(wlr_surface*); - PHLWINDOW getWindowFromHandle(uint32_t); - bool isWorkspaceVisible(PHLWORKSPACE); - PHLWORKSPACE getWorkspaceByID(const int&); - PHLWORKSPACE getWorkspaceByName(const std::string&); - PHLWORKSPACE getWorkspaceByString(const std::string&); - void sanityCheckWorkspaces(); - void updateWorkspaceWindowDecos(const int&); - void updateWorkspaceSpecialRenderData(const int&); - int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); - PHLWINDOW getUrgentWindow(); - bool hasUrgentWindowOnWorkspace(const int&); - PHLWINDOW getFirstWindowOnWorkspace(const int&); - PHLWINDOW getTopLeftWindowOnWorkspace(const int&); - PHLWINDOW getFullscreenWindowOnWorkspace(const int&); - bool isWindowActive(PHLWINDOW); - void changeWindowZOrder(PHLWINDOW, bool); - void cleanupFadingOut(const int& monid); - PHLWINDOW getWindowInDirection(PHLWINDOW, char); - PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); - PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); - int getNextAvailableNamedWorkspace(); - bool isPointOnAnyMonitor(const Vector2D&); - bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); - CMonitor* getMonitorInDirection(const char&); - CMonitor* getMonitorInDirection(CMonitor*, const char&); - void updateAllWindowsAnimatedDecorationValues(); - void updateWorkspaceWindows(const int64_t& id); - void updateWindowAnimatedDecorationValues(PHLWINDOW); - int getNextAvailableMonitorID(std::string const& name); - void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); - void swapActiveWorkspaces(CMonitor*, CMonitor*); - CMonitor* getMonitorFromString(const std::string&); - bool workspaceIDOutOfBounds(const int64_t&); - void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); - void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); - PHLWINDOW getX11Parent(PHLWINDOW); - void scheduleFrameForMonitor(CMonitor*); - void addToFadingOutSafe(PHLLS); - void addToFadingOutSafe(PHLWINDOW); - PHLWINDOW getWindowByRegex(const std::string&); - void warpCursorTo(const Vector2D&, bool force = false); - PHLLS getLayerSurfaceFromSurface(wlr_surface*); - void closeWindow(PHLWINDOW); - Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - void forceReportSizesToWindowsOnWorkspace(const int&); - PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! - void renameWorkspace(const int&, const std::string& name = ""); - void setActiveMonitor(CMonitor*); - bool isWorkspaceSpecial(const int&); - int getNewSpecialID(); - void performUserChecks(); - void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); - PHLWINDOW getForceFocus(); - void arrangeMonitors(); - void enterUnsafeState(); - void leaveUnsafeState(); - void setPreferredScaleForSurface(wlr_surface* pSurface, double scale); - void setPreferredTransformForSurface(wlr_surface* pSurface, wl_output_transform transform); - void updateSuspendedStates(); - PHLWINDOW windowForCPointer(CWindow*); + CMonitor* getMonitorFromID(const int&); + CMonitor* getMonitorFromName(const std::string&); + CMonitor* getMonitorFromDesc(const std::string&); + CMonitor* getMonitorFromCursor(); + CMonitor* getMonitorFromVector(const Vector2D&); + void removeWindowFromVectorSafe(PHLWINDOW); + void focusWindow(PHLWINDOW, SP pSurface = nullptr); + void focusSurface(SP, PHLWINDOW pWindowOwner = nullptr); + bool monitorExists(CMonitor*); + PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); + SP vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); + SP vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); + SP vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); + Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP); + CMonitor* getMonitorFromOutput(wlr_output*); + CMonitor* getRealMonitorFromOutput(wlr_output*); + PHLWINDOW getWindowFromSurface(SP); + PHLWINDOW getWindowFromHandle(uint32_t); + bool isWorkspaceVisible(PHLWORKSPACE); + PHLWORKSPACE getWorkspaceByID(const int&); + PHLWORKSPACE getWorkspaceByName(const std::string&); + PHLWORKSPACE getWorkspaceByString(const std::string&); + void sanityCheckWorkspaces(); + void updateWorkspaceWindowDecos(const int&); + void updateWorkspaceSpecialRenderData(const int&); + int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + PHLWINDOW getUrgentWindow(); + bool hasUrgentWindowOnWorkspace(const int&); + PHLWINDOW getFirstWindowOnWorkspace(const int&); + PHLWINDOW getTopLeftWindowOnWorkspace(const int&); + PHLWINDOW getFullscreenWindowOnWorkspace(const int&); + bool isWindowActive(PHLWINDOW); + void changeWindowZOrder(PHLWINDOW, bool); + void cleanupFadingOut(const int& monid); + PHLWINDOW getWindowInDirection(PHLWINDOW, char); + PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); + PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); + int getNextAvailableNamedWorkspace(); + bool isPointOnAnyMonitor(const Vector2D&); + bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); + CMonitor* getMonitorInDirection(const char&); + CMonitor* getMonitorInDirection(CMonitor*, const char&); + void updateAllWindowsAnimatedDecorationValues(); + void updateWorkspaceWindows(const int64_t& id); + void updateWindowAnimatedDecorationValues(PHLWINDOW); + int getNextAvailableMonitorID(std::string const& name); + void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); + void swapActiveWorkspaces(CMonitor*, CMonitor*); + CMonitor* getMonitorFromString(const std::string&); + bool workspaceIDOutOfBounds(const int64_t&); + void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); + void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); + PHLWINDOW getX11Parent(PHLWINDOW); + void scheduleFrameForMonitor(CMonitor*); + void addToFadingOutSafe(PHLLS); + void addToFadingOutSafe(PHLWINDOW); + PHLWINDOW getWindowByRegex(const std::string&); + void warpCursorTo(const Vector2D&, bool force = false); + PHLLS getLayerSurfaceFromSurface(SP); + void closeWindow(PHLWINDOW); + Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); + void forceReportSizesToWindowsOnWorkspace(const int&); + PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + void renameWorkspace(const int&, const std::string& name = ""); + void setActiveMonitor(CMonitor*); + bool isWorkspaceSpecial(const int&); + int getNewSpecialID(); + void performUserChecks(); + void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); + PHLWINDOW getForceFocus(); + void arrangeMonitors(); + void enterUnsafeState(); + void leaveUnsafeState(); + void setPreferredScaleForSurface(SP pSurface, double scale); + void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); + void updateSuspendedStates(); + PHLWINDOW windowForCPointer(CWindow*); - std::string explicitConfigPath; + std::string explicitConfigPath; private: void initAllSignals(); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 6d3ec907..889be8ea 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -3,6 +3,10 @@ #include "config/ConfigValue.hpp" #include "../Compositor.hpp" +CHyprDebugOverlay::CHyprDebugOverlay() { + m_pTexture = makeShared(); +} + void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_dLastRenderTimes.push_back(µs / 1000.f); @@ -222,8 +226,8 @@ void CHyprDebugOverlay::draw() { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -235,5 +239,5 @@ void CHyprDebugOverlay::draw() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); CBox pMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; - g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); + g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f); } diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index f3beab45..a6063ee9 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -31,6 +31,7 @@ class CHyprMonitorDebugOverlay { class CHyprDebugOverlay { public: + CHyprDebugOverlay(); void draw(); void renderData(CMonitor*, float µs); void renderDataNoOverlay(CMonitor*, float µs); @@ -42,7 +43,7 @@ class CHyprDebugOverlay { cairo_surface_t* m_pCairoSurface = nullptr; cairo_t* m_pCairo = nullptr; - CTexture m_tTexture; + SP m_pTexture; friend class CHyprMonitorDebugOverlay; friend class CHyprRenderer; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index e1fc810b..aec3853e 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -23,6 +23,8 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { g_pHyprRenderer->damageBox(&m_bLastDamage); }); + + m_pTexture = makeShared(); } CHyprNotificationOverlay::~CHyprNotificationOverlay() { @@ -227,8 +229,8 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(m_pCairoSurface); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -240,7 +242,7 @@ void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, MONSIZE.x, MONSIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); CBox pMonBox = {0, 0, MONSIZE.x, MONSIZE.y}; - g_pHyprOpenGL->renderTexture(m_tTexture, &pMonBox, 1.f); + g_pHyprOpenGL->renderTexture(m_pTexture, &pMonBox, 1.f); } bool CHyprNotificationOverlay::hasAny() { diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 5c978089..352c44c9 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -58,7 +58,7 @@ class CHyprNotificationOverlay { CMonitor* m_pLastMonitor = nullptr; Vector2D m_vecLastSize = Vector2D(-1, -1); - CTexture m_tTexture; + SP m_pTexture; }; inline std::unique_ptr g_pHyprNotificationOverlay; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 759eb09f..62cae8f6 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../events/Events.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" PHLLS CLayerSurface::create(SP resource) { @@ -9,6 +10,8 @@ PHLLS CLayerSurface::create(SP resource) { CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); + pLS->surface->assign(resource->surface.lock(), pLS); + if (!pMonitor) { Debug::log(ERR, "New LS has no monitor??"); return pLS; @@ -39,8 +42,6 @@ PHLLS CLayerSurface::create(SP resource) { pLS->alpha.setValueAndWarp(0.f); - pLS->surface.assign(resource->surface, pLS); - Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); return pLS; @@ -58,13 +59,16 @@ CLayerSurface::CLayerSurface(SP resource_) : layerSurface(r listeners.map = layerSurface->events.map.registerListener([this](std::any d) { onMap(); }); listeners.unmap = layerSurface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.destroy = layerSurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); + + surface = CWLSurface::create(); } CLayerSurface::~CLayerSurface() { if (!g_pHyprOpenGL) return; - surface.unassign(); + if (surface) + surface->unassign(); g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); } @@ -105,7 +109,8 @@ void CLayerSurface::onDestroy() { readyToDelete = true; layerSurface.reset(); - surface.unassign(); + if (surface) + surface->unassign(); } void CLayerSurface::onMap() { @@ -126,7 +131,7 @@ void CLayerSurface::onMap() { g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); - wlr_surface_send_enter(surface.wlr(), PMONITOR->output); + surface->resource()->enter(PMONITOR->self.lock()); if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); @@ -139,10 +144,10 @@ void CLayerSurface::onMap() { // TODO: use the new superb really very cool grab g_pSeatManager->setGrab(nullptr); g_pInputManager->releaseAllMouseButtons(); - g_pCompositor->focusSurface(surface.wlr()); + g_pCompositor->focusSurface(surface->resource()); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(surface.wlr(), LOCAL); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; } @@ -160,8 +165,8 @@ void CLayerSurface::onMap() { g_pEventManager->postEvent(SHyprIPCEvent{"openlayer", szNamespace}); EMIT_HOOK_EVENT("openLayer", self.lock()); - g_pCompositor->setPreferredScaleForSurface(surface.wlr(), PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(surface.wlr(), PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); } void CLayerSurface::onUnmap() { @@ -173,7 +178,7 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->layerSurface->surface); + g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource()); if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -197,9 +202,9 @@ void CLayerSurface::onUnmap() { const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); - const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == layerSurface->surface; + const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); - surface = nullptr; + surface.reset(); if (!PMONITOR) return; @@ -208,11 +213,11 @@ void CLayerSurface::onUnmap() { if (WASLASTFOCUS) { g_pInputManager->releaseAllMouseButtons(); - Vector2D surfaceCoords; - PHLLS pFoundLayerSurface; - wlr_surface* foundSurface = nullptr; + Vector2D surfaceCoords; + PHLLS pFoundLayerSurface; + SP foundSurface = nullptr; - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); // find LS-es to focus foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], @@ -236,8 +241,8 @@ void CLayerSurface::onUnmap() { CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); - geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.width, - (int)layerSurface->surface->current.height}; + geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x, + (int)layerSurface->surface->current.size.y}; g_pHyprRenderer->damageBox(&geomFixed); g_pInputManager->sendMotionEventsToFocused(); @@ -284,12 +289,12 @@ void CLayerSurface::onCommit() { position = Vector2D(geometry.x, geometry.y); // update geom if it changed - if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.has_dst) { + if (layerSurface->surface->current.scale == 1 && PMONITOR->scale != 1.f && layerSurface->surface->current.viewport.hasDestination) { // fractional scaling. Dirty hack. - geometry = {geometry.x, geometry.y, (int)(layerSurface->surface->current.viewport.dst_width), (int)(layerSurface->surface->current.viewport.dst_height)}; + geometry = {geometry.pos(), layerSurface->surface->current.viewport.destination}; } else { // this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly. - geometry = {geometry.x, geometry.y, (int)layerSurface->surface->current.width, (int)layerSurface->surface->current.height}; + geometry = {geometry.pos(), layerSurface->surface->current.size}; } } @@ -308,10 +313,10 @@ void CLayerSurface::onCommit() { if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained && !keyboardExclusive && mapped) { - g_pCompositor->focusSurface(layerSurface->surface); + g_pCompositor->focusSurface(surface->resource()); const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(layerSurface->surface, LOCAL); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); g_pInputManager->m_bEmptyFocusCursorSet = false; } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { g_pInputManager->refocus(); @@ -319,10 +324,10 @@ void CLayerSurface::onCommit() { keyboardExclusive = layerSurface->current.interactivity; - g_pHyprRenderer->damageSurface(layerSurface->surface, position.x, position.y); + g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); - g_pCompositor->setPreferredScaleForSurface(layerSurface->surface, PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(layerSurface->surface, PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(surface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(surface->resource(), PMONITOR->transform); } void CLayerSurface::applyRules() { diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index d60a6dd0..9fa96d2d 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -36,7 +36,7 @@ class CLayerSurface { bool keyboardExclusive = false; - CWLSurface surface; + SP surface; bool mapped = false; uint32_t layer = 0; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 6bc76fc7..f0fd556c 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { @@ -14,7 +15,8 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { } CPopup::CPopup(SP popup, CPopup* pOwner) : m_pParent(pOwner), m_pResource(popup) { - m_sWLSurface.assign(popup->surface->surface, this); + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(popup->surface->surface.lock(), this); m_pLayerOwner = pOwner->m_pLayerOwner; m_pWindowOwner = pOwner->m_pWindowOwner; @@ -26,7 +28,8 @@ CPopup::CPopup(SP popup, CPopup* pOwner) : m_pParent(pOwner), } CPopup::~CPopup() { - m_sWLSurface.unassign(); + if (m_pWLSurface) + m_pWLSurface->unassign(); } void CPopup::initAllSignals() { @@ -69,14 +72,14 @@ void CPopup::onMap() { if (m_bMapped) return; - m_bMapped = true; - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_bMapped = true; + m_vLastSize = m_pResource->surface->surface->current.size; + const auto COORDS = coordsGlobal(); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); - CBox box; - wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr()); - box.applyFromWlr().translate(COORDS).expand(4); + CBox box = m_pWLSurface->resource()->extends(); + box.translate(COORDS).expand(4); g_pHyprRenderer->damageBox(&box); m_vLastPos = coordsRelativeToParent(); @@ -87,7 +90,7 @@ void CPopup::onMap() { //unconstrain(); sendScale(); - wlr_surface_send_enter(m_pResource->surface->surface, PMONITOR->output); + m_pResource->surface->surface->enter(PMONITOR->self.lock()); if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); @@ -103,12 +106,12 @@ void CPopup::onUnmap() { return; } - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; + const auto COORDS = coordsGlobal(); - CBox box; - wlr_surface_get_extends(m_sWLSurface.wlr(), box.pWlr()); - box.applyFromWlr().translate(COORDS).expand(4); + CBox box = m_pWLSurface->resource()->extends(); + box.translate(COORDS).expand(4); g_pHyprRenderer->damageBox(&box); m_pSubsurfaceHead.reset(); @@ -143,7 +146,7 @@ void CPopup::onCommit(bool ignoreSiblings) { } if (!m_pWindowOwner.expired() && (!m_pWindowOwner->m_bIsMapped || !m_pWindowOwner->m_pWorkspace->m_bVisible)) { - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); if (*PLOGDAMAGE) @@ -157,11 +160,10 @@ void CPopup::onCommit(bool ignoreSiblings) { const auto COORDS = coordsGlobal(); const auto COORDSLOCAL = coordsRelativeToParent(); - if (m_vLastSize != Vector2D{m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height} || m_bRequestedReposition || - m_vLastPos != COORDSLOCAL) { + if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; g_pHyprRenderer->damageBox(&box); - m_vLastSize = {m_pResource->surface->surface->current.width, m_pResource->surface->surface->current.height}; + m_vLastSize = m_pResource->surface->surface->current.size; box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); @@ -171,7 +173,7 @@ void CPopup::onCommit(bool ignoreSiblings) { if (!ignoreSiblings && m_pSubsurfaceHead) m_pSubsurfaceHead->recheckDamageForSubsurfaces(); - g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); m_bRequestedReposition = false; @@ -211,7 +213,7 @@ Vector2D CPopup::coordsRelativeToParent() { while (current->m_pParent && current->m_pResource) { - offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; + offset += current->m_pWLSurface->resource()->current.offset; offset += current->m_pResource->geometry.pos(); current = current->m_pParent; @@ -260,9 +262,9 @@ Vector2D CPopup::size() { void CPopup::sendScale() { if (!m_pWindowOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pWindowOwner->m_pWLSurface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pWindowOwner->m_pWLSurface->m_fLastScale); else if (!m_pLayerOwner.expired()) - g_pCompositor->setPreferredScaleForSurface(m_sWLSurface.wlr(), m_pLayerOwner->surface.m_fLastScale); + g_pCompositor->setPreferredScaleForSurface(m_pWLSurface->resource(), m_pLayerOwner->surface->m_fLastScale); else UNREACHABLE(); } @@ -318,9 +320,8 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { return p; } else { const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const auto REGION = CRegion{&p->m_sWLSurface.wlr()->current.input} - .intersect(CBox{{}, {p->m_sWLSurface.wlr()->current.width, p->m_sWLSurface.wlr()->current.height}}) - .translate(p->coordsGlobal() + offset); + const auto REGION = + CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 7fdabee6..91e569e7 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -39,7 +39,7 @@ class CPopup { CPopup* at(const Vector2D& globalCoords, bool allowsInput = false); // - CWLSurface m_sWLSurface; + SP m_pWLSurface; private: // T1 owners, each popup has to have one of these diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 21482ff7..71ee16f0 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -2,29 +2,31 @@ #include "../events/Events.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" - -static void onNewSubsurface(void* owner, void* data); +#include "../protocols/core/Compositor.hpp" +#include "../protocols/core/Subcompositor.hpp" CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface.wlr()); + initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) { initSignals(); - initExistingSubsurfaces(pOwner->m_sWLSurface.wlr()); + initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } -CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { - m_sWLSurface.assign(pSubsurface->surface, this); +CSubsurface::CSubsurface(SP pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(pSubsurface->surface.lock(), this); initSignals(); - initExistingSubsurfaces(pSubsurface->surface); + initExistingSubsurfaces(pSubsurface->surface.lock()); } -CSubsurface::CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { - m_sWLSurface.assign(pSubsurface->surface, this); +CSubsurface::CSubsurface(SP pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { + m_pWLSurface = CWLSurface::create(); + m_pWLSurface->assign(pSubsurface->surface.lock(), this); initSignals(); - initExistingSubsurfaces(pSubsurface->surface); + initExistingSubsurfaces(pSubsurface->surface.lock()); } CSubsurface::~CSubsurface() { @@ -33,52 +35,27 @@ CSubsurface::~CSubsurface() { if (!m_pSubsurface) return; - m_pSubsurface->data = nullptr; - hyprListener_commitSubsurface.removeCallback(); hyprListener_destroySubsurface.removeCallback(); } -static void onNewSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onNewSubsurface((wlr_subsurface*)data); -} - -static void onDestroySubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onDestroy(); -} - -static void onCommitSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onCommit(); -} - -static void onMapSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onMap(); -} - -static void onUnmapSubsurface(void* owner, void* data) { - const auto PSUBSURFACE = (CSubsurface*)owner; - PSUBSURFACE->onUnmap(); -} - void CSubsurface::initSignals() { if (m_pSubsurface) { - m_pSubsurface->data = this; - hyprListener_commitSubsurface.initCallback(&m_pSubsurface->surface->events.commit, &onCommitSubsurface, this, "CSubsurface"); - hyprListener_destroySubsurface.initCallback(&m_pSubsurface->events.destroy, &onDestroySubsurface, this, "CSubsurface"); - hyprListener_newSubsurface.initCallback(&m_pSubsurface->surface->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface"); - hyprListener_mapSubsurface.initCallback(&m_pSubsurface->surface->events.map, &onMapSubsurface, this, "CSubsurface"); - hyprListener_unmapSubsurface.initCallback(&m_pSubsurface->surface->events.unmap, &onUnmapSubsurface, this, "CSubsurface"); + listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); + listeners.destroySubsurface = m_pSubsurface->events.destroy.registerListener([this](std::any d) { onDestroy(); }); + listeners.mapSubsurface = m_pSubsurface->surface->events.map.registerListener([this](std::any d) { onMap(); }); + listeners.unmapSubsurface = m_pSubsurface->surface->events.unmap.registerListener([this](std::any d) { onUnmap(); }); + listeners.newSubsurface = + m_pSubsurface->surface->events.newSubsurface.registerListener([this](std::any d) { onNewSubsurface(std::any_cast>(d)); }); } else { - if (!m_pWindowParent.expired()) - hyprListener_newSubsurface.initCallback(&m_pWindowParent->m_pWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); + if (m_pWindowParent) + listeners.newSubsurface = m_pWindowParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( + [this](std::any d) { onNewSubsurface(std::any_cast>(d)); }); else if (m_pPopupParent) - hyprListener_newSubsurface.initCallback(&m_pPopupParent->m_sWLSurface.wlr()->events.new_subsurface, &::onNewSubsurface, this, "CSubsurface Head"); + listeners.newSubsurface = m_pPopupParent->m_pWLSurface->resource()->events.newSubsurface.registerListener( + [this](std::any d) { onNewSubsurface(std::any_cast>(d)); }); else - RASSERT(false, "CSubsurface::initSignals empty subsurface"); + ASSERT(false); } } @@ -93,21 +70,21 @@ void CSubsurface::checkSiblingDamage() { continue; const auto COORDS = n->coordsGlobal(); - g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y, SCALE); + g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y, SCALE); } } void CSubsurface::recheckDamageForSubsurfaces() { for (auto& n : m_vChildren) { const auto COORDS = n->coordsGlobal(); - g_pHyprRenderer->damageSurface(n->m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); } } void CSubsurface::onCommit() { // no damaging if it's not visible if (!m_pWindowParent.expired() && (!m_pWindowParent->m_bIsMapped || !m_pWindowParent->m_pWorkspace->m_bVisible)) { - m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); if (*PLOGDAMAGE) @@ -117,7 +94,7 @@ void CSubsurface::onCommit() { const auto COORDS = coordsGlobal(); - g_pHyprRenderer->damageSurface(m_sWLSurface.wlr(), COORDS.x, COORDS.y); + g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); if (m_pPopupParent) m_pPopupParent->recheckTree(); @@ -127,10 +104,10 @@ void CSubsurface::onCommit() { // I do not think this is correct, but it solves a lot of issues with some apps (e.g. firefox) checkSiblingDamage(); - if (m_vLastSize != Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}) { + if (m_vLastSize != m_pWLSurface->resource()->current.size) { CBox box{COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); - m_vLastSize = Vector2D{m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; box = {COORDS, m_vLastSize}; g_pHyprRenderer->damageBox(&box); } @@ -149,20 +126,21 @@ void CSubsurface::onDestroy() { std::erase_if(m_pParent->m_vChildren, [this](const auto& other) { return other.get() == this; }); } -void CSubsurface::onNewSubsurface(wlr_subsurface* pSubsurface) { +void CSubsurface::onNewSubsurface(SP pSubsurface) { CSubsurface* PSUBSURFACE = nullptr; if (!m_pWindowParent.expired()) PSUBSURFACE = m_vChildren.emplace_back(std::make_unique(pSubsurface, m_pWindowParent.lock())).get(); else if (m_pPopupParent) PSUBSURFACE = m_vChildren.emplace_back(std::make_unique(pSubsurface, m_pPopupParent)).get(); - PSUBSURFACE->m_pParent = this; ASSERT(PSUBSURFACE); + + PSUBSURFACE->m_pParent = this; } void CSubsurface::onMap() { - m_vLastSize = {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + m_vLastSize = m_pWLSurface->resource()->current.size; const auto COORDS = coordsGlobal(); CBox box{COORDS, m_vLastSize}; @@ -179,7 +157,7 @@ void CSubsurface::onUnmap() { box.expand(4); g_pHyprRenderer->damageBox(&box); - if (m_sWLSurface.wlr() == g_pCompositor->m_pLastFocus) + if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus) g_pInputManager->releaseAllMouseButtons(); g_pInputManager->simulateMouseMovement(); @@ -188,19 +166,9 @@ void CSubsurface::onUnmap() { } Vector2D CSubsurface::coordsRelativeToParent() { - Vector2D offset; - - CSubsurface* current = this; - - while (current->m_pParent) { - - offset += {current->m_sWLSurface.wlr()->current.dx, current->m_sWLSurface.wlr()->current.dy}; - offset += {current->m_pSubsurface->current.x, current->m_pSubsurface->current.y}; - - current = current->m_pParent; - } - - return offset; + if (!m_pSubsurface) + return {}; + return m_pSubsurface->posRelativeToParent(); } Vector2D CSubsurface::coordsGlobal() { @@ -214,18 +182,16 @@ Vector2D CSubsurface::coordsGlobal() { return coords; } -void CSubsurface::initExistingSubsurfaces(wlr_surface* pSurface) { - wlr_subsurface* wlrSubsurface; - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_below, current.link) { - ::onNewSubsurface(this, wlrSubsurface); - } - wl_list_for_each(wlrSubsurface, &pSurface->current.subsurfaces_above, current.link) { - ::onNewSubsurface(this, wlrSubsurface); +void CSubsurface::initExistingSubsurfaces(SP pSurface) { + for (auto& s : pSurface->subsurfaces) { + if (!s || s->surface->hlSurface /* already assigned */) + continue; + onNewSubsurface(s.lock()); } } Vector2D CSubsurface::size() { - return {m_sWLSurface.wlr()->current.width, m_sWLSurface.wlr()->current.height}; + return m_pWLSurface->resource()->current.size; } bool CSubsurface::visible() { diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index f3a5ea4b..101f4f19 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -5,6 +5,7 @@ #include "WLSurface.hpp" class CPopup; +class CWLSubsurfaceResource; class CSubsurface { public: @@ -13,8 +14,8 @@ class CSubsurface { CSubsurface(CPopup* pOwner); // real nodes - CSubsurface(wlr_subsurface* pSubsurface, PHLWINDOW pOwner); - CSubsurface(wlr_subsurface* pSubsurface, CPopup* pOwner); + CSubsurface(SP pSubsurface, PHLWINDOW pOwner); + CSubsurface(SP pSubsurface, CPopup* pOwner); ~CSubsurface(); @@ -25,7 +26,7 @@ class CSubsurface { void onCommit(); void onDestroy(); - void onNewSubsurface(wlr_subsurface* pSubsurface); + void onNewSubsurface(SP pSubsurface); void onMap(); void onUnmap(); @@ -37,12 +38,18 @@ class CSubsurface { DYNLISTENER(destroySubsurface); DYNLISTENER(commitSubsurface); DYNLISTENER(newSubsurface); - DYNLISTENER(mapSubsurface); - DYNLISTENER(unmapSubsurface); - wlr_subsurface* m_pSubsurface = nullptr; - CWLSurface m_sWLSurface; - Vector2D m_vLastSize = {}; + struct { + CHyprSignalListener destroySubsurface; + CHyprSignalListener commitSubsurface; + CHyprSignalListener mapSubsurface; + CHyprSignalListener unmapSubsurface; + CHyprSignalListener newSubsurface; + } listeners; + + WP m_pSubsurface; + SP m_pWLSurface; + Vector2D m_vLastSize = {}; // if nullptr, means it's a dummy node CSubsurface* m_pParent = nullptr; @@ -55,6 +62,6 @@ class CSubsurface { bool m_bInert = false; void initSignals(); - void initExistingSubsurfaces(wlr_surface* pSurface); + void initExistingSubsurfaces(SP pSurface); void checkSiblingDamage(); }; \ No newline at end of file diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 78b50d45..c7a09b40 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -1,36 +1,37 @@ #include "WLSurface.hpp" #include "../Compositor.hpp" +#include "../protocols/core/Compositor.hpp" -void CWLSurface::assign(wlr_surface* pSurface) { - m_pWLRSurface = pSurface; +void CWLSurface::assign(SP pSurface) { + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, PHLWINDOW pOwner) { +void CWLSurface::assign(SP pSurface, PHLWINDOW pOwner) { m_pWindowOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, PHLLS pOwner) { +void CWLSurface::assign(SP pSurface, PHLLS pOwner) { m_pLayerOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, CSubsurface* pOwner) { +void CWLSurface::assign(SP pSurface, CSubsurface* pOwner) { m_pSubsurfaceOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } -void CWLSurface::assign(wlr_surface* pSurface, CPopup* pOwner) { +void CWLSurface::assign(SP pSurface, CPopup* pOwner) { m_pPopupOwner = pOwner; - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); m_bInert = false; } @@ -44,20 +45,23 @@ CWLSurface::~CWLSurface() { } bool CWLSurface::exists() const { - return m_pWLRSurface; + return m_pResource; } -wlr_surface* CWLSurface::wlr() const { - return m_pWLRSurface; +SP CWLSurface::resource() const { + return m_pResource.lock(); } bool CWLSurface::small() const { if (!validMapped(m_pWindowOwner) || !exists()) return false; + if (!m_pResource->current.buffer) + return false; + const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || O->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1; + return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { @@ -71,29 +75,28 @@ Vector2D CWLSurface::correctSmallVec() const { } Vector2D CWLSurface::getViewporterCorrectedSize() const { - if (!exists()) + if (!exists() || !m_pResource->current.buffer) return {}; - return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} : - Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height}; + return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; } CRegion CWLSurface::logicalDamage() const { - CRegion damage{&m_pWLRSurface->buffer_damage}; - damage.transform(m_pWLRSurface->current.transform, m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height); - damage.scale(1.0 / m_pWLRSurface->current.scale); + if (!m_pResource->current.buffer) + return {}; + + CRegion damage = m_pResource->accumulateCurrentBufferDamage(); + damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); + damage.scale(1.0 / m_pResource->current.scale); const auto VPSIZE = getViewporterCorrectedSize(); const auto CORRECTVEC = correctSmallVec(); - if (m_pWLRSurface->current.viewport.has_src) { - damage.intersect(CBox{std::floor(m_pWLRSurface->current.viewport.src.x), std::floor(m_pWLRSurface->current.viewport.src.y), - std::ceil(m_pWLRSurface->current.viewport.src.width), std::ceil(m_pWLRSurface->current.viewport.src.height)}); - } + if (m_pResource->current.viewport.hasSource) + damage.intersect(m_pResource->current.viewport.source); - const auto SCALEDSRCSIZE = m_pWLRSurface->current.viewport.has_src ? - Vector2D{m_pWLRSurface->current.viewport.src.width, m_pWLRSurface->current.viewport.src.height} * m_pWLRSurface->current.scale : - Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height}; + const auto SCALEDSRCSIZE = + m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size; damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y}); damage.translate(CORRECTVEC); @@ -102,48 +105,38 @@ CRegion CWLSurface::logicalDamage() const { } void CWLSurface::destroy() { - if (!m_pWLRSurface) + if (!m_pResource) return; events.destroy.emit(); m_pConstraint.reset(); - hyprListener_destroy.removeCallback(); - hyprListener_commit.removeCallback(); - m_pWLRSurface->data = nullptr; + listeners.destroy.reset(); + m_pResource->hlSurface.reset(); m_pWindowOwner.reset(); m_pLayerOwner.reset(); m_pPopupOwner = nullptr; m_pSubsurfaceOwner = nullptr; m_bInert = true; - if (g_pCompositor && g_pCompositor->m_pLastFocus == m_pWLRSurface) - g_pCompositor->m_pLastFocus = nullptr; - if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this) + if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf && g_pHyprRenderer->m_sLastCursorData.surf->get() == this) g_pHyprRenderer->m_sLastCursorData.surf.reset(); - m_pWLRSurface = nullptr; + m_pResource.reset(); Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this); } -static void onCommit(void* owner, void* data) { - const auto SURF = (CWLSurface*)owner; - SURF->onCommit(); -} - void CWLSurface::init() { - if (!m_pWLRSurface) + if (!m_pResource) return; - RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!"); + RASSERT(!m_pResource->hlSurface, "Attempted to duplicate CWLSurface ownership!"); - m_pWLRSurface->data = this; + m_pResource->hlSurface = self.lock(); - hyprListener_destroy.initCallback( - &m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface"); - hyprListener_commit.initCallback(&m_pWLRSurface->events.commit, ::onCommit, this, "CWLSurface"); + listeners.destroy = m_pResource->events.destroy.registerListener([this](std::any d) { destroy(); }); Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); } @@ -188,10 +181,6 @@ void CWLSurface::appendConstraint(WP constraint) { m_pConstraint = constraint; } -void CWLSurface::onCommit() { - ; -} - SP CWLSurface::constraint() { return m_pConstraint.lock(); } @@ -207,3 +196,9 @@ bool CWLSurface::visible() { return m_pSubsurfaceOwner->visible(); return true; // non-desktop, we don't know much. } + +SP CWLSurface::fromResource(SP pSurface) { + if (!pSurface) + return nullptr; + return pSurface->hlSurface.lock(); +} diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 03e81b45..4ba381a9 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -7,33 +7,37 @@ class CSubsurface; class CPopup; class CPointerConstraint; +class CWLSurfaceResource; class CWLSurface { public: - CWLSurface() = default; + static SP create() { + auto p = SP(new CWLSurface); + p->self = p; + return p; + } ~CWLSurface(); // anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD - void assign(wlr_surface* pSurface); - void assign(wlr_surface* pSurface, PHLWINDOW pOwner); - void assign(wlr_surface* pSurface, PHLLS pOwner); - void assign(wlr_surface* pSurface, CSubsurface* pOwner); - void assign(wlr_surface* pSurface, CPopup* pOwner); + void assign(SP pSurface); + void assign(SP pSurface, PHLWINDOW pOwner); + void assign(SP pSurface, PHLLS pOwner); + void assign(SP pSurface, CSubsurface* pOwner); + void assign(SP pSurface, CPopup* pOwner); void unassign(); - CWLSurface(const CWLSurface&) = delete; - CWLSurface(CWLSurface&&) = delete; - CWLSurface& operator=(const CWLSurface&) = delete; - CWLSurface& operator=(CWLSurface&&) = delete; + CWLSurface(const CWLSurface&) = delete; + CWLSurface(CWLSurface&&) = delete; + CWLSurface& operator=(const CWLSurface&) = delete; + CWLSurface& operator=(CWLSurface&&) = delete; - wlr_surface* wlr() const; - bool exists() const; - bool small() const; // means surface is smaller than the requested size - Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces - Vector2D getViewporterCorrectedSize() const; - CRegion logicalDamage() const; - void onCommit(); - bool visible(); + SP resource() const; + bool exists() const; + bool small() const; // means surface is smaller than the requested size + Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces + Vector2D getViewporterCorrectedSize() const; + CRegion logicalDamage() const; + bool visible(); // getters for owners. PHLWINDOW getWindow(); @@ -55,31 +59,27 @@ class CWLSurface { wl_output_transform m_eLastTransform = (wl_output_transform)-1; // - CWLSurface& operator=(wlr_surface* pSurface) { + CWLSurface& operator=(SP pSurface) { destroy(); - m_pWLRSurface = pSurface; + m_pResource = pSurface; init(); return *this; } bool operator==(const CWLSurface& other) const { - return other.wlr() == wlr(); + return other.resource() == resource(); } - bool operator==(const wlr_surface* other) const { - return other == wlr(); + bool operator==(const SP other) const { + return other == resource(); } explicit operator bool() const { return exists(); } - static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) { - if (!pSurface) - return nullptr; - return (CWLSurface*)pSurface->data; - } + static SP fromResource(SP pSurface); // used by the alpha-modifier protocol float m_pAlphaModifier = 1.F; @@ -88,15 +88,19 @@ class CWLSurface { CSignal destroy; } events; + WP self; + private: - bool m_bInert = true; + CWLSurface() = default; - wlr_surface* m_pWLRSurface = nullptr; + bool m_bInert = true; - PHLWINDOWREF m_pWindowOwner; - PHLLSREF m_pLayerOwner; - CPopup* m_pPopupOwner = nullptr; - CSubsurface* m_pSubsurfaceOwner = nullptr; + WP m_pResource; + + PHLWINDOWREF m_pWindowOwner; + PHLLSREF m_pLayerOwner; + CPopup* m_pPopupOwner = nullptr; + CSubsurface* m_pSubsurfaceOwner = nullptr; // WP m_pConstraint; @@ -105,8 +109,9 @@ class CWLSurface { void init(); bool desktopComponent(); - DYNLISTENER(destroy); - DYNLISTENER(commit); + struct { + CHyprSignalListener destroy; + } listeners; friend class CPointerConstraint; }; \ No newline at end of file diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index c478b766..5d6e32e9 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -9,6 +9,7 @@ #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" PHLWINDOW CWindow::create(SP surface) { @@ -51,12 +52,14 @@ PHLWINDOW CWindow::create(SP resource) { pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); - pWindow->m_pWLSurface.assign(pWindow->m_pXDGSurface->surface, pWindow); + pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow); return pWindow; } CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { + m_pWLSurface = CWLSurface::create(); + listeners.map = m_pXDGSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); listeners.ack = m_pXDGSurface->events.ack.registerListener([this](std::any d) { onAck(std::any_cast(d)); }); listeners.unmap = m_pXDGSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); @@ -67,6 +70,8 @@ CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { } CWindow::CWindow(SP surface) : m_pXWaylandSurface(surface) { + m_pWLSurface = CWLSurface::create(); + listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); @@ -83,7 +88,7 @@ CWindow::CWindow(SP surface) : m_pXWaylandSurface(surface) { CWindow::~CWindow() { if (g_pCompositor->m_pLastWindow.lock().get() == this) { - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pCompositor->m_pLastWindow.reset(); } @@ -124,12 +129,12 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { if (EXTENTS.bottomRight.y > maxExtents.bottomRight.y) maxExtents.bottomRight.y = EXTENTS.bottomRight.y; - if (m_pWLSurface.exists() && !m_bIsX11 && m_pPopupHead) { + if (m_pWLSurface->exists() && !m_bIsX11 && m_pPopupHead) { CBox surfaceExtents = {0, 0, 0, 0}; // TODO: this could be better, perhaps make a getFullWindowRegion? m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; CBox* pSurfaceExtents = (CBox*)data; @@ -151,11 +156,11 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { if (-surfaceExtents.y > maxExtents.topLeft.y) maxExtents.topLeft.y = -surfaceExtents.y; - if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface.wlr()->current.width + maxExtents.bottomRight.x) - maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface.wlr()->current.width; + if (surfaceExtents.x + surfaceExtents.width > m_pWLSurface->resource()->current.size.x + maxExtents.bottomRight.x) + maxExtents.bottomRight.x = surfaceExtents.x + surfaceExtents.width - m_pWLSurface->resource()->current.size.x; - if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface.wlr()->current.height + maxExtents.bottomRight.y) - maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface.wlr()->current.height; + if (surfaceExtents.y + surfaceExtents.height > m_pWLSurface->resource()->current.size.y + maxExtents.bottomRight.y) + maxExtents.bottomRight.y = surfaceExtents.y + surfaceExtents.height - m_pWLSurface->resource()->current.size.y; } return maxExtents; @@ -340,17 +345,7 @@ void CWindow::updateToplevel() { updateSurfaceScaleTransformDetails(); } -void sendEnterIter(wlr_surface* pSurface, int x, int y, void* data) { - const auto OUTPUT = (wlr_output*)data; - wlr_surface_send_enter(pSurface, OUTPUT); -} - -void sendLeaveIter(wlr_surface* pSurface, int x, int y, void* data) { - const auto OUTPUT = (wlr_output*)data; - wlr_surface_send_leave(pSurface, OUTPUT); -} - -void CWindow::updateSurfaceScaleTransformDetails() { +void CWindow::updateSurfaceScaleTransformDetails(bool force) { if (!m_bIsMapped || m_bHidden || g_pCompositor->m_bUnsafeState) return; @@ -363,26 +358,25 @@ void CWindow::updateSurfaceScaleTransformDetails() { if (!PNEWMONITOR) return; - if (PNEWMONITOR != PLASTMONITOR) { - if (PLASTMONITOR && PLASTMONITOR->m_bEnabled) - wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendLeaveIter, PLASTMONITOR->output); + if (PNEWMONITOR != PLASTMONITOR || force) { + if (PLASTMONITOR && PLASTMONITOR->m_bEnabled && PNEWMONITOR != PLASTMONITOR) + m_pWLSurface->resource()->breadthfirst([PLASTMONITOR](SP s, const Vector2D& offset, void* d) { s->leave(PLASTMONITOR->self.lock()); }, nullptr); - wlr_surface_for_each_surface(m_pWLSurface.wlr(), sendEnterIter, PNEWMONITOR->output); + m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); } - wlr_surface_for_each_surface( - m_pWLSurface.wlr(), - [](wlr_surface* surf, int x, int y, void* data) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(((CWindow*)data)->m_iMonitorID); + m_pWLSurface->resource()->breadthfirst( + [this](SP s, const Vector2D& offset, void* d) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); - const auto PSURFACE = CWLSurface::surfaceFromWlr(surf); + const auto PSURFACE = CWLSurface::fromResource(s); if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) return; - g_pCompositor->setPreferredScaleForSurface(surf, PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(surf, PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(s, PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(s, PMONITOR->transform); }, - this); + nullptr); } void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { @@ -568,6 +562,8 @@ void CWindow::onMap() { m_vReportedSize = m_vPendingReportedSize; m_bAnimatingIn = true; + updateSurfaceScaleTransformDetails(true); + if (m_bIsX11) return; @@ -860,7 +856,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) { CPopup* popup = m_pPopupHead->at(pos); - return popup && popup->m_sWLSurface.wlr(); + return popup && popup->m_pWLSurface->resource(); } void CWindow::applyGroupRules() { @@ -1135,23 +1131,24 @@ bool CWindow::opaque() { const auto PWORKSPACE = m_pWorkspace; - if (m_pWLSurface.small() && !m_pWLSurface.m_bFillIgnoreSmall) + if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall) return false; if (PWORKSPACE->m_fAlpha.value() != 1.f) return false; - if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface) - return m_pXWaylandSurface->surface->opaque; + if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer) + return m_pXWaylandSurface->surface->current.buffer->opaque; - if (m_pXDGSurface && m_pXDGSurface->surface->opaque) + if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer) + return false; + + // TODO: this is wrong + const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents(); + if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y) return true; - const auto EXTENTS = pixman_region32_extents(&m_pXDGSurface->surface->opaque_region); - if (EXTENTS->x2 - EXTENTS->x1 >= m_pXDGSurface->surface->current.buffer_width && EXTENTS->y2 - EXTENTS->y1 >= m_pXDGSurface->surface->current.buffer_height) - return true; - - return false; + return m_pWLSurface->resource()->current.buffer->opaque; } float CWindow::rounding() { @@ -1282,8 +1279,7 @@ int CWindow::surfacesCount() { return 1; int no = 0; - wlr_surface_for_each_surface( - m_pWLSurface.wlr(), [](wlr_surface* surf, int x, int y, void* data) { *((int*)data) += 1; }, &no); + m_pWLSurface->resource()->breadthfirst([](SP r, const Vector2D& offset, void* d) { *((int*)d) += 1; }, &no); return no; } @@ -1456,16 +1452,16 @@ void CWindow::onAck(uint32_t serial) { } void CWindow::onResourceChangeX11() { - if (m_pXWaylandSurface->surface && !m_pWLSurface.wlr()) - m_pWLSurface.assign(m_pXWaylandSurface->surface, m_pSelf.lock()); - else if (!m_pXWaylandSurface->surface && m_pWLSurface.wlr()) - m_pWLSurface.unassign(); + if (m_pXWaylandSurface->surface && !m_pWLSurface->resource()) + m_pWLSurface->assign(m_pXWaylandSurface->surface.lock(), m_pSelf.lock()); + else if (!m_pXWaylandSurface->surface && m_pWLSurface->resource()) + m_pWLSurface->unassign(); // update metadata as well, // could be first assoc and we need to catch the class onUpdateMeta(); - Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface.wlr()); + Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get()); } void CWindow::onX11Configure(CBox box) { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 151d9809..85c74622 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -213,7 +213,7 @@ class CWindow { public: ~CWindow(); - CWLSurface m_pWLSurface; + SP m_pWLSurface; struct { CSignal destroy; @@ -396,7 +396,7 @@ class CWindow { IHyprWindowDecoration* getDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType); void updateToplevel(); - void updateSurfaceScaleTransformDetails(); + void updateSurfaceScaleTransformDetails(bool force = false); void moveToWorkspace(PHLWORKSPACE); PHLWINDOW X11TransientFor(); void onUnmap(); diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp index f5b610a9..b5ab16c1 100644 --- a/src/devices/Tablet.cpp +++ b/src/devices/Tablet.cpp @@ -1,6 +1,7 @@ #include "Tablet.hpp" #include "../defines.hpp" #include "../protocols/Tablet.hpp" +#include "../protocols/core/Compositor.hpp" SP CTablet::create(wlr_tablet* tablet) { SP pTab = SP(new CTablet(tablet)); @@ -295,32 +296,29 @@ CTabletTool::~CTabletTool() { void CTabletTool::disconnectCallbacks() { hyprListener_destroy.removeCallback(); - hyprListener_destroySurface.removeCallback(); + listeners.destroySurface.reset(); } -wlr_surface* CTabletTool::getSurface() { - return pSurface; +SP CTabletTool::getSurface() { + return pSurface.lock(); } -void CTabletTool::setSurface(wlr_surface* surf) { +void CTabletTool::setSurface(SP surf) { if (surf == pSurface) return; if (pSurface) { - hyprListener_destroySurface.removeCallback(); - pSurface = nullptr; + listeners.destroySurface.reset(); + pSurface.reset(); } pSurface = surf; if (surf) { - hyprListener_destroySurface.initCallback( - &surf->events.destroy, - [this](void* owner, void* data) { - PROTO::tablet->proximityOut(self.lock()); - pSurface = nullptr; - hyprListener_destroySurface.removeCallback(); - }, - this, "CTabletTool"); + listeners.destroySurface = surf->events.destroy.registerListener([this](std::any d) { + PROTO::tablet->proximityOut(self.lock()); + pSurface.reset(); + listeners.destroySurface.reset(); + }); } } diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index f2444972..1805f3ba 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -12,6 +12,7 @@ struct wlr_tablet_pad; class CTabletTool; class CTabletPad; +class CWLSurfaceResource; /* A tablet device @@ -197,32 +198,35 @@ class CTabletTool : public IHID { HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), }; - virtual uint32_t getCapabilities(); - wlr_tablet_tool* wlr(); - virtual eHIDType getType(); - wlr_surface* getSurface(); - void setSurface(wlr_surface*); + virtual uint32_t getCapabilities(); + wlr_tablet_tool* wlr(); + virtual eHIDType getType(); + SP getSurface(); + void setSurface(SP); - WP self; - Vector2D tilt; - bool active = false; // true if in proximity - uint32_t toolCapabilities = 0; + WP self; + Vector2D tilt; + bool active = false; // true if in proximity + uint32_t toolCapabilities = 0; - bool isDown = false; - std::vector buttonsDown; - Vector2D absolutePos; // last known absolute position. + bool isDown = false; + std::vector buttonsDown; + Vector2D absolutePos; // last known absolute position. - std::string hlName; + std::string hlName; private: CTabletTool(wlr_tablet_tool* tool); - void disconnectCallbacks(); + void disconnectCallbacks(); - wlr_surface* pSurface = nullptr; + WP pSurface; - wlr_tablet_tool* tool = nullptr; + wlr_tablet_tool* tool = nullptr; DYNLISTENER(destroy); - DYNLISTENER(destroySurface); + + struct { + CHyprSignalListener destroySurface; + } listeners; }; \ No newline at end of file diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 5372a105..88b28c87 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -9,6 +9,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" // ------------------------------------------------------------ // @@ -104,7 +105,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // registers the animated vars and stuff PWINDOW->onMap(); - const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface.wlr(); + const auto PWINDOWSURFACE = PWINDOW->m_pWLSurface->resource(); if (!PWINDOWSURFACE) { g_pCompositor->removeWindowFromVectorSafe(PWINDOW); @@ -463,7 +464,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // check LS focus grab const auto PFORCEFOCUS = g_pCompositor->getForceFocus(); - const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { @@ -618,8 +619,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating) PWINDOW->m_fAlpha.setValueAndWarp(0.f); - g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->scale); - g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface.wlr(), PMONITOR->transform); + g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); + g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform); if (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) g_pInputManager->sendMotionEventsToFocused(); @@ -638,7 +639,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { Debug::log(LOG, "{:c} unmapped", PWINDOW); - if (!PWINDOW->m_pWLSurface.exists() || !PWINDOW->m_bIsMapped) { + if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); PWINDOW->m_bFadingOut = false; return; @@ -674,7 +675,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { wasLastWindow = true; g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pInputManager->releaseAllMouseButtons(); } @@ -788,7 +789,7 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_pWorkspace->m_bVisible) return; - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface.wlr(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); if (!PWINDOW->m_bIsX11) { @@ -798,9 +799,8 @@ void Events::listener_commitWindow(void* owner, void* data) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); - if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && - PWINDOW->m_pWLSurface.wlr()->current.committed & WLR_SURFACE_STATE_BUFFER) { - CRegion damageBox{&PWINDOW->m_pWLSurface.wlr()->buffer_damage}; + if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { + CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage}; if (!damageBox.empty()) { if (PMONITOR->tearingState.busy) { @@ -820,10 +820,10 @@ void Events::listener_destroyWindow(void* owner, void* data) { if (PWINDOW == g_pCompositor->m_pLastWindow.lock()) { g_pCompositor->m_pLastWindow.reset(); - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); } - PWINDOW->m_pWLSurface.unassign(); + PWINDOW->m_pWLSurface->unassign(); PWINDOW->listeners = {}; diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp new file mode 100644 index 00000000..3d6b7cc3 --- /dev/null +++ b/src/helpers/Format.cpp @@ -0,0 +1,271 @@ +#include "Format.hpp" +#include +#include "../includes.hpp" + +/* + DRM formats are LE, while OGL is BE. The two primary formats + will be flipped, so we will set flipRB which will later use swizzle + to flip the red and blue channels. + This will not work on GLES2, but I want to drop support for it one day anyways. +*/ +inline const std::vector GLES3_FORMATS = { + { + .drmFormat = DRM_FORMAT_ARGB8888, + .flipRB = true, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XRGB8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XRGB8888, + .flipRB = true, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XRGB8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XBGR8888, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ABGR8888, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR8888, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_BGR888, + .glFormat = GL_RGB, + .glType = GL_UNSIGNED_BYTE, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_BGR888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_RGBX4444, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_4_4_4_4, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBA4444, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_4_4_4_4, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBX5551, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_5_5_5_1, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGBX5551, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGBA5551, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT_5_5_5_1, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_RGBX5551, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGB565, + .glFormat = GL_RGB, + .glType = GL_UNSIGNED_SHORT_5_6_5, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_RGB565, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_XBGR2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ABGR2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XRGB2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XRGB2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_ARGB2101010, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XRGB2101010, + .bytesPerBlock = 4, + }, + { + .drmFormat = DRM_FORMAT_XBGR16161616F, + .glFormat = GL_RGBA, + .glType = GL_HALF_FLOAT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616F, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_ABGR16161616F, + .glFormat = GL_RGBA, + .glType = GL_HALF_FLOAT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616F, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_XBGR16161616, + .glInternalFormat = GL_RGBA16UI, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_ABGR16161616, + .glInternalFormat = GL_RGBA16UI, + .glFormat = GL_RGBA, + .glType = GL_UNSIGNED_SHORT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, + }, + { + .drmFormat = DRM_FORMAT_YVYU, + .bytesPerBlock = 4, + .blockSize = {2, 1}, + }, + { + .drmFormat = DRM_FORMAT_VYUY, + .bytesPerBlock = 4, + .blockSize = {2, 1}, + }, + { + .drmFormat = DRM_FORMAT_R8, + .bytesPerBlock = 1, + }, + { + .drmFormat = DRM_FORMAT_GR88, + .bytesPerBlock = 2, + }, + { + .drmFormat = DRM_FORMAT_RGB888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_BGR888, + .bytesPerBlock = 3, + }, + { + .drmFormat = DRM_FORMAT_RGBX4444, + .bytesPerBlock = 2, + }, +}; + +SHMFormat FormatUtils::drmToShm(DRMFormat drm) { + switch (drm) { + case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; + case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; + default: return drm; + } + + return drm; +} + +DRMFormat FormatUtils::shmToDRM(SHMFormat shm) { + switch (shm) { + case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; + case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; + default: return shm; + } + + return shm; +} + +const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { + for (auto& fmt : GLES3_FORMATS) { + if (fmt.drmFormat == drm) + return &fmt; + } + + return nullptr; +} + +const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) { + for (auto& fmt : GLES3_FORMATS) { + if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha) + return &fmt; + } + + return nullptr; +} + +bool FormatUtils::isFormatOpaque(DRMFormat drm) { + const auto FMT = FormatUtils::getPixelFormatFromDRM(drm); + if (!FMT) + return false; + + return !FMT->withAlpha; +} + +int FormatUtils::pixelsPerBlock(const SPixelFormat* const fmt) { + return fmt->blockSize.x * fmt->blockSize.y > 0 ? fmt->blockSize.x * fmt->blockSize.y : 1; +} + +int FormatUtils::minStride(const SPixelFormat* const fmt, int32_t width) { + return std::ceil((width * fmt->bytesPerBlock) / pixelsPerBlock(fmt)); +} + +uint32_t FormatUtils::drmFormatToGL(DRMFormat drm) { + switch (drm) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case. + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: +#ifdef GLES2 + return GL_RGB10_A2_EXT; +#else + return GL_RGB10_A2; +#endif + default: return GL_RGBA; + } + UNREACHABLE(); + return GL_RGBA; +} + +uint32_t FormatUtils::glFormatToType(uint32_t gl) { + return gl != GL_RGBA ? +#ifdef GLES2 + GL_UNSIGNED_INT_2_10_10_10_REV_EXT : +#else + GL_UNSIGNED_INT_2_10_10_10_REV : +#endif + GL_UNSIGNED_BYTE; +} diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp new file mode 100644 index 00000000..b86f44dd --- /dev/null +++ b/src/helpers/Format.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include +#include "Vector2D.hpp" + +typedef uint32_t DRMFormat; +typedef uint32_t SHMFormat; + +struct SPixelFormat { + DRMFormat drmFormat = 0; /* DRM_FORMAT_INVALID */ + bool flipRB = false; + int glInternalFormat = 0; + int glFormat = 0; + int glType = 0; + bool withAlpha = true; + DRMFormat alphaStripped = 0; /* DRM_FORMAT_INVALID */ + uint32_t bytesPerBlock = 0; + Vector2D blockSize; +}; + +struct SDRMFormat { + uint32_t format = 0; + std::vector mods; +}; + +namespace FormatUtils { + SHMFormat drmToShm(DRMFormat drm); + DRMFormat shmToDRM(SHMFormat shm); + + const SPixelFormat* getPixelFormatFromDRM(DRMFormat drm); + const SPixelFormat* getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha); + bool isFormatOpaque(DRMFormat drm); + int pixelsPerBlock(const SPixelFormat* const fmt); + int minStride(const SPixelFormat* const fmt, int32_t width); + uint32_t drmFormatToGL(DRMFormat drm); + uint32_t glFormatToType(uint32_t gl); +}; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index a520c9d4..32cd9868 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -857,33 +857,6 @@ void throwError(const std::string& err) { throw std::runtime_error(err); } -uint32_t drmFormatToGL(uint32_t drm) { - switch (drm) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: return GL_RGBA; // doesn't matter, opengl is gucci in this case. - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: -#ifdef GLES2 - return GL_RGB10_A2_EXT; -#else - return GL_RGB10_A2; -#endif - default: return GL_RGBA; - } - UNREACHABLE(); - return GL_RGBA; -} - -uint32_t glFormatToType(uint32_t gl) { - return gl != GL_RGBA ? -#ifdef GLES2 - GL_UNSIGNED_INT_2_10_10_10_REV_EXT : -#else - GL_UNSIGNED_INT_2_10_10_10_REV : -#endif - GL_UNSIGNED_BYTE; -} - bool envEnabled(const std::string& env) { const auto ENV = getenv(env.c_str()); if (!ENV) @@ -922,3 +895,42 @@ int allocateSHMFile(size_t len) { return fd; } + +bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { + auto [fd, name] = openExclusiveShm(); + if (fd < 0) { + return false; + } + + // CLOEXEC is guaranteed to be set by shm_open + int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); + if (ro_fd < 0) { + shm_unlink(name.c_str()); + close(fd); + return false; + } + + shm_unlink(name.c_str()); + + // Make sure the file cannot be re-opened in read-write mode (e.g. via + // "/proc/self/fd/" on Linux) + if (fchmod(fd, 0) != 0) { + close(fd); + close(ro_fd); + return false; + } + + int ret; + do { + ret = ftruncate(fd, size); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + close(fd); + close(ro_fd); + return false; + } + + *rw_fd_ptr = fd; + *ro_fd_ptr = ro_fd; + return true; +} diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 80103eac..9d34174c 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -35,10 +35,9 @@ double normalizeAngleRad(double ang); std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::vector getBacktrace(); void throwError(const std::string& err); -uint32_t drmFormatToGL(uint32_t drm); -uint32_t glFormatToType(uint32_t gl); bool envEnabled(const std::string& env); int allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); template [[deprecated("use std::format instead")]] std::string getFormat(std::format_string fmt, Args&&... args) { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d13acf0c..5962b73d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -216,7 +216,6 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); - updateGlobal(); } void CMonitor::onDisconnect(bool destroy) { @@ -284,8 +283,6 @@ void CMonitor::onDisconnect(bool destroy) { m_bEnabled = false; m_bRenderingInitPassed = false; - updateGlobal(); - if (BACKUPMON) { // snap cursor g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true); @@ -304,7 +301,7 @@ void CMonitor::onDisconnect(bool destroy) { w->startAnim(true, true, true); } } else { - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pCompositor->m_pLastWindow.reset(); g_pCompositor->m_pLastMonitor.reset(); } @@ -750,13 +747,6 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } -void CMonitor::updateGlobal() { - if (output->width > 0 && output->height > 0 && m_bEnabled) - wlr_output_create_global(output, g_pCompositor->m_sWLDisplay); - else - wlr_output_destroy_global(output); -} - CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; wlr_output_state_init(&m_state); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index e4456084..4bfbf53c 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -172,7 +172,6 @@ class CMonitor { int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); CBox logicalBox(); - void updateGlobal(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp index 20eaf452..9e572b34 100644 --- a/src/helpers/Region.cpp +++ b/src/helpers/Region.cpp @@ -4,6 +4,8 @@ extern "C" { #include } +constexpr const int64_t MAX_REGION_SIDE = 10000000; + CRegion::CRegion() { pixman_region32_init(&m_rRegion); } @@ -103,6 +105,11 @@ CRegion& CRegion::transform(const wl_output_transform t, double w, double h) { return *this; } +CRegion& CRegion::rationalize() { + intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2}); + return *this; +} + CRegion CRegion::copy() const { return CRegion(*this); } diff --git a/src/helpers/Region.hpp b/src/helpers/Region.hpp index 27f460f4..42693c21 100644 --- a/src/helpers/Region.hpp +++ b/src/helpers/Region.hpp @@ -50,6 +50,7 @@ class CRegion { CRegion& invert(const CBox& box); CRegion& scale(float scale); CRegion& scale(const Vector2D& scale); + CRegion& rationalize(); CBox getExtents(); bool containsPoint(const Vector2D& vec) const; bool empty() const; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 30f5aebf..d5be9f40 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -13,6 +13,7 @@ class CMonitor; class IPointer; class IKeyboard; +class CWLSurfaceResource; struct SRenderData { CMonitor* pMonitor; @@ -20,9 +21,9 @@ struct SRenderData { double x, y; // for iters - void* data = nullptr; - wlr_surface* surface = nullptr; - double w, h; + void* data = nullptr; + SP surface = nullptr; + double w, h; // for rounding bool dontRound = true; @@ -52,12 +53,6 @@ struct SRenderData { bool popup = false; }; -struct SExtensionFindingData { - Vector2D origin; - Vector2D vec; - wlr_surface** found; -}; - struct SSwipeGesture { PHLWORKSPACE pWorkspaceBegin = nullptr; diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp index 77f5164a..02900911 100644 --- a/src/helpers/memory/SharedPtr.hpp +++ b/src/helpers/memory/SharedPtr.hpp @@ -60,7 +60,7 @@ namespace CSharedPointer_ { bool _destroying = false; void _destroy() { - if (!_data) + if (!_data || _destroying) return; // first, we destroy the data, but keep the pointer. @@ -297,6 +297,6 @@ static CSharedPointer makeShared(Args&&... args) { template struct std::hash> { std::size_t operator()(const CSharedPointer& p) const noexcept { - return std::hash{}(p->impl_); + return std::hash{}(p.impl_); } }; diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp index f0e72146..872f8e55 100644 --- a/src/helpers/memory/WeakPtr.hpp +++ b/src/helpers/memory/WeakPtr.hpp @@ -185,6 +185,6 @@ class CWeakPointer { template struct std::hash> { std::size_t operator()(const CWeakPointer& p) const noexcept { - return std::hash{}(p->impl_); + return std::hash{}(p.impl_); } }; diff --git a/src/helpers/signal/Signal.cpp b/src/helpers/signal/Signal.cpp index fdd2cc23..fd2d11c8 100644 --- a/src/helpers/signal/Signal.cpp +++ b/src/helpers/signal/Signal.cpp @@ -2,19 +2,40 @@ #include void CSignal::emit(std::any data) { - bool dirty = false; + bool dirty = false; + std::vector> listeners; for (auto& l : m_vListeners) { - if (const CHyprSignalListener L = l.lock()) - L->emit(data); - else + if (l.expired()) { dirty = true; + continue; + } + + listeners.emplace_back(l.lock()); } + std::vector statics; for (auto& l : m_vStaticListeners) { + statics.emplace_back(l.get()); + } + + for (auto& l : listeners) { + // if there is only one lock, it means the event is only held by the listeners + // vector and was removed during our iteration + if (l.strongRef() == 1) { + dirty = true; + continue; + } l->emit(data); } + for (auto& l : statics) { + l->emit(data); + } + + // release SPs + listeners.clear(); + if (dirty) std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); } diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index d147a6bb..a325d858 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -22,6 +22,8 @@ CHyprError::CHyprError() { if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); }); + + m_pTexture = makeShared(); } CHyprError::~CHyprError() { @@ -34,9 +36,8 @@ void CHyprError::queueCreate(std::string message, const CColor& color) { } void CHyprError::createQueued() { - if (m_bIsCreated) { - m_tTexture.destroyTexture(); - } + if (m_bIsCreated) + m_pTexture->destroyTexture(); m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); @@ -136,8 +137,8 @@ void CHyprError::createQueued() { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - m_tTexture.allocate(); - glBindTexture(GL_TEXTURE_2D, m_tTexture.m_iTexID); + m_pTexture->allocate(); + glBindTexture(GL_TEXTURE_2D, m_pTexture->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -170,7 +171,7 @@ void CHyprError::draw() { if (!m_fFadeOpacity.isBeingAnimated()) { if (m_fFadeOpacity.value() == 0.f) { m_bQueuedDestroy = false; - m_tTexture.destroyTexture(); + m_pTexture->destroyTexture(); m_bIsCreated = false; m_szQueued = ""; return; @@ -193,7 +194,7 @@ void CHyprError::draw() { m_bMonitorChanged = false; - g_pHyprOpenGL->renderTexture(m_tTexture, &monbox, m_fFadeOpacity.value(), 0); + g_pHyprOpenGL->renderTexture(m_pTexture, &monbox, m_fFadeOpacity.value(), 0); } void CHyprError::destroy() { diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index aaa8bd12..8dbb4521 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -21,7 +21,7 @@ class CHyprError { CColor m_cQueued; bool m_bQueuedDestroy = false; bool m_bIsCreated = false; - CTexture m_tTexture; + SP m_pTexture; CAnimatedVariable m_fFadeOpacity; CBox m_bDamageBox = {0, 0, 0, 0}; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 7fadf188..b4270bb8 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -5,6 +5,7 @@ #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { @@ -99,8 +100,8 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { - const auto PWINDOWSURFACE = pWindow->m_pWLSurface.wlr(); - pWindow->m_vRealSize = Vector2D(PWINDOWSURFACE->current.width, PWINDOWSURFACE->current.height); + const auto PWINDOWSURFACE = pWindow->m_pWLSurface->resource(); + pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms? diff --git a/src/macros.hpp b/src/macros.hpp index 66dfe783..4c6d621c 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -89,4 +89,14 @@ } #else #define UNREACHABLE() std::unreachable(); -#endif \ No newline at end of file +#endif + +#define GLCALL(__CALL__) \ + { \ + __CALL__; \ + auto err = glGetError(); \ + if (err != GL_NO_ERROR) { \ + Debug::log(ERR, "[GLES] Error in call at {}@{}: 0x{:x}", __LINE__, \ + ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err); \ + } \ + } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index e3ebce80..4430d0f4 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -117,8 +117,8 @@ wlr_buffer* CCursorManager::getCursorBuffer() { return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; } -void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { - if (!surf || !surf->wlr()) +void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotspot) { + if (!surf || !surf->resource()) g_pPointerManager->resetCursorImage(); else g_pPointerManager->setCursorSurface(surf, hotspot); diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index e76b6829..6fbff636 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -18,7 +18,7 @@ class CCursorManager { wlr_buffer* getCursorBuffer(); void setCursorFromName(const std::string& name); - void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot); + void setCursorSurface(SP surf, const Vector2D& hotspot); void setXCursor(const std::string& name); bool changeTheme(const std::string& name, const int size); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f7009afb..5811f4a1 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2003,14 +2003,14 @@ void CKeybindManager::pass(std::string regexp) { } const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; - const auto LASTSRF = g_pCompositor->m_pLastFocus; + const auto LASTSRF = g_pCompositor->m_pLastFocus.lock(); // pass all mf shit if (!XWTOXW) { if (g_pKeybindManager->m_uLastCode != 0) - g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource()); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1}); } g_pSeatManager->sendKeyboardMods(g_pInputManager->accumulateModsFromAllKBs(), 0, 0, 0); @@ -2044,10 +2044,10 @@ void CKeybindManager::pass(std::string regexp) { // please kill me if (PWINDOW->m_bIsX11) { if (g_pKeybindManager->m_uLastCode != 0) { - g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocus.reset(); g_pSeatManager->state.keyboardFocusResource.reset(); } else { - g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocus.reset(); g_pSeatManager->state.pointerFocusResource.reset(); } } @@ -2057,7 +2057,7 @@ void CKeybindManager::pass(std::string regexp) { if (g_pKeybindManager->m_uLastCode != 0) g_pSeatManager->setKeyboardFocus(LASTSRF); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), SL); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), SL); } void CKeybindManager::sendshortcut(std::string args) { @@ -2136,7 +2136,7 @@ void CKeybindManager::sendshortcut(std::string args) { const std::string regexp = ARGS[2]; PHLWINDOW PWINDOW = nullptr; - const auto LASTSURFACE = g_pCompositor->m_pLastFocus; + const auto LASTSURFACE = g_pCompositor->m_pLastFocus.lock(); //if regexp is not empty, send shortcut to current window //else, dont change focus @@ -2154,15 +2154,15 @@ void CKeybindManager::sendshortcut(std::string args) { } if (!isMouse) - g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface.wlr()); + g_pSeatManager->setKeyboardFocus(PWINDOW->m_pWLSurface->resource()); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface.wlr(), {1, 1}); + g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), {1, 1}); } //copied the rest from pass and modified it // if wl -> xwl, activate destination if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11) - g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface.wlr(), true); + g_pXWaylandManager->activateSurface(PWINDOW->m_pWLSurface->resource(), true); // if xwl -> xwl, send to current. Timing issues make this not work. if (PWINDOW && PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) PWINDOW = nullptr; @@ -2195,10 +2195,10 @@ void CKeybindManager::sendshortcut(std::string args) { if (PWINDOW->m_bIsX11) { //xwayland hack, see pass if (!isMouse) { - g_pSeatManager->state.keyboardFocus = nullptr; + g_pSeatManager->state.keyboardFocus.reset(); g_pSeatManager->state.keyboardFocusResource.reset(); } else { - g_pSeatManager->state.pointerFocus = nullptr; + g_pSeatManager->state.pointerFocus.reset(); g_pSeatManager->state.pointerFocusResource.reset(); } } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 66d12076..80a7ee76 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/core/Compositor.hpp" #include "SeatManager.hpp" #include #include @@ -212,13 +213,13 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, damageIfSoftware(); } -void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) { +void CPointerManager::setCursorSurface(SP surf, const Vector2D& hotspot) { damageIfSoftware(); if (surf == currentCursorImage.surface) { - if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) { + if (hotspot != currentCursorImage.hotspot || (surf && surf->resource() ? surf->resource()->current.scale : 1.F) != currentCursorImage.scale) { currentCursorImage.hotspot = hotspot; - currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F; + currentCursorImage.scale = surf && surf->resource() ? surf->resource()->current.scale : 1.F; updateCursorBackend(); damageIfSoftware(); } @@ -229,27 +230,24 @@ void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot resetCursorImage(false); if (surf) { - currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height}; currentCursorImage.surface = surf; - currentCursorImage.scale = surf->wlr()->current.scale; + currentCursorImage.scale = surf->resource()->current.scale; currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); - currentCursorImage.hyprListener_commitSurface.initCallback( - &surf->wlr()->events.commit, - [this](void* owner, void* data) { - damageIfSoftware(); - currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height}; - currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F; - recheckEnteredOutputs(); - updateCursorBackend(); - damageIfSoftware(); - }, - nullptr, "CPointerManager"); + currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) { + damageIfSoftware(); + currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{}; + currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F; + recheckEnteredOutputs(); + updateCursorBackend(); + damageIfSoftware(); + }); - if (wlr_surface_has_buffer(surf->wlr())) { + if (surf->resource()->current.buffer) { + currentCursorImage.size = surf->resource()->current.buffer->size; timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(surf->wlr(), &now); + surf->resource()->frame(&now); } } @@ -278,9 +276,9 @@ void CPointerManager::recheckEnteredOutputs() { if (!currentCursorImage.surface) continue; - wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output); - PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale); - g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale); + currentCursorImage.surface->resource()->enter(s->monitor.lock()); + PROTO::fractional->sendScale(currentCursorImage.surface->resource(), s->monitor->scale); + g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->resource(), s->monitor->scale); } else if (s->entered && !overlaps) { s->entered = false; @@ -293,7 +291,7 @@ void CPointerManager::recheckEnteredOutputs() { if (!currentCursorImage.surface) continue; - wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output); + currentCursorImage.surface->resource()->leave(s->monitor.lock()); } } } @@ -303,12 +301,12 @@ void CPointerManager::resetCursorImage(bool apply) { if (currentCursorImage.surface) { for (auto& m : g_pCompositor->m_vMonitors) { - wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output); + currentCursorImage.surface->resource()->leave(m); } currentCursorImage.destroySurface.reset(); - currentCursorImage.hyprListener_commitSurface.removeCallback(); - currentCursorImage.surface = nullptr; + currentCursorImage.commitSurface.reset(); + currentCursorImage.surface.reset(); } else if (currentCursorImage.pBuffer) { wlr_buffer_unlock(currentCursorImage.pBuffer); currentCursorImage.hyprListener_destroyBuffer.removeCallback(); @@ -451,7 +449,7 @@ bool CPointerManager::setHWCursorBuffer(SP state, wlr_buff return true; } -wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, wlr_texture* texture) { +wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, SP texture) { auto output = state->monitor->output; int w = currentCursorImage.size.x, h = currentCursorImage.size.y; @@ -528,7 +526,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* if ((!state->hardwareFailed && state->softwareLocks == 0)) { if (currentCursorImage.surface) - wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + currentCursorImage.surface->resource()->frame(now); return; } @@ -550,7 +548,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); if (currentCursorImage.surface) - wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now); + currentCursorImage.surface->resource()->frame(now); } Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { @@ -762,17 +760,19 @@ void CPointerManager::onMonitorLayoutChange() { damageIfSoftware(); } -wlr_texture* CPointerManager::getCurrentCursorTexture() { - if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr()))) +SP CPointerManager::getCurrentCursorTexture() { + if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer)) return nullptr; if (currentCursorImage.pBuffer) { - if (!currentCursorImage.pBufferTexture) + if (!currentCursorImage.pBufferTexture) { currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); - return currentCursorImage.pBufferTexture; + currentCursorImage.bufferTex = makeShared(currentCursorImage.pBufferTexture); + } + return currentCursorImage.bufferTex; } - return wlr_surface_get_texture(currentCursorImage.surface->wlr()); + return currentCursorImage.surface->resource()->current.buffer->texture; } void CPointerManager::attachPointer(SP pointer) { diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index db9f27e7..b71a79c3 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -11,6 +11,7 @@ class CMonitor; struct wlr_input_device; class IHID; +class CTexture; /* The naming here is a bit confusing. @@ -37,7 +38,7 @@ class CPointerManager { void warpAbsolute(Vector2D abs, SP dev); void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); - void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot); + void setCursorSurface(SP buf, const Vector2D& hotspot); void resetCursorImage(bool apply = true); void lockSoftwareForMonitor(SP pMonitor); @@ -76,7 +77,7 @@ class CPointerManager { Vector2D transformedHotspot(SP pMonitor); - wlr_texture* getCurrentCursorTexture(); + SP getCurrentCursorTexture(); struct SPointerListener { CHyprSignalListener destroy; @@ -129,8 +130,9 @@ class CPointerManager { } currentMonitorLayout; struct { - wlr_buffer* pBuffer = nullptr; - CWLSurface* surface = nullptr; + wlr_buffer* pBuffer = nullptr; + SP bufferTex; + WP surface; wlr_texture* pBufferTexture = nullptr; Vector2D hotspot; @@ -138,7 +140,7 @@ class CPointerManager { float scale = 1.F; CHyprSignalListener destroySurface; - DYNLISTENER(commitSurface); + CHyprSignalListener commitSurface; DYNLISTENER(destroyBuffer); } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors @@ -165,7 +167,7 @@ class CPointerManager { std::vector> monitorStates; SP stateFor(SP mon); bool attemptHardwareCursor(SP state); - wlr_buffer* renderHWCursorBuffer(SP state, wlr_texture* texture); + wlr_buffer* renderHWCursorBuffer(SP state, SP texture); bool setHWCursorBuffer(SP state, wlr_buffer* buf); struct { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index feff69e0..bd435b27 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -32,17 +32,45 @@ #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/Viewporter.hpp" +#include "../protocols/MesaDRM.hpp" +#include "../protocols/LinuxDMABUF.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/core/Compositor.hpp" +#include "../protocols/core/Subcompositor.hpp" +#include "../protocols/core/Output.hpp" +#include "../protocols/core/Shm.hpp" + +#include "../helpers/Monitor.hpp" CProtocolManager::CProtocolManager() { + // Outputs are a bit dumb, we have to agree. + static auto P = g_pHookSystem->hookDynamic("monitorAdded", [](void* self, SCallbackInfo& info, std::any param) { + auto M = std::any_cast(param); + if (PROTO::outputs.contains(M->szName)) + PROTO::outputs.erase(M->szName); + PROTO::outputs.emplace(M->szName, std::make_unique(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock())); + }); + + static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [](void* self, SCallbackInfo& info, std::any param) { + auto M = std::any_cast(param); + if (!PROTO::outputs.contains(M->szName)) + return; + PROTO::outputs.at(M->szName)->remove(); + }); + // Core - PROTO::seat = std::make_unique(&wl_seat_interface, 9, "WLSeat"); - PROTO::data = std::make_unique(&wl_data_device_manager_interface, 3, "WLDataDevice"); + PROTO::seat = std::make_unique(&wl_seat_interface, 9, "WLSeat"); + PROTO::data = std::make_unique(&wl_data_device_manager_interface, 3, "WLDataDevice"); + PROTO::compositor = std::make_unique(&wl_compositor_interface, 6, "WLCompositor"); + PROTO::subcompositor = std::make_unique(&wl_subcompositor_interface, 1, "WLSubcompositor"); + PROTO::shm = std::make_unique(&wl_shm_interface, 1, "WLSHM"); // Extensions + PROTO::viewport = std::make_unique(&wp_viewporter_interface, 1, "Viewporter"); 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"); @@ -75,6 +103,8 @@ CProtocolManager::CProtocolManager() { PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); + PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 7899386b..399ef419 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -3,6 +3,7 @@ #include "../protocols/core/DataDevice.hpp" #include "../protocols/DataDeviceWlr.hpp" #include "../protocols/PrimarySelection.hpp" +#include "../protocols/core/Compositor.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" #include @@ -98,7 +99,7 @@ void CSeatManager::updateActiveKeyboardData() { PROTO::seat->updateKeymap(); } -void CSeatManager::setKeyboardFocus(wlr_surface* surf) { +void CSeatManager::setKeyboardFocus(SP surf) { if (state.keyboardFocus == surf) return; @@ -107,7 +108,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { return; } - hyprListener_keyboardSurfaceDestroy.removeCallback(); + listeners.keyboardSurfaceDestroy.reset(); if (state.keyboardFocusResource) { auto client = state.keyboardFocusResource->client(); @@ -132,7 +133,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -147,8 +148,7 @@ void CSeatManager::setKeyboardFocus(wlr_surface* surf) { } } - hyprListener_keyboardSurfaceDestroy.initCallback( - &surf->events.destroy, [this](void* owner, void* data) { setKeyboardFocus(nullptr); }, nullptr, "CSeatManager"); + listeners.keyboardSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setKeyboardFocus(nullptr); }); events.keyboardFocusChange.emit(); } @@ -187,7 +187,7 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32 } } -void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { +void CSeatManager::setPointerFocus(SP surf, const Vector2D& local) { if (state.pointerFocus == surf) return; @@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { return; } - hyprListener_pointerSurfaceDestroy.removeCallback(); + listeners.pointerSurfaceDestroy.reset(); if (state.pointerFocusResource) { auto client = state.pointerFocusResource->client(); @@ -224,7 +224,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -243,8 +243,7 @@ void CSeatManager::setPointerFocus(wlr_surface* surf, const Vector2D& local) { sendPointerFrame(); - hyprListener_pointerSurfaceDestroy.initCallback( - &surf->events.destroy, [this](void* owner, void* data) { setPointerFocus(nullptr, {}); }, nullptr, "CSeatManager"); + listeners.pointerSurfaceDestroy = surf->events.destroy.registerListener([this](std::any d) { setPointerFocus(nullptr, {}); }); events.pointerFocusChange.emit(); } @@ -340,11 +339,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double } } -void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local) { +void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, int32_t id, const Vector2D& local) { if (state.touchFocus == surf) return; - hyprListener_touchSurfaceDestroy.removeCallback(); + listeners.touchSurfaceDestroy.reset(); if (state.touchFocusResource) { auto client = state.touchFocusResource->client(); @@ -369,7 +368,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, return; } - auto client = wl_resource_get_client(surf->resource); + auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; @@ -383,8 +382,7 @@ void CSeatManager::sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, } } - hyprListener_touchSurfaceDestroy.initCallback( - &surf->events.destroy, [this, timeMs, id](void* owner, void* data) { sendTouchUp(timeMs + 10, id); }, nullptr, "CSeatManager"); + listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); }); events.touchFocusChange.emit(); } @@ -486,7 +484,7 @@ void CSeatManager::refocusGrab() { // try to find a surf in focus first const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); for (auto& s : seatGrab->surfs) { - auto hlSurf = CWLSurface::surfaceFromWlr(s); + auto hlSurf = CWLSurface::fromResource(s.lock()); if (!hlSurf) continue; @@ -498,13 +496,13 @@ void CSeatManager::refocusGrab() { continue; if (seatGrab->keyboard) - setKeyboardFocus(s); + setKeyboardFocus(s.lock()); if (seatGrab->pointer) - setPointerFocus(s, MOUSE - b->pos()); + setPointerFocus(s.lock(), MOUSE - b->pos()); return; } - wlr_surface* surf = seatGrab->surfs.at(0); + SP surf = seatGrab->surfs.at(0).lock(); if (seatGrab->keyboard) setKeyboardFocus(surf); if (seatGrab->pointer) @@ -512,7 +510,7 @@ void CSeatManager::refocusGrab() { } } -void CSeatManager::onSetCursor(SP seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot) { +void CSeatManager::onSetCursor(SP seatResource, uint32_t serial, SP surf, const Vector2D& hotspot) { if (!state.pointerFocusResource || !seatResource || seatResource->client() != state.pointerFocusResource->client()) { Debug::log(LOG, "[seatmgr] Rejecting a setCursor because the client ain't in focus"); return; @@ -599,10 +597,10 @@ void CSeatManager::setGrab(SP grab) { } void CSeatManager::resendEnterEvents() { - wlr_surface* kb = state.keyboardFocus; - wlr_surface* pt = state.pointerFocus; + SP kb = state.keyboardFocus.lock(); + SP pt = state.pointerFocus.lock(); - auto last = lastLocalCoords; + auto last = lastLocalCoords; setKeyboardFocus(nullptr); setPointerFocus(nullptr, {}); @@ -611,15 +609,15 @@ void CSeatManager::resendEnterEvents() { setPointerFocus(pt, last); } -bool CSeatGrab::accepts(wlr_surface* surf) { +bool CSeatGrab::accepts(SP surf) { return std::find(surfs.begin(), surfs.end(), surf) != surfs.end(); } -void CSeatGrab::add(wlr_surface* surf) { +void CSeatGrab::add(SP surf) { surfs.push_back(surf); } -void CSeatGrab::remove(wlr_surface* surf) { +void CSeatGrab::remove(SP surf) { std::erase(surfs, surf); if ((keyboard && g_pSeatManager->state.keyboardFocus == surf) || (pointer && g_pSeatManager->state.pointerFocus == surf)) g_pSeatManager->refocusGrab(); diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 35456cb3..e74d9ace 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -11,7 +11,7 @@ constexpr size_t MAX_SERIAL_STORE_LEN = 100; -struct wlr_surface; +class CWLSurfaceResource; class CWLSeatResource; class IPointer; class IKeyboard; @@ -29,9 +29,9 @@ class IKeyboard; */ class CSeatGrab { public: - bool accepts(wlr_surface* surf); - void add(wlr_surface* surf); - void remove(wlr_surface* surf); + bool accepts(SP surf); + void add(SP surf); + void remove(SP surf); void setCallback(std::function onEnd_); void clear(); @@ -42,8 +42,8 @@ class CSeatGrab { bool removeOnInput = true; // on hard input e.g. click outside, remove private: - std::vector surfs; // read-only - std::function onEnd; + std::vector> surfs; + std::function onEnd; friend class CSeatManager; }; @@ -57,11 +57,11 @@ class CSeatManager { void setKeyboard(SP keeb); void updateActiveKeyboardData(); // updates the clients with the keymap and repeat info - void setKeyboardFocus(wlr_surface* surf); + void setKeyboardFocus(SP surf); void sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); void sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void setPointerFocus(wlr_surface* surf, const Vector2D& local); + void setPointerFocus(SP surf, const Vector2D& local); void sendPointerMotion(uint32_t timeMs, const Vector2D& local); void sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_button_state state); void sendPointerFrame(); @@ -69,7 +69,7 @@ class CSeatManager { void sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double value, int32_t discrete, int32_t value120, wl_pointer_axis_source source, wl_pointer_axis_relative_direction relative); - void sendTouchDown(wlr_surface* surf, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendTouchDown(SP surf, uint32_t timeMs, int32_t id, const Vector2D& local); void sendTouchUp(uint32_t timeMs, int32_t id); void sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local); void sendTouchFrame(); @@ -83,24 +83,24 @@ class CSeatManager { // pops the serial if it was valid, meaning it is consumed. bool serialValid(SP seatResource, uint32_t serial); - void onSetCursor(SP seatResource, uint32_t serial, wlr_surface* surf, const Vector2D& hotspot); + void onSetCursor(SP seatResource, uint32_t serial, SP surf, const Vector2D& hotspot); SP seatResourceForClient(wl_client* client); struct { - wlr_surface* keyboardFocus = nullptr; - WP keyboardFocusResource; + WP keyboardFocus; + WP keyboardFocusResource; - wlr_surface* pointerFocus = nullptr; - WP pointerFocusResource; + WP pointerFocus; + WP pointerFocusResource; - wlr_surface* touchFocus = nullptr; - WP touchFocusResource; + WP touchFocus; + WP touchFocusResource; } state; struct SSetCursorEvent { - wlr_surface* surf = nullptr; - Vector2D hotspot; + SP surf = nullptr; + Vector2D hotspot; }; struct { @@ -149,14 +149,13 @@ class CSeatManager { struct { CHyprSignalListener newSeatResource; + CHyprSignalListener keyboardSurfaceDestroy; + CHyprSignalListener pointerSurfaceDestroy; + CHyprSignalListener touchSurfaceDestroy; } listeners; Vector2D lastLocalCoords; - DYNLISTENER(keyboardSurfaceDestroy); - DYNLISTENER(pointerSurfaceDestroy); - DYNLISTENER(touchSurfaceDestroy); - friend struct SSeatResourceContainer; friend class CSeatGrab; }; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index fd4841f4..3bec1c4b 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -20,7 +20,7 @@ SSessionLockSurface::SSessionLockSurface(SP surface_) : sur listeners.destroy = surface_->events.destroy.registerListener([this](std::any data) { if (pWlrSurface == g_pCompositor->m_pLastFocus) - g_pCompositor->m_pLastFocus = nullptr; + g_pCompositor->m_pLastFocus.reset(); g_pSessionLockManager->removeSessionLockSurface(this); }); @@ -70,7 +70,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pHyprRenderer->damageMonitor(m.get()); }); - m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) { + m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([](std::any data) { g_pCompositor->focusSurface(nullptr); for (auto& m : g_pCompositor->m_vMonitors) @@ -117,7 +117,7 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f); } -bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) { +bool CSessionLockManager::isSurfaceSessionLock(SP pSurface) { // TODO: this has some edge cases when it's wrong (e.g. destroyed lock but not yet surfaces) // but can be easily fixed when I rewrite wlr_surface diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index d655a2bc..ea1b2029 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -8,13 +8,14 @@ class CSessionLockSurface; class CSessionLock; +class CWLSurfaceResource; struct SSessionLockSurface { SSessionLockSurface(SP surface_); WP surface; - wlr_surface* pWlrSurface = nullptr; - uint64_t iMonitorID = -1; + WP pWlrSurface; + uint64_t iMonitorID = -1; bool mapped = false; @@ -49,7 +50,7 @@ class CSessionLockManager { bool isSessionLocked(); bool isSessionLockPresent(); - bool isSurfaceSessionLock(wlr_surface*); + bool isSurfaceSessionLock(SP); void removeSessionLockSurface(SSessionLockSurface*); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 4aebefcb..12387900 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -3,6 +3,7 @@ #include "../events/Events.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/XDGShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" #define OUTPUT_MANAGER_VERSION 3 @@ -19,11 +20,11 @@ CHyprXWaylandManager::~CHyprXWaylandManager() { #endif } -wlr_surface* CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { - return pWindow->m_pWLSurface.wlr(); +SP CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { + return pWindow->m_pWLSurface->resource(); } -void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) { +void CHyprXWaylandManager::activateSurface(SP pSurface, bool activate) { if (!pSurface) return; @@ -33,7 +34,7 @@ void CHyprXWaylandManager::activateSurface(wlr_surface* pSurface, bool activate) if (!w->m_bIsMapped) continue; - if (w->m_pWLSurface.wlr() != pSurface) + if (w->m_pWLSurface->resource() != pSurface) continue; if (w->m_bIsX11) { @@ -131,10 +132,6 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); } -wlr_surface* CHyprXWaylandManager::surfaceAt(PHLWINDOW pWindow, const Vector2D& client, Vector2D& surface) { - return wlr_surface_surface_at(pWindow->m_pWLSurface.wlr(), client.x, client.y, &surface.x, &surface.y); -} - bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { for (auto& a : pWindow->m_pXWaylandSurface->atoms) diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 5bbab802..a9f95974 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -5,25 +5,25 @@ class CWindow; // because clangd typedef SP PHLWINDOW; +class CWLSurfaceResource; class CHyprXWaylandManager { public: CHyprXWaylandManager(); ~CHyprXWaylandManager(); - wlr_surface* getWindowSurface(PHLWINDOW); - void activateSurface(wlr_surface*, bool); - void activateWindow(PHLWINDOW, bool); - void getGeometryForWindow(PHLWINDOW, CBox*); - void sendCloseWindow(PHLWINDOW); - void setWindowSize(PHLWINDOW, Vector2D, bool force = false); - void setWindowFullscreen(PHLWINDOW, bool); - wlr_surface* surfaceAt(PHLWINDOW, const Vector2D&, Vector2D&); - bool shouldBeFloated(PHLWINDOW, bool pending = false); - void checkBorders(PHLWINDOW); - Vector2D getMaxSizeForWindow(PHLWINDOW); - Vector2D getMinSizeForWindow(PHLWINDOW); - Vector2D xwaylandToWaylandCoords(const Vector2D&); + SP getWindowSurface(PHLWINDOW); + void activateSurface(SP, bool); + void activateWindow(PHLWINDOW, bool); + void getGeometryForWindow(PHLWINDOW, CBox*); + void sendCloseWindow(PHLWINDOW); + void setWindowSize(PHLWINDOW, Vector2D, bool force = false); + void setWindowFullscreen(PHLWINDOW, bool); + bool shouldBeFloated(PHLWINDOW, bool pending = false); + void checkBorders(PHLWINDOW); + Vector2D getMaxSizeForWindow(PHLWINDOW); + Vector2D getMinSizeForWindow(PHLWINDOW); + Vector2D xwaylandToWaylandCoords(const Vector2D&); }; inline std::unique_ptr g_pXWaylandManager; \ No newline at end of file diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index a71059e4..a38acdbf 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -14,7 +14,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { recheckIdleInhibitorStatus(); }); - auto WLSurface = CWLSurface::surfaceFromWlr(PINHIBIT->inhibitor->surface); + auto WLSurface = CWLSurface::fromResource(PINHIBIT->inhibitor->surface.lock()); if (!WLSurface) { Debug::log(LOG, "Inhibitor has no HL Surface attached to it, likely meaning it's a non-desktop element. Assuming it's visible."); @@ -37,7 +37,7 @@ void CInputManager::recheckIdleInhibitorStatus() { return; } - auto WLSurface = CWLSurface::surfaceFromWlr(ii->inhibitor->surface); + auto WLSurface = CWLSurface::fromResource(ii->inhibitor->surface.lock()); if (!WLSurface) continue; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 27d04699..c12ac389 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -43,7 +43,7 @@ CInputManager::CInputManager() { Debug::log(LOG, "cursorImage request: shape {} -> {}", (uint32_t)event.shape, event.shapeName); - m_sCursorSurfaceInfo.wlSurface.unassign(); + m_sCursorSurfaceInfo.wlSurface->unassign(); m_sCursorSurfaceInfo.vHotspot = {}; m_sCursorSurfaceInfo.name = event.shapeName; m_sCursorSurfaceInfo.hidden = false; @@ -58,6 +58,8 @@ CInputManager::CInputManager() { m_sListeners.newVirtualMouse = PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast>(data)); }); m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); }); + + m_sCursorSurfaceInfo.wlSurface = CWLSurface::create(); } CInputManager::~CInputManager() { @@ -115,8 +117,8 @@ void CInputManager::sendMotionEventsToFocused() { return; // todo: this sucks ass - const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus); - const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); + const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -125,7 +127,7 @@ void CInputManager::sendMotionEventsToFocused() { m_bEmptyFocusCursorSet = false; - g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus, LOCAL); + g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { @@ -141,14 +143,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; - m_pFoundSurfaceToFocus = nullptr; + m_pFoundSurfaceToFocus.reset(); m_pFoundLSToFocus.reset(); m_pFoundWindowToFocus.reset(); - wlr_surface* foundSurface = nullptr; - Vector2D surfaceCoords; - Vector2D surfacePos = Vector2D(-1337, -1337); - PHLWINDOW pFoundWindow; - PHLLS pFoundLayerSurface; + SP foundSurface; + Vector2D surfaceCoords; + Vector2D surfacePos = Vector2D(-1337, -1337); + PHLWINDOW pFoundWindow; + PHLLS pFoundLayerSurface; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -191,12 +193,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (forcedFocus) { pFoundWindow = forcedFocus; surfacePos = pFoundWindow->m_vRealPosition.value(); - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); } // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { - const auto SURF = CWLSurface::surfaceFromWlr(g_pCompositor->m_pLastFocus); + const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); const auto CONSTRAINT = SURF->constraint(); if (SURF && CONSTRAINT) { @@ -223,7 +225,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { - foundSurface = g_pSeatManager->state.pointerFocus; + foundSurface = g_pSeatManager->state.pointerFocus.lock(); // IME popups aren't desktop-like elements // TODO: make them. @@ -233,7 +235,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_bFocusHeldByButtons = true; m_bRefocusHeldByButtons = refocus; } else { - auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + auto HLSurface = CWLSurface::fromResource(foundSurface); if (HLSurface) { const auto BOX = HLSurface->getSurfaceBoxGlobal(); @@ -275,7 +277,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!foundSurface) { auto popup = g_pInputManager->m_sIMERelay.popupFromCoords(mouseCoords); if (popup) { - foundSurface = popup->getWlrSurface(); + foundSurface = popup->getSurface(); surfacePos = popup->globalBox().pos(); } } @@ -306,7 +308,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); surfacePos = Vector2D(-1337, -1337); } else { - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); } } @@ -345,7 +347,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); } else { - foundSurface = pFoundWindow->m_pWLSurface.wlr(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); } } @@ -369,9 +371,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; // setGrab will refocus } else { // we need to grab the last surface. - foundSurface = g_pSeatManager->state.pointerFocus; + foundSurface = g_pSeatManager->state.pointerFocus.lock(); - auto HLSurface = CWLSurface::surfaceFromWlr(foundSurface); + auto HLSurface = CWLSurface::fromResource(foundSurface); if (HLSurface) { const auto BOX = HLSurface->getSurfaceBoxGlobal(); @@ -423,7 +425,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { bool allowKeyboardRefocus = true; if (!refocus && g_pCompositor->m_pLastFocus) { - const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus); + const auto PLS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); if (PLS && PLS->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) allowKeyboardRefocus = false; @@ -441,7 +443,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; } - if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface.wlr() && !m_bCursorImageOverridden) { + if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface->resource() && !m_bCursorImageOverridden) { const auto BOX = pFoundWindow->getWindowMainSurfaceBox(); if (!VECINRECT(mouseCoords, BOX.x, BOX.y, BOX.x + BOX.width, BOX.y + BOX.height)) setCursorImageOverride("left_ptr"); @@ -555,11 +557,11 @@ void CInputManager::processMouseRequest(std::any E) { Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf); - if (e.surf != m_sCursorSurfaceInfo.wlSurface.wlr()) { - m_sCursorSurfaceInfo.wlSurface.unassign(); + if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) { + m_sCursorSurfaceInfo.wlSurface->unassign(); if (e.surf) - m_sCursorSurfaceInfo.wlSurface.assign(e.surf); + m_sCursorSurfaceInfo.wlSurface->assign(e.surf); } if (e.surf) { @@ -573,7 +575,7 @@ void CInputManager::processMouseRequest(std::any E) { m_sCursorSurfaceInfo.name = ""; m_sCursorSurfaceInfo.inUse = true; - g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y); + g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, e.hotspot.x, e.hotspot.y); } void CInputManager::restoreCursorIconToApp() { @@ -586,8 +588,8 @@ void CInputManager::restoreCursorIconToApp() { } if (m_sCursorSurfaceInfo.name.empty()) { - if (m_sCursorSurfaceInfo.wlSurface.exists()) - g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); + if (m_sCursorSurfaceInfo.wlSurface->exists()) + g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y); } else { g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name); } @@ -696,7 +698,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { if (!g_pSeatManager->state.pointerFocus) break; - auto HLSurf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); + auto HLSurf = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); if (HLSurf && HLSurf->getWindow()) g_pCompositor->changeWindowZOrder(HLSurf->getWindow(), true); @@ -1399,7 +1401,7 @@ bool CInputManager::isConstrained() { if (!C) continue; - if (!C->isActive() || C->owner()->wlr() != g_pCompositor->m_pLastFocus) + if (!C->isActive() || C->owner()->resource() != g_pCompositor->m_pLastFocus) continue; return true; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index f7d9ae57..9fdf061c 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -44,10 +44,10 @@ enum eBorderIconDirection { }; struct STouchData { - PHLWINDOWREF touchFocusWindow; - PHLLSREF touchFocusLS; - wlr_surface* touchFocusSurface = nullptr; - Vector2D touchSurfaceOrigin; + PHLWINDOWREF touchFocusWindow; + PHLLSREF touchFocusLS; + WP touchFocusSurface; + Vector2D touchSurfaceOrigin; }; // The third row is always 0 0 1 and is not expected by `libinput_device_config_calibration_set_matrix` @@ -236,9 +236,9 @@ class CInputManager { void applyConfigToKeyboard(SP); // this will be set after a refocus() - wlr_surface* m_pFoundSurfaceToFocus = nullptr; - PHLLSREF m_pFoundLSToFocus; - PHLWINDOWREF m_pFoundWindowToFocus; + WP m_pFoundSurfaceToFocus; + PHLLSREF m_pFoundLSToFocus; + PHLWINDOWREF m_pFoundWindowToFocus; // for holding focus on buttons held bool m_bFocusHeldByButtons = false; @@ -268,11 +268,11 @@ class CInputManager { // cursor surface struct cursorSI { - bool hidden = false; // null surface = hidden - CWLSurface wlSurface; - Vector2D vHotspot; - std::string name; // if not empty, means set by name. - bool inUse = false; + bool hidden = false; // null surface = hidden + SP wlSurface; + Vector2D vHotspot; + std::string name; // if not empty, means set by name. + bool inUse = false; } m_sCursorSurfaceInfo; void restoreCursorIconToApp(); // no-op if restored diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index 9ff584e6..a8757030 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -3,22 +3,24 @@ #include "../../Compositor.hpp" #include "../../protocols/FractionalScale.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CInputPopup::CInputPopup(SP popup_) : popup(popup_) { listeners.commit = popup_->events.commit.registerListener([this](std::any d) { onCommit(); }); listeners.map = popup_->events.map.registerListener([this](std::any d) { onMap(); }); listeners.unmap = popup_->events.unmap.registerListener([this](std::any d) { onUnmap(); }); listeners.destroy = popup_->events.destroy.registerListener([this](std::any d) { onDestroy(); }); - surface.assign(popup_->surface()); + surface = CWLSurface::create(); + surface->assign(popup_->surface()); } -CWLSurface* CInputPopup::queryOwner() { +SP CInputPopup::queryOwner() { const auto FOCUSED = g_pInputManager->m_sIMERelay.getFocusedTextInput(); if (!FOCUSED) return nullptr; - return CWLSurface::surfaceFromWlr(FOCUSED->focusedSurface()); + return CWLSurface::fromResource(FOCUSED->focusedSurface()); } void CInputPopup::onDestroy() { @@ -36,7 +38,7 @@ void CInputPopup::onMap() { if (!PMONITOR) return; - PROTO::fractional->sendScale(surface.wlr(), PMONITOR->scale); + PROTO::fractional->sendScale(surface->resource(), PMONITOR->scale); } void CInputPopup::onUnmap() { @@ -69,7 +71,7 @@ void CInputPopup::damageSurface() { } Vector2D pos = globalBox().pos(); - g_pHyprRenderer->damageSurface(surface.wlr(), pos.x, pos.y); + g_pHyprRenderer->damageSurface(surface->resource(), pos.x, pos.y); } void CInputPopup::updateBox() { @@ -98,7 +100,7 @@ void CInputPopup::updateBox() { cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h}; } - Vector2D currentPopupSize = surface.getViewporterCorrectedSize(); + Vector2D currentPopupSize = surface->getViewporterCorrectedSize(); CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); @@ -127,9 +129,9 @@ void CInputPopup::updateBox() { const auto PML = g_pCompositor->getMonitorFromID(lastMonitor); if (PML) - wlr_surface_send_leave(surface.wlr(), PML->output); + surface->resource()->leave(PML->self.lock()); - wlr_surface_send_enter(surface.wlr(), PM->output); + surface->resource()->enter(PM->self.lock()); lastMonitor = PM->ID; } @@ -151,6 +153,6 @@ bool CInputPopup::isVecInPopup(const Vector2D& point) { return globalBox().containsPoint(point); } -wlr_surface* CInputPopup::getWlrSurface() { - return surface.wlr(); +SP CInputPopup::getSurface() { + return surface->resource(); } diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index 61b45d74..9c5491bf 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -12,18 +12,18 @@ class CInputPopup { public: CInputPopup(SP popup); - void damageEntire(); - void damageSurface(); + void damageEntire(); + void damageSurface(); - bool isVecInPopup(const Vector2D& point); + bool isVecInPopup(const Vector2D& point); - CBox globalBox(); - wlr_surface* getWlrSurface(); + CBox globalBox(); + SP getSurface(); - void onCommit(); + void onCommit(); private: - CWLSurface* queryOwner(); + SP queryOwner(); void updateBox(); void onDestroy(); @@ -31,7 +31,7 @@ class CInputPopup { void onUnmap(); WP popup; - CWLSurface surface; + SP surface; CBox lastBoxLocal; uint64_t lastMonitor = -1; diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index abf18fba..92ab14d8 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -3,9 +3,11 @@ #include "../../Compositor.hpp" #include "../../protocols/TextInputV3.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CInputMethodRelay::CInputMethodRelay() { - static auto P = g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast(param)); }); + static auto P = + g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast>(param)); }); listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(ti); }); listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast>(ime)); }); @@ -54,17 +56,17 @@ void CInputMethodRelay::onNewIME(SP pIME) { return; for (auto& ti : m_vTextInputs) { - if (ti->client() != wl_resource_get_client(g_pCompositor->m_pLastFocus->resource)) + if (ti->client() != g_pCompositor->m_pLastFocus->client()) continue; if (ti->isV3()) - ti->enter(g_pCompositor->m_pLastFocus); + ti->enter(g_pCompositor->m_pLastFocus.lock()); else - ti->onEnabled(g_pCompositor->m_pLastFocus); + ti->onEnabled(g_pCompositor->m_pLastFocus.lock()); } } -void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, wlr_surface* pSurface) { +void CInputMethodRelay::setIMEPopupFocus(CInputPopup* pPopup, SP pSurface) { pPopup->onCommit(); } @@ -125,7 +127,7 @@ void CInputMethodRelay::commitIMEState(CTextInput* pInput) { pInput->commitStateToIME(m_pIME.lock()); } -void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) { +void CInputMethodRelay::onKeyboardFocus(SP pSurface) { if (m_pIME.expired()) return; @@ -145,7 +147,7 @@ void CInputMethodRelay::onKeyboardFocus(wlr_surface* pSurface) { if (!ti->isV3()) continue; - if (ti->client() != wl_resource_get_client(pSurface->resource)) + if (ti->client() != pSurface->client()) continue; ti->enter(pSurface); @@ -161,9 +163,9 @@ CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { return nullptr; } -CInputPopup* CInputMethodRelay::popupFromSurface(const wlr_surface* surface) { +CInputPopup* CInputMethodRelay::popupFromSurface(const SP surface) { for (auto& p : m_vIMEPopups) { - if (p->getWlrSurface() == surface) + if (p->getSurface() == surface) return p.get(); } diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 2896e8e8..e942add8 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -26,15 +26,15 @@ class CInputMethodRelay { void commitIMEState(CTextInput* pInput); void removeTextInput(CTextInput* pInput); - void onKeyboardFocus(wlr_surface*); + void onKeyboardFocus(SP); CTextInput* getFocusedTextInput(); - void setIMEPopupFocus(CInputPopup*, wlr_surface*); + void setIMEPopupFocus(CInputPopup*, SP); void removePopup(CInputPopup*); CInputPopup* popupFromCoords(const Vector2D& point); - CInputPopup* popupFromSurface(const wlr_surface* surface); + CInputPopup* popupFromSurface(const SP surface); void updateAllPopups(); @@ -44,7 +44,7 @@ class CInputMethodRelay { std::vector> m_vTextInputs; std::vector> m_vIMEPopups; - wlr_surface* m_pLastKbFocus = nullptr; + WP m_pLastKbFocus; struct { CHyprSignalListener newTIV3; @@ -57,6 +57,6 @@ class CInputMethodRelay { friend class CHyprRenderer; friend class CInputManager; friend class CTextInputV1ProtocolManager; - friend struct CTextInput; + friend class CTextInput; friend class CHyprRenderer; }; diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 56e817ec..f1157e4b 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -20,7 +20,7 @@ static void unfocusTool(SP tool) { PROTO::tablet->proximityOut(tool); } -static void focusTool(SP tool, SP tablet, wlr_surface* surf) { +static void focusTool(SP tool, SP tablet, SP surf) { if (tool->getSurface() == surf || !surf) return; @@ -37,7 +37,7 @@ static void focusTool(SP tool, SP tablet, wlr_surface* sur } static void refocusTablet(SP tab, SP tool, bool motion = false) { - const auto LASTHLSURFACE = CWLSurface::surfaceFromWlr(g_pSeatManager->state.pointerFocus); + const auto LASTHLSURFACE = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); if (!LASTHLSURFACE || !tool->active) { if (tool->getSurface()) @@ -57,7 +57,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f const auto CURSORPOS = g_pInputManager->getMouseCoordsInternal(); - focusTool(tool, tab, g_pSeatManager->state.pointerFocus); + focusTool(tool, tab, g_pSeatManager->state.pointerFocus.lock()); if (!motion) return; diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index b3f0b0cb..4c7ffe6e 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -5,6 +5,7 @@ #include "../../Compositor.hpp" #include "../../protocols/TextInputV3.hpp" #include "../../protocols/InputMethodV2.hpp" +#include "../../protocols/core/Compositor.hpp" CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) { ti->pTextInput = this; @@ -56,8 +57,8 @@ void CTextInput::initCallbacks() { hyprListener_textInputDestroy.removeCallback(); hyprListener_textInputDisable.removeCallback(); hyprListener_textInputEnable.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - hyprListener_surfaceUnmapped.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.removeTextInput(this); }, @@ -65,7 +66,7 @@ void CTextInput::initCallbacks() { } } -void CTextInput::onEnabled(wlr_surface* surfV1) { +void CTextInput::onEnabled(SP surfV1) { Debug::log(LOG, "TI ENABLE"); if (g_pInputManager->m_sIMERelay.m_pIME.expired()) { @@ -75,7 +76,7 @@ void CTextInput::onEnabled(wlr_surface* surfV1) { // v1 only, map surface to PTI if (!isV3()) { - wlr_surface* pSurface = surfV1; + SP pSurface = surfV1; if (g_pCompositor->m_pLastFocus != pSurface || !pV1Input->active) return; @@ -97,8 +98,8 @@ void CTextInput::onDisabled() { if (!isV3()) leave(); - hyprListener_surfaceDestroyed.removeCallback(); - hyprListener_surfaceUnmapped.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.deactivateIME(this); } @@ -117,50 +118,44 @@ void CTextInput::onCommit() { g_pInputManager->m_sIMERelay.commitIMEState(this); } -void CTextInput::setFocusedSurface(wlr_surface* pSurface) { +void CTextInput::setFocusedSurface(SP pSurface) { if (pSurface == pFocusedSurface) return; pFocusedSurface = pSurface; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); if (!pSurface) return; - hyprListener_surfaceUnmapped.initCallback( - &pSurface->events.unmap, - [this](void* owner, void* data) { - Debug::log(LOG, "Unmap TI owner1"); + listeners.surfaceUnmap = pSurface->events.unmap.registerListener([this](std::any d) { + Debug::log(LOG, "Unmap TI owner1"); - if (enterLocks) - enterLocks--; - pFocusedSurface = nullptr; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - }, - this, "CTextInput"); + if (enterLocks) + enterLocks--; + pFocusedSurface.reset(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + }); - hyprListener_surfaceDestroyed.initCallback( - &pSurface->events.destroy, - [this](void* owner, void* data) { - Debug::log(LOG, "destroy TI owner1"); + listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { + Debug::log(LOG, "Destroy TI owner1"); - if (enterLocks) - enterLocks--; - pFocusedSurface = nullptr; - hyprListener_surfaceUnmapped.removeCallback(); - hyprListener_surfaceDestroyed.removeCallback(); - }, - this, "CTextInput"); + if (enterLocks) + enterLocks--; + pFocusedSurface.reset(); + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + }); } bool CTextInput::isV3() { return !pV1Input; } -void CTextInput::enter(wlr_surface* pSurface) { +void CTextInput::enter(SP pSurface) { if (!pSurface || !pSurface->mapped) return; @@ -182,7 +177,7 @@ void CTextInput::enter(wlr_surface* pSurface) { if (isV3()) pV3Input->enter(pSurface); else { - zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->resource); + zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->getResource()->resource()); pV1Input->active = true; } @@ -211,8 +206,8 @@ void CTextInput::leave() { g_pInputManager->m_sIMERelay.deactivateIME(this); } -wlr_surface* CTextInput::focusedSurface() { - return pFocusedSurface; +SP CTextInput::focusedSurface() { + return pFocusedSurface.lock(); } wl_client* CTextInput::client() { diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index ff21da95..30fbb4cc 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -6,12 +6,12 @@ #include "../../helpers/signal/Listener.hpp" #include -struct wlr_surface; struct wl_client; struct STextInputV1; class CTextInputV3; class CInputMethodV2; +class CWLSurfaceResource; class CTextInput { public: @@ -19,43 +19,43 @@ class CTextInput { CTextInput(STextInputV1* ti); ~CTextInput(); - bool isV3(); - void enter(wlr_surface* pSurface); - void leave(); - void tiV1Destroyed(); - wl_client* client(); - void commitStateToIME(SP ime); - void updateIMEState(SP ime); + bool isV3(); + void enter(SP pSurface); + void leave(); + void tiV1Destroyed(); + wl_client* client(); + void commitStateToIME(SP ime); + void updateIMEState(SP ime); - void onEnabled(wlr_surface* surfV1 = nullptr); - void onDisabled(); - void onCommit(); + void onEnabled(SP surfV1 = nullptr); + void onDisabled(); + void onCommit(); - bool hasCursorRectangle(); - CBox cursorBox(); + bool hasCursorRectangle(); + CBox cursorBox(); - wlr_surface* focusedSurface(); + SP focusedSurface(); private: - void setFocusedSurface(wlr_surface* pSurface); - void initCallbacks(); + void setFocusedSurface(SP pSurface); + void initCallbacks(); - wlr_surface* pFocusedSurface = nullptr; - int enterLocks = 0; - WP pV3Input; - STextInputV1* pV1Input = nullptr; + WP pFocusedSurface; + int enterLocks = 0; + WP pV3Input; + STextInputV1* pV1Input = nullptr; DYNLISTENER(textInputEnable); DYNLISTENER(textInputDisable); DYNLISTENER(textInputCommit); DYNLISTENER(textInputDestroy); - DYNLISTENER(surfaceUnmapped); - DYNLISTENER(surfaceDestroyed); struct { CHyprSignalListener enable; CHyprSignalListener disable; CHyprSignalListener commit; CHyprSignalListener destroy; + CHyprSignalListener surfaceUnmap; + CHyprSignalListener surfaceDestroy; } listeners; }; \ No newline at end of file diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7748813b..a1f949c2 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -77,7 +77,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } else return; // oops, nothing found. - g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local); + g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface.lock(), e.timeMs, e.touchID, local); PROTO::idle->onActivity(); } diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index b9b99f69..04dcd0a8 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -2,10 +2,11 @@ #include #include "../desktop/WLSurface.hpp" #include "../render/Renderer.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::alphaModifier->protoLog -CAlphaModifier::CAlphaModifier(SP resource_, wlr_surface* surface_) : resource(resource_), pSurface(surface_) { +CAlphaModifier::CAlphaModifier(SP resource_, SP surface_) : resource(resource_), pSurface(surface_) { if (!resource->resource()) return; @@ -18,8 +19,7 @@ CAlphaModifier::CAlphaModifier(SP resource_, wlr_surf setSurfaceAlpha(1.F); }); - hyprListener_surfaceDestroy.initCallback( - &surface_->events.destroy, [this](void* owner, void* data) { onSurfaceDestroy(); }, this, "CAlphaModifier"); + listeners.destroySurface = pSurface->events.destroy.registerListener([this](std::any d) { onSurfaceDestroy(); }); resource->setSetMultiplier([this](CWpAlphaModifierSurfaceV1* mod, uint32_t alpha) { if (!pSurface) { @@ -35,19 +35,19 @@ CAlphaModifier::CAlphaModifier(SP resource_, wlr_surf } CAlphaModifier::~CAlphaModifier() { - hyprListener_surfaceDestroy.removeCallback(); + ; } bool CAlphaModifier::good() { return resource->resource(); } -wlr_surface* CAlphaModifier::getSurface() { - return pSurface; +SP CAlphaModifier::getSurface() { + return pSurface.lock(); } void CAlphaModifier::setSurfaceAlpha(float a) { - CWLSurface* surf = CWLSurface::surfaceFromWlr(pSurface); + auto surf = CWLSurface::fromResource(pSurface.lock()); if (!surf) { LOGM(ERR, "CAlphaModifier::setSurfaceAlpha: No CWLSurface for given surface??"); @@ -62,8 +62,7 @@ void CAlphaModifier::setSurfaceAlpha(float a) { } void CAlphaModifier::onSurfaceDestroy() { - hyprListener_surfaceDestroy.removeCallback(); - pSurface = nullptr; + pSurface.reset(); } CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { @@ -75,7 +74,7 @@ void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t RESOURCE->setOnDestroy([this](CWpAlphaModifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpAlphaModifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, wlr_surface_from_resource(surface)); }); + RESOURCE->setGetSurface([this](CWpAlphaModifierV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetSurface(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) { @@ -83,29 +82,11 @@ void CAlphaModifierProtocol::onManagerResourceDestroy(wl_resource* res) { } void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) { - if (modifier->getSurface()) - m_mAlphaModifiers.erase(modifier->getSurface()); - else { - // find it first - wlr_surface* deadptr = nullptr; - for (auto& [k, v] : m_mAlphaModifiers) { - if (v.get() == modifier) { - deadptr = k; - break; - } - } - - if (!deadptr) { - LOGM(ERR, "CAlphaModifierProtocol::destroyModifier: dead resource but no deadptr???"); - return; - } - - m_mAlphaModifiers.erase(deadptr); - } + std::erase_if(m_mAlphaModifiers, [](const auto& e) { return e.first.expired(); }); } -void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface) { - if (m_mAlphaModifiers.contains(surface)) { +void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP surface) { + if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) { LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface); pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present"); return; diff --git a/src/protocols/AlphaModifier.hpp b/src/protocols/AlphaModifier.hpp index 457d1b4c..d49d1e4e 100644 --- a/src/protocols/AlphaModifier.hpp +++ b/src/protocols/AlphaModifier.hpp @@ -5,23 +5,28 @@ #include #include "WaylandProtocol.hpp" #include "alpha-modifier-v1.hpp" +#include "../helpers/signal/Listener.hpp" + +class CWLSurfaceResource; class CAlphaModifier { public: - CAlphaModifier(SP resource_, wlr_surface* surface); + CAlphaModifier(SP resource_, SP surface); ~CAlphaModifier(); - bool good(); - wlr_surface* getSurface(); - void onSurfaceDestroy(); + bool good(); + SP getSurface(); + void onSurfaceDestroy(); private: SP resource; - wlr_surface* pSurface = nullptr; + WP pSurface; void setSurfaceAlpha(float a); - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CAlphaModifierProtocol : public IWaylandProtocol { @@ -33,15 +38,15 @@ class CAlphaModifierProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyModifier(CAlphaModifier* decoration); - void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, wlr_surface* surface); + void onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP surface); // - std::vector> m_vManagers; - std::unordered_map> m_mAlphaModifiers; // xdg_toplevel -> deco + std::vector> m_vManagers; + std::unordered_map, UP> m_mAlphaModifiers; // xdg_toplevel -> deco friend class CAlphaModifier; }; namespace PROTO { inline UP alphaModifier; -}; \ No newline at end of file +}; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 5f0771e0..40f9af44 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -1,21 +1,21 @@ #include "FocusGrab.hpp" -#include "Compositor.hpp" +#include "../Compositor.hpp" #include #include "../managers/input/InputManager.hpp" #include "../managers/SeatManager.hpp" +#include "core/Compositor.hpp" #include #include #include #define LOGM PROTO::focusGrab->protoLog -CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [=](void*, void*) { grab->eraseSurface(surface); }, this, "CFocusGrab"); +CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP surface) { + listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { - hyprListener_surfaceDestroy.removeCallback(); + ; } CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) { @@ -29,8 +29,8 @@ CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) resource->setDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); resource->setOnDestroy([this](CHyprlandFocusGrabV1* pMgr) { PROTO::focusGrab->destroyGrab(this); }); - resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(wlr_surface_from_resource(surface)); }); - resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(wlr_surface_from_resource(surface)); }); + resource->setAddSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { addSurface(CWLSurfaceResource::fromResource(surface)); }); + resource->setRemoveSurface([this](CHyprlandFocusGrabV1* pMgr, wl_resource* surface) { removeSurface(CWLSurfaceResource::fromResource(surface)); }); resource->setCommit([this](CHyprlandFocusGrabV1* pMgr) { commit(); }); } @@ -42,8 +42,8 @@ bool CFocusGrab::good() { return resource->resource(); } -bool CFocusGrab::isSurfaceComitted(wlr_surface* surface) { - auto iter = m_mSurfaces.find(surface); +bool CFocusGrab::isSurfaceComitted(SP surface) { + auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& o) { return o.first == surface; }); if (iter == m_mSurfaces.end()) return false; @@ -77,14 +77,14 @@ void CFocusGrab::finish(bool sendCleared) { } } -void CFocusGrab::addSurface(wlr_surface* surface) { - auto iter = m_mSurfaces.find(surface); +void CFocusGrab::addSurface(SP surface) { + auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; }); if (iter == m_mSurfaces.end()) { m_mSurfaces.emplace(surface, std::make_unique(this, surface)); } } -void CFocusGrab::removeSurface(wlr_surface* surface) { +void CFocusGrab::removeSurface(SP surface) { auto iter = m_mSurfaces.find(surface); if (iter != m_mSurfaces.end()) { if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) { @@ -94,20 +94,20 @@ void CFocusGrab::removeSurface(wlr_surface* surface) { } } -void CFocusGrab::eraseSurface(wlr_surface* surface) { +void CFocusGrab::eraseSurface(SP surface) { removeSurface(surface); commit(true); } void CFocusGrab::refocusKeyboard() { auto keyboardSurface = g_pSeatManager->state.keyboardFocus; - if (keyboardSurface != nullptr && isSurfaceComitted(keyboardSurface)) + if (keyboardSurface && isSurfaceComitted(keyboardSurface.lock())) return; - wlr_surface* surface = nullptr; + SP surface = nullptr; for (auto& [surf, state] : m_mSurfaces) { if (state->state == CFocusGrabSurfaceState::Comitted) { - surface = surf; + surface = surf.lock(); break; } } @@ -124,14 +124,14 @@ void CFocusGrab::commit(bool removeOnly) { for (auto iter = m_mSurfaces.begin(); iter != m_mSurfaces.end();) { switch (iter->second->state) { case CFocusGrabSurfaceState::PendingRemoval: - grab->remove(iter->first); + grab->remove(iter->first.lock()); iter = m_mSurfaces.erase(iter); surfacesChanged = true; continue; case CFocusGrabSurfaceState::PendingAddition: if (!removeOnly) { iter->second->state = CFocusGrabSurfaceState::Comitted; - grab->add(iter->first); + grab->add(iter->first.lock()); surfacesChanged = true; anyComitted = true; } diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 40922c22..80166f9f 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -6,13 +6,15 @@ #include #include #include +#include "../helpers/signal/Listener.hpp" class CFocusGrab; class CSeatGrab; +class CWLSurfaceResource; class CFocusGrabSurfaceState { public: - CFocusGrabSurfaceState(CFocusGrab* grab, wlr_surface* surface); + CFocusGrabSurfaceState(CFocusGrab* grab, SP surface); ~CFocusGrabSurfaceState(); enum State { @@ -22,7 +24,9 @@ class CFocusGrabSurfaceState { } state = PendingAddition; private: - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroy; + } listeners; }; class CFocusGrab { @@ -31,23 +35,23 @@ class CFocusGrab { ~CFocusGrab(); bool good(); - bool isSurfaceComitted(wlr_surface* surface); + bool isSurfaceComitted(SP surface); void start(); void finish(bool sendCleared); private: - void addSurface(wlr_surface* surface); - void removeSurface(wlr_surface* surface); - void eraseSurface(wlr_surface* surface); - void refocusKeyboard(); - void commit(bool removeOnly = false); + void addSurface(SP surface); + void removeSurface(SP surface); + void eraseSurface(SP surface); + void refocusKeyboard(); + void commit(bool removeOnly = false); - SP resource; - std::unordered_map> m_mSurfaces; - SP grab; + SP resource; + std::unordered_map, UP> m_mSurfaces; + SP grab; - bool m_bGrabActive = false; + bool m_bGrabActive = false; DYNLISTENER(pointerGrabStarted); DYNLISTENER(keyboardGrabStarted); diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 691ab697..6d225e99 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -1,13 +1,9 @@ #include "FractionalScale.hpp" +#include +#include "core/Compositor.hpp" #define LOGM PROTO::fractional->protoLog -static void onWlrSurfaceDestroy(void* owner, void* data) { - const auto SURF = (wlr_surface*)owner; - - PROTO::fractional->onSurfaceDestroy(SURF); -} - CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -18,7 +14,7 @@ void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32 RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setGetFractionalScale( - [this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, wlr_surface_from_resource(surface)); }); + [this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CFractionalScaleProtocol::removeAddon(CFractionalScaleAddon* addon) { @@ -29,11 +25,13 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagers, [res](const auto& other) { return other->resource() == res; }); } -void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface) { - if (m_mAddons.contains(surface)) { - LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface); - pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); - return; +void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP surface) { + for (auto& [k, v] : m_mAddons) { + if (k == surface) { + LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface); + pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); + return; + } } const auto PADDON = @@ -48,35 +46,22 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); - if (!m_mSurfaceScales.contains(surface)) - m_mSurfaceScales[surface] = 1.F; + if (std::find_if(m_mSurfaceScales.begin(), m_mSurfaceScales.end(), [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end()) + m_mSurfaceScales.emplace(surface, 1.F); - PADDON->setScale(m_mSurfaceScales[surface]); - registerSurface(surface); + PADDON->setScale(m_mSurfaceScales.at(surface)); + + // clean old + std::erase_if(m_mSurfaceScales, [](const auto& e) { return e.first.expired(); }); } -void CFractionalScaleProtocol::sendScale(wlr_surface* surf, const float& scale) { +void CFractionalScaleProtocol::sendScale(SP surf, const float& scale) { m_mSurfaceScales[surf] = scale; if (m_mAddons.contains(surf)) m_mAddons[surf]->setScale(scale); - registerSurface(surf); } -void CFractionalScaleProtocol::registerSurface(wlr_surface* surf) { - if (m_mSurfaceDestroyListeners.contains(surf)) - return; - - m_mSurfaceDestroyListeners[surf].hyprListener_surfaceDestroy.initCallback(&surf->events.destroy, ::onWlrSurfaceDestroy, surf, "FractionalScale"); -} - -void CFractionalScaleProtocol::onSurfaceDestroy(wlr_surface* surf) { - m_mSurfaceDestroyListeners.erase(surf); - m_mSurfaceScales.erase(surf); - if (m_mAddons.contains(surf)) - m_mAddons[surf]->onSurfaceDestroy(); -} - -CFractionalScaleAddon::CFractionalScaleAddon(SP resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) { +CFractionalScaleAddon::CFractionalScaleAddon(SP resource_, SP surf_) : resource(resource_), surface(surf_) { resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); } @@ -93,6 +78,6 @@ bool CFractionalScaleAddon::good() { return resource->resource(); } -wlr_surface* CFractionalScaleAddon::surf() { - return surface; +SP CFractionalScaleAddon::surf() { + return surface.lock(); } \ No newline at end of file diff --git a/src/protocols/FractionalScale.hpp b/src/protocols/FractionalScale.hpp index 10ebf49a..f6d1f96f 100644 --- a/src/protocols/FractionalScale.hpp +++ b/src/protocols/FractionalScale.hpp @@ -6,19 +6,20 @@ #include "fractional-scale-v1.hpp" class CFractionalScaleProtocol; +class CWLSurfaceResource; class CFractionalScaleAddon { public: - CFractionalScaleAddon(SP resource_, wlr_surface* surf_); + CFractionalScaleAddon(SP resource_, SP surf_); - void setScale(const float& scale); - void onSurfaceDestroy(); + void setScale(const float& scale); + void onSurfaceDestroy(); - bool good(); + bool good(); - wlr_surface* surf(); + SP surf(); - bool operator==(const wl_resource* other) const { + bool operator==(const wl_resource* other) const { return other == resource->resource(); } @@ -28,42 +29,36 @@ class CFractionalScaleAddon { private: SP resource; - float scale = 1.F; - wlr_surface* surface = nullptr; + float scale = 1.F; + WP surface; bool surfaceGone = false; friend class CFractionalScaleProtocol; }; -struct SSurfaceListener { - DYNLISTENER(surfaceDestroy); -}; - class CFractionalScaleProtocol : public IWaylandProtocol { public: CFractionalScaleProtocol(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); - void onSurfaceDestroy(wlr_surface* surf); - void sendScale(wlr_surface* surf, const float& scale); + void onSurfaceDestroy(SP surf); + void sendScale(SP surf, const float& scale); private: void removeAddon(CFractionalScaleAddon*); - void registerSurface(wlr_surface*); void onManagerResourceDestroy(wl_resource* res); - void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface); + void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP surface); // - std::unordered_map m_mSurfaceDestroyListeners; - std::unordered_map m_mSurfaceScales; - std::unordered_map> m_mAddons; - std::vector> m_vManagers; + std::unordered_map, float> m_mSurfaceScales; + std::unordered_map, UP> m_mAddons; + std::vector> m_vManagers; friend class CFractionalScaleAddon; }; namespace PROTO { inline UP fractional; -}; \ No newline at end of file +}; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index c8db7100..7c3b39ce 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -3,6 +3,7 @@ #include #include "../helpers/Monitor.hpp" #include "../Compositor.hpp" +#include "../protocols/core/Output.hpp" #define LOGM PROTO::gamma->protoLog @@ -10,15 +11,15 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out if (!resource_->resource()) return; - wlr_output* wlrOutput = wlr_output_from_resource(output); + auto OUTPUTRES = CWLOutputResource::fromResource(output); - if (!wlrOutput) { - LOGM(ERR, "No wlr_output in CGammaControl"); + if (!OUTPUTRES) { + LOGM(ERR, "No output in CGammaControl"); resource->sendFailed(); return; } - pMonitor = g_pCompositor->getRealMonitorFromOutput(wlrOutput); + pMonitor = OUTPUTRES->monitor.get(); if (!pMonitor) { LOGM(ERR, "No CMonitor"); @@ -33,7 +34,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } } - gammaSize = wlr_output_get_gamma_size(wlrOutput); + gammaSize = wlr_output_get_gamma_size(pMonitor->output); if (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); diff --git a/src/protocols/IdleInhibit.cpp b/src/protocols/IdleInhibit.cpp index 0ff11a56..89eb3108 100644 --- a/src/protocols/IdleInhibit.cpp +++ b/src/protocols/IdleInhibit.cpp @@ -1,26 +1,23 @@ #include "IdleInhibit.hpp" +#include "core/Compositor.hpp" -CIdleInhibitor::CIdleInhibitor(SP resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) { +CIdleInhibitor::CIdleInhibitor(SP resource_, SP surf_) : resource(resource_), surface(surf_) { ; } -CIdleInhibitorResource::CIdleInhibitorResource(SP resource_, wlr_surface* surface_) : resource(resource_), surface(surface_) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - surface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); - destroySent = true; - events.destroy.emit(); - }, - this, "CIdleInhibitorResource"); +CIdleInhibitorResource::CIdleInhibitorResource(SP resource_, SP surface_) : resource(resource_), surface(surface_) { + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + surface.reset(); + listeners.destroySurface.reset(); + destroySent = true; + events.destroy.emit(); + }); resource->setOnDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); }); resource->setDestroy([this](CZwpIdleInhibitorV1* p) { PROTO::idleInhibit->removeInhibitor(this); }); } CIdleInhibitorResource::~CIdleInhibitorResource() { - hyprListener_surfaceDestroy.removeCallback(); if (!destroySent) events.destroy.emit(); } @@ -39,14 +36,14 @@ void CIdleInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t v RESOURCE->setDestroy([this](CZwpIdleInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setCreateInhibitor( - [this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, wlr_surface_from_resource(surface)); }); + [this](CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onCreateInhibitor(pMgr, id, CWLSurfaceResource::fromResource(surface)); }); } void CIdleInhibitProtocol::removeInhibitor(CIdleInhibitorResource* resource) { std::erase_if(m_vInhibitors, [resource](const auto& el) { return el.get() == resource; }); } -void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface) { +void CIdleInhibitProtocol::onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP surface) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vInhibitors.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), surface)); diff --git a/src/protocols/IdleInhibit.hpp b/src/protocols/IdleInhibit.hpp index b59e8789..3cbfd78d 100644 --- a/src/protocols/IdleInhibit.hpp +++ b/src/protocols/IdleInhibit.hpp @@ -7,22 +7,23 @@ #include "../helpers/signal/Signal.hpp" class CIdleInhibitorResource; +class CWLSurfaceResource; class CIdleInhibitor { public: - CIdleInhibitor(SP resource_, wlr_surface* surf_); + CIdleInhibitor(SP resource_, SP surf_); struct { CHyprSignalListener destroy; } listeners; WP resource; - wlr_surface* surface = nullptr; + WP surface; }; class CIdleInhibitorResource { public: - CIdleInhibitorResource(SP resource_, wlr_surface* surface_); + CIdleInhibitorResource(SP resource_, SP surface_); ~CIdleInhibitorResource(); SP inhibitor; @@ -33,10 +34,12 @@ class CIdleInhibitorResource { private: SP resource; - wlr_surface* surface = nullptr; + WP surface; bool destroySent = false; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CIdleInhibitProtocol : public IWaylandProtocol { @@ -51,7 +54,7 @@ class CIdleInhibitProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); - void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, wlr_surface* surface); + void onCreateInhibitor(CZwpIdleInhibitManagerV1* pMgr, uint32_t id, SP surface); void removeInhibitor(CIdleInhibitorResource*); @@ -64,4 +67,4 @@ class CIdleInhibitProtocol : public IWaylandProtocol { namespace PROTO { inline UP idleInhibit; -} \ No newline at end of file +} diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 93ca38c0..5d0bd417 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "../devices/IKeyboard.hpp" #include +#include "core/Compositor.hpp" #define LOGM PROTO::ime->protoLog @@ -83,51 +84,45 @@ wl_client* CInputMethodKeyboardGrabV2::client() { return resource->client(); } -CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, SP owner_, wlr_surface* wlrSurface) : resource(resource_), owner(owner_) { +CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, SP owner_, SP surface) : resource(resource_), owner(owner_) { if (!resource->resource()) return; resource->setDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); }); resource->setOnDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); }); - pSurface = wlrSurface; + pSurface = surface; - hyprListener_destroySurface.initCallback( - &wlrSurface->events.destroy, - [this](void* owner, void* data) { - if (mapped) - events.unmap.emit(); + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + if (mapped) + events.unmap.emit(); - hyprListener_commitSurface.removeCallback(); - hyprListener_destroySurface.removeCallback(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); - if (g_pCompositor->m_pLastFocus == pSurface) - g_pCompositor->m_pLastFocus = nullptr; + if (g_pCompositor->m_pLastFocus == pSurface) + g_pCompositor->m_pLastFocus.reset(); - pSurface = nullptr; - }, - this, "IMEPopup"); + pSurface.reset(); + }); - hyprListener_commitSurface.initCallback( - &wlrSurface->events.commit, - [this](void* owner, void* data) { - if (pSurface->pending.buffer_width > 0 && pSurface->pending.buffer_height > 0 && !mapped) { - mapped = true; - wlr_surface_map(pSurface); - events.map.emit(); - return; - } + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (pSurface->current.buffer && !mapped) { + mapped = true; + pSurface->map(); + events.map.emit(); + return; + } - if (pSurface->pending.buffer_width <= 0 && pSurface->pending.buffer_height <= 0 && mapped) { - mapped = false; - wlr_surface_unmap(pSurface); - events.unmap.emit(); - return; - } + if (!pSurface->current.buffer && mapped) { + mapped = false; + pSurface->unmap(); + events.unmap.emit(); + return; + } - events.commit.emit(); - }, - this, "IMEPopup"); + events.commit.emit(); + }); } CInputMethodPopupV2::~CInputMethodPopupV2() { @@ -145,8 +140,8 @@ void CInputMethodPopupV2::sendInputRectangle(const CBox& box) { resource->sendTextInputRectangle(box.x, box.y, box.w, box.h); } -wlr_surface* CInputMethodPopupV2::surface() { - return pSurface; +SP CInputMethodPopupV2::surface() { + return pSurface.lock(); } void CInputMethodV2::SState::reset() { @@ -194,7 +189,7 @@ CInputMethodV2::CInputMethodV2(SP resource_) : resource(resou resource->setGetInputPopupSurface([this](CZwpInputMethodV2* r, uint32_t id, wl_resource* surface) { const auto RESOURCE = PROTO::ime->m_vPopups.emplace_back( - makeShared(makeShared(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surface))); + makeShared(makeShared(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surface))); if (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index 1f5d2598..bc21270c 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -101,12 +101,12 @@ class CInputMethodKeyboardGrabV2 { class CInputMethodPopupV2 { public: - CInputMethodPopupV2(SP resource_, SP owner_, wlr_surface* surface); + CInputMethodPopupV2(SP resource_, SP owner_, SP surface); ~CInputMethodPopupV2(); - bool good(); - void sendInputRectangle(const CBox& box); - wlr_surface* surface(); + bool good(); + void sendInputRectangle(const CBox& box); + SP surface(); struct { CSignal map; @@ -120,10 +120,12 @@ class CInputMethodPopupV2 { private: SP resource; WP owner; - wlr_surface* pSurface = nullptr; + WP pSurface; - DYNLISTENER(commitSurface); - DYNLISTENER(destroySurface); + struct { + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; + } listeners; }; class CInputMethodV2Protocol : public IWaylandProtocol { diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 962b89a3..8fa6dd27 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -1,6 +1,8 @@ #include "LayerShell.hpp" #include "../Compositor.hpp" #include "XDGShell.hpp" +#include "core/Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::layerShell->protoLog @@ -14,7 +16,7 @@ void CLayerShellResource::SState::reset() { margin = {0, 0, 0, 0}; } -CLayerShellResource::CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : +CLayerShellResource::CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : layerNamespace(namespace_), surface(surf_), resource(resource_) { if (!good()) return; @@ -31,57 +33,52 @@ CLayerShellResource::CLayerShellResource(SP resource_, wlr_ PROTO::layerShell->destroyResource(this); }); - hyprListener_destroySurface.initCallback( - &surf_->events.destroy, - [this](void* owner, void* data) { - events.destroy.emit(); - PROTO::layerShell->destroyResource(this); - }, - this, "CLayerShellResource"); + listeners.destroySurface = surf_->events.destroy.registerListener([this](std::any d) { + events.destroy.emit(); + PROTO::layerShell->destroyResource(this); + }); - hyprListener_commitSurface.initCallback( - &surf_->events.commit, - [this](void* owner, void* data) { - current = pending; - pending.committed = 0; + listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) { + current = pending; + pending.committed = 0; - bool attachedBuffer = surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0; + bool attachedBuffer = surface->current.buffer; - if (attachedBuffer && !configured) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "layerSurface was not configured, but a buffer was attached"); - return; - } + if (attachedBuffer && !configured) { + surface->error(-1, "layerSurface was not configured, but a buffer was attached"); + return; + } - constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + constexpr uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + constexpr uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "x == 0 but anchor doesn't have left and right"); - return; - } + if (current.desiredSize.x <= 0 && (current.anchor & horiz) != horiz) { + surface->error(-1, "x == 0 but anchor doesn't have left and right"); + return; + } - if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { - wlr_surface_reject_pending(surface, resource->resource(), -1, "y == 0 but anchor doesn't have top and bottom"); - return; - } + if (current.desiredSize.y <= 0 && (current.anchor & vert) != vert) { + surface->error(-1, "y == 0 but anchor doesn't have top and bottom"); + return; + } - if (attachedBuffer && !mapped) { - mapped = true; - wlr_surface_map(surface); - events.map.emit(); - return; - } + if (attachedBuffer && !mapped) { + mapped = true; + surface->map(); + events.map.emit(); + return; + } - if (!attachedBuffer && mapped) { - mapped = false; - wlr_surface_unmap(surface); - events.unmap.emit(); - return; - } + if (!attachedBuffer && mapped) { + mapped = false; + surface->unmap(); + events.unmap.emit(); + configured = false; + return; + } - events.commit.emit(); - }, - this, "CLayerShellResource"); + events.commit.emit(); + }); resource->setSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) { pending.committed |= STATE_SIZE; @@ -209,9 +206,9 @@ void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { const auto CLIENT = pMgr->client(); - const auto PMONITOR = output ? g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)) : nullptr; + const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.get() : nullptr; const auto RESOURCE = m_vLayers.emplace_back( - makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), namespace_, PMONITOR, layer)); + makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), namespace_, PMONITOR, layer)); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 9ed6bc66..f348e86b 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -10,10 +10,11 @@ #include "../helpers/signal/Signal.hpp" class CMonitor; +class CWLSurfaceResource; class CLayerShellResource { public: - CLayerShellResource(SP resource_, wlr_surface* surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); + CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); ~CLayerShellResource(); bool good(); @@ -54,18 +55,20 @@ class CLayerShellResource { void reset(); } current, pending; - Vector2D size; - std::string layerNamespace; - std::string monitor = ""; - wlr_surface* surface = nullptr; - bool mapped = false; - bool configured = false; + Vector2D size; + std::string layerNamespace; + std::string monitor = ""; + WP surface; + bool mapped = false; + bool configured = false; private: SP resource; - DYNLISTENER(destroySurface); - DYNLISTENER(commitSurface); + struct { + CHyprSignalListener commitSurface; + CHyprSignalListener destroySurface; + } listeners; bool closed = false; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp new file mode 100644 index 00000000..f7911f6e --- /dev/null +++ b/src/protocols/LinuxDMABUF.cpp @@ -0,0 +1,454 @@ +#include "LinuxDMABUF.hpp" +#include +#include +#include +#include "../helpers/MiscFunctions.hpp" +#include +#include +#include +#include "core/Compositor.hpp" +#include "types/DMABuffer.hpp" +#include "types/WLBuffer.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../render/OpenGL.hpp" +#include "../Compositor.hpp" + +#define LOGM PROTO::linuxDma->protoLog + +static std::optional devIDFromFD(int fd) { + struct stat stat; + if (fstat(fd, &stat) != 0) + return {}; + return stat.st_rdev; +} + +CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector tranches_) { + std::set> formats; + for (auto& t : tranches_) { + for (auto& fmt : t.formats) { + for (auto& mod : fmt.mods) { + formats.insert(std::make_pair<>(fmt.format, mod)); + } + } + } + + tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); + int fds[2] = {0}; + allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + + auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + + if (!arr) { + LOGM(ERR, "mmap failed"); + close(fds[0]); + close(fds[1]); + return; + } + + close(fds[0]); + + std::vector> formatsVec; + for (auto& f : formats) { + formatsVec.push_back(f); + } + + size_t i = 0; + for (auto& [fmt, mod] : formatsVec) { + arr[i++] = SDMABUFFeedbackTableEntry{ + .fmt = fmt, + .modifier = mod, + }; + } + + munmap(arr, tableLen); + + mainDevice = device; + tableFD = fds[1]; + tranches = formatsVec; + + // TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho. +} + +CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { + close(tableFD); +} + +CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) { + buffer = makeShared(id, client, attrs); + + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::linuxDma->destroyResource(this); + }); + + if (!buffer->success) + LOGM(ERR, "Possibly compositor bug: buffer failed to create"); +} + +CLinuxDMABuffer::~CLinuxDMABuffer() { + buffer.reset(); + listeners.bufferResourceDestroy.reset(); +} + +bool CLinuxDMABuffer::good() { + return buffer && buffer->good(); +} + +CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); + + attrs = makeShared(); + + attrs->success = true; + + resource->setAdd([this](CZwpLinuxBufferParamsV1* r, int32_t fd, uint32_t plane, uint32_t offset, uint32_t stride, uint32_t modHi, uint32_t modLo) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (plane > 3) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane > 3"); + return; + } + + if (attrs->fds.at(plane) != -1) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX, "plane used"); + return; + } + + attrs->fds[plane] = fd; + attrs->strides[plane] = stride; + attrs->offsets[plane] = offset; + attrs->modifier = ((uint64_t)modHi << 32) | modLo; + }); + + resource->setCreate([this](CZwpLinuxBufferParamsV1* r, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (flags > 0) { + r->sendFailed(); + LOGM(ERR, "DMABUF flags are not supported"); + return; + } + + attrs->size = {w, h}; + attrs->format = fmt; + attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1); + + create(0); + }); + + resource->setCreateImmed([this](CZwpLinuxBufferParamsV1* r, uint32_t id, int32_t w, int32_t h, uint32_t fmt, zwpLinuxBufferParamsV1Flags flags) { + if (used) { + r->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, "Already used"); + return; + } + + if (flags > 0) { + r->sendFailed(); + LOGM(ERR, "DMABUF flags are not supported"); + return; + } + + attrs->size = {w, h}; + attrs->format = fmt; + attrs->planes = 4 - std::count(attrs->fds.begin(), attrs->fds.end(), -1); + + create(id); + }); +} + +CLinuxDMABBUFParamsResource::~CLinuxDMABBUFParamsResource() { + ; +} + +bool CLinuxDMABBUFParamsResource::good() { + return resource->resource(); +} + +void CLinuxDMABBUFParamsResource::create(uint32_t id) { + used = true; + + if (!verify()) { + LOGM(ERR, "Failed creating a dmabuf: verify() said no"); + return; // if verify failed, we errored the resource. + } + + if (!commence()) { + LOGM(ERR, "Failed creating a dmabuf: commence() said no"); + resource->sendFailed(); + return; + } + + LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes); + for (int i = 0; i < attrs->planes; ++i) { + LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]); + } + + auto buf = PROTO::linuxDma->m_vBuffers.emplace_back(makeShared(id, resource->client(), *attrs)); + + if (!buf->good() || !buf->buffer->success) { + resource->sendFailed(); + return; + } + + if (!id) + resource->sendCreated(PROTO::linuxDma->m_vBuffers.back()->buffer->resource->getResource()); + + createdBuffer = buf; +} + +bool CLinuxDMABBUFParamsResource::commence() { + if (PROTO::linuxDma->mainDeviceFD < 0) + return true; + + for (int i = 0; i < attrs->planes; i++) { + uint32_t handle = 0; + + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + LOGM(ERR, "Failed to import dmabuf fd"); + return false; + } + + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + LOGM(ERR, "Failed to close dmabuf handle"); + return false; + } + } + + return true; +} + +bool CLinuxDMABBUFParamsResource::verify() { + if (attrs->planes <= 0) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added"); + return false; + } + + if (attrs->fds.at(0) < 0) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No plane 0"); + return false; + } + + bool empty = false; + for (auto& plane : attrs->fds) { + if (empty && plane != -1) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "Gap in planes"); + return false; + } + + if (plane == -1) { + empty = true; + continue; + } + } + + if (attrs->size.x < 1 || attrs->size.y < 1) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, "x/y < 1"); + return false; + } + + for (size_t i = 0; i < (size_t)attrs->planes; ++i) { + if ((uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i) * attrs->size.y > UINT32_MAX) { + resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS, + std::format("size overflow on plane {}: offset {} + stride {} * height {} = {}, overflows UINT32_MAX", i, (uint64_t)attrs->offsets.at(i), + (uint64_t)attrs->strides.at(i), attrs->size.y, (uint64_t)attrs->offsets.at(i) + (uint64_t)attrs->strides.at(i))); + return false; + } + } + + return true; +} + +CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); + + if (surface) + LOGM(ERR, "FIXME: surface feedback stub"); + + auto* feedback = PROTO::linuxDma->defaultFeedback.get(); + + resource->sendFormatTable(feedback->tableFD, feedback->tableLen); + + // send default feedback + struct wl_array deviceArr = { + .size = sizeof(feedback->mainDevice), + .data = (void*)&feedback->mainDevice, + }; + resource->sendMainDevice(&deviceArr); + resource->sendTrancheTargetDevice(&deviceArr); + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0); + + wl_array indices; + wl_array_init(&indices); + for (size_t i = 0; i < feedback->tranches.size(); ++i) { + *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; + } + resource->sendTrancheFormats(&indices); + wl_array_release(&indices); + resource->sendTrancheDone(); + + resource->sendDone(); +} + +CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { + ; +} + +bool CLinuxDMABUFFeedbackResource::good() { + return resource->resource(); +} + +CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); }); + resource->setDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); }); + + resource->setGetDefaultFeedback([](CZwpLinuxDmabufV1* r, uint32_t id) { + const auto RESOURCE = + PROTO::linuxDma->m_vFeedbacks.emplace_back(makeShared(makeShared(r->client(), r->version(), id), nullptr)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vFeedbacks.pop_back(); + return; + } + }); + + resource->setGetSurfaceFeedback([](CZwpLinuxDmabufV1* r, uint32_t id, wl_resource* surf) { + const auto RESOURCE = PROTO::linuxDma->m_vFeedbacks.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vFeedbacks.pop_back(); + return; + } + }); + + resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) { + const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::linuxDma->m_vParams.pop_back(); + return; + } + }); + + if (resource->version() < 4) + sendMods(); +} + +bool CLinuxDMABUFResource::good() { + return resource->resource(); +} + +void CLinuxDMABUFResource::sendMods() { + for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID) + resource->sendFormat(fmt); + continue; + } + + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); + } +} + +CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { + int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + auto dev = devIDFromFD(rendererFD); + + if (!dev.has_value()) { + LOGM(ERR, "failed to get drm dev"); + PROTO::linuxDma.reset(); + return; + } + + mainDevice = *dev; + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + + SDMABufTranche tranche = { + .device = *dev, + .formats = fmts, + }; + + std::vector tches; + tches.push_back(tranche); + + defaultFeedback = std::make_unique(*dev, tches); + + drmDevice* device = nullptr; + if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { + LOGM(ERR, "failed to get drm dev"); + PROTO::linuxDma.reset(); + return; + } + + if (device->available_nodes & (1 << DRM_NODE_RENDER)) { + const char* name = device->nodes[DRM_NODE_RENDER]; + mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + drmFreeDevice(&device); + if (mainDeviceFD < 0) { + LOGM(ERR, "failed to open drm dev"); + PROTO::linuxDma.reset(); + return; + } + } else { + LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]); + drmFreeDevice(&device); + } + }); +} + +CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { + if (mainDeviceFD >= 0) + close(mainDeviceFD); +} + +void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFFeedbackResource* resource) { + std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resource) { + std::erase_if(m_vParams, [&](const auto& other) { return other.get() == resource; }); +} + +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp new file mode 100644 index 00000000..2b8ce736 --- /dev/null +++ b/src/protocols/LinuxDMABUF.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wayland.hpp" +#include "linux-dmabuf-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CDMABuffer; +struct SDRMFormat; +struct SDMABUFAttrs; +class CWLSurfaceResource; + +class CLinuxDMABuffer { + public: + CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + ~CLinuxDMABuffer(); + + bool good(); + + private: + SP buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; + + friend class CLinuxDMABBUFParamsResource; +}; + +#pragma pack(push, 1) +struct SDMABUFFeedbackTableEntry { + uint32_t fmt = 0; + char pad[4]; + uint64_t modifier = 0; +}; +#pragma pack(pop) + +class SCompiledDMABUFTranche { + dev_t device = 0; + uint32_t flags = 0; + std::vector indices; +}; + +struct SDMABufTranche { + dev_t device = 0; + uint32_t flags = 0; + std::vector formats; +}; + +class CCompiledDMABUFFeedback { + public: + CCompiledDMABUFFeedback(dev_t device, std::vector tranches); + ~CCompiledDMABUFFeedback(); + + dev_t mainDevice = 0; + int tableFD = -1; + size_t tableLen = 0; + std::vector> tranches; +}; + +class CLinuxDMABBUFParamsResource { + public: + CLinuxDMABBUFParamsResource(SP resource_); + ~CLinuxDMABBUFParamsResource(); + + bool good(); + void create(uint32_t id); // 0 means not immed + + SP attrs; + WP createdBuffer; + bool used = false; + + private: + SP resource; + + bool verify(); + bool commence(); +}; + +class CLinuxDMABUFFeedbackResource { + public: + CLinuxDMABUFFeedbackResource(SP resource_, SP surface_); + ~CLinuxDMABUFFeedbackResource(); + + bool good(); + + SP surface; // optional, for surface feedbacks + + private: + SP resource; +}; + +class CLinuxDMABUFResource { + public: + CLinuxDMABUFResource(SP resource_); + + bool good(); + void sendMods(); + + private: + SP resource; +}; + +class CLinuxDMABufV1Protocol : public IWaylandProtocol { + public: + CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); + ~CLinuxDMABufV1Protocol(); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + private: + void destroyResource(CLinuxDMABUFResource* resource); + void destroyResource(CLinuxDMABUFFeedbackResource* resource); + void destroyResource(CLinuxDMABBUFParamsResource* resource); + void destroyResource(CLinuxDMABuffer* resource); + + // + std::vector> m_vManagers; + std::vector> m_vFeedbacks; + std::vector> m_vParams; + std::vector> m_vBuffers; + + UP defaultFeedback; + dev_t mainDevice; + int mainDeviceFD = -1; + + friend class CLinuxDMABUFResource; + friend class CLinuxDMABUFFeedbackResource; + friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABuffer; +}; + +namespace PROTO { + inline UP linuxDma; +}; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp new file mode 100644 index 00000000..0bcf4a9c --- /dev/null +++ b/src/protocols/MesaDRM.cpp @@ -0,0 +1,133 @@ +#include "MesaDRM.hpp" +#include +#include +#include "../Compositor.hpp" +#include +#include "types/WLBuffer.hpp" + +#define LOGM PROTO::mesaDRM->protoLog + +CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) { + LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); + for (int i = 0; i < attrs_.planes; ++i) { + LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); + } + + buffer = makeShared(id, client, attrs_); + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::mesaDRM->destroyResource(this); + }); + + if (!buffer->success) + LOGM(ERR, "Possibly compositor bug: buffer failed to create"); +} + +CMesaDRMBufferResource::~CMesaDRMBufferResource() { + if (buffer && buffer->resource) + buffer->resource->sendRelease(); + buffer.reset(); + listeners.bufferResourceDestroy.reset(); +} + +bool CMesaDRMBufferResource::good() { + return buffer && buffer->good(); +} + +CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); }); + + resource->setAuthenticate([this](CWlDrm* r, uint32_t token) { + // we don't need this + resource->sendAuthenticated(); + }); + + resource->setCreateBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, uint32_t) { r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); }); + + resource->setCreatePlanarBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) { + r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); + }); + + resource->setCreatePrimeBuffer( + [this](CWlDrm* r, uint32_t id, int32_t nameFd, int32_t w, int32_t h, uint32_t fmt, int32_t off0, int32_t str0, int32_t off1, int32_t str1, int32_t off2, int32_t str2) { + if (off0 < 0 || w <= 0 || h <= 0) { + r->error(WL_DRM_ERROR_INVALID_FORMAT, "Invalid w, h, or offset"); + return; + } + + SDMABUFAttrs attrs; + attrs.success = true; + attrs.size = {w, h}; + attrs.modifier = DRM_FORMAT_MOD_INVALID; + attrs.planes = 1; + attrs.offsets[0] = off0; + attrs.strides[0] = str0; + attrs.fds[0] = nameFd; + attrs.format = fmt; + + const auto RESOURCE = PROTO::mesaDRM->m_vBuffers.emplace_back(makeShared(id, resource->client(), attrs)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::mesaDRM->m_vBuffers.pop_back(); + return; + } + + // append instance so that buffer knows its owner + RESOURCE->buffer->resource->buffer = RESOURCE->buffer; + }); + + resource->sendDevice(PROTO::mesaDRM->nodeName.c_str()); + resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME); + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + for (auto& fmt : fmts) { + resource->sendFormat(fmt.format); + } +} + +bool CMesaDRMResource::good() { + return resource->resource(); +} + +CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + drmDevice* dev = nullptr; + int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + if (drmGetDevice2(drmFD, 0, &dev) != 0) { + LOGM(ERR, "Failed to get device"); + PROTO::mesaDRM.reset(); + return; + } + + if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { + nodeName = dev->nodes[DRM_NODE_RENDER]; + } else { + ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); + LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + nodeName = dev->nodes[DRM_NODE_PRIMARY]; + } + drmFreeDevice(&dev); +} + +void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CMesaDRMProtocol::destroyResource(CMesaDRMResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CMesaDRMProtocol::destroyResource(CMesaDRMBufferResource* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp new file mode 100644 index 00000000..ad31a182 --- /dev/null +++ b/src/protocols/MesaDRM.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "wayland-drm.hpp" +#include "types/Buffer.hpp" +#include "types/DMABuffer.hpp" + +class CMesaDRMBufferResource { + public: + CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + ~CMesaDRMBufferResource(); + + bool good(); + + private: + SP buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; + + friend class CMesaDRMResource; +}; + +class CMesaDRMResource { + public: + CMesaDRMResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CMesaDRMProtocol : public IWaylandProtocol { + public: + CMesaDRMProtocol(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); + + private: + void destroyResource(CMesaDRMResource* resource); + void destroyResource(CMesaDRMBufferResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vBuffers; + + std::string nodeName = ""; + + friend class CMesaDRMResource; + friend class CMesaDRMBufferResource; +}; + +namespace PROTO { + inline UP mesaDRM; +}; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index db241048..ef287cfa 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -1,5 +1,6 @@ #include "OutputPower.hpp" #include "../Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::outputPower->protoLog @@ -61,15 +62,15 @@ void COutputPowerProtocol::destroyOutputPower(COutputPower* power) { void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uint32_t id, wl_resource* output) { - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + const auto OUTPUT = CWLOutputResource::fromResource(output); - if (!PMONITOR) { + if (!OUTPUT) { pMgr->error(0, "Invalid output resource"); return; } const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), PMONITOR)).get(); + const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.get())).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 87abdcdd..c7b78a5b 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -3,10 +3,11 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../managers/SeatManager.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::constraints->protoLog -CPointerConstraint::CPointerConstraint(SP resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : +CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : resourceL(resource_), locked(true) { if (!resource_->resource()) return; @@ -14,13 +15,13 @@ CPointerConstraint::CPointerConstraint(SP resource_, wlr_su resource_->setOnDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); resource_->setDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); - pHLSurface = CWLSurface::surfaceFromWlr(surf); + pHLSurface = CWLSurface::fromResource(surf); if (!pHLSurface) return; if (region_) - region.set(wlr_region_from_resource(region_)); + region.set(CWLRegionResource::fromResource(region_)->region); resource_->setSetRegion([this](CZwpLockedPointerV1* p, wl_resource* region) { onSetRegion(region); }); resource_->setSetCursorPositionHint([this](CZwpLockedPointerV1* p, wl_fixed_t x, wl_fixed_t y) { @@ -45,7 +46,7 @@ CPointerConstraint::CPointerConstraint(SP resource_, wlr_su sharedConstructions(); } -CPointerConstraint::CPointerConstraint(SP resource_, wlr_surface* surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : +CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : resourceC(resource_), locked(false) { if (!resource_->resource()) return; @@ -53,13 +54,13 @@ CPointerConstraint::CPointerConstraint(SP resource_, wlr_ resource_->setOnDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); resource_->setDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); - pHLSurface = CWLSurface::surfaceFromWlr(surf); + pHLSurface = CWLSurface::fromResource(surf); if (!pHLSurface) return; if (region_) - region.set(wlr_region_from_resource(region_)); + region.set(CWLRegionResource::fromResource(region_)->region); resource_->setSetRegion([this](CZwpConfinedPointerV1* p, wl_resource* region) { onSetRegion(region); }); @@ -79,7 +80,7 @@ CPointerConstraint::~CPointerConstraint() { void CPointerConstraint::sharedConstructions() { if (pHLSurface) { listeners.destroySurface = pHLSurface->events.destroy.registerListener([this](std::any d) { - pHLSurface = nullptr; + pHLSurface.reset(); if (active) deactivate(); @@ -92,7 +93,7 @@ void CPointerConstraint::sharedConstructions() { cursorPosOnActivate = g_pInputManager->getMouseCoordsInternal(); - if (g_pCompositor->m_pLastFocus == pHLSurface->wlr()) + if (g_pCompositor->m_pLastFocus == pHLSurface->resource()) activate(); } @@ -126,10 +127,10 @@ void CPointerConstraint::activate() { return; // TODO: hack, probably not a super duper great idea - if (g_pSeatManager->state.pointerFocus != pHLSurface->wlr()) { + if (g_pSeatManager->state.pointerFocus != pHLSurface->resource()) { const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); const auto LOCAL = SURFBOX.has_value() ? logicPositionHint() - SURFBOX->pos() : Vector2D{}; - g_pSeatManager->setPointerFocus(pHLSurface->wlr(), LOCAL); + g_pSeatManager->setPointerFocus(pHLSurface->resource(), LOCAL); } if (locked) @@ -152,15 +153,15 @@ void CPointerConstraint::onSetRegion(wl_resource* wlRegion) { return; } - const auto REGION = wlr_region_from_resource(wlRegion); + const auto REGION = region.set(CWLRegionResource::fromResource(wlRegion)->region); region.set(REGION); positionHint = region.closestPoint(positionHint); g_pInputManager->simulateMouseMovement(); // to warp the cursor if anything's amiss } -CWLSurface* CPointerConstraint::owner() { - return pHLSurface; +SP CPointerConstraint::owner() { + return pHLSurface.lock(); } CRegion CPointerConstraint::logicConstraintRegion() { @@ -241,7 +242,7 @@ void CPointerConstraintsProtocol::onLockPointer(CZwpPointerConstraintsV1* pMgr, zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } @@ -250,7 +251,7 @@ void CPointerConstraintsProtocol::onConfinePointer(CZwpPointerConstraintsV1* pMg zwpPointerConstraintsV1Lifetime lifetime) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vConstraints.emplace_back( - makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surface), region, lifetime)); + makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), region, lifetime)); onNewConstraint(RESOURCE, pMgr); } diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 93e57c46..06bebb02 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -12,31 +12,32 @@ #include "../helpers/signal/Listener.hpp" class CWLSurface; +class CWLSurfaceResource; class CPointerConstraint { public: - CPointerConstraint(SP resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); - CPointerConstraint(SP resource_, wlr_surface* surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); + CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); + CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); ~CPointerConstraint(); - bool good(); + bool good(); - void deactivate(); - void activate(); - bool isActive(); + void deactivate(); + void activate(); + bool isActive(); - CWLSurface* owner(); + SP owner(); - CRegion logicConstraintRegion(); - bool isLocked(); - Vector2D logicPositionHint(); + CRegion logicConstraintRegion(); + bool isLocked(); + Vector2D logicPositionHint(); private: SP resourceL; SP resourceC; wl_client* pClient = nullptr; - CWLSurface* pHLSurface = nullptr; + WP pHLSurface; CRegion region; bool hintSet = false; diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 2bfd74da..86510779 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::pointerGestures->protoLog @@ -116,7 +117,7 @@ void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } @@ -162,7 +163,7 @@ void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } @@ -208,7 +209,7 @@ void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) { if (sw->resource->client() != FOCUSEDCLIENT) continue; - sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->resource, fingers); + sw->resource->sendBegin(SERIAL, timeMs, g_pSeatManager->state.pointerFocus->getResource()->resource(), fingers); } } diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index e21c8403..0275b53f 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -2,10 +2,11 @@ #include #include "../helpers/Monitor.hpp" #include "../managers/HookSystemManager.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::presentation->protoLog -CQueuedPresentationData::CQueuedPresentationData(wlr_surface* surf) : surface(surf) { +CQueuedPresentationData::CQueuedPresentationData(SP surf) : surface(surf) { ; } @@ -25,7 +26,7 @@ void CQueuedPresentationData::discarded() { wasPresented = false; } -CPresentationFeedback::CPresentationFeedback(SP resource_, wlr_surface* surf) : resource(resource_), surface(surf) { +CPresentationFeedback::CPresentationFeedback(SP resource_, SP surf) : resource(resource_), surface(surf) { if (!good()) return; @@ -69,7 +70,7 @@ void CPresentationFeedback::sendQueued(SP data, timespe CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - std::erase_if(m_vQueue, [PMONITOR, this](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); + std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); }); } @@ -92,7 +93,8 @@ void CPresentationProtocol::destroyResource(CPresentationFeedback* feedback) { void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* surf, uint32_t id) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vFeedbacks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); + m_vFeedbacks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) + .get(); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -116,8 +118,8 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint } } - std::erase_if(m_vFeedbacks, [pMonitor, this](const auto& other) { return !other->surface || other->done; }); - std::erase_if(m_vQueue, [pMonitor, this](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); + std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); + std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); } void CPresentationProtocol::queueData(SP data) { diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 2df1c781..2c6ce3e9 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -7,10 +7,11 @@ #include "presentation-time.hpp" class CMonitor; +class CWLSurfaceResource; class CQueuedPresentationData { public: - CQueuedPresentationData(wlr_surface* surf); + CQueuedPresentationData(SP surf); void setPresentationType(bool zeroCopy); void attachMonitor(CMonitor* pMonitor); @@ -19,10 +20,10 @@ class CQueuedPresentationData { void discarded(); private: - bool wasPresented = false; - bool zeroCopy = false; - CMonitor* pMonitor = nullptr; - wlr_surface* surface = nullptr; // READ-ONLY + bool wasPresented = false; + bool zeroCopy = false; + CMonitor* pMonitor = nullptr; + WP surface; DYNLISTENER(destroySurface); @@ -32,7 +33,7 @@ class CQueuedPresentationData { class CPresentationFeedback { public: - CPresentationFeedback(SP resource_, wlr_surface* surf); + CPresentationFeedback(SP resource_, SP surf); bool good(); @@ -40,8 +41,8 @@ class CPresentationFeedback { private: SP resource; - wlr_surface* surface = nullptr; // READ-ONLY - bool done = false; + WP surface; + bool done = false; friend class CPresentationProtocol; }; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 622d9d68..0c4eac86 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -2,11 +2,13 @@ #include "../Compositor.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/PointerManager.hpp" +#include "core/Output.hpp" +#include "types/WLBuffer.hpp" +#include "types/Buffer.hpp" +#include "../helpers/Format.hpp" #include -#include "ToplevelExportWlrFuncs.hpp" - #define SCREENCOPY_VERSION 3 static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { @@ -202,8 +204,8 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->n_locks > 0) - wlr_buffer_unlock(frame->buffer); + if (frame->buffer && frame->buffer->locked()) + frame->buffer->unlock(); removeClient(frame->client, force); m_lFrames.remove(*frame); } @@ -214,7 +216,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r const auto PFRAME = &m_lFrames.emplace_back(); PFRAME->overlayCursor = !!overlay_cursor; PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame); - PFRAME->pMonitor = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + PFRAME->pMonitor = CWLOutputResource::fromResource(output)->monitor.get(); if (!PFRAME->pMonitor) { Debug::log(ERR, "client requested sharing of a monitor that doesnt exist"); @@ -256,7 +258,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r return; } - const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); if (!PSHMINFO) { Debug::log(ERR, "No pixel format supported by renderer in capture output"); zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); @@ -279,9 +281,9 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round(); - PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w); + PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); - zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); if (wl_resource_get_version(resource) >= 3) { if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { @@ -307,7 +309,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - const auto PBUFFER = wlr_buffer_try_from_resource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer); if (!PBUFFER) { Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); @@ -315,7 +317,9 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) { + PBUFFER->buffer->lock(); + + if (PBUFFER->buffer->size != PFRAME->box.size()) { Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); removeFrame(PFRAME); @@ -329,28 +333,22 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - wlr_dmabuf_attributes dmabufAttrs; - void* wlrBufferAccessData; - uint32_t wlrBufferAccessFormat; - size_t wlrBufferAccessStride; - if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) { - PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF; + if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { + PFRAME->bufferDMA = true; - if (dmabufAttrs.format != PFRAME->dmabufFormat) { + if (attrs.format != PFRAME->dmabufFormat) { Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; } - } else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) { - wlr_buffer_end_data_ptr_access(PBUFFER); - - if (wlrBufferAccessFormat != PFRAME->shmFormat) { + } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { + if (attrs.format != PFRAME->shmFormat) { Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; - } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) { + } else if ((int)attrs.stride != PFRAME->shmStride) { Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME); wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); removeFrame(PFRAME); @@ -363,7 +361,7 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou return; } - PFRAME->buffer = PBUFFER; + PFRAME->buffer = PBUFFER->buffer; m_vFramesAwaitingWrite.emplace_back(PFRAME); @@ -432,7 +430,7 @@ void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) { clock_gettime(CLOCK_MONOTONIC, &now); uint32_t flags = 0; - if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { + if (frame->bufferDMA) { if (!copyFrameDmabuf(frame)) { Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame); zwlr_screencopy_frame_v1_send_failed(frame->resource); @@ -471,7 +469,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { // std::clamp(RECT.x2 - RECT.x1, 0, frame->buffer->width - RECT.x1), std::clamp(RECT.y2 - RECT.y1, 0, frame->buffer->height - RECT.y1)); // } - zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->width, frame->buffer->height); + zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->size.x, frame->buffer->size.y); } bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { @@ -479,13 +477,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* if (!sourceTex) return false; - void* data; - uint32_t format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) { - wlr_texture_destroy(sourceTex); - return false; - } + auto TEXTURE = makeShared(sourceTex); + + auto shm = frame->buffer->shm(); + auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; @@ -496,14 +491,13 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { wlr_texture_destroy(sourceTex); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y}); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); @@ -513,14 +507,15 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb); #endif - const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); + const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { g_pHyprRenderer->endRender(); wlr_texture_destroy(sourceTex); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } + auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; + g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); @@ -530,21 +525,20 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* glPixelStorei(GL_PACK_ALIGNMENT, 1); - const wlr_pixel_format_info* drmFmtWlr = drm_get_pixel_format_info(format); - uint32_t packStride = pixel_format_info_min_stride(drmFmtWlr, frame->box.w); + const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format); + uint32_t packStride = FormatUtils::minStride(drmFmt, frame->box.w); - if (packStride == stride) { - glReadPixels(0, 0, frame->box.w, frame->box.h, PFORMAT->glFormat, PFORMAT->glType, data); + if (packStride == (uint32_t)shm.stride) { + glReadPixels(0, 0, frame->box.w, frame->box.h, glFormat, PFORMAT->glType, pixelData); } else { for (size_t i = 0; i < frame->box.h; ++i) { uint32_t y = i; - glReadPixels(0, y, frame->box.w, 1, PFORMAT->glFormat, PFORMAT->glType, ((unsigned char*)data) + i * stride); + glReadPixels(0, y, frame->box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride); } } g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - wlr_buffer_end_data_ptr_access(frame->buffer); wlr_texture_destroy(sourceTex); return true; @@ -555,9 +549,11 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { if (!sourceTex) return false; + auto TEXTURE = makeShared(sourceTex); + CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer, nullptr, true)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) return false; CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} @@ -565,7 +561,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { .transform(wlr_output_transform_invert(frame->pMonitor->output->transform), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(sourceTex, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index 1bdf6963..be434285 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -10,6 +10,7 @@ #include "../managers/eventLoop/EventLoopTimer.hpp" class CMonitor; +class IWLBuffer; enum eClientOwners { CLIENT_SCREENCOPY = 0, @@ -53,9 +54,9 @@ struct SScreencopyFrame { bool withDamage = false; bool lockedSWCursors = false; - wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM; + bool bufferDMA = false; - wlr_buffer* buffer = nullptr; + WP buffer; CMonitor* pMonitor = nullptr; PHLWINDOWREF pWindow; diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index d47467b3..42da52a9 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -1,8 +1,9 @@ #include "ServerDecorationKDE.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::serverDecorationKDE->protoLog -CServerDecorationKDE::CServerDecorationKDE(SP resource_, wlr_surface* surf) : resource(resource_) { +CServerDecorationKDE::CServerDecorationKDE(SP resource_, SP surf) : resource(resource_) { if (!good()) return; @@ -42,7 +43,8 @@ void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperl void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vDecos.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), wlr_surface_from_resource(surf))).get(); + m_vDecos.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) + .get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/ServerDecorationKDE.hpp b/src/protocols/ServerDecorationKDE.hpp index ec7a852f..ab082b17 100644 --- a/src/protocols/ServerDecorationKDE.hpp +++ b/src/protocols/ServerDecorationKDE.hpp @@ -6,9 +6,11 @@ #include "WaylandProtocol.hpp" #include "kde-server-decoration.hpp" +class CWLSurfaceResource; + class CServerDecorationKDE { public: - CServerDecorationKDE(SP resource_, wlr_surface* surf); + CServerDecorationKDE(SP resource_, SP surf); bool good(); diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index fd803eda..ae45b0f1 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -2,10 +2,12 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "FractionalScale.hpp" +#include "core/Compositor.hpp" +#include "core/Output.hpp" #define LOGM PROTO::sessionLock->protoLog -CSessionLockSurface::CSessionLockSurface(SP resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP owner_) : +CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { if (!resource->resource()) return; @@ -21,45 +23,38 @@ CSessionLockSurface::CSessionLockSurface(SP resource_, resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; }); - hyprListener_surfaceCommit.initCallback( - &pSurface->events.commit, - [this](void* owner, void* data) { - if (pSurface->pending.buffer_width <= 0 || pSurface->pending.buffer_height <= 0) { - LOGM(ERR, "SessionLock attached a null buffer"); - resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); - return; - } + listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) { + if (!pSurface->current.buffer) { + LOGM(ERR, "SessionLock attached a null buffer"); + resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); + return; + } - if (!ackdConfigure) { - LOGM(ERR, "SessionLock committed without an ack"); - resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack"); - return; - } + if (!ackdConfigure) { + LOGM(ERR, "SessionLock committed without an ack"); + resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack"); + return; + } - if (committed) - events.commit.emit(); - else { - wlr_surface_map(pSurface); - events.map.emit(); - } - committed = true; - }, - this, "SessionLockSurface"); + if (committed) + events.commit.emit(); + else { + pSurface->map(); + events.map.emit(); + } + committed = true; + }); - hyprListener_surfaceDestroy.initCallback( - &pSurface->events.destroy, - [this](void* owner, void* data) { - LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???"); - wlr_surface_unmap(pSurface); - hyprListener_surfaceCommit.removeCallback(); - hyprListener_surfaceDestroy.removeCallback(); + listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { + LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???"); + pSurface->unmap(); + listeners.surfaceCommit.reset(); + listeners.surfaceDestroy.reset(); + if (g_pCompositor->m_pLastFocus == pSurface) + g_pCompositor->m_pLastFocus.reset(); - if (g_pCompositor->m_pLastFocus == pSurface) - g_pCompositor->m_pLastFocus = nullptr; - - pSurface = nullptr; - }, - this, "SessionLockSurface"); + pSurface.reset(); + }); PROTO::fractional->sendScale(surface_, pMonitor_->scale); @@ -70,9 +65,9 @@ CSessionLockSurface::CSessionLockSurface(SP resource_, CSessionLockSurface::~CSessionLockSurface() { if (pSurface && pSurface->mapped) - wlr_surface_unmap(pSurface); - hyprListener_surfaceCommit.removeCallback(); - hyprListener_surfaceDestroy.removeCallback(); + pSurface->unmap(); + listeners.surfaceCommit.reset(); + listeners.surfaceDestroy.reset(); events.destroy.emit(); // just in case. } @@ -93,8 +88,8 @@ CMonitor* CSessionLockSurface::monitor() { return pMonitor; } -wlr_surface* CSessionLockSurface::surface() { - return pSurface; +SP CSessionLockSurface::surface() { + return pSurface.lock(); } CSessionLock::CSessionLock(SP resource_) : resource(resource_) { @@ -195,8 +190,8 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id, wl_resource* surface, wl_resource* output) { LOGM(LOG, "New sessionLockSurface with id {}", id); - auto PSURFACE = wlr_surface_from_resource(surface); - auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + auto PSURFACE = CWLSurfaceResource::fromResource(surface); + auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get(); SP sessionLock; for (auto& l : m_vLocks) { diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp index 6b0c4e08..a0c67e88 100644 --- a/src/protocols/SessionLock.hpp +++ b/src/protocols/SessionLock.hpp @@ -9,16 +9,17 @@ class CMonitor; class CSessionLock; +class CWLSurfaceResource; class CSessionLockSurface { public: - CSessionLockSurface(SP resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP owner_); + CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_); ~CSessionLockSurface(); - bool good(); - bool inert(); - CMonitor* monitor(); - wlr_surface* surface(); + bool good(); + bool inert(); + CMonitor* monitor(); + SP surface(); struct { CSignal map; @@ -29,7 +30,7 @@ class CSessionLockSurface { private: SP resource; WP sessionLock; - wlr_surface* pSurface = nullptr; + WP pSurface; CMonitor* pMonitor = nullptr; bool ackdConfigure = false; @@ -37,11 +38,10 @@ class CSessionLockSurface { void sendConfigure(); - DYNLISTENER(surfaceCommit); - DYNLISTENER(surfaceDestroy); - struct { CHyprSignalListener monitorMode; + CHyprSignalListener surfaceCommit; + CHyprSignalListener surfaceDestroy; } listeners; }; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index af9724b5..211a7a01 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -1,10 +1,11 @@ #include "ShortcutsInhibit.hpp" #include #include "../Compositor.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::shortcutsInhibit->protoLog -CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, wlr_surface* surf) : resource(resource_), pSurface(surf) { +CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, SP surf) : resource(resource_), pSurface(surf) { if (!resource->resource()) return; @@ -16,8 +17,8 @@ CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SPsendActive(); } -wlr_surface* CKeyboardShortcutsInhibitor::surface() { - return pSurface; +SP CKeyboardShortcutsInhibitor::surface() { + return pSurface.lock(); } bool CKeyboardShortcutsInhibitor::good() { @@ -46,8 +47,8 @@ void CKeyboardShortcutsInhibitProtocol::destroyInhibitor(CKeyboardShortcutsInhib } void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitManagerV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* seat) { - wlr_surface* surf = wlr_surface_from_resource(surface); - const auto CLIENT = pMgr->client(); + SP surf = CWLSurfaceResource::fromResource(surface); + const auto CLIENT = pMgr->client(); for (auto& in : m_vInhibitors) { if (in->surface() != surf) diff --git a/src/protocols/ShortcutsInhibit.hpp b/src/protocols/ShortcutsInhibit.hpp index 4e06938f..ba1c134c 100644 --- a/src/protocols/ShortcutsInhibit.hpp +++ b/src/protocols/ShortcutsInhibit.hpp @@ -6,17 +6,19 @@ #include "WaylandProtocol.hpp" #include "keyboard-shortcuts-inhibit-unstable-v1.hpp" +class CWLSurfaceResource; + class CKeyboardShortcutsInhibitor { public: - CKeyboardShortcutsInhibitor(SP resource_, wlr_surface* surf); + CKeyboardShortcutsInhibitor(SP resource_, SP surf); // read-only pointer, may be invalid - wlr_surface* surface(); - bool good(); + SP surface(); + bool good(); private: SP resource; - wlr_surface* pSurface = nullptr; + WP pSurface; }; class CKeyboardShortcutsInhibitProtocol : public IWaylandProtocol { diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 54c55176..393dfd38 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #include #define LOGM PROTO::tablet->protoLog @@ -160,11 +161,11 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP< resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); resource->setOnDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); - resource->setSetCursor([this](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { + resource->setSetCursor([](CZwpTabletToolV2* r, uint32_t serial, wl_resource* surf, int32_t hot_x, int32_t hot_y) { if (!g_pSeatManager->state.pointerFocusResource || g_pSeatManager->state.pointerFocusResource->client() != r->client()) return; - g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? wlr_surface_from_resource(surf) : nullptr, {hot_x, hot_y}}); + g_pInputManager->processMouseRequest(CSeatManager::SSetCursorEvent{surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hot_x, hot_y}}); }); } @@ -448,7 +449,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { if (t->current) { t->resource->sendProximityOut(); t->sendFrame(); - t->lastSurf = nullptr; + t->lastSurf.reset(); } t->resource->sendRemoved(); @@ -545,9 +546,9 @@ void CTabletV2Protocol::down(SP tool) { } } -void CTabletV2Protocol::proximityIn(SP tool, SP tablet, wlr_surface* surf) { +void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP surf) { proximityOut(tool); - const auto CLIENT = wl_resource_get_client(surf->resource); + const auto CLIENT = surf->client(); SP toolResource; SP tabletResource; @@ -587,7 +588,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, wl toolResource->lastSurf = surf; auto serial = g_pSeatManager->nextSerial(g_pSeatManager->seatResourceForClient(toolResource->resource->client())); - toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->resource); + toolResource->resource->sendProximityIn(serial, tabletResource->resource.get(), surf->getResource()->resource()); toolResource->queueFrame(); LOGM(ERR, "proximityIn: found no resource to send enter"); @@ -598,8 +599,8 @@ void CTabletV2Protocol::proximityOut(SP tool) { if (t->tool != tool || !t->current) continue; - t->current = false; - t->lastSurf = nullptr; + t->current = false; + t->lastSurf.reset(); t->resource->sendProximityOut(); t->sendFrame(); } diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 74a45c63..c61395c9 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -12,6 +12,7 @@ class CTabletTool; class CTabletPad; class CEventLoopTimer; class CTabletSeat; +class CWLSurfaceResource; class CTabletPadStripV2Resource { public: @@ -112,19 +113,19 @@ class CTabletToolV2Resource { CTabletToolV2Resource(SP resource_, SP tool_, SP seat_); ~CTabletToolV2Resource(); - bool good(); - void sendData(); - void queueFrame(); - void sendFrame(bool removeSource = true); + bool good(); + void sendData(); + void queueFrame(); + void sendFrame(bool removeSource = true); - bool current = false; - wlr_surface* lastSurf = nullptr; // READ-ONLY + bool current = false; + WP lastSurf; - WP tool; - WP seat; - wl_event_source* frameSource = nullptr; + WP tool; + WP seat; + wl_event_source* frameSource = nullptr; - bool inert = false; // removed was sent + bool inert = false; // removed was sent private: SP resource; @@ -180,7 +181,7 @@ class CTabletV2Protocol : public IWaylandProtocol { void tilt(SP tool, const Vector2D& value); void up(SP tool); void down(SP tool); - void proximityIn(SP tool, SP tablet, wlr_surface* surf); + void proximityIn(SP tool, SP tablet, SP surf); void proximityOut(SP tool); void buttonTool(SP tool, uint32_t button, uint32_t state); void motion(SP tool, const Vector2D& value); diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index df3126fe..7f3c0a18 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -2,6 +2,7 @@ #include "../managers/ProtocolManager.hpp" #include "../desktop/Window.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = @@ -13,15 +14,16 @@ void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_ RESOURCE->setOnDestroy([this](CWpTearingControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpTearingControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetTearingControl( - [this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetController(pMgr->client(), pMgr, id, wlr_surface_from_resource(surface)); }); + RESOURCE->setGetTearingControl([this](CWpTearingControlManagerV1* pMgr, uint32_t id, wl_resource* surface) { + this->onGetController(pMgr->client(), pMgr, id, CWLSurfaceResource::fromResource(surface)); + }); } void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); } -void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf) { +void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP surf) { const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique(makeShared(client, pMgr->version(), id), surf)).get(); if (!CONTROLLER->good()) { @@ -44,14 +46,14 @@ void CTearingControlProtocol::onWindowDestroy(PHLWINDOW pWindow) { // -CTearingControl::CTearingControl(SP resource_, wlr_surface* surf_) : resource(resource_) { +CTearingControl::CTearingControl(SP resource_, SP surf_) : resource(resource_) { resource->setData(this); resource->setOnDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setSetPresentationHint([this](CWpTearingControlV1* res, wpTearingControlV1PresentationHint hint) { this->onHint(hint); }); for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_pWLSurface.wlr() == surf_) { + if (w->m_pWLSurface->resource() == surf_) { pWindow = w; break; } diff --git a/src/protocols/TearingControl.hpp b/src/protocols/TearingControl.hpp index 199397a3..d81a27cd 100644 --- a/src/protocols/TearingControl.hpp +++ b/src/protocols/TearingControl.hpp @@ -6,10 +6,11 @@ class CWindow; class CTearingControlProtocol; +class CWLSurfaceResource; class CTearingControl { public: - CTearingControl(SP resource_, wlr_surface* surf_); + CTearingControl(SP resource_, SP surf_); void onHint(wpTearingControlV1PresentationHint hint_); @@ -42,7 +43,7 @@ class CTearingControlProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void onControllerDestroy(CTearingControl* control); - void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, wlr_surface* surf); + void onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP surf); void onWindowDestroy(PHLWINDOW pWindow); // diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 8fff4db5..7c16ef8c 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -1,6 +1,7 @@ #include "TextInputV1.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" #define TEXT_INPUT_VERSION 1 @@ -168,7 +169,7 @@ void CTextInputV1ProtocolManager::handleActivate(wl_client* client, wl_resource* return; } PTI->active = true; - PTI->pTextInput->onEnabled(wlr_surface_from_resource(surface)); + PTI->pTextInput->onEnabled(CWLSurfaceResource::fromResource(surface)); } void CTextInputV1ProtocolManager::handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) { diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index b463c6d6..1302a57f 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -1,5 +1,6 @@ #include "TextInputV3.hpp" #include +#include "core/Compositor.hpp" #define LOGM PROTO::textInputV3->protoLog @@ -66,12 +67,12 @@ CTextInputV3::~CTextInputV3() { events.destroy.emit(); } -void CTextInputV3::enter(wlr_surface* surf) { - resource->sendEnter(surf->resource); +void CTextInputV3::enter(SP surf) { + resource->sendEnter(surf->getResource()->resource()); } -void CTextInputV3::leave(wlr_surface* surf) { - resource->sendLeave(surf->resource); +void CTextInputV3::leave(SP surf) { + resource->sendLeave(surf->getResource()->resource()); } void CTextInputV3::preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd) { diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index 6d4f3d54..3959e72b 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -9,13 +9,15 @@ #include "../helpers/signal/Signal.hpp" #include "../helpers/Box.hpp" +class CWLSurfaceResource; + class CTextInputV3 { public: CTextInputV3(SP resource_); ~CTextInputV3(); - void enter(wlr_surface* surf); - void leave(wlr_surface* surf); + void enter(SP surf); + void leave(SP surf); void preeditString(const std::string& text, int32_t cursorBegin, int32_t cursorEnd); void commitString(const std::string& text); void deleteSurroundingText(uint32_t beforeLength, uint32_t afterLength); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 14629214..80f9defa 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -2,11 +2,12 @@ #include "../Compositor.hpp" #include "ForeignToplevelWlr.hpp" #include "../managers/PointerManager.hpp" +#include "types/WLBuffer.hpp" +#include "types/Buffer.hpp" +#include "../helpers/Format.hpp" #include -#include "ToplevelExportWlrFuncs.hpp" - #define TOPLEVEL_EXPORT_VERSION 2 static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { @@ -131,8 +132,8 @@ void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool f std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->n_locks > 0) - wlr_buffer_unlock(frame->buffer); + if (frame->buffer && frame->buffer->locked() > 0) + frame->buffer->unlock(); removeClient(frame->client, force); m_lFrames.remove(*frame); } @@ -184,7 +185,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou return; } - const auto PSHMINFO = drm_get_pixel_format_info(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); if (!PSHMINFO) { Debug::log(ERR, "No pixel format supported by renderer in capture toplevel"); hyprland_toplevel_export_frame_v1_send_failed(resource); @@ -203,9 +204,9 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); PFRAME->box.transform(PMONITOR->transform, ow, oh).round(); - PFRAME->shmStride = pixel_format_info_min_stride(PSHMINFO, PFRAME->box.w); + PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); - hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, convert_drm_format_to_wl_shm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height); @@ -238,14 +239,16 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - const auto PBUFFER = wlr_buffer_try_from_resource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer); if (!PBUFFER) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); removeFrame(PFRAME); return; } - if (PBUFFER->width != PFRAME->box.width || PBUFFER->height != PFRAME->box.height) { + PBUFFER->buffer->lock(); + + if (PBUFFER->buffer->size != PFRAME->box.size()) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); removeFrame(PFRAME); return; @@ -257,26 +260,20 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - wlr_dmabuf_attributes dmabufAttrs; - void* wlrBufferAccessData; - uint32_t wlrBufferAccessFormat; - size_t wlrBufferAccessStride; - if (wlr_buffer_get_dmabuf(PBUFFER, &dmabufAttrs)) { - PFRAME->bufferCap = WLR_BUFFER_CAP_DMABUF; + if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { + PFRAME->bufferDMA = true; - if (dmabufAttrs.format != PFRAME->dmabufFormat) { + if (attrs.format != PFRAME->dmabufFormat) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; } - } else if (wlr_buffer_begin_data_ptr_access(PBUFFER, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &wlrBufferAccessData, &wlrBufferAccessFormat, &wlrBufferAccessStride)) { - wlr_buffer_end_data_ptr_access(PBUFFER); - - if (wlrBufferAccessFormat != PFRAME->shmFormat) { + } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { + if (attrs.format != PFRAME->shmFormat) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); removeFrame(PFRAME); return; - } else if ((int)wlrBufferAccessStride != PFRAME->shmStride) { + } else if ((int)attrs.stride != PFRAME->shmStride) { wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); removeFrame(PFRAME); return; @@ -287,7 +284,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r return; } - PFRAME->buffer = PBUFFER; + PFRAME->buffer = PBUFFER->buffer; m_vFramesAwaitingWrite.emplace_back(PFRAME); } @@ -338,7 +335,7 @@ void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { clock_gettime(CLOCK_MONOTONIC, &now); uint32_t flags = 0; - if (frame->bufferCap == WLR_BUFFER_CAP_DMABUF) { + if (frame->bufferDMA) { if (!copyFrameDmabuf(frame, &now)) { hyprland_toplevel_export_frame_v1_send_failed(frame->resource); return; @@ -363,11 +360,8 @@ void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) { } bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - void* data; - uint32_t format; - size_t stride; - if (!wlr_buffer_begin_data_ptr_access(frame->buffer, WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data, &format, &stride)) - return false; + auto shm = frame->buffer->shm(); + auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm // render the client const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); @@ -383,10 +377,8 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pPointerManager->damageCursor(PMONITOR->self.lock()); } - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) { - wlr_buffer_end_data_ptr_access(frame->buffer); + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) return false; - } g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); @@ -398,10 +390,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times if (frame->overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); - const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format); + const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { g_pHyprRenderer->endRender(); - wlr_buffer_end_data_ptr_access(frame->buffer); return false; } @@ -418,9 +409,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, data); - - wlr_buffer_end_data_ptr_access(frame->buffer); + glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, pixelData); if (frame->overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); @@ -435,7 +424,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer)) + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock())) return false; g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); diff --git a/src/protocols/ToplevelExportWlrFuncs.hpp b/src/protocols/ToplevelExportWlrFuncs.hpp deleted file mode 100644 index b6f387e8..00000000 --- a/src/protocols/ToplevelExportWlrFuncs.hpp +++ /dev/null @@ -1,243 +0,0 @@ -#include - -#ifndef DRM_WLR_FUNCS -#define DRM_WLR_FUNCS - -struct wlr_pixel_format_info { - uint32_t drm_format; - - /* Equivalent of the format if it has an alpha channel, - * DRM_FORMAT_INVALID (0) if NA - */ - uint32_t opaque_substitute; - - /* Bytes per block (including padding) */ - uint32_t bytes_per_block; - /* Size of a block in pixels (zero for 1×1) */ - uint32_t block_width, block_height; - - /* True if the format has an alpha channel */ - bool has_alpha; -}; - -static const struct wlr_pixel_format_info pixel_format_info[] = { - { - .drm_format = DRM_FORMAT_XRGB8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ARGB8888, - .opaque_substitute = DRM_FORMAT_XRGB8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ABGR8888, - .opaque_substitute = DRM_FORMAT_XBGR8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGBX8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_RGBA8888, - .opaque_substitute = DRM_FORMAT_RGBX8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX8888, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_BGRA8888, - .opaque_substitute = DRM_FORMAT_BGRX8888, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_R8, - .bytes_per_block = 1, - }, - { - .drm_format = DRM_FORMAT_GR88, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGB888, - .bytes_per_block = 3, - }, - { - .drm_format = DRM_FORMAT_BGR888, - .bytes_per_block = 3, - }, - { - .drm_format = DRM_FORMAT_RGBX4444, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGBA4444, - .opaque_substitute = DRM_FORMAT_RGBX4444, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX4444, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGRA4444, - .opaque_substitute = DRM_FORMAT_BGRX4444, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGBX5551, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_RGBA5551, - .opaque_substitute = DRM_FORMAT_RGBX5551, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_BGRX5551, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGRA5551, - .opaque_substitute = DRM_FORMAT_BGRX5551, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XRGB1555, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_ARGB1555, - .opaque_substitute = DRM_FORMAT_XRGB1555, - .bytes_per_block = 2, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_RGB565, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_BGR565, - .bytes_per_block = 2, - }, - { - .drm_format = DRM_FORMAT_XRGB2101010, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ARGB2101010, - .opaque_substitute = DRM_FORMAT_XRGB2101010, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR2101010, - .bytes_per_block = 4, - }, - { - .drm_format = DRM_FORMAT_ABGR2101010, - .opaque_substitute = DRM_FORMAT_XBGR2101010, - .bytes_per_block = 4, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR16161616F, - .bytes_per_block = 8, - }, - { - .drm_format = DRM_FORMAT_ABGR16161616F, - .opaque_substitute = DRM_FORMAT_XBGR16161616F, - .bytes_per_block = 8, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_XBGR16161616, - .bytes_per_block = 8, - }, - { - .drm_format = DRM_FORMAT_ABGR16161616, - .opaque_substitute = DRM_FORMAT_XBGR16161616, - .bytes_per_block = 8, - .has_alpha = true, - }, - { - .drm_format = DRM_FORMAT_YVYU, - .bytes_per_block = 4, - .block_width = 2, - .block_height = 1, - }, - { - .drm_format = DRM_FORMAT_VYUY, - .bytes_per_block = 4, - .block_width = 2, - .block_height = 1, - }, -}; - -static const size_t pixel_format_info_size = sizeof(pixel_format_info) / sizeof(pixel_format_info[0]); - -static const struct wlr_pixel_format_info* drm_get_pixel_format_info(uint32_t fmt) { - for (size_t i = 0; i < pixel_format_info_size; ++i) { - if (pixel_format_info[i].drm_format == fmt) { - return &pixel_format_info[i]; - } - } - - return NULL; -} - -/*static uint32_t convert_wl_shm_format_to_drm(enum wl_shm_format fmt) { - switch (fmt) { - case WL_SHM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; - case WL_SHM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; - default: return (uint32_t)fmt; - } -}*/ - -static enum wl_shm_format convert_drm_format_to_wl_shm(uint32_t fmt) { - switch (fmt) { - case DRM_FORMAT_XRGB8888: return WL_SHM_FORMAT_XRGB8888; - case DRM_FORMAT_ARGB8888: return WL_SHM_FORMAT_ARGB8888; - default: return (enum wl_shm_format)fmt; - } -} - -static uint32_t pixel_format_info_pixels_per_block(const struct wlr_pixel_format_info* info) { - uint32_t pixels = info->block_width * info->block_height; - return pixels > 0 ? pixels : 1; -} - -static int32_t div_round_up(int32_t dividend, int32_t divisor) { - int32_t quotient = dividend / divisor; - if (dividend % divisor != 0) { - quotient++; - } - return quotient; -} - -static int32_t pixel_format_info_min_stride(const wlr_pixel_format_info* fmt, int32_t width) { - int32_t pixels_per_block = (int32_t)pixel_format_info_pixels_per_block(fmt); - int32_t bytes_per_block = (int32_t)fmt->bytes_per_block; - if (width > INT32_MAX / bytes_per_block) { - wlr_log(WLR_DEBUG, "Invalid width %d (overflow)", width); - return 0; - } - return div_round_up(width * bytes_per_block, pixels_per_block); -} - -#endif \ No newline at end of file diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp new file mode 100644 index 00000000..8cb69dbe --- /dev/null +++ b/src/protocols/Viewporter.cpp @@ -0,0 +1,126 @@ +#include "Viewporter.hpp" +#include "core/Compositor.hpp" +#include + +#define LOGM PROTO::viewport->protoLog + +CViewportResource::CViewportResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); + resource->setOnDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); + + resource->setSetDestination([this](CWpViewport* r, int32_t x, int32_t y) { + if (!surface) { + r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + if (x == -1 && y == -1) { + surface->pending.viewport.hasDestination = false; + return; + } + + if (x <= 0 || y <= 0) { + r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Size was <= 0"); + return; + } + + surface->pending.viewport.hasDestination = true; + surface->pending.viewport.destination = {x, y}; + }); + + resource->setSetSource([this](CWpViewport* r, wl_fixed_t fx, wl_fixed_t fy, wl_fixed_t fw, wl_fixed_t fh) { + if (!surface) { + r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + double x = wl_fixed_to_double(fx), y = wl_fixed_to_double(fy), w = wl_fixed_to_double(fw), h = wl_fixed_to_double(fh); + + if (x == -1 && y == -1 && w == -1 && h == -1) { + surface->pending.viewport.hasSource = false; + return; + } + + if (x < 0 || y < 0) { + r->error(WP_VIEWPORT_ERROR_BAD_SIZE, "Pos was < 0"); + return; + } + + surface->pending.viewport.hasSource = true; + surface->pending.viewport.source = {x, y, w, h}; + }); +} + +CViewportResource::~CViewportResource() { + if (!surface) + return; + + surface->pending.viewport.hasDestination = false; + surface->pending.viewport.hasSource = false; +} + +bool CViewportResource::good() { + return resource->resource(); +} + +void CViewportResource::verify() { + if (!surface) + return; + + if (surface->pending.viewport.hasSource) { + auto& src = surface->pending.viewport.source; + + if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) { + resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); + return; + } + } +} + +CViewporterResource::CViewporterResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); }); + resource->setOnDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); }); + + resource->setGetViewport([](CWpViewporter* r, uint32_t id, wl_resource* surf) { + const auto RESOURCE = PROTO::viewport->m_vViewports.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::viewport->m_vViewports.pop_back(); + return; + } + }); +} + +bool CViewporterResource::good() { + return resource->resource(); +} + +CViewporterProtocol::CViewporterProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CViewporterProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CViewporterProtocol::destroyResource(CViewporterResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CViewporterProtocol::destroyResource(CViewportResource* resource) { + std::erase_if(m_vViewports, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp new file mode 100644 index 00000000..01278203 --- /dev/null +++ b/src/protocols/Viewporter.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "viewporter.hpp" +#include "../helpers/signal/Signal.hpp" + +class CWLSurfaceResource; + +class CViewportResource { + public: + CViewportResource(SP resource_, SP surface_); + ~CViewportResource(); + + bool good(); + void verify(); + WP surface; + + private: + SP resource; +}; + +class CViewporterResource { + public: + CViewporterResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CViewporterProtocol : public IWaylandProtocol { + public: + CViewporterProtocol(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); + + private: + void destroyResource(CViewporterResource* resource); + void destroyResource(CViewportResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vViewports; + + friend class CViewporterResource; + friend class CViewportResource; +}; + +namespace PROTO { + inline UP viewport; +}; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 30120235..23a6721c 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -10,6 +10,8 @@ static void displayDestroyInternal(struct wl_listener* listener, void* data) { } void IWaylandProtocol::onDisplayDestroy() { + wl_list_remove(&m_liDisplayDestroy.link); + wl_list_init(&m_liDisplayDestroy.link); wl_global_destroy(m_pGlobal); } @@ -30,3 +32,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co IWaylandProtocol::~IWaylandProtocol() { onDisplayDestroy(); } + +void IWaylandProtocol::removeGlobal() { + wl_global_remove(m_pGlobal); +} diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index a7487c15..b443e253 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -14,9 +14,10 @@ class IWaylandProtocol { public: IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name); - ~IWaylandProtocol(); + virtual ~IWaylandProtocol(); virtual void onDisplayDestroy(); + virtual void removeGlobal(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 1d9814ac..40f33f02 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -1,6 +1,7 @@ #include "XDGActivation.hpp" #include "../managers/TokenManager.hpp" #include "../Compositor.hpp" +#include "core/Compositor.hpp" #include #define LOGM PROTO::activation->protoLog @@ -79,8 +80,8 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t // remove token. It's been now spent. m_vSentTokens.erase(TOKEN); - wlr_surface* surf = wlr_surface_from_resource(surface); - const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); + SP surf = CWLSurfaceResource::fromResource(surface); + const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); if (!PWINDOW) { LOGM(WARN, "activate event for non-window or gone surface with token {}, ignoring", token); diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 771f5f78..03e58956 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../xwayland/XWayland.hpp" +#include "core/Output.hpp" #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 @@ -48,9 +49,9 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver } void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { - const auto OUTPUT = wlr_output_from_resource(outputResource); + const auto OUTPUT = CWLOutputResource::fromResource(outputResource); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT); + const auto PMONITOR = OUTPUT->monitor.get(); const auto CLIENT = mgr->client(); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 80e3487d..97de49f6 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +#include "core/Compositor.hpp" #define LOGM PROTO::xdgShell->protoLog @@ -288,7 +289,8 @@ void CXDGToplevelResource::close() { resource->sendClose(); } -CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, wlr_surface* surface_) : owner(owner_), surface(surface_), resource(resource_) { +CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, SP surface_) : + owner(owner_), surface(surface_), resource(resource_) { if (!good()) return; @@ -307,56 +309,50 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPdestroyResource(this); }); - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - LOGM(WARN, "wl_surface destroyed before its xdg_surface role object"); - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); + listeners.surfaceDestroy = surface->events.destroy.registerListener([this](std::any d) { + LOGM(WARN, "wl_surface destroyed before its xdg_surface role object"); + listeners.surfaceDestroy.reset(); + listeners.surfaceCommit.reset(); - if (mapped) - events.unmap.emit(); + if (mapped) + events.unmap.emit(); - mapped = false; - surface = nullptr; - events.destroy.emit(); - }, - nullptr, "CXDGSurfaceResource"); + mapped = false; + surface.reset(); + events.destroy.emit(); + }); - hyprListener_surfaceCommit.initCallback( - &surface->events.commit, - [this](void* owner, void* data) { - current = pending; + listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + current = pending; + if (toplevel) + toplevel->current = toplevel->pending; + + if (initialCommit && surface->pending.buffer) { + resource->error(-1, "Buffer attached before initial commit"); + return; + } + + if (surface->current.buffer && !mapped) { + // this forces apps to not draw CSD. if (toplevel) - toplevel->current = toplevel->pending; + toplevel->setMaximized(true); - if (initialCommit && surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { - resource->error(-1, "Buffer attached before initial commit"); - return; - } + mapped = true; + surface->map(); + events.map.emit(); + return; + } - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { - // this forces apps to not draw CSD. - if (toplevel) - toplevel->setMaximized(true); + if (!surface->current.buffer && mapped) { + mapped = false; + surface->unmap(); + events.unmap.emit(); + return; + } - mapped = true; - wlr_surface_map(surface); - events.map.emit(); - return; - } - - if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { - mapped = false; - wlr_surface_unmap(surface); - events.unmap.emit(); - return; - } - - events.commit.emit(); - initialCommit = false; - }, - nullptr, "CXDGSurfaceResource"); + events.commit.emit(); + initialCommit = false; + }); resource->setGetToplevel([this](CXdgSurface* r, uint32_t id) { const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); @@ -649,7 +645,7 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) { const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back( - makeShared(makeShared(r->client(), r->version(), id), self.lock(), wlr_surface_from_resource(surf))); + makeShared(makeShared(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surf))); if (!RESOURCE->good()) { r->noMemory(); @@ -724,9 +720,9 @@ void CXDGShellProtocol::addOrStartGrab(SP popup) { grabOwner = popup; grabbed.clear(); grab->clear(); - grab->add(popup->surface->surface); + grab->add(popup->surface->surface.lock()); if (popup->parent) - grab->add(popup->parent->surface); + grab->add(popup->parent->surface.lock()); g_pSeatManager->setGrab(grab); grabbed.emplace_back(popup); return; @@ -734,10 +730,10 @@ void CXDGShellProtocol::addOrStartGrab(SP popup) { grabbed.emplace_back(popup); - grab->add(popup->surface->surface); + grab->add(popup->surface->surface.lock()); if (popup->parent) - grab->add(popup->parent->surface); + grab->add(popup->parent->surface.lock()); } void CXDGShellProtocol::onPopupDestroy(WP popup) { @@ -752,5 +748,5 @@ void CXDGShellProtocol::onPopupDestroy(WP popup) { std::erase(grabbed, popup); if (popup->surface) - grab->remove(popup->surface->surface); + grab->remove(popup->surface->surface.lock()); } diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 1dbeb209..fe2517a2 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -16,6 +16,7 @@ class CXDGSurfaceResource; class CXDGToplevelResource; class CXDGPopupResource; class CSeatGrab; +class CWLSurfaceResource; struct SXDGPositionerState { Vector2D requestedSize; @@ -138,7 +139,7 @@ class CXDGToplevelResource { class CXDGSurfaceResource { public: - CXDGSurfaceResource(SP resource_, SP owner_, wlr_surface* surface_); + CXDGSurfaceResource(SP resource_, SP owner_, SP surface_); ~CXDGSurfaceResource(); static SP fromResource(wl_resource*); @@ -146,7 +147,7 @@ class CXDGSurfaceResource { bool good(); WP owner; - wlr_surface* surface = nullptr; + WP surface; WP toplevel; WP popup; @@ -184,8 +185,10 @@ class CXDGSurfaceResource { // std::vector> popups; - DYNLISTENER(surfaceDestroy); - DYNLISTENER(surfaceCommit); + struct { + CHyprSignalListener surfaceDestroy; + CHyprSignalListener surfaceCommit; + } listeners; friend class CXDGPopupResource; friend class CXDGToplevelResource; diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp index 8b9905f8..6cc5256f 100644 --- a/src/protocols/XWaylandShell.cpp +++ b/src/protocols/XWaylandShell.cpp @@ -1,9 +1,10 @@ #include "XWaylandShell.hpp" +#include "core/Compositor.hpp" #include #define LOGM PROTO::xwaylandShell->protoLog -CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, wlr_surface* surface_) : surface(surface_), resource(resource_) { +CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; @@ -45,7 +46,7 @@ CXWaylandShellResource::CXWaylandShellResource(SP resource_) : resource->setGetXwaylandSurface([this](CXwaylandShellV1* r, uint32_t id, wl_resource* surface) { const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back( - makeShared(makeShared(r->client(), r->version(), id), wlr_surface_from_resource(surface))); + makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surface))); if (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/XWaylandShell.hpp b/src/protocols/XWaylandShell.hpp index 2c03d172..c8c0c04a 100644 --- a/src/protocols/XWaylandShell.hpp +++ b/src/protocols/XWaylandShell.hpp @@ -7,9 +7,11 @@ #include "xwayland-shell-v1.hpp" #include "../helpers/signal/Signal.hpp" +class CWLSurfaceResource; + class CXWaylandSurfaceResource { public: - CXWaylandSurfaceResource(SP resource_, wlr_surface* surface_); + CXWaylandSurfaceResource(SP resource_, SP surface_); ~CXWaylandSurfaceResource(); bool good(); @@ -19,8 +21,8 @@ class CXWaylandSurfaceResource { CSignal destroy; } events; - uint64_t serial = 0; - wlr_surface* surface = nullptr; + uint64_t serial = 0; + WP surface; WP self; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp new file mode 100644 index 00000000..e8503ae8 --- /dev/null +++ b/src/protocols/core/Compositor.cpp @@ -0,0 +1,467 @@ +#include "Compositor.hpp" +#include "Output.hpp" +#include "../types/WLBuffer.hpp" +#include +#include +#include "Subcompositor.hpp" +#include "../Viewporter.hpp" +#include "../../helpers/Monitor.hpp" + +#define LOGM PROTO::compositor->protoLog + +class CDefaultSurfaceRole : public ISurfaceRole { + public: + virtual eSurfaceRole role() { + return SURFACE_ROLE_UNASSIGNED; + } +}; + +SP defaultRole = makeShared(); + +CWLCallbackResource::CWLCallbackResource(SP resource_) : resource(resource_) { + ; +} + +bool CWLCallbackResource::good() { + return resource->resource(); +} + +void CWLCallbackResource::send(timespec* now) { + resource->sendDone(now->tv_sec * 1000 + now->tv_nsec / 1000000); +} + +CWLRegionResource::CWLRegionResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); }); + resource->setOnDestroy([this](CWlRegion* r) { PROTO::compositor->destroyResource(this); }); + + resource->setAdd([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.add(CBox{x, y, w, h}); }); + resource->setSubtract([this](CWlRegion* r, int32_t x, int32_t y, int32_t w, int32_t h) { region.subtract(CBox{x, y, w, h}); }); +} + +bool CWLRegionResource::good() { + return resource->resource(); +} + +SP CWLRegionResource::fromResource(wl_resource* res) { + auto data = (CWLRegionResource*)(((CWlRegion*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setData(this); + + role = defaultRole; + + resource->setDestroy([this](CWlSurface* r) { destroy(); }); + resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); + + resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) { + pending.offset = {x, y}; + + if (!buffer) { + pending.buffer.reset(); + pending.texture.reset(); + } else { + auto res = CWLBufferResource::fromResource(buffer); + pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr; + pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; + pending.texture = res && res->buffer ? res->buffer->texture : nullptr; + } + + Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; + Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{}; + + if (oldBufSize != newBufSize) + pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; + + bufferReleased = false; + }); + + resource->setCommit([this](CWlSurface* r) { + if (pending.buffer) + pending.bufferDamage.intersect(CBox{{}, pending.buffer->size}); + + if (!pending.buffer) + pending.size = {}; + else if (pending.viewport.hasDestination) + pending.size = pending.viewport.destination; + else if (pending.viewport.hasSource) + pending.size = pending.viewport.source.size(); + else { + Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size; + pending.size = tfs / pending.scale; + } + + if (viewportResource) + viewportResource->verify(); + + pending.damage.intersect(CBox{{}, pending.size}); + + CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + + current = pending; + pending.damage.clear(); + pending.bufferDamage.clear(); + + if (current.buffer && !bufferReleased) { + // without previous dolphin et al are weird vvv + //CRegion surfaceDamage = + // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); + current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + + // release the buffer, glTexImage2D is synchronous (as in, data is consumed after the call returns) + // so we can let the app know we're done. + // for dma buffers, this doesn't matter. + current.buffer->sendRelease(); + bufferReleased = true; + } + + // TODO: we should _accumulate_ and not replace above if sync + if (role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)role.get(); + if (subsurface->sync) + return; + + events.commit.emit(); + } else { + // send commit to all synced surfaces in this tree. + breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + if (!subsurface->sync) + return; + } + surf->events.commit.emit(); + }, + nullptr); + } + }); + + resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); + resource->setDamageBuffer([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.bufferDamage.add(CBox{x, y, w, h}); }); + + resource->setSetBufferScale([this](CWlSurface* r, int32_t scale) { pending.scale = scale; }); + resource->setSetBufferTransform([this](CWlSurface* r, uint32_t tr) { pending.transform = (wl_output_transform)tr; }); + + resource->setSetInputRegion([this](CWlSurface* r, wl_resource* region) { + if (!region) { + pending.input = CBox{{}, {INT32_MAX, INT32_MAX}}; + return; + } + + auto RG = CWLRegionResource::fromResource(region); + pending.input = RG->region; + }); + + resource->setSetOpaqueRegion([this](CWlSurface* r, wl_resource* region) { + if (!region) { + pending.opaque = CBox{{}, {}}; + return; + } + + auto RG = CWLRegionResource::fromResource(region); + pending.opaque = RG->region; + }); + + resource->setFrame([this](CWlSurface* r, uint32_t id) { callbacks.emplace_back(makeShared(makeShared(pClient, 1, id))); }); + + resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) { pending.offset = {x, y}; }); +} + +CWLSurfaceResource::~CWLSurfaceResource() { + events.destroy.emit(); +} + +void CWLSurfaceResource::destroy() { + if (mapped) + unmap(); + events.destroy.emit(); + PROTO::compositor->destroyResource(this); +} + +SP CWLSurfaceResource::fromResource(wl_resource* res) { + auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLSurfaceResource::good() { + return resource->resource(); +} + +wl_client* CWLSurfaceResource::client() { + return pClient; +} + +void CWLSurfaceResource::enter(SP monitor) { + if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) != enteredOutputs.end()) + return; + + if (!PROTO::outputs.contains(monitor->szName)) { + // can happen on unplug/replug + LOGM(ERR, "enter() called on a non-existent output global"); + return; + } + + auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); + + if (!output || !output->getResource() || !output->getResource()->resource()) { + LOGM(ERR, "Cannot enter surface {:x} to {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); + return; + } + + enteredOutputs.emplace_back(monitor); + + resource->sendEnter(output->getResource().get()); +} + +void CWLSurfaceResource::leave(SP monitor) { + if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end()) + return; + + auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); + + if (!output) { + LOGM(ERR, "Cannot leave surface {:x} from {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); + return; + } + + std::erase(enteredOutputs, monitor); + + resource->sendLeave(output->getResource().get()); +} + +void CWLSurfaceResource::sendPreferredTransform(wl_output_transform t) { + if (resource->version() < 6) + return; + resource->sendPreferredBufferTransform(t); +} + +void CWLSurfaceResource::sendPreferredScale(int32_t scale) { + if (resource->version() < 6) + return; + resource->sendPreferredBufferScale(scale); +} + +void CWLSurfaceResource::frame(timespec* now) { + if (callbacks.empty()) + return; + + for (auto& c : callbacks) { + c->send(now); + } + + callbacks.clear(); +} + +void CWLSurfaceResource::resetRole() { + role = defaultRole; +} + +void CWLSurfaceResource::bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data) { + for (auto& n : nodes) { + + Vector2D offset = {}; + if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)n->role.get(); + offset = subsurface->posRelativeToParent(); + } + + fn(n, offset, data); + } + + std::vector> nodes2; + + for (auto& n : nodes) { + std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); + for (auto& c : n->subsurfaces) { + nodes2.push_back(c->surface.lock()); + } + } + + if (!nodes2.empty()) + bfHelper(nodes2, fn, data); +} + +void CWLSurfaceResource::breadthfirst(std::function, const Vector2D&, void*)> fn, void* data) { + std::vector> surfs; + surfs.push_back(self.lock()); + bfHelper(surfs, fn, data); +} + +std::pair, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput) { + std::vector, Vector2D>> surfs; + breadthfirst([](SP surf, const Vector2D& offset, + void* data) { ((std::vector, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, + &surfs); + + for (auto& [surf, pos] : surfs | std::views::reverse) { + if (!allowsInput) { + const auto BOX = CBox{pos, surf->current.size}; + if (BOX.containsPoint(localCoords)) + return {surf, localCoords - pos}; + } else { + const auto REGION = surf->current.input.copy().intersect(CBox{{}, surf->current.size}).translate(pos); + if (REGION.containsPoint(localCoords)) + return {surf, localCoords - pos}; + } + } + + return {nullptr, {}}; +} + +uint32_t CWLSurfaceResource::id() { + return wl_resource_get_id(resource->resource()); +} + +void CWLSurfaceResource::map() { + if (mapped) + return; + + mapped = true; + + events.map.emit(); + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + frame(&now); + + current.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; + pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; +} + +void CWLSurfaceResource::unmap() { + if (!mapped) + return; + + mapped = false; + + events.unmap.emit(); +} + +void CWLSurfaceResource::error(int code, const std::string& str) { + resource->error(code, str); +} + +SP CWLSurfaceResource::getResource() { + return resource; +} + +CBox CWLSurfaceResource::extends() { + CRegion full = CBox{{}, current.size}; + breadthfirst( + [](SP surf, const Vector2D& offset, void* d) { + if (surf->role->role() != SURFACE_ROLE_SUBSURFACE) + return; + + ((CRegion*)d)->add(CBox{offset, surf->current.size}); + }, + &full); + return full.getExtents(); +} + +Vector2D CWLSurfaceResource::sourceSize() { + if (!current.buffer) + return {}; + + if (current.viewport.hasSource) + return current.viewport.source.size(); + + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + return trc / current.scale; +} + +CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { + if (!current.buffer) + return {}; + + CRegion surfaceDamage = current.damage; + if (current.viewport.hasDestination) { + Vector2D scale = sourceSize() / current.viewport.destination; + surfaceDamage.scale(scale); + } + + if (current.viewport.hasSource) + surfaceDamage.translate(current.viewport.source.pos()); + + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + + return surfaceDamage.scale(current.scale).transform(wlr_output_transform_invert(current.transform), trc.x, trc.y).add(current.bufferDamage); +} + +CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlCompositor* r) { PROTO::compositor->destroyResource(this); }); + + resource->setCreateSurface([](CWlCompositor* r, uint32_t id) { + const auto RESOURCE = PROTO::compositor->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::compositor->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New wl_surface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + + PROTO::compositor->events.newSurface.emit(RESOURCE); + }); + + resource->setCreateRegion([](CWlCompositor* r, uint32_t id) { + const auto RESOURCE = PROTO::compositor->m_vRegions.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::compositor->m_vRegions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New wl_region with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + }); +} + +bool CWLCompositorResource::good() { + return resource->resource(); +} + +CWLCompositorProtocol::CWLCompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLCompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLCompositorProtocol::destroyResource(CWLCompositorResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLCompositorProtocol::destroyResource(CWLSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLCompositorProtocol::destroyResource(CWLRegionResource* resource) { + std::erase_if(m_vRegions, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp new file mode 100644 index 00000000..f50144bf --- /dev/null +++ b/src/protocols/core/Compositor.hpp @@ -0,0 +1,175 @@ +#pragma once + +/* + Implementations for: + - wl_compositor + - wl_surface + - wl_region + - wl_callback +*/ + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../helpers/Region.hpp" +#include "../types/Buffer.hpp" +#include "../types/SurfaceRole.hpp" + +class CWLOutputResource; +class CMonitor; +class CWLSurface; +class CWLSurfaceResource; +class CWLSubsurfaceResource; +class CViewportResource; + +class CWLCallbackResource { + public: + CWLCallbackResource(SP resource_); + + bool good(); + void send(timespec* now); + + private: + SP resource; +}; + +class CWLRegionResource { + public: + CWLRegionResource(SP resource_); + static SP fromResource(wl_resource* res); + + bool good(); + + CRegion region; + WP self; + + private: + SP resource; +}; + +class CWLSurfaceResource { + public: + CWLSurfaceResource(SP resource_); + ~CWLSurfaceResource(); + + static SP fromResource(wl_resource* res); + + bool good(); + wl_client* client(); + void enter(SP monitor); + void leave(SP monitor); + void sendPreferredTransform(wl_output_transform t); + void sendPreferredScale(int32_t scale); + void frame(timespec* now); + uint32_t id(); + void map(); + void unmap(); + void error(int code, const std::string& str); + SP getResource(); + CBox extends(); + void resetRole(); + Vector2D sourceSize(); + + struct { + CSignal commit; + CSignal map; + CSignal unmap; + CSignal newSubsurface; + CSignal destroy; + } events; + + struct { + CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + int scale = 1; + SP buffer; + SP texture; + Vector2D offset; + Vector2D size; + struct { + bool hasDestination = false; + bool hasSource = false; + Vector2D destination; + CBox source; + } viewport; + + // + void reset() { + damage.clear(); + bufferDamage.clear(); + transform = WL_OUTPUT_TRANSFORM_NORMAL; + scale = 1; + offset = {}; + size = {}; + } + } current, pending; + + std::vector> callbacks; + WP self; + WP hlSurface; + std::vector> enteredOutputs; + bool mapped = false; + std::vector> subsurfaces; + WP role; + WP viewportResource; + + void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); + CRegion accumulateCurrentBufferDamage(); + + // returns a pair: found surface (null if not found) and surface local coords. + // localCoords param is relative to 0,0 of this surface + std::pair, Vector2D> at(const Vector2D& localCoords, bool allowsInput = false); + + private: + SP resource; + wl_client* pClient = nullptr; + + // tracks whether we should release the buffer + bool bufferReleased = false; + + void destroy(); + void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); +}; + +class CWLCompositorResource { + public: + CWLCompositorResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CWLCompositorProtocol : public IWaylandProtocol { + public: + CWLCompositorProtocol(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); + + struct { + CSignal newSurface; // SP + } events; + + private: + void destroyResource(CWLCompositorResource* resource); + void destroyResource(CWLSurfaceResource* resource); + void destroyResource(CWLRegionResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vSurfaces; + std::vector> m_vRegions; + + friend class CWLSurfaceResource; + friend class CWLCompositorResource; + friend class CWLRegionResource; + friend class CWLCallbackResource; +}; + +namespace PROTO { + inline UP compositor; +}; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 354259fe..ca044e93 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -4,6 +4,7 @@ #include "../../managers/PointerManager.hpp" #include "../../Compositor.hpp" #include "Seat.hpp" +#include "Compositor.hpp" #define LOGM PROTO::data->protoLog @@ -233,7 +234,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : reso source->dnd = true; - PROTO::data->initiateDrag(source, icon ? wlr_surface_from_resource(icon) : nullptr, wlr_surface_from_resource(origin)); + PROTO::data->initiateDrag(source, icon ? CWLSurfaceResource::fromResource(icon) : nullptr, CWLSurfaceResource::fromResource(origin)); }); } @@ -252,8 +253,8 @@ void CWLDataDeviceResource::sendDataOffer(SP offer) { resource->sendDataOfferRaw(nullptr); } -void CWLDataDeviceResource::sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP offer) { - resource->sendEnterRaw(serial, surf->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource()); +void CWLDataDeviceResource::sendEnter(uint32_t serial, SP surf, const Vector2D& local, SP offer) { + resource->sendEnterRaw(serial, surf->getResource()->resource(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y), offer->resource->resource()); } void CWLDataDeviceResource::sendLeave() { @@ -454,7 +455,7 @@ void CWLDataDeviceProtocol::onKeyboardFocus() { updateDrag(); } -void CWLDataDeviceProtocol::initiateDrag(WP currentSource, wlr_surface* dragSurface, wlr_surface* origin) { +void CWLDataDeviceProtocol::initiateDrag(WP currentSource, SP dragSurface, SP origin) { if (dnd.currentSource) { LOGM(WARN, "New drag started while old drag still active??"); @@ -472,22 +473,18 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.originSurface = origin; dnd.dndSurface = dragSurface; if (dragSurface) { - dnd.hyprListener_dndSurfaceDestroy.initCallback( - &dragSurface->events.destroy, [this](void* owner, void* data) { abortDrag(); }, nullptr, "CWLDataDeviceProtocol::drag"); - dnd.hyprListener_dndSurfaceCommit.initCallback( - &dragSurface->events.commit, - [this](void* owner, void* data) { - if (dnd.dndSurface->pending.buffer_width > 0 && dnd.dndSurface->pending.buffer_height > 0 && !dnd.dndSurface->mapped) { - wlr_surface_map(dnd.dndSurface); - return; - } + dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); }); + dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) { + if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) { + dnd.dndSurface->map(); + return; + } - if (dnd.dndSurface->pending.buffer_width <= 0 && dnd.dndSurface->pending.buffer_height <= 0 && dnd.dndSurface->mapped) { - wlr_surface_unmap(dnd.dndSurface); - return; - } - }, - nullptr, "CWLDataDeviceProtocol::drag"); + if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) { + dnd.dndSurface->unmap(); + return; + } + }); } dnd.mouseButton = g_pHookSystem->hookDynamic("mouseButton", [this](void* self, SCallbackInfo& info, std::any e) { @@ -506,7 +503,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.mouseMove = g_pHookSystem->hookDynamic("mouseMove", [this](void* self, SCallbackInfo& info, std::any e) { auto V = std::any_cast(e); if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); if (!surf) return; @@ -524,7 +521,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource dnd.touchMove = g_pHookSystem->hookDynamic("touchMove", [this](void* self, SCallbackInfo& info, std::any e) { auto E = std::any_cast(e); if (dnd.focusedDevice && g_pSeatManager->state.keyboardFocus) { - auto surf = CWLSurface::surfaceFromWlr(g_pSeatManager->state.keyboardFocus); + auto surf = CWLSurface::fromResource(g_pSeatManager->state.keyboardFocus.lock()); if (!surf) return; @@ -572,14 +569,14 @@ void CWLDataDeviceProtocol::updateDrag() { dnd.focusedDevice->sendDataOffer(OFFER); OFFER->sendData(); - dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus, - Vector2D{g_pSeatManager->state.keyboardFocus->current.width, g_pSeatManager->state.keyboardFocus->current.height} / 2.F, OFFER); + dnd.focusedDevice->sendEnter(wl_display_next_serial(g_pCompositor->m_sWLDisplay), g_pSeatManager->state.keyboardFocus.lock(), + g_pSeatManager->state.keyboardFocus->current.size / 2.F, OFFER); } void CWLDataDeviceProtocol::resetDndState() { - dnd.dndSurface = nullptr; - dnd.hyprListener_dndSurfaceDestroy.removeCallback(); - dnd.hyprListener_dndSurfaceCommit.removeCallback(); + dnd.dndSurface.reset(); + dnd.dndSurfaceCommit.reset(); + dnd.dndSurfaceDestroy.reset(); dnd.mouseButton.reset(); dnd.mouseMove.reset(); dnd.touchUp.reset(); @@ -638,20 +635,18 @@ void CWLDataDeviceProtocol::abortDrag() { } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { - if (!dnd.dndSurface || !wlr_surface_get_texture(dnd.dndSurface)) + if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture) return; const auto POS = g_pInputManager->getMouseCoordsInternal(); - CBox box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}} - .translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F) - .scale(pMonitor->scale); - g_pHyprOpenGL->renderTexture(wlr_surface_get_texture(dnd.dndSurface), &box, 1.F); + CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale); + g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F); - box = CBox{POS, {dnd.dndSurface->current.width, dnd.dndSurface->current.height}}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); + box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); g_pHyprRenderer->damageBox(&box); - wlr_surface_send_frame_done(dnd.dndSurface, when); + dnd.dndSurface->frame(when); } bool CWLDataDeviceProtocol::dndActive() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 3112b720..f31725ee 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -23,6 +23,7 @@ class CWLDataDeviceManagerResource; class CWLDataSourceResource; class CWLDataOfferResource; +class CWLSurfaceResource; class CMonitor; class CWLDataOfferResource { @@ -92,7 +93,7 @@ class CWLDataDeviceResource { wl_client* client(); void sendDataOffer(SP offer); - void sendEnter(uint32_t serial, wlr_surface* surf, const Vector2D& local, SP offer); + void sendEnter(uint32_t serial, SP surf, const Vector2D& local, SP offer); void sendLeave(); void sendMotion(uint32_t timeMs, const Vector2D& local); void sendDrop(); @@ -155,11 +156,11 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { struct { WP focusedDevice; WP currentSource; - wlr_surface* dndSurface = nullptr; - wlr_surface* originSurface = nullptr; // READ-ONLY + WP dndSurface; + WP originSurface; bool overriddenCursor = false; - DYNLISTENER(dndSurfaceDestroy); - DYNLISTENER(dndSurfaceCommit); + CHyprSignalListener dndSurfaceDestroy; + CHyprSignalListener dndSurfaceCommit; // for ending a dnd SP mouseMove; @@ -169,7 +170,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { } dnd; void abortDrag(); - void initiateDrag(WP currentSource, wlr_surface* dragSurface, wlr_surface* origin); + void initiateDrag(WP currentSource, SP dragSurface, SP origin); void updateDrag(); void dropDrag(); void completeDrag(); diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp new file mode 100644 index 00000000..3778e453 --- /dev/null +++ b/src/protocols/core/Output.cpp @@ -0,0 +1,107 @@ +#include "Output.hpp" +#include "../../helpers/Monitor.hpp" + +CWLOutputResource::CWLOutputResource(SP resource_, SP pMonitor) : monitor(pMonitor), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + pClient = resource->client(); + + resource->setOnDestroy([this](CWlOutput* r) { + if (monitor && PROTO::outputs.contains(monitor->szName)) + PROTO::outputs.at(monitor->szName)->destroyResource(this); + }); + resource->setRelease([this](CWlOutput* r) { + if (monitor && PROTO::outputs.contains(monitor->szName)) + PROTO::outputs.at(monitor->szName)->destroyResource(this); + }); + + resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null", + monitor->output->model ? monitor->output->model : "null", monitor->transform); + if (resource->version() >= 4) { + resource->sendName(monitor->szName.c_str()); + resource->sendDescription(monitor->szDescription.c_str()); + } + + updateState(); +} + +SP CWLOutputResource::fromResource(wl_resource* res) { + auto data = (CWLOutputResource*)(((CWlOutput*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CWLOutputResource::good() { + return resource->resource(); +} + +wl_client* CWLOutputResource::client() { + return pClient; +} + +SP CWLOutputResource::getResource() { + return resource; +} + +void CWLOutputResource::updateState() { + if (!monitor) + return; + + if (resource->version() >= 2) + resource->sendScale(std::ceil(monitor->scale)); + + resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecSize.x, monitor->vecSize.y, monitor->refreshRate * 1000.0); + + if (resource->version() >= 2) + resource->sendDone(); +} + +CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP pMonitor) : + IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) { + + listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) { + for (auto& o : m_vOutputs) { + o->updateState(); + } + }); +} + +void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vOutputs.emplace_back(makeShared(makeShared(client, ver, id), monitor.lock())); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vOutputs.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; +} + +void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) { + std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); + + if (m_vOutputs.empty() && defunct) + PROTO::outputs.erase(szName); +} + +SP CWLOutputProtocol::outputResourceFrom(wl_client* client) { + for (auto& r : m_vOutputs) { + if (r->client() != client) + continue; + + return r; + } + + return nullptr; +} + +void CWLOutputProtocol::remove() { + if (defunct) + return; + + defunct = true; + removeGlobal(); +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp new file mode 100644 index 00000000..5c274612 --- /dev/null +++ b/src/protocols/core/Output.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Listener.hpp" + +class CMonitor; + +class CWLOutputResource { + public: + CWLOutputResource(SP resource_, SP pMonitor); + static SP fromResource(wl_resource*); + + bool good(); + wl_client* client(); + SP getResource(); + void updateState(); + + WP monitor; + + WP self; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CWLOutputProtocol : public IWaylandProtocol { + public: + CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP pMonitor); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + SP outputResourceFrom(wl_client* client); + + WP monitor; + + // will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global) + void remove(); + + private: + void destroyResource(CWLOutputResource* resource); + + // + std::vector> m_vOutputs; + bool defunct = false; + std::string szName = ""; + + struct { + CHyprSignalListener modeChanged; + } listeners; + + friend class CWLOutputResource; +}; + +namespace PROTO { + inline std::unordered_map> outputs; +}; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 9d5cf496..8bf03909 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -1,4 +1,5 @@ #include "Seat.hpp" +#include "Compositor.hpp" #include "../../devices/IKeyboard.hpp" #include "../../managers/SeatManager.hpp" #include "../../config/ConfigValue.hpp" @@ -20,7 +21,7 @@ bool CWLTouchResource::good() { return resource->resource(); } -void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local) { +void CWLTouchResource::sendDown(SP surface, uint32_t timeMs, int32_t id, const Vector2D& local) { if (!owner) return; @@ -29,15 +30,12 @@ void CWLTouchResource::sendDown(wlr_surface* surface, uint32_t timeMs, int32_t i sendUp(timeMs, id); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this, id, timeMs](void* owner, void* data) { sendUp(timeMs + 10 /* hack */, id); }, this, "CWLTouchResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); }); - // FIXME: - // fix this once we get our own wlr_surface, this is horrible - resource->sendDownRaw(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->resource, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { @@ -45,8 +43,8 @@ void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { return; resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { @@ -97,7 +95,7 @@ CWLPointerResource::CWLPointerResource(SP resource_, SPonSetCursor(owner.lock(), serial, surf ? wlr_surface_from_resource(surf) : nullptr, {hotX, hotY}); + g_pSeatManager->onSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY}); }); } @@ -105,7 +103,7 @@ bool CWLPointerResource::good() { return resource->resource(); } -void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) { +void CWLPointerResource::sendEnter(SP surface, const Vector2D& local) { if (!owner || currentSurface == surface) return; @@ -114,22 +112,21 @@ void CWLPointerResource::sendEnter(wlr_surface* surface, const Vector2D& local) sendLeave(); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLPointerResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); }); - resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLPointerResource::sendLeave() { if (!owner || !currentSurface) return; - resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) { @@ -237,7 +234,7 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { close(fd); } -void CWLKeyboardResource::sendEnter(wlr_surface* surface) { +void CWLKeyboardResource::sendEnter(SP surface) { if (!owner || currentSurface == surface) return; @@ -246,16 +243,15 @@ void CWLKeyboardResource::sendEnter(wlr_surface* surface) { sendLeave(); } - ASSERT(wl_resource_get_client(surface->resource) == owner->client()); + ASSERT(surface->client() == owner->client()); - currentSurface = surface; - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, [this](void* owner, void* data) { sendLeave(); }, this, "CWLKeyboardResource"); + currentSurface = surface; + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { sendLeave(); }); wl_array arr; wl_array_init(&arr); - resource->sendEnterRaw(g_pSeatManager->nextSerial(owner.lock()), surface->resource, &arr); + resource->sendEnter(g_pSeatManager->nextSerial(owner.lock()), surface->getResource().get(), &arr); wl_array_release(&arr); } @@ -264,9 +260,9 @@ void CWLKeyboardResource::sendLeave() { if (!owner || !currentSurface) return; - resource->sendLeaveRaw(g_pSeatManager->nextSerial(owner.lock()), currentSurface->resource); - currentSurface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); + currentSurface.reset(); + listeners.destroySurface.reset(); } void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state) { diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 4cd0d124..524783f9 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -20,6 +20,7 @@ constexpr const char* HL_SEAT_NAME = "Hyprland"; class IKeyboard; +class CWLSurfaceResource; class CWLPointerResource; class CWLKeyboardResource; @@ -31,7 +32,7 @@ class CWLTouchResource { CWLTouchResource(SP resource_, SP owner_); bool good(); - void sendDown(wlr_surface* surface, uint32_t timeMs, int32_t id, const Vector2D& local); + void sendDown(SP surface, uint32_t timeMs, int32_t id, const Vector2D& local); void sendUp(uint32_t timeMs, int32_t id); void sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local); void sendFrame(); @@ -42,10 +43,12 @@ class CWLTouchResource { WP owner; private: - SP resource; - wlr_surface* currentSurface = nullptr; + SP resource; + WP currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLPointerResource { @@ -53,7 +56,7 @@ class CWLPointerResource { CWLPointerResource(SP resource_, SP owner_); bool good(); - void sendEnter(wlr_surface* surface, const Vector2D& local); + void sendEnter(SP surface, const Vector2D& local); void sendLeave(); void sendMotion(uint32_t timeMs, const Vector2D& local); void sendButton(uint32_t timeMs, uint32_t button, wl_pointer_button_state state); @@ -68,10 +71,12 @@ class CWLPointerResource { WP owner; private: - SP resource; - wlr_surface* currentSurface = nullptr; + SP resource; + WP currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLKeyboardResource { @@ -80,7 +85,7 @@ class CWLKeyboardResource { bool good(); void sendKeymap(SP keeb); - void sendEnter(wlr_surface* surface); + void sendEnter(SP surface); void sendLeave(); void sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); @@ -89,10 +94,12 @@ class CWLKeyboardResource { WP owner; private: - SP resource; - wlr_surface* currentSurface = nullptr; + SP resource; + WP currentSurface; - DYNLISTENER(surfaceDestroy); + struct { + CHyprSignalListener destroySurface; + } listeners; }; class CWLSeatResource { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp new file mode 100644 index 00000000..0c01cf80 --- /dev/null +++ b/src/protocols/core/Shm.cpp @@ -0,0 +1,214 @@ +#include "Shm.hpp" +#include +#include +#include +#include "../../render/Texture.hpp" +#include "../types/WLBuffer.hpp" +#include "../../Compositor.hpp" +#include "../../helpers/Format.hpp" + +#define LOGM PROTO::shm->protoLog + +CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { + if (!pool_->pool->data) + return; + + g_pHyprRenderer->makeEGLCurrent(); + + size = size_; + pool = pool_->pool; + stride = stride_; + fmt = fmt_; + offset = offset_; + opaque = FormatUtils::isFormatOpaque(FormatUtils::shmToDRM(fmt_)); + + texture = makeShared(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, size_); + + resource = CWLBufferResource::create(makeShared(pool_->resource->client(), 1, id)); + + listeners.bufferResourceDestroy = events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::shm->destroyResource(this); + }); + + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed creating a shm texture: null texture id"); +} + +CWLSHMBuffer::~CWLSHMBuffer() { + ; +} + +eBufferCapability CWLSHMBuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType CWLSHMBuffer::type() { + return BUFFER_TYPE_SHM; +} + +SSHMAttrs CWLSHMBuffer::shm() { + SSHMAttrs attrs; + attrs.success = true; + attrs.fd = pool->fd; + attrs.format = FormatUtils::shmToDRM(fmt); + attrs.size = size; + attrs.stride = stride; + attrs.offset = offset; + return attrs; +} + +std::tuple CWLSHMBuffer::beginDataPtr(uint32_t flags) { + return {(uint8_t*)pool->data + offset, fmt, size.x * size.y * 4}; +} + +void CWLSHMBuffer::endDataPtr() { + ; +} + +bool CWLSHMBuffer::good() { + return success; +} + +void CWLSHMBuffer::update(const CRegion& damage) { + texture->update(FormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); +} + +CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_) { + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); +} + +CSHMPool::~CSHMPool() { + munmap(data, size); + close(fd); +} + +void CSHMPool::resize(size_t size_) { + LOGM(LOG, "Resizing a SHM pool from {} to {}", size, size_); + + if (data) + munmap(data, size); + size = size_; + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (!data) + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); +} + +CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { + if (!good()) + return; + + pool = makeShared(fd_, size_); + + resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); + resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); + + resource->setResize([this](CWlShmPool* r, int32_t size_) { + if (size_ < (int32_t)pool->size) { + r->error(-1, "Shrinking a shm pool is illegal"); + return; + } + pool->resize(size_); + }); + + resource->setCreateBuffer([this](CWlShmPool* r, uint32_t id, int32_t offset, int32_t w, int32_t h, int32_t stride, uint32_t fmt) { + if (!pool || !pool->data) { + r->error(-1, "The provided shm pool failed to allocate properly"); + return; + } + + if (std::find(PROTO::shm->shmFormats.begin(), PROTO::shm->shmFormats.end(), fmt) == PROTO::shm->shmFormats.end()) { + r->error(WL_SHM_ERROR_INVALID_FORMAT, "Format invalid"); + return; + } + + if (offset < 0 || w <= 0 || h <= 0 || stride <= 0) { + r->error(WL_SHM_ERROR_INVALID_STRIDE, "Invalid stride, w, h, or offset"); + return; + } + + const auto RESOURCE = PROTO::shm->m_vBuffers.emplace_back(makeShared(self.lock(), id, offset, Vector2D{w, h}, stride, fmt)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::shm->m_vBuffers.pop_back(); + return; + } + + // append instance so that buffer knows its owner + RESOURCE->resource->buffer = RESOURCE; + }); + + if (!pool->data) + resource->error(WL_SHM_ERROR_INVALID_FD, "Couldn't mmap from fd"); +} + +bool CWLSHMPoolResource::good() { + return resource->resource(); +} + +CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); + + resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::shm->m_vPools.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + + // send a few supported formats. No need for any other I think? + for (auto& s : PROTO::shm->shmFormats) { + resource->sendFormat((wl_shm_format)s); + } +} + +bool CWLSHMResource::good() { + return resource->resource(); +} + +CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + if (shmFormats.empty()) { + size_t len = 0; + const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len); + + for (size_t i = 0; i < len; ++i) { + shmFormats.push_back(FormatUtils::drmToShm(formats[i])); + } + } + + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLSHMProtocol::destroyResource(CWLSHMResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSHMProtocol::destroyResource(CWLSHMPoolResource* resource) { + std::erase_if(m_vPools, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSHMProtocol::destroyResource(CWLSHMBuffer* resource) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp new file mode 100644 index 00000000..862ea112 --- /dev/null +++ b/src/protocols/core/Shm.hpp @@ -0,0 +1,111 @@ +#pragma once + +/* + Implementations for: + - wl_shm + - wl_shm_pool + - wl_buffer with shm +*/ + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../types/Buffer.hpp" +#include "../../helpers/Vector2D.hpp" + +class CWLSHMPoolResource; + +class CSHMPool { + public: + CSHMPool(int fd, size_t size); + ~CSHMPool(); + + int fd = 0; + size_t size = 0; + void* data = nullptr; + + void resize(size_t size); +}; + +class CWLSHMBuffer : public IWLBuffer { + public: + CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); + virtual ~CWLSHMBuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const CRegion& damage); + virtual SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + bool good(); + void updateTexture(); + + int32_t offset = 0, stride = 0; + uint32_t fmt = 0; + SP pool; + + private: + bool success = false; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; +}; + +class CWLSHMPoolResource { + public: + CWLSHMPoolResource(SP resource_, int fd, size_t size); + + bool good(); + + SP pool; + + WP self; + + private: + SP resource; + + friend class CWLSHMBuffer; +}; + +class CWLSHMResource { + public: + CWLSHMResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CWLSHMProtocol : public IWaylandProtocol { + public: + CWLSHMProtocol(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); + + private: + void destroyResource(CWLSHMResource* resource); + void destroyResource(CWLSHMPoolResource* resource); + void destroyResource(CWLSHMBuffer* resource); + + // + std::vector> m_vManagers; + std::vector> m_vPools; + std::vector> m_vBuffers; + + // + std::vector shmFormats; + + friend class CWLSHMResource; + friend class CWLSHMPoolResource; + friend class CWLSHMBuffer; +}; + +namespace PROTO { + inline UP shm; +}; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp new file mode 100644 index 00000000..213fdc42 --- /dev/null +++ b/src/protocols/core/Subcompositor.cpp @@ -0,0 +1,192 @@ +#include "Subcompositor.hpp" +#include "Compositor.hpp" +#include + +#define LOGM PROTO::subcompositor->protoLog + +CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_) : + surface(surface_), parent(parent_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubsurface* r) { destroy(); }); + resource->setDestroy([this](CWlSubsurface* r) { destroy(); }); + + resource->setSetPosition([this](CWlSubsurface* r, int32_t x, int32_t y) { position = {x, y}; }); + + resource->setSetDesync([this](CWlSubsurface* r) { sync = false; }); + resource->setSetSync([this](CWlSubsurface* r) { sync = true; }); + + resource->setPlaceAbove([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeAbove"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it, self.lock()); + }); + + resource->setPlaceBelow([this](CWlSubsurface* r, wl_resource* surf) { + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!parent) + return; + + std::erase(parent->subsurfaces, self.lock()); + + auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); + + if (it == parent->subsurfaces.end()) { + LOGM(ERR, "Invalid surface reference in placeBelow"); + parent->subsurfaces.emplace_back(self.lock()); + } else + parent->subsurfaces.insert(it--, self.lock()); + }); + + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (surface->current.buffer && !surface->mapped) { + surface->map(); + return; + } + + if (!surface->current.buffer && surface->mapped) { + surface->unmap(); + return; + } + }); +} + +CWLSubsurfaceResource::~CWLSubsurfaceResource() { + events.destroy.emit(); + if (surface) + surface->resetRole(); +} + +void CWLSubsurfaceResource::destroy() { + if (surface && surface->mapped) + surface->unmap(); + events.destroy.emit(); + PROTO::subcompositor->destroyResource(this); +} + +Vector2D CWLSubsurfaceResource::posRelativeToParent() { + Vector2D pos = position; + SP surf = parent.lock(); + + // some apps might create cycles, which I believe _technically_ are not a protocol error + // in some cases, notably firefox likes to do that, so we keep track of what + // surfaces we've visited and if we hit a surface we've visited we bail out. + std::vector> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + pos += subsurface->position; + surf = subsurface->parent.lock(); + } + return pos; +} + +bool CWLSubsurfaceResource::good() { + return resource->resource(); +} + +eSurfaceRole CWLSubsurfaceResource::role() { + return SURFACE_ROLE_SUBSURFACE; +} + +SP CWLSubsurfaceResource::t1Parent() { + SP surf = parent.lock(); + std::vector> surfacesVisited; + + while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && + std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + surfacesVisited.emplace_back(surf); + auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + surf = subsurface->parent.lock(); + } + return surf; +} + +CWLSubcompositorResource::CWLSubcompositorResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + resource->setDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); + + resource->setGetSubsurface([](CWlSubcompositor* r, uint32_t id, wl_resource* surface, wl_resource* parent) { + auto SURF = CWLSurfaceResource::fromResource(surface); + auto PARENT = CWLSurfaceResource::fromResource(parent); + + if (!SURF || !PARENT || SURF == PARENT) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Invalid surface/parent"); + return; + } + + SP t1Parent = nullptr; + + if (PARENT->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)PARENT->role.get(); + t1Parent = subsurface->t1Parent(); + } else + t1Parent = PARENT; + + if (t1Parent == SURF) { + r->error(WL_SUBCOMPOSITOR_ERROR_BAD_PARENT, "Bad parent, t1 parent == surf"); + return; + } + + const auto RESOURCE = + PROTO::subcompositor->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF, PARENT)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::subcompositor->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + SURF->role = RESOURCE; + PARENT->subsurfaces.emplace_back(RESOURCE); + + LOGM(LOG, "New wl_subsurface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); + + PARENT->events.newSubsurface.emit(RESOURCE); + }); +} + +bool CWLSubcompositorResource::good() { + return resource->resource(); +} + +CWLSubcompositorProtocol::CWLSubcompositorProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CWLSubcompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubcompositorResource* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CWLSubcompositorProtocol::destroyResource(CWLSubsurfaceResource* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/core/Subcompositor.hpp b/src/protocols/core/Subcompositor.hpp new file mode 100644 index 00000000..abcfbf6d --- /dev/null +++ b/src/protocols/core/Subcompositor.hpp @@ -0,0 +1,82 @@ + +#pragma once + +/* + Implementations for: + - wl_subsurface + - wl_subcompositor +*/ + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../types/SurfaceRole.hpp" + +class CWLSurfaceResource; + +class CWLSubsurfaceResource : public ISurfaceRole { + public: + CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_); + ~CWLSubsurfaceResource(); + + Vector2D posRelativeToParent(); + bool good(); + virtual eSurfaceRole role(); + SP t1Parent(); + + bool sync = false; + Vector2D position; + + WP surface; + WP parent; + + WP self; + + struct { + CSignal destroy; + } events; + + private: + SP resource; + + void destroy(); + + struct { + CHyprSignalListener commitSurface; + } listeners; +}; + +class CWLSubcompositorResource { + public: + CWLSubcompositorResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CWLSubcompositorProtocol : public IWaylandProtocol { + public: + CWLSubcompositorProtocol(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); + + private: + void destroyResource(CWLSubcompositorResource* resource); + void destroyResource(CWLSubsurfaceResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vSurfaces; + + friend class CWLSubcompositorResource; + friend class CWLSubsurfaceResource; +}; + +namespace PROTO { + inline UP subcompositor; +}; diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp new file mode 100644 index 00000000..5ed942e1 --- /dev/null +++ b/src/protocols/types/Buffer.cpp @@ -0,0 +1,41 @@ +#include "Buffer.hpp" +#include "WLBuffer.hpp" + +SDMABUFAttrs IWLBuffer::dmabuf() { + return SDMABUFAttrs{}; +} + +SSHMAttrs IWLBuffer::shm() { + return SSHMAttrs{}; +} + +std::tuple IWLBuffer::beginDataPtr(uint32_t flags) { + return {nullptr, 0, 0}; +} + +void IWLBuffer::endDataPtr() { + ; // empty +} + +void IWLBuffer::sendRelease() { + if (!resource || !resource->resource) + return; + resource->resource->sendRelease(); +} + +void IWLBuffer::lock() { + locks++; +} + +void IWLBuffer::unlock() { + locks--; + + ASSERT(locks >= 0); + + if (locks <= 0) + sendRelease(); +} + +bool IWLBuffer::locked() { + return locks; +} diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp new file mode 100644 index 00000000..c9902f8d --- /dev/null +++ b/src/protocols/types/Buffer.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "../../defines.hpp" +#include "../../helpers/signal/Signal.hpp" +#include "../../render/Texture.hpp" + +#include +#include + +enum eBufferCapability { + BUFFER_CAPABILITY_DATAPTR = (1 << 0), +}; + +enum eBufferType { + BUFFER_TYPE_DMABUF = 0, + BUFFER_TYPE_SHM, + BUFFER_TYPE_MISC, +}; + +class CWLBufferResource; + +struct SDMABUFAttrs { + bool success = false; + Vector2D size; + uint32_t format = 0; // fourcc + uint64_t modifier = 0; + + int planes = 1; + std::array offsets = {0}; + std::array strides = {0}; + std::array fds = {-1, -1, -1, -1}; +}; + +struct SSHMAttrs { + bool success = false; + int fd = 0; + uint32_t format = 0; + Vector2D size; + int stride = 0; + int64_t offset = 0; +}; + +class IWLBuffer { + public: + virtual ~IWLBuffer() { + ; + }; + + virtual eBufferCapability caps() = 0; + virtual eBufferType type() = 0; + virtual void update(const CRegion& damage) = 0; + virtual SDMABUFAttrs dmabuf(); + virtual SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + virtual void sendRelease(); + virtual void lock(); + virtual void unlock(); + virtual bool locked(); + + Vector2D size; + bool opaque = false; + + SP resource; + + SP texture; + + struct { + CSignal destroy; + } events; + + private: + int locks = 0; +}; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp new file mode 100644 index 00000000..930e71e6 --- /dev/null +++ b/src/protocols/types/DMABuffer.cpp @@ -0,0 +1,75 @@ +#include "DMABuffer.hpp" +#include "WLBuffer.hpp" +#include "../../render/Renderer.hpp" +#include "../../helpers/Format.hpp" + +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) : attrs(attrs_) { + g_pHyprRenderer->makeEGLCurrent(); + + listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { + closeFDs(); + listeners.resourceDestroy.reset(); + }); + + size = attrs.size; + resource = CWLBufferResource::create(makeShared(client, 1, id)); + + auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); + + if (!eglImage) + return; + + texture = makeShared(attrs, eglImage); // texture takes ownership of the eglImage + opaque = FormatUtils::isFormatOpaque(attrs.format); + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed to create a dmabuf: texture is null"); +} + +CDMABuffer::~CDMABuffer() { + closeFDs(); +} + +eBufferCapability CDMABuffer::caps() { + return BUFFER_CAPABILITY_DATAPTR; +} + +eBufferType CDMABuffer::type() { + return BUFFER_TYPE_DMABUF; +} + +void CDMABuffer::update(const CRegion& damage) { + ; +} + +SDMABUFAttrs CDMABuffer::dmabuf() { + return attrs; +} + +std::tuple CDMABuffer::beginDataPtr(uint32_t flags) { + // FIXME: + return {nullptr, 0, 0}; +} + +void CDMABuffer::endDataPtr() { + // FIXME: +} + +bool CDMABuffer::good() { + return success; +} + +void CDMABuffer::updateTexture() { + ; +} + +void CDMABuffer::closeFDs() { + for (int i = 0; i < attrs.planes; ++i) { + if (attrs.fds[i] == -1) + continue; + close(attrs.fds[i]); + attrs.fds[i] = -1; + } + attrs.planes = 0; +} \ No newline at end of file diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp new file mode 100644 index 00000000..e06b5791 --- /dev/null +++ b/src/protocols/types/DMABuffer.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Buffer.hpp" + +class CDMABuffer : public IWLBuffer { + public: + CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_); + virtual ~CDMABuffer(); + + virtual eBufferCapability caps(); + virtual eBufferType type(); + virtual void update(const CRegion& damage); + virtual SDMABUFAttrs dmabuf(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + bool good(); + void updateTexture(); + void closeFDs(); + + bool success = false; + + private: + SDMABUFAttrs attrs; + + struct { + CHyprSignalListener resourceDestroy; + } listeners; +}; \ No newline at end of file diff --git a/src/protocols/types/SurfaceRole.hpp b/src/protocols/types/SurfaceRole.hpp new file mode 100644 index 00000000..05c0ea66 --- /dev/null +++ b/src/protocols/types/SurfaceRole.hpp @@ -0,0 +1,14 @@ +#pragma once + +enum eSurfaceRole { + SURFACE_ROLE_UNASSIGNED = 0, + SURFACE_ROLE_XDG_SHELL, + SURFACE_ROLE_LAYER_SHELL, + SURFACE_ROLE_EASTER_EGG, + SURFACE_ROLE_SUBSURFACE, +}; + +class ISurfaceRole { + public: + virtual eSurfaceRole role() = 0; +}; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp new file mode 100644 index 00000000..e53538cb --- /dev/null +++ b/src/protocols/types/WLBuffer.cpp @@ -0,0 +1,43 @@ +#include "WLBuffer.hpp" +#include "Buffer.hpp" + +CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWlBuffer* r) { + if (buffer.expired()) + return; + buffer->events.destroy.emit(); + }); + resource->setDestroy([this](CWlBuffer* r) { + if (buffer.expired()) + return; + buffer->events.destroy.emit(); + }); + + resource->setData(this); +} + +bool CWLBufferResource::good() { + return resource->resource(); +} + +void CWLBufferResource::sendRelease() { + resource->sendRelease(); +} + +wl_resource* CWLBufferResource::getResource() { + return resource->resource(); +} + +SP CWLBufferResource::fromResource(wl_resource* res) { + auto data = (CWLBufferResource*)(((CWlBuffer*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +SP CWLBufferResource::create(SP resource) { + auto p = SP(new CWLBufferResource(resource)); + p->self = p; + return p; +} diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp new file mode 100644 index 00000000..ac177965 --- /dev/null +++ b/src/protocols/types/WLBuffer.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include "../WaylandProtocol.hpp" +#include "wayland.hpp" +#include "../../helpers/signal/Signal.hpp" + +class IWLBuffer; + +class CWLBufferResource { + public: + static SP create(SP resource); + static SP fromResource(wl_resource* res); + + bool good(); + void sendRelease(); + wl_resource* getResource(); + + WP buffer; + + WP self; + + private: + CWLBufferResource(SP resource_); + + SP resource; + + friend class IWLBuffer; +}; diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 83325dd7..67629e23 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -1,22 +1,26 @@ #include "Framebuffer.hpp" #include "OpenGL.hpp" +CFramebuffer::CFramebuffer() { + m_cTex = makeShared(); +} + bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { bool firstAlloc = false; RASSERT((w > 1 && h > 1), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h); - uint32_t glFormat = drmFormatToGL(drmFormat); - uint32_t glType = glFormatToType(glFormat); + uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); + uint32_t glType = FormatUtils::glFormatToType(glFormat); if (m_iFb == (uint32_t)-1) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); } - if (m_cTex.m_iTexID == 0) { + if (m_cTex->m_iTexID == 0) { firstAlloc = true; - glGenTextures(1, &m_cTex.m_iTexID); - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + m_cTex->allocate(); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -24,11 +28,11 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } if (firstAlloc || m_vSize != Vector2D(w, h)) { - glBindTexture(GL_TEXTURE_2D, m_cTex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, 0); glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex.m_iTexID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0); // TODO: Allow this with gles2 #ifndef GLES2 @@ -87,12 +91,9 @@ void CFramebuffer::release() { if (m_iFb != (uint32_t)-1 && m_iFb) glDeleteFramebuffers(1, &m_iFb); - if (m_cTex.m_iTexID) - glDeleteTextures(1, &m_cTex.m_iTexID); - - m_cTex.m_iTexID = 0; - m_iFb = -1; - m_vSize = Vector2D(); + m_cTex->destroyTexture(); + m_iFb = -1; + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 22809158..a46a4859 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -5,19 +5,20 @@ class CFramebuffer { public: + CFramebuffer(); ~CFramebuffer(); - bool alloc(int w, int h, uint32_t format = GL_RGBA); - void addStencil(); - void bind(); - void release(); - void reset(); - bool isAllocated(); + bool alloc(int w, int h, uint32_t format = GL_RGBA); + void addStencil(); + void bind(); + void release(); + void reset(); + bool isAllocated(); - Vector2D m_vSize; + Vector2D m_vSize; - CTexture m_cTex; - GLuint m_iFb = -1; + SP m_cTex; + GLuint m_iFb = -1; - CTexture* m_pStencilTex = nullptr; + SP m_pStencilTex; }; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a1e6f73e..d4e8faa6 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -7,6 +7,8 @@ #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" +#include "../protocols/core/Compositor.hpp" +#include inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); @@ -21,7 +23,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), "Couldn't unset current EGL!"); - auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS); RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); @@ -33,12 +36,25 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION)); Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR)); Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); - Debug::log(LOG, "Supported extensions size: {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' ')); + Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions); loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); + loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); + loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); + loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); - m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); + m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); + m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + + RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required"); + + if (!m_sExts.EXT_read_format_bgra) + Debug::log(WARN, "Your GPU does not support GL_EXT_read_format_bgra, this may cause issues with texture importing"); + if (!m_sExts.EXT_image_dma_buf_import || !m_sExts.EXT_image_dma_buf_import_modifiers) + Debug::log(WARN, "Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance."); #ifdef USE_TRACY_GPU @@ -54,6 +70,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(WARN, "!RENDERER: Using the legacy GLES2 renderer!"); #endif + initDRMFormats(); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -61,6 +79,171 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } +std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { + // TODO: return std::expected when clang supports it + + if (!m_sExts.EXT_image_dma_buf_import_modifiers) + return {}; + + EGLint len = 0; + if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { + Debug::log(ERR, "EGL: Failed to query mods"); + return {}; + } + + if (len <= 0) + return {}; + + std::vector mods; + std::vector external; + + mods.resize(len); + external.resize(len); + + m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); + + std::vector result; + for (size_t i = 0; i < mods.size(); ++i) { + if (external.at(i)) + continue; + + result.push_back(mods.at(i)); + } + + return result; +} + +void CHyprOpenGLImpl::initDRMFormats() { + const auto DISABLE_MODS = envEnabled("HYPRLAND_EGL_NO_MODIFIERS"); + if (DISABLE_MODS) + Debug::log(WARN, "HYPRLAND_EGL_NO_MODIFIERS set, disabling modifiers"); + + if (!m_sExts.EXT_image_dma_buf_import) { + Debug::log(ERR, "EGL: No dmabuf import, DMABufs will not work."); + return; + } + + std::vector formats; + + if (!m_sExts.EXT_image_dma_buf_import_modifiers || !m_sProc.eglQueryDmaBufFormatsEXT) { + formats.push_back(DRM_FORMAT_ARGB8888); + formats.push_back(DRM_FORMAT_XRGB8888); + Debug::log(WARN, "EGL: No mod support"); + } else { + EGLint len = 0; + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len); + formats.resize(len); + m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len); + } + + if (formats.size() == 0) { + Debug::log(ERR, "EGL: Failed to get formats, DMABufs will not work."); + return; + } + + wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:"); + + std::vector dmaFormats; + + for (auto& fmt : formats) { + std::vector mods; + if (!DISABLE_MODS) + mods = getModsForFormat(fmt); + else + mods = {DRM_FORMAT_MOD_LINEAR}; + + m_bHasModifiers = m_bHasModifiers || mods.size() > 0; + + if (mods.size() == 0) + continue; + + dmaFormats.push_back(SDRMFormat{ + .format = fmt, + .mods = mods, + }); + + std::vector> modifierData; + + auto fmtName = drmGetFormatName(fmt); + Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); + for (auto& mod : mods) { + auto modName = drmGetFormatModifierName(mod); + modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?")); + free(modName); + } + free(fmtName); + + mods.clear(); + std::sort(modifierData.begin(), modifierData.end(), [](const auto& a, const auto& b) { + if (a.first == 0) + return false; + if (a.second.contains("DCC")) + return false; + return true; + }); + + for (auto& [m, name] : modifierData) { + Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m); + mods.emplace_back(m); + } + } + + Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size()); + + drmFormats = dmaFormats; +} + +EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { + std::vector attribs; + + attribs.push_back(EGL_WIDTH); + attribs.push_back(attrs.size.x); + attribs.push_back(EGL_HEIGHT); + attribs.push_back(attrs.size.y); + attribs.push_back(EGL_LINUX_DRM_FOURCC_EXT); + attribs.push_back(attrs.format); + + struct { + EGLint fd; + EGLint offset; + EGLint pitch; + EGLint modlo; + EGLint modhi; + } attrNames[4] = { + {EGL_DMA_BUF_PLANE0_FD_EXT, EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE1_FD_EXT, EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGL_DMA_BUF_PLANE1_PITCH_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE2_FD_EXT, EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGL_DMA_BUF_PLANE2_PITCH_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT}, + {EGL_DMA_BUF_PLANE3_FD_EXT, EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGL_DMA_BUF_PLANE3_PITCH_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT}}; + + for (int i = 0; i < attrs.planes; i++) { + attribs.push_back(attrNames[i].fd); + attribs.push_back(attrs.fds[i]); + attribs.push_back(attrNames[i].offset); + attribs.push_back(attrs.offsets[i]); + attribs.push_back(attrNames[i].pitch); + attribs.push_back(attrs.strides[i]); + if (m_bHasModifiers && attrs.modifier != DRM_FORMAT_MOD_INVALID) { + attribs.push_back(attrNames[i].modlo); + attribs.push_back(attrs.modifier & 0xFFFFFFFF); + attribs.push_back(attrNames[i].modhi); + attribs.push_back(attrs.modifier >> 32); + } + } + + attribs.push_back(EGL_IMAGE_PRESERVED_KHR); + attribs.push_back(EGL_TRUE); + + attribs.push_back(EGL_NONE); + + EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); + if (image == EGL_NO_IMAGE_KHR) { + Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError()); + return EGL_NO_IMAGE_KHR; + } + + return image; +} + void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) { GLint maxLength = 0; if (program) @@ -339,12 +522,12 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // ensure a framebuffer for the monitor exists if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { - m_RenderData.pCurrentMonData->stencilTex.allocate(); + m_RenderData.pCurrentMonData->stencilTex->allocate(); - m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); @@ -381,8 +564,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu // we can render to the rbo / fbo (fake) directly const auto PFBO = fb ? fb : PRBO->getFB(); m_RenderData.currentFB = PFBO; - if (PFBO->m_pStencilTex != &m_RenderData.pCurrentMonData->stencilTex) { - PFBO->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + if (PFBO->m_pStencilTex != m_RenderData.pCurrentMonData->stencilTex) { + PFBO->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; PFBO->addStencil(); } PFBO->bind(); @@ -863,19 +1046,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) { - RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - - renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV); -} - -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); renderTextureInternalWithDamage(tex, pBox, alpha, &m_RenderData.damage, round, discardActive, false, allowCustomUV, true); @@ -883,7 +1054,7 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); @@ -891,10 +1062,10 @@ void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, C scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureInternalWithDamage"); @@ -934,11 +1105,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; usingFinalShader = true; } else { - switch (tex.m_iType) { + switch (tex->m_iType) { case TEXTURE_RGBA: shader = &m_RenderData.pCurrentMonData->m_shRGBA; break; case TEXTURE_RGBX: shader = &m_RenderData.pCurrentMonData->m_shRGBX; break; case TEXTURE_EXTERNAL: shader = &m_RenderData.pCurrentMonData->m_shEXT; break; - default: RASSERT(false, "tex.m_iTarget unsupported!"); + default: RASSERT(false, "tex->m_iTarget unsupported!"); } } } @@ -947,14 +1118,14 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* shader = &m_RenderData.pCurrentMonData->m_shRGBX; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); if (m_RenderData.useNearestNeighbor) { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } glUseProgram(shader->program); @@ -1057,12 +1228,12 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { +void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTexturePrimitive"); @@ -1083,7 +1254,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glUseProgram(shader->program); @@ -1111,12 +1282,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) { glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte) { +void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); + RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); TRACY_GPU_ZONE("RenderTextureMatte"); @@ -1148,10 +1319,10 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glUniform1i(shader->alphaMatte, 1); glActiveTexture(GL_TEXTURE0); - glBindTexture(tex.m_iTarget, tex.m_iTexID); + glBindTexture(tex->m_iTarget, tex->m_iTexID); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(matte.m_cTex.m_iTarget, matte.m_cTex.m_iTexID); + glBindTexture(matte.m_cTex->m_iTarget, matte.m_cTex->m_iTexID); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1169,7 +1340,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); - glBindTexture(tex.m_iTarget, 0); + glBindTexture(tex->m_iTarget, 0); } // This probably isn't the fastest @@ -1221,9 +1392,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(m_RenderData.currentFB->m_cTex.m_iTarget, m_RenderData.currentFB->m_cTex.m_iTexID); + glBindTexture(m_RenderData.currentFB->m_cTex->m_iTarget, m_RenderData.currentFB->m_cTex->m_iTexID); - glTexParameteri(m_RenderData.currentFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(m_RenderData.currentFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); @@ -1265,9 +1436,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(pShader->program); @@ -1315,7 +1486,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // draw the things. // first draw is swap -> mirr PMIRRORFB->bind(); - glBindTexture(PMIRRORSWAPFB->m_cTex.m_iTarget, PMIRRORSWAPFB->m_cTex.m_iTexID); + glBindTexture(PMIRRORSWAPFB->m_cTex->m_iTarget, PMIRRORSWAPFB->m_cTex->m_iTexID); // damage region will be scaled, make a temp CRegion tempDamage{damage}; @@ -1343,9 +1514,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex.m_iTarget, currentRenderToFB->m_cTex.m_iTexID); + glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); - glTexParameteri(currentRenderToFB->m_cTex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); @@ -1383,7 +1554,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } // finish - glBindTexture(PMIRRORFB->m_cTex.m_iTarget, 0); + glBindTexture(PMIRRORFB->m_cTex->m_iTarget, 0); blend(BLENDBEFORE); @@ -1417,23 +1588,23 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (pWindow->m_sAdditionalConfigData.forceNoBlur) return false; - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) return true; - const auto PSURFACE = pWindow->m_pWLSurface.wlr(); + const auto PSURFACE = pWindow->m_pWLSurface->resource(); const auto PWORKSPACE = pWindow->m_pWorkspace; const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value(); if (A >= 1.f) { - if (PSURFACE->opaque) - return false; + // if (PSURFACE->opaque) + // return false; CRegion inverseOpaque; - pixman_box32_t surfbox = {0, 0, PSURFACE->current.width, PSURFACE->current.height}; - CRegion opaqueRegion{&PSURFACE->current.opaque}; - inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.width, PSURFACE->current.height); + pixman_box32_t surfbox = {0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y}; + CRegion opaqueRegion{PSURFACE->current.opaque}; + inverseOpaque.set(opaqueRegion).invert(&surfbox).intersect(0, 0, PSURFACE->current.size.x, PSURFACE->current.size.y); if (inverseOpaque.empty()) return false; @@ -1461,8 +1632,8 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (!ls->layerSurface || ls->xray != 1) continue; - if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) - continue; + // if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) + // continue; hasWindows = true; break; @@ -1527,7 +1698,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin static auto PBLURNEWOPTIMIZE = CConfigValue("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue("decoration:blur:xray"); - if (!m_RenderData.pCurrentMonData->blurFB.m_cTex.m_iTexID) + if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) return false; if (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 0) @@ -1545,7 +1716,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, float a, wlr_surface* pSurface, int round, bool blockBlurOptimization, float blurA) { +void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, bool blockBlurOptimization, float blurA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto PBLURENABLED = CConfigValue("decoration:blur:enabled"); @@ -1570,11 +1741,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, CBox* pBox, flo // amazing hack: the surface has an opaque region! CRegion inverseOpaque; - if (a >= 1.f && std::round(pSurface->current.width * m_RenderData.pMonitor->scale) == pBox->w && - std::round(pSurface->current.height * m_RenderData.pMonitor->scale) == pBox->h) { - pixman_box32_t surfbox = {0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale}; - inverseOpaque = &pSurface->current.opaque; - inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.width * pSurface->current.scale, pSurface->current.height * pSurface->current.scale); + if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == pBox->w && + std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == pBox->h) { + pixman_box32_t surfbox = {0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale}; + inverseOpaque = pSurface->current.opaque; + inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { renderTexture(tex, pBox, a, round, false, true); @@ -1765,7 +1936,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr g_pHyprRenderer->makeEGLCurrent(); - pFramebuffer->m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); @@ -1903,7 +2074,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { const auto FBDATA = &m_mWindowFramebuffers.at(ref); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); @@ -1942,7 +2113,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { const auto FBDATA = &m_mLayerFramebuffers.at(pLayer); - if (!FBDATA->m_cTex.m_iTexID) + if (!FBDATA->m_cTex->m_iTexID) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); @@ -2077,7 +2248,7 @@ void CHyprOpenGLImpl::renderMirrored() { monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB; - if (!PFB->isAllocated() || PFB->m_cTex.m_iTexID <= 0) + if (!PFB->isAllocated() || PFB->m_cTex->m_iTexID <= 0) return; // replace monitor projection to undo the mirrored monitor's projection @@ -2179,12 +2350,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { } // create a new one with cairo - CTexture tex; + SP tex = makeShared(); - const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); + const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); - tex.allocate(); + tex->allocate(); const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)}; // calc the target box @@ -2220,8 +2391,8 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { cairo_surface_flush(CAIROSURFACE); - CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; - tex.m_vSize = IMAGESIZE * scale; + CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; + tex->m_vSize = IMAGESIZE * scale; // copy the data to an OpenGL texture we have const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? @@ -2235,7 +2406,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 @@ -2244,7 +2415,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); } #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex.m_vSize.x, tex.m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); cairo_surface_destroy(CAIROISURFACE); @@ -2293,7 +2464,7 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { RESIT->second.monitorMirrorFB.release(); RESIT->second.blurFB.release(); RESIT->second.offMainFB.release(); - RESIT->second.stencilTex.destroyTexture(); + RESIT->second.stencilTex->destroyTexture(); g_pHyprOpenGL->m_mMonitorRenderResources.erase(RESIT); } @@ -2343,109 +2514,6 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { m_RenderData.renderModif.enabled = enabled; } -inline const SGLPixelFormat GLES2_FORMATS[] = { - { - .drmFormat = DRM_FORMAT_ARGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XRGB8888, - .glFormat = GL_BGRA_EXT, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR8888, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_BGR888, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_BYTE, - .withAlpha = false, - }, -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - { - .drmFormat = DRM_FORMAT_RGBX4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA4444, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_4_4_4_4, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGBX5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_RGBA5551, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT_5_5_5_1, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_RGB565, - .glFormat = GL_RGB, - .glType = GL_UNSIGNED_SHORT_5_6_5, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_XBGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT_OES, - .withAlpha = true, - }, - { - .drmFormat = DRM_FORMAT_XBGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = false, - }, - { - .drmFormat = DRM_FORMAT_ABGR16161616, - .glInternalFormat = GL_RGBA16_EXT, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = true, - }, -#endif -}; - uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { GLint glf = -1, glt = -1, as = 0; /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf); @@ -2453,14 +2521,12 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { glGetIntegerv(GL_ALPHA_BITS, &as);*/ if (glf == 0 || glt == 0) { - glf = drmFormatToGL(pMonitor->drmFormat); - glt = glFormatToType(glf); + glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat); + glt = FormatUtils::glFormatToType(glf); } - for (auto& fmt : GLES2_FORMATS) { - if (fmt.glFormat == glf && fmt.glType == glt && fmt.withAlpha == (as > 0)) - return fmt.drmFormat; - } + if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT) + return FMT->drmFormat; if (m_sExts.EXT_read_format_bgra) return DRM_FORMAT_XRGB8888; @@ -2468,13 +2534,8 @@ uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { return DRM_FORMAT_XBGR8888; } -const SGLPixelFormat* CHyprOpenGLImpl::getPixelFormatFromDRM(uint32_t drmFormat) { - for (auto& fmt : GLES2_FORMATS) { - if (fmt.drmFormat == drmFormat) - return &fmt; - } - - return nullptr; +std::vector CHyprOpenGLImpl::getDRMFormats() { + return drmFormats; } void SRenderModifData::applyToBox(CBox& box) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index ca9eecc6..db0f8ea1 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -5,6 +5,7 @@ #include "../helpers/Color.hpp" #include "../helpers/Timer.hpp" #include "../helpers/Region.hpp" +#include "../helpers/Format.hpp" #include #include #include @@ -54,14 +55,6 @@ struct SRenderModifData { bool enabled = true; }; -struct SGLPixelFormat { - uint32_t drmFormat = DRM_FORMAT_INVALID; - GLint glInternalFormat = 0; - GLint glFormat = 0; - GLint glType = 0; - bool withAlpha = false; -}; - struct SMonitorRenderData { CFramebuffer offloadFB; CFramebuffer mirrorFB; // these are used for some effects, @@ -70,7 +63,7 @@ struct SMonitorRenderData { CFramebuffer monitorMirrorFB; // used for mirroring outputs, does not contain artifacts like offloadFB - CTexture stencilTex; + SP stencilTex = makeShared(); CFramebuffer blurFB; bool blurFBDirty = true; @@ -132,74 +125,73 @@ class CHyprOpenGLImpl { public: CHyprOpenGLImpl(); - void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); + void end(); - void renderRect(CBox*, const CColor&, int round = 0); - void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); - void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false); - void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false); - void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderTextureMatte(const CTexture& tex, CBox* pBox, CFramebuffer& matte); + void renderRect(CBox*, const CColor&, int round = 0); + void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); + void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); + void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); + void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - void makeWindowSnapshot(PHLWINDOW); - void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); - void makeLayerSnapshot(PHLLS); - void renderSnapshot(PHLWINDOW); - void renderSnapshot(PHLLS); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + void makeWindowSnapshot(PHLWINDOW); + void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); + void makeLayerSnapshot(PHLLS); + void renderSnapshot(PHLWINDOW); + void renderSnapshot(PHLLS); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CColor&); - void clearWithTex(); - void scissor(const CBox*, bool transform = true); - void scissor(const pixman_box32*, bool transform = true); - void scissor(const int x, const int y, const int w, const int h, bool transform = true); + void clear(const CColor&); + void clearWithTex(); + void scissor(const CBox*, bool transform = true); + void scissor(const pixman_box32*, bool transform = true); + void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(CMonitor*); + void destroyMonitorResources(CMonitor*); - void markBlurDirtyForMonitor(CMonitor*); + void markBlurDirtyForMonitor(CMonitor*); - void preWindowPass(); - bool preBlurQueued(); - void preRender(CMonitor*); + void preWindowPass(); + bool preBlurQueued(); + void preRender(CMonitor*); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(CBox*); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void setDamage(const CRegion& damage, std::optional finalDamage = {}); - uint32_t getPreferredReadFormat(CMonitor* pMonitor); - const SGLPixelFormat* getPixelFormatFromDRM(uint32_t drmFormat); + uint32_t getPreferredReadFormat(CMonitor* pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window - PHLLS m_pCurrentLayer; // hack to get the current rendered layer + PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window + PHLLS m_pCurrentLayer; // hack to get the current rendered layer std::map m_mWindowFramebuffers; std::map m_mLayerFramebuffers; @@ -208,41 +200,52 @@ class CHyprOpenGLImpl { struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr; + PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; + PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr; + PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; } m_sProc; struct { - bool EXT_read_format_bgra = false; + bool EXT_read_format_bgra = false; + bool EXT_image_dma_buf_import = false; + bool EXT_image_dma_buf_import_modifiers = false; } m_sExts; private: - std::list m_lBuffers; - std::list m_lTextures; + std::list m_lBuffers; + std::list m_lTextures; - int m_iDRMFD; - std::string m_szExtensions; + std::vector drmFormats; + bool m_bHasModifiers = false; - bool m_bFakeFrame = false; - bool m_bEndFrame = false; - bool m_bApplyFinalShader = false; - bool m_bBlend = false; - bool m_bOffloadedFramebuffer = false; + int m_iDRMFD; + std::string m_szExtensions; - CShader m_sFinalScreenShader; - CTimer m_tGlobalTimer; + bool m_bFakeFrame = false; + bool m_bEndFrame = false; + bool m_bApplyFinalShader = false; + bool m_bBlend = false; + bool m_bOffloadedFramebuffer = false; - void logShaderError(const GLuint&, bool program = false); - GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); - GLuint compileShader(const GLuint&, std::string, bool dynamic = false); - void createBGTextureForMonitor(CMonitor*); - void initShaders(); + CShader m_sFinalScreenShader; + CTimer m_tGlobalTimer; + + void logShaderError(const GLuint&, bool program = false); + GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); + GLuint compileShader(const GLuint&, std::string, bool dynamic = false); + void createBGTextureForMonitor(CMonitor*); + void initShaders(); + void initDRMFormats(); + std::vector getModsForFormat(EGLint format); // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(const CTexture&, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, + void renderTextureInternalWithDamage(SP, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowCustomUV = false, bool allowDim = false); - void renderTexturePrimitive(const CTexture& tex, CBox* pBox); + void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); void preBlurForCurrentMonitor(); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 5003f600..694485c2 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -1,6 +1,7 @@ #include "Renderbuffer.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" #include @@ -61,6 +62,29 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } +CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { + auto dma = buffer->dmabuf(); + + m_iImage = g_pHyprOpenGL->createEGLImage(dma); + if (m_iImage == EGL_NO_IMAGE_KHR) + throw std::runtime_error("createEGLImage failed"); + + glGenRenderbuffers(1, &m_iRBO); + glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); + g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glGenFramebuffers(1, &m_sFramebuffer.m_iFb); + m_sFramebuffer.m_vSize = buffer->size; + m_sFramebuffer.bind(); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void CRenderbuffer::bind() { glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); bindFB(); diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index 2a8bf250..ed7050c5 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -3,10 +3,12 @@ #include "Framebuffer.hpp" class CMonitor; +class IWLBuffer; class CRenderbuffer { public: CRenderbuffer(wlr_buffer* buffer, uint32_t format); + CRenderbuffer(SP buffer, uint32_t format); ~CRenderbuffer(); void bind(); @@ -16,6 +18,7 @@ class CRenderbuffer { uint32_t getFormat(); wlr_buffer* m_pWlrBuffer = nullptr; + WP m_pHLBuffer = {}; DYNLISTENER(destroyBuffer); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 40ae953e..2a6cbb3b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,6 +1,5 @@ #include "Renderer.hpp" #include "../Compositor.hpp" -#include "linux-dmabuf-unstable-v1-protocol.h" #include "../helpers/Region.hpp" #include #include "../config/ConfigValue.hpp" @@ -13,6 +12,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" +#include "../protocols/core/Compositor.hpp" extern "C" { #include @@ -90,19 +90,24 @@ CHyprRenderer::CHyprRenderer() { wl_event_source_timer_update(m_pCursorTicker, 500); } -static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { - const auto TEXTURE = wlr_surface_get_texture(surface); - const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; +static void renderSurface(SP surface, int x, int y, void* data) { + if (!surface->current.buffer || !surface->current.buffer->texture) + return; - if (!TEXTURE) + const auto& TEXTURE = surface->current.buffer->texture; + const auto RDATA = (SRenderData*)data; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; + + // this is bad, probably has been logged elsewhere. Means the texture failed + // uploading to the GPU. + if (!TEXTURE->m_iTexID) return; TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; - auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface); + auto PSURFACE = CWLSurface::fromResource(surface); const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F); @@ -140,7 +145,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) } } else { // here we clamp to 2, these might be some tiny specks - windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max(surface->current.width, 2), std::max(surface->current.height, 2)}; + windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { // adjust subsurfaces to the window windowBox.width = (windowBox.width / RDATA->pWindow->m_vReportedSize.x) * RDATA->pWindow->m_vRealSize.value().x; @@ -155,15 +160,23 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) windowBox.height = RDATA->h - y; } - if (windowBox.width <= 1 || windowBox.height <= 1) + if (windowBox.width <= 1 || windowBox.height <= 1) { + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { + surface->frame(RDATA->when); + auto FEEDBACK = makeShared(surface); + FEEDBACK->attachMonitor(RDATA->pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + } return; // invisible + } windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && - windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ && - DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ && + windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) && + DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); @@ -183,8 +196,8 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->dontRound) rounding = 0; - const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface.wlr() == surface ? RDATA->pWindow->opaque() : false; - const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && (WINDOWOPAQUE || surface->opaque); + const bool WINDOWOPAQUE = RDATA->pWindow && RDATA->pWindow->m_pWLSurface->resource() == surface ? RDATA->pWindow->opaque() : false; + const bool CANDISABLEBLEND = ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE; if (CANDISABLEBLEND) g_pHyprOpenGL->blend(false); @@ -195,16 +208,16 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } else { if (RDATA->blur && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - wlr_surface_send_frame_done(surface, RDATA->when); + surface->frame(RDATA->when); auto FEEDBACK = makeShared(surface); FEEDBACK->attachMonitor(RDATA->pMonitor); FEEDBACK->presented(); @@ -506,7 +519,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (ignoreAllGeometry) decorate = false; - renderdata.surface = pWindow->m_pWLSurface.wlr(); + renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); @@ -576,7 +589,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { + if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, @@ -584,7 +597,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec renderdata.blur = false; } - wlr_surface_for_each_surface(pWindow->m_pWLSurface.wlr(), renderSurface, &renderdata); + pWindow->m_pWLSurface->resource()->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + &renderdata); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; @@ -641,14 +655,15 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec pWindow->m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; auto pos = popup->coordsRelativeToParent(); auto rd = (SRenderData*)data; Vector2D oldPos = {rd->x, rd->y}; rd->x += pos.x; rd->y += pos.y; - wlr_surface_for_each_surface(popup->m_sWLSurface.wlr(), renderSurface, rd); + popup->m_pWLSurface->resource()->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, + data); rd->x = oldPos.x; rd->y = oldPos.y; }, @@ -698,7 +713,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y}; renderdata.fadeAlpha = pLayer->alpha.value(); renderdata.blur = pLayer->forceBlur; - renderdata.surface = pLayer->layerSurface->surface; + renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; renderdata.w = REALSIZ.x; renderdata.h = REALSIZ.y; @@ -717,7 +732,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time } if (!popups) - wlr_surface_for_each_surface(pLayer->layerSurface->surface, renderSurface, &renderdata); + pLayer->surface->resource()->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); renderdata.squishOversized = false; // don't squish popups renderdata.dontRound = true; @@ -726,11 +741,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time if (popups) { pLayer->popupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_sWLSurface.wlr()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; Vector2D pos = popup->coordsRelativeToParent(); - renderSurface(popup->m_sWLSurface.wlr(), pos.x, pos.y, data); + renderSurface(popup->m_pWLSurface->resource(), pos.x, pos.y, data); }, &renderdata); } @@ -746,15 +761,15 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, time SRenderData renderdata = {pMonitor, time, POS.x, POS.y}; - const auto SURF = pPopup->getWlrSurface(); + const auto SURF = pPopup->getSurface(); renderdata.blur = false; renderdata.surface = SURF; renderdata.decorate = false; - renderdata.w = SURF->current.width; - renderdata.h = SURF->current.height; + renderdata.w = SURF->current.size.x; + renderdata.h = SURF->current.size.y; - wlr_surface_for_each_surface(SURF, renderSurface, &renderdata); + SURF->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMonitor* pMonitor, timespec* time) { @@ -766,7 +781,7 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon renderdata.w = pMonitor->vecSize.x; renderdata.h = pMonitor->vecSize.y; - wlr_surface_for_each_surface(pSurface->surface->surface(), renderSurface, &renderdata); + renderdata.surface->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { @@ -966,17 +981,15 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB } } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); - if (pSurface->current.viewport.has_src) { + if (pSurface->current.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 - wlr_fbox bufferSource; - wlr_surface_get_buffer_source_box(pSurface, &bufferSource); - - Vector2D bufferSize = Vector2D(pSurface->buffer->texture->width, pSurface->buffer->texture->height); + Vector2D bufferSize = pSurface->current.buffer->size; + auto bufferSource = pSurface->current.viewport.source; // calculate UV for the basic src_box. Assume dest == size. Scale to dest later uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y); @@ -991,8 +1004,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa if (projSize != Vector2D{} && fixMisalignedFSV1) { // instead of nearest_neighbor (we will repeat / skip) // just cut off / expand surface - const Vector2D PIXELASUV = Vector2D{1, 1} / Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height}; - const Vector2D MISALIGNMENT = Vector2D{pSurface->buffer->texture->width, pSurface->buffer->texture->height} - projSize; + const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.buffer->size; + const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize; if (MISALIGNMENT != Vector2D{}) uvBR -= MISALIGNMENT * PIXELASUV; } @@ -1013,10 +1026,10 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // ignore X and Y, adjust uv if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { - const auto XPERC = (double)geom.x / (double)pSurface->current.width; - const auto YPERC = (double)geom.y / (double)pSurface->current.height; - const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.width; - const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.height; + const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; + const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; + const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; + const auto HPERC = (double)(geom.y + geom.height) / (double)pSurface->current.size.y; const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); @@ -1025,8 +1038,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa // TODO: make this passed to the func. Might break in the future. auto maxSize = pWindow->m_vRealSize.value(); - if (pWindow->m_pWLSurface.small() && !pWindow->m_pWLSurface.m_bFillIgnoreSmall) - maxSize = pWindow->m_pWLSurface.getViewporterCorrectedSize(); + if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) + maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); if (geom.width > maxSize.x) uvBR.x = uvBR.x * (maxSize.x / geom.width); @@ -1048,53 +1061,51 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, wlr_surface* pSurfa } } -void countSubsurfacesIter(wlr_surface* pSurface, int x, int y, void* data) { - *(int*)data += 1; -} - bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) { - if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - return false; // do not DS if this monitor is being mirrored. Will break the functionality. + return false; // FIXME: fix when we move to new lib for backend. - if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - return false; + // if (!pMonitor->mirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) + // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - const auto PCANDIDATE = pMonitor->solitaryClient.lock(); + // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) + // return false; - if (!PCANDIDATE) - return false; + // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + // if (!PCANDIDATE) + // return false; - if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - return false; + // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - // finally, we should be GTG. - wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); + // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) + // return false; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - return false; + // // finally, we should be GTG. + // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(PSURFACE, &now); - auto FEEDBACK = makeShared(PSURFACE); - FEEDBACK->attachMonitor(pMonitor); - FEEDBACK->presented(); - FEEDBACK->setPresentationType(true); - PROTO::presentation->queueData(FEEDBACK); + // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) + // return false; - if (pMonitor->state.commit()) { - if (m_pLastScanout.expired()) { - m_pLastScanout = PCANDIDATE; - Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - } - } else { - m_pLastScanout.reset(); - return false; - } + // timespec now; + // clock_gettime(CLOCK_MONOTONIC, &now); + // PSURFACE->frame(&now); + // auto FEEDBACK = makeShared(PSURFACE); + // FEEDBACK->attachMonitor(pMonitor); + // FEEDBACK->presented(); + // FEEDBACK->setPresentationType(true); + // PROTO::presentation->queueData(FEEDBACK); - return true; + // if (pMonitor->state.commit()) { + // if (m_pLastScanout.expired()) { + // m_pLastScanout = PCANDIDATE; + // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + // } + // } else { + // m_pLastScanout.reset(); + // return false; + // } + + // return true; } void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { @@ -1430,53 +1441,52 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { for (auto& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface.wlr()) + if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; if (!shouldRenderWindow(w, pMonitor)) continue; - wlr_surface_for_each_surface( - w->m_pWLSurface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + w->m_pWLSurface->resource()->breadthfirst([now](SP r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { for (auto& ls : lsl) { - if (ls->fadingOut || !ls->surface.wlr()) + if (ls->fadingOut || !ls->surface->resource()) continue; - wlr_surface_for_each_surface( - ls->surface.wlr(), [](wlr_surface* s, int x, int y, void* data) { wlr_surface_send_frame_done(s, (timespec*)data); }, now); + ls->surface->resource()->breadthfirst([now](SP r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } } } void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - return; + // FIXME: fix when moved to new impl + // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) + // return; - if (!pWindow->m_bIsFullscreen) { - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), nullptr); - Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - return; - } + // if (!pWindow->m_bIsFullscreen) { + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); + // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); + // return; + // } - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - .main_renderer = g_pCompositor->m_sWLRRenderer, - .scanout_primary_output = PMONITOR->output, - }; + // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { + // .main_renderer = g_pCompositor->m_sWLRRenderer, + // .scanout_primary_output = PMONITOR->output, + // }; - wlr_linux_dmabuf_feedback_v1 feedback = {0}; + // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - return; + // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) + // return; - wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface.wlr(), &feedback); - wlr_linux_dmabuf_feedback_v1_finish(&feedback); + // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); + // wlr_linux_dmabuf_feedback_v1_finish(&feedback); - Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); } // taken from Sway. @@ -1662,26 +1672,25 @@ void CHyprRenderer::arrangeLayersForMonitor(const int& monitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitor); } -void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y, double scale) { +void CHyprRenderer::damageSurface(SP pSurface, double x, double y, double scale) { if (!pSurface) return; // wut? if (g_pCompositor->m_bUnsafeState) return; - const auto WLSURF = CWLSurface::surfaceFromWlr(pSurface); + const auto WLSURF = CWLSurface::fromResource(pSurface); CRegion damageBox = WLSURF ? WLSURF->logicalDamage() : CRegion{}; if (!WLSURF) { Debug::log(ERR, "BUG THIS: No CWLSurface for surface in damageSurface!!!"); - wlr_surface_get_effective_damage(pSurface, damageBox.pixman()); + return; } if (scale != 1.0) damageBox.scale(scale); // schedule frame events - if (!wl_list_empty(&pSurface->current.frame_callback_list)) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); if (damageBox.empty()) return; @@ -1836,7 +1845,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->onDisconnect(); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } @@ -2242,12 +2250,11 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr); pMonitor->events.modeChanged.emit(); - pMonitor->updateGlobal(); return true; } -void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) { +void CHyprRenderer::setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force) { m_bCursorHasSurface = surf; m_sLastCursorData.name = ""; @@ -2464,8 +2471,8 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { continue; // TODO: cache maybe? - CRegion opaque = &ls->layerSurface->surface->opaque_region; - CBox lsbox = {0, 0, ls->layerSurface->surface->current.buffer_width, ls->layerSurface->surface->current.buffer_height}; + CRegion opaque = ls->layerSurface->surface->current.opaque; + CBox lsbox = {{}, ls->layerSurface->surface->current.size}; opaque.invert(lsbox); if (!opaque.empty()) @@ -2544,6 +2551,15 @@ CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32 return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); } +CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { + auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); + + if (it != m_vRenderbuffers.end()) + return it->get(); + + return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); +} + void CHyprRenderer::makeEGLCurrent() { if (!g_pCompositor) return; @@ -2556,7 +2572,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2586,10 +2602,13 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return false; } } else - m_pCurrentWlrBuffer = wlr_buffer_lock(buffer); + m_pCurrentHLBuffer = buffer; try { - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + if (m_pCurrentWlrBuffer) + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); + else + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); wlr_buffer_unlock(m_pCurrentWlrBuffer); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index da38fed2..f88bfebf 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -12,6 +12,7 @@ struct SMonitorRule; class CWorkspace; class CWindow; class CInputPopup; +class IWLBuffer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -44,7 +45,7 @@ class CHyprRenderer { void renderMonitor(CMonitor* pMonitor); void arrangeLayersForMonitor(const int&); - void damageSurface(wlr_surface*, double, double, double scale = 1.0); + void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*); void damageBox(const int& x, const int& y, const int& w, const int& h); @@ -57,14 +58,14 @@ class CHyprRenderer { void ensureCursorRenderingMode(); bool shouldRenderCursor(); void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, wlr_surface*, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void calculateUVForSurface(PHLWINDOW, SP, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); std::tuple getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods bool canSkipBackBufferClear(CMonitor* pMonitor); void recheckSolitaryForMonitor(CMonitor* pMonitor); - void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false); + void setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); CRenderbuffer* getCurrentRBO(); @@ -74,7 +75,7 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); void endRender(); bool m_bBlockSurfaceFeedback = false; @@ -98,10 +99,10 @@ class CHyprRenderer { CTimer m_tRenderTimer; struct { - int hotspotX; - int hotspotY; - std::optional surf = nullptr; - std::string name; + int hotspotX; + int hotspotY; + std::optional> surf; + std::string name; } m_sLastCursorData; private: @@ -121,6 +122,7 @@ class CHyprRenderer { bool m_bCursorHasSurface = false; CRenderbuffer* m_pCurrentRenderbuffer = nullptr; wlr_buffer* m_pCurrentWlrBuffer = nullptr; + WP m_pCurrentHLBuffer = {}; eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; bool m_bNvidia = false; @@ -132,6 +134,7 @@ class CHyprRenderer { } m_sCursorHiddenConditions; CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt); + CRenderbuffer* getOrCreateRenderbuffer(SP buffer, uint32_t fmt); std::vector> m_vRenderbuffers; friend class CHyprOpenGLImpl; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 1820d0fb..aef8e4ac 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -1,16 +1,54 @@ #include "Texture.hpp" +#include "Renderer.hpp" +#include "../Compositor.hpp" +#include "../protocols/types/Buffer.hpp" +#include "../helpers/Format.hpp" CTexture::CTexture() { // naffin' } +CTexture::~CTexture() { + if (m_bNonOwning) + return; + + g_pHyprRenderer->makeEGLCurrent(); + destroyTexture(); +} + +CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + m_iType = format->withAlpha ? TEXTURE_RGBA : TEXTURE_RGBX; + m_vSize = size_; + allocate(); + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels)); + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + CTexture::CTexture(wlr_texture* tex) { RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!"); wlr_gles2_texture_attribs attrs; wlr_gles2_texture_get_attribs(tex, &attrs); - m_iTarget = attrs.target; - m_iTexID = attrs.tex; + m_iTarget = attrs.target; + m_iTexID = attrs.tex; + m_bNonOwning = true; if (m_iTarget == GL_TEXTURE_2D) m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX; @@ -20,14 +58,72 @@ CTexture::CTexture(wlr_texture* tex) { m_vSize = Vector2D(tex->width, tex->height); } +CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { + if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) { + Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); + return; + } + + m_iTarget = GL_TEXTURE_2D; + m_iType = TEXTURE_RGBA; + m_vSize = attrs.size; + m_iType = FormatUtils::isFormatOpaque(attrs.format) ? TEXTURE_RGBX : TEXTURE_RGBA; + allocate(); + m_pEglImage = image; + + GLCALL(glBindTexture(GL_TEXTURE_2D, m_iTexID)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + GLCALL(g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES(m_iTarget, image)); + GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); +} + +void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) { + g_pHyprRenderer->makeEGLCurrent(); + + const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); + ASSERT(format); + + glBindTexture(GL_TEXTURE_2D, m_iTexID); + + auto rects = damage.copy().intersect(CBox{{}, m_vSize}).getRects(); + +#ifndef GLES2 + if (format->flipRB) { + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE)); + GLCALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)); + } +#endif + + for (auto& rect : rects) { + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); + + int width = rect.x2 - rect.x1; + int height = rect.y2 - rect.y1; + GLCALL(glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x1, rect.y1, width, height, format->glFormat, format->glType, pixels)); + } + + GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0)); + GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void CTexture::destroyTexture() { if (m_iTexID) { - glDeleteTextures(1, &m_iTexID); + GLCALL(glDeleteTextures(1, &m_iTexID)); m_iTexID = 0; } + + if (m_pEglImage) + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage); + m_pEglImage = nullptr; } void CTexture::allocate() { if (!m_iTexID) - glGenTextures(1, &m_iTexID); -} \ No newline at end of file + GLCALL(glGenTextures(1, &m_iTexID)); +} diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index 93a6aa5f..fa1ca4fe 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -2,6 +2,10 @@ #include "../defines.hpp" +class IWLBuffer; +struct SDMABUFAttrs; +class CRegion; + enum TEXTURETYPE { TEXTURE_INVALID, // Invalid TEXTURE_RGBA, // 4 channels @@ -12,13 +16,27 @@ enum TEXTURETYPE { class CTexture { public: CTexture(); + + CTexture(CTexture&) = delete; + CTexture(CTexture&&) = delete; + CTexture(const CTexture&&) = delete; + CTexture(const CTexture&) = delete; + + CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); CTexture(wlr_texture*); + // this ctor takes ownership of the eglImage. + CTexture(const SDMABUFAttrs&, void* image); + ~CTexture(); + void destroyTexture(); void allocate(); + void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); TEXTURETYPE m_iType = TEXTURE_RGBA; GLenum m_iTarget = GL_TEXTURE_2D; GLuint m_iTexID = 0; Vector2D m_vSize; + void* m_pEglImage = nullptr; + bool m_bNonOwning = false; // wlr }; \ No newline at end of file diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 04f69aaa..d96f2c3c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -6,23 +6,23 @@ #include // shared things to conserve VRAM -static CTexture m_tGradientActive; -static CTexture m_tGradientInactive; -static CTexture m_tGradientLockedActive; -static CTexture m_tGradientLockedInactive; +static SP m_tGradientActive = makeShared(); +static SP m_tGradientInactive = makeShared(); +static SP m_tGradientLockedActive = makeShared(); +static SP m_tGradientLockedInactive = makeShared(); -constexpr int BAR_INDICATOR_HEIGHT = 3; -constexpr int BAR_PADDING_OUTER_VERT = 2; -constexpr int BAR_PADDING_OUTER_HORZ = 2; -constexpr int BAR_TEXT_PAD = 2; -constexpr int BAR_HORIZONTAL_PADDING = 2; +constexpr int BAR_INDICATOR_HEIGHT = 3; +constexpr int BAR_PADDING_OUTER_VERT = 2; +constexpr int BAR_PADDING_OUTER_HORZ = 2; +constexpr int BAR_TEXT_PAD = 2; +constexpr int BAR_HORIZONTAL_PADDING = 2; CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) { static auto PGRADIENTS = CConfigValue("group:groupbar:enabled"); static auto PENABLED = CConfigValue("group:groupbar:gradients"); m_pWindow = pWindow; - if (m_tGradientActive.m_iTexID == 0 && *PENABLED && *PGRADIENTS) + if (m_tGradientActive->m_iTexID == 0 && *PENABLED && *PGRADIENTS) refreshGroupBarGradients(); } @@ -157,10 +157,9 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { rect.scale(pMonitor->scale); if (*PGRADIENTS) { - const auto& GRADIENTTEX = - (m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX.m_iTexID != 0) + const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + if (GRADIENTTEX->m_iTexID != 0) g_pHyprOpenGL->renderTexture(GRADIENTTEX, &rect, 1.0); } @@ -204,6 +203,7 @@ void CHyprGroupBarDecoration::invalidateTextures() { } CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { + tex = makeShared(); szContent = pWindow->m_szTitle; pWindowOwner = pWindow; const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); @@ -254,8 +254,8 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -272,10 +272,10 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float } CTitleTex::~CTitleTex() { - tex.destroyTexture(); + tex->destroyTexture(); } -void renderGradientTo(CTexture& tex, CGradientValueData* grad) { +void renderGradientTo(SP tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) return; @@ -308,8 +308,8 @@ void renderGradientTo(CTexture& tex, CGradientValueData* grad) { // copy the data to an OpenGL texture we have const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - tex.allocate(); - glBindTexture(GL_TEXTURE_2D, tex.m_iTexID); + tex->allocate(); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -340,11 +340,11 @@ void refreshGroupBarGradients() { g_pHyprRenderer->makeEGLCurrent(); - if (m_tGradientActive.m_iTexID != 0) { - m_tGradientActive.destroyTexture(); - m_tGradientInactive.destroyTexture(); - m_tGradientLockedActive.destroyTexture(); - m_tGradientLockedInactive.destroyTexture(); + if (m_tGradientActive->m_iTexID != 0) { + m_tGradientActive->destroyTexture(); + m_tGradientInactive->destroyTexture(); + m_tGradientLockedActive->destroyTexture(); + m_tGradientLockedInactive->destroyTexture(); } if (!*PENABLED || !*PGRADIENTS) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index e3f553c5..64870d45 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -12,7 +12,7 @@ class CTitleTex { CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); ~CTitleTex(); - CTexture tex; + SP tex; std::string szContent; PHLWINDOWREF pWindowOwner; }; diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 8994e975..07cac832 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -1,6 +1,7 @@ #include "XSurface.hpp" #include "XWayland.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/core/Compositor.hpp" #ifndef NO_XWAYLAND @@ -44,46 +45,41 @@ CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID } void CXWaylandSurface::ensureListeners() { - bool connected = hyprListener_surfaceDestroy.isConnected(); + bool connected = listeners.destroySurface; if (connected && !surface) { - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); } else if (!connected && surface) { - hyprListener_surfaceDestroy.initCallback( - &surface->events.destroy, - [this](void* owner, void* data) { - if (mapped) - unmap(); + listeners.destroySurface = surface->events.destroy.registerListener([this](std::any d) { + if (mapped) + unmap(); - surface = nullptr; - hyprListener_surfaceDestroy.removeCallback(); - hyprListener_surfaceCommit.removeCallback(); - events.resourceChange.emit(); - }, - nullptr, "CXWaylandSurface"); - hyprListener_surfaceCommit.initCallback( - &surface->events.commit, - [this](void* owner, void* data) { - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0 && !mapped) { - map(); - return; - } + surface.reset(); + listeners.destroySurface.reset(); + listeners.commitSurface.reset(); + events.resourceChange.emit(); + }); - if (surface->pending.buffer_width <= 0 && surface->pending.buffer_height <= 0 && mapped) { - unmap(); - return; - } + listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { + if (surface->pending.buffer && !mapped) { + map(); + return; + } - events.commit.emit(); - }, - nullptr, "CXWaylandSurface"); + if (!surface->pending.buffer && mapped) { + unmap(); + return; + } + + events.commit.emit(); + }); } if (resource) { listeners.destroyResource = resource->events.destroy.registerListener([this](std::any d) { unmap(); - surface = nullptr; + surface.reset(); events.resourceChange.emit(); }); } @@ -99,7 +95,7 @@ void CXWaylandSurface::map() { g_pXWayland->pWM->mappedSurfacesStacking.emplace_back(self); mapped = true; - wlr_surface_map(surface); + surface->map(); Debug::log(LOG, "XWayland surface {:x} mapping", (uintptr_t)this); @@ -118,7 +114,7 @@ void CXWaylandSurface::unmap() { std::erase(g_pXWayland->pWM->mappedSurfacesStacking, self); mapped = false; - wlr_surface_unmap(surface); + surface->unmap(); Debug::log(LOG, "XWayland surface {:x} unmapping", (uintptr_t)this); @@ -136,7 +132,7 @@ void CXWaylandSurface::considerMap() { return; } - if (surface->pending.buffer_width > 0 && surface->pending.buffer_height > 0) { + if (surface->pending.buffer) { Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer"); map(); return; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 73cb89a5..0cdac1d5 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -5,7 +5,7 @@ #include "../helpers/Box.hpp" #include -struct wlr_surface; +class CWLSurfaceResource; class CXWaylandSurfaceResource; #ifdef NO_XWAYLAND @@ -39,7 +39,7 @@ typedef struct { class CXWaylandSurface { public: - wlr_surface* surface = nullptr; + WP surface; WP resource; struct { @@ -109,11 +109,10 @@ class CXWaylandSurface { void considerMap(); void setWithdrawn(bool withdrawn); - DYNLISTENER(surfaceDestroy); - DYNLISTENER(surfaceCommit); - struct { CHyprSignalListener destroyResource; + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; } listeners; friend class CXWM; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 5dfd4839..7af1d506 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -6,6 +6,7 @@ #include #include "../Compositor.hpp" #include "../protocols/XWaylandShell.hpp" +#include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" #include "../protocols/core/Seat.hpp" #include @@ -296,7 +297,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { auto id = e->data.data32[0]; auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id); if (resource) { - auto wlrSurface = wlr_surface_from_resource(resource); + auto wlrSurface = CWLSurfaceResource::fromResource(resource); associate(XSURF, wlrSurface); } } else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) { @@ -318,7 +319,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { if (res->serial != XSURF->wlSerial || !XSURF->wlSerial) continue; - associate(XSURF, res->surface); + associate(XSURF, res->surface.lock()); break; } @@ -827,9 +828,7 @@ CXWM::CXWM() { initSelection(); - hyprListener_newSurface.initCallback( - &g_pCompositor->m_sWLRCompositor->events.new_surface, [this](void* owner, void* data) { onNewSurface((wlr_surface*)data); }, nullptr, "XWM"); - + listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast>(d)); }); listeners.newXShellSurface = PROTO::xwaylandShell->events.newSurface.registerListener([this](std::any d) { onNewResource(std::any_cast>(d)); }); createWMWindow(); @@ -903,13 +902,13 @@ void CXWM::sendState(SP surf) { xcb_change_property(connection, XCB_PROP_MODE_REPLACE, surf->xID, HYPRATOMS["_NET_WM_STATE"], XCB_ATOM_ATOM, 32, props.size(), props.data()); } -void CXWM::onNewSurface(wlr_surface* surf) { - if (wl_resource_get_client(surf->resource) != g_pXWayland->pServer->xwaylandClient) +void CXWM::onNewSurface(SP surf) { + if (surf->client() != g_pXWayland->pServer->xwaylandClient) return; Debug::log(LOG, "[xwm] New XWayland surface at {:x}", (uintptr_t)surf); - const auto WLID = wl_resource_get_id(surf->resource); + const auto WLID = surf->id(); for (auto& sr : surfaces) { if (sr->surface || sr->wlID != WLID) @@ -932,7 +931,7 @@ void CXWM::onNewResource(SP resource) { if (surf->resource || surf->wlSerial != resource->serial) continue; - associate(surf, resource->surface); + associate(surf, resource->surface.lock()); break; } } @@ -955,7 +954,7 @@ void CXWM::readWindowData(SP surf) { } } -void CXWM::associate(SP surf, wlr_surface* wlSurf) { +void CXWM::associate(SP surf, SP wlSurf) { if (surf->surface) return; @@ -981,7 +980,7 @@ void CXWM::dissociate(SP surf) { if (surf->mapped) surf->unmap(); - surf->surface = nullptr; + surf->surface.reset(); surf->events.resourceChange.emit(); Debug::log(LOG, "Dissociate for {:x}", (uintptr_t)surf.get()); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 1d695a15..bdf4fac2 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -73,7 +73,7 @@ class CXWM { void createWMWindow(); void initSelection(); - void onNewSurface(wlr_surface* surf); + void onNewSurface(SP surf); void onNewResource(SP resource); void setActiveWindow(xcb_window_t window); @@ -87,7 +87,7 @@ class CXWM { SP windowForXID(xcb_window_t wid); void readWindowData(SP surf); - void associate(SP surf, wlr_surface* wlSurf); + void associate(SP surf, SP wlSurf); void dissociate(SP surf); void updateClientList(); @@ -147,9 +147,8 @@ class CXWM { SXSelection clipboard; - DYNLISTENER(newSurface); - struct { + CHyprSignalListener newWLSurface; CHyprSignalListener newXShellSurface; } listeners; From 5b6d54cae0e3355d71d86853a5a1350aa63527bb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 8 Jun 2024 10:57:37 +0200 Subject: [PATCH 0170/2393] xdg_shell: ignore outdated ack_configure events --- src/protocols/XDGShell.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 97de49f6..191a1124 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -403,8 +403,10 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPsetAckConfigure([this](CXdgSurface* r, uint32_t serial) { + if (serial < lastConfigureSerial) + return; + lastConfigureSerial = serial; events.ack.emit(serial); - ; // TODO: verify it }); resource->setSetWindowGeometry([this](CXdgSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { From 10e02076b183f508ef72198366d53902fe0d9098 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 8 Jun 2024 11:50:44 +0200 Subject: [PATCH 0171/2393] wayland: fix invalid wl_output_mode dimensions sent --- src/protocols/core/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 3778e453..a1b0c7b0 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -52,7 +52,7 @@ void CWLOutputResource::updateState() { if (resource->version() >= 2) resource->sendScale(std::ceil(monitor->scale)); - resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecSize.x, monitor->vecSize.y, monitor->refreshRate * 1000.0); + resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); if (resource->version() >= 2) resource->sendDone(); From 211353dc34b8f0fa17fc1e4d1d5f04d6fe1910e5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 8 Jun 2024 12:03:47 +0200 Subject: [PATCH 0172/2393] core: verify surface roles on creation of objects --- src/protocols/LayerShell.cpp | 22 ++++++++++++++++++++-- src/protocols/LayerShell.hpp | 10 ++++++---- src/protocols/XDGShell.cpp | 22 ++++++++++++++++++++-- src/protocols/XDGShell.hpp | 5 ++++- src/protocols/core/Subcompositor.cpp | 5 +++++ 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 8fa6dd27..d4b105cb 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -159,6 +159,12 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPresetRole(); +} + +eSurfaceRole CLayerShellResource::role() { + return SURFACE_ROLE_LAYER_SHELL; } bool CLayerShellResource::good() { @@ -207,8 +213,19 @@ void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { const auto CLIENT = pMgr->client(); const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.get() : nullptr; - const auto RESOURCE = m_vLayers.emplace_back( - makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surface), namespace_, PMONITOR, layer)); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + pMgr->error(-1, "Invalid surface"); + return; + } + + if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + pMgr->error(-1, "Surface already has a different role"); + return; + } + + const auto RESOURCE = m_vLayers.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), SURF, namespace_, PMONITOR, layer)); if (!RESOURCE->good()) { pMgr->noMemory(); @@ -216,6 +233,7 @@ void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id return; } + SURF->role = RESOURCE; g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE)); LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get()); diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index f348e86b..7fa14447 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -8,18 +8,20 @@ #include "wlr-layer-shell-unstable-v1.hpp" #include "../helpers/Vector2D.hpp" #include "../helpers/signal/Signal.hpp" +#include "types/SurfaceRole.hpp" class CMonitor; class CWLSurfaceResource; -class CLayerShellResource { +class CLayerShellResource : public ISurfaceRole { public: CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); ~CLayerShellResource(); - bool good(); - void configure(const Vector2D& size); - void sendClosed(); + bool good(); + void configure(const Vector2D& size); + void sendClosed(); + virtual eSurfaceRole role(); enum eCommittedState { STATE_SIZE = (1 << 0), diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 191a1124..dcbc6162 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -419,6 +419,12 @@ CXDGSurfaceResource::~CXDGSurfaceResource() { events.destroy.emit(); if (configureSource) wl_event_source_remove(configureSource); + if (surface) + surface->resetRole(); +} + +eSurfaceRole CXDGSurfaceResource::role() { + return SURFACE_ROLE_XDG_SHELL; } bool CXDGSurfaceResource::good() { @@ -646,8 +652,19 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { }); resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) { - const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back( - makeShared(makeShared(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surf))); + auto SURF = CWLSurfaceResource::fromResource(surf); + + if (!SURF) { + r->error(-1, "Invalid surface passed"); + return; + } + + if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + r->error(-1, "Surface already has a different role"); + return; + } + + const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock(), SURF)); if (!RESOURCE->good()) { r->noMemory(); @@ -656,6 +673,7 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { } RESOURCE->self = RESOURCE; + SURF->role = RESOURCE; surfaces.emplace_back(RESOURCE); diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index fe2517a2..d60db86a 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -9,6 +9,7 @@ #include "../helpers/Vector2D.hpp" #include "../helpers/Box.hpp" #include "../helpers/signal/Signal.hpp" +#include "types/SurfaceRole.hpp" class CXDGWMBase; class CXDGPositionerResource; @@ -137,13 +138,15 @@ class CXDGToplevelResource { void applyState(); }; -class CXDGSurfaceResource { +class CXDGSurfaceResource : public ISurfaceRole { public: CXDGSurfaceResource(SP resource_, SP owner_, SP surface_); ~CXDGSurfaceResource(); static SP fromResource(wl_resource*); + virtual eSurfaceRole role(); + bool good(); WP owner; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 213fdc42..d407636c 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -133,6 +133,11 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource return; } + if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + r->error(-1, "Surface already has a different role"); + return; + } + SP t1Parent = nullptr; if (PARENT->role->role() == SURFACE_ROLE_SUBSURFACE) { From 3fb079a2a365976b846644571322288d91a1ebc2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 8 Jun 2024 16:16:43 +0200 Subject: [PATCH 0173/2393] renderer: allow custom uv for surface no-blur passes --- src/render/Renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2a6cbb3b..17f91d48 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -208,12 +208,12 @@ static void renderSurface(SP surface, int x, int y, void* da if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } else { if (RDATA->blur && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { From 7789caad39f9c19553fe8baf779c0196938f645a Mon Sep 17 00:00:00 2001 From: memchr <118117622+memchr@users.noreply.github.com> Date: Sat, 8 Jun 2024 14:25:01 +0000 Subject: [PATCH 0174/2393] build: include missing header: "debug/Log.hpp" in Format.cpp (#6365) --- src/helpers/Format.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 3d6b7cc3..343440b4 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -1,6 +1,7 @@ #include "Format.hpp" #include #include "../includes.hpp" +#include "debug/Log.hpp" /* DRM formats are LE, while OGL is BE. The two primary formats From d724556b7ece61a5ff4eb764e6f47ec8089439bf Mon Sep 17 00:00:00 2001 From: void0red <30990023+void0red@users.noreply.github.com> Date: Sat, 8 Jun 2024 23:15:57 +0800 Subject: [PATCH 0175/2393] input: fix virtual devices not updating capabilities (#6366) Signed-off-by: void0red --- src/managers/input/InputManager.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index c12ac389..ff10f303 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -52,12 +52,16 @@ CInputManager::CInputManager() { g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name); }); - m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); }); - m_sListeners.newVirtualKeyboard = - PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { this->newVirtualKeyboard(std::any_cast>(data)); }); - m_sListeners.newVirtualMouse = - PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { this->newVirtualMouse(std::any_cast>(data)); }); - m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); }); + m_sListeners.newIdleInhibitor = PROTO::idleInhibit->events.newIdleInhibitor.registerListener([this](std::any data) { this->newIdleInhibitor(data); }); + m_sListeners.newVirtualKeyboard = PROTO::virtualKeyboard->events.newKeyboard.registerListener([this](std::any data) { + this->newVirtualKeyboard(std::any_cast>(data)); + updateCapabilities(); + }); + m_sListeners.newVirtualMouse = PROTO::virtualPointer->events.newPointer.registerListener([this](std::any data) { + this->newVirtualMouse(std::any_cast>(data)); + updateCapabilities(); + }); + m_sListeners.setCursor = g_pSeatManager->events.setCursor.registerListener([this](std::any d) { this->processMouseRequest(d); }); m_sCursorSurfaceInfo.wlSurface = CWLSurface::create(); } From 9994b73ad0af5c9ba5fc4058234cea77d0a1ddb1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 8 Jun 2024 17:27:50 +0200 Subject: [PATCH 0176/2393] buffer: track asynchronous buffers and don't release them until unref synchronous buffers are read instantly and we can release them, but asynchronous ones have to be locked until they are unref'd from .current to avoid reading from a buffer after .release() --- src/protocols/core/Compositor.cpp | 16 ++++++++++++---- src/protocols/core/Shm.cpp | 4 ++++ src/protocols/core/Shm.hpp | 1 + src/protocols/types/Buffer.hpp | 1 + src/protocols/types/DMABuffer.cpp | 4 ++++ src/protocols/types/DMABuffer.hpp | 1 + 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index e8503ae8..db6e3258 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -107,6 +107,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.damage.intersect(CBox{{}, pending.size}); + auto previousBuffer = current.buffer; CRegion previousBufferDamage = accumulateCurrentBufferDamage(); current = pending; @@ -119,11 +120,12 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. - // release the buffer, glTexImage2D is synchronous (as in, data is consumed after the call returns) + // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - // for dma buffers, this doesn't matter. - current.buffer->sendRelease(); - bufferReleased = true; + if (current.buffer->isSynchronous()) { + current.buffer->sendRelease(); + bufferReleased = true; + } } // TODO: we should _accumulate_ and not replace above if sync @@ -146,6 +148,12 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso }, nullptr); } + + // for async buffers, we can only release the buffer once we are unrefing it from current. + if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { + previousBuffer->sendRelease(); + bufferReleased = true; + } }); resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 0c01cf80..ce7d3a61 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -49,6 +49,10 @@ eBufferType CWLSHMBuffer::type() { return BUFFER_TYPE_SHM; } +bool CWLSHMBuffer::isSynchronous() { + return true; +} + SSHMAttrs CWLSHMBuffer::shm() { SSHMAttrs attrs; attrs.success = true; diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 862ea112..687e2031 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -37,6 +37,7 @@ class CWLSHMBuffer : public IWLBuffer { virtual eBufferCapability caps(); virtual eBufferType type(); virtual void update(const CRegion& damage); + virtual bool isSynchronous(); virtual SSHMAttrs shm(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index c9902f8d..9999a4e9 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -49,6 +49,7 @@ class IWLBuffer { virtual eBufferCapability caps() = 0; virtual eBufferType type() = 0; virtual void update(const CRegion& damage) = 0; + virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu virtual SDMABUFAttrs dmabuf(); virtual SSHMAttrs shm(); virtual std::tuple beginDataPtr(uint32_t flags); diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 930e71e6..f26328e9 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -43,6 +43,10 @@ void CDMABuffer::update(const CRegion& damage) { ; } +bool CDMABuffer::isSynchronous() { + return false; +} + SDMABUFAttrs CDMABuffer::dmabuf() { return attrs; } diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp index e06b5791..dac89493 100644 --- a/src/protocols/types/DMABuffer.hpp +++ b/src/protocols/types/DMABuffer.hpp @@ -9,6 +9,7 @@ class CDMABuffer : public IWLBuffer { virtual eBufferCapability caps(); virtual eBufferType type(); + virtual bool isSynchronous(); virtual void update(const CRegion& damage); virtual SDMABUFAttrs dmabuf(); virtual std::tuple beginDataPtr(uint32_t flags); From c62f0015aed0c0918281b1ce17def00d7025041b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Jun 2024 09:42:14 +0200 Subject: [PATCH 0177/2393] hyprpm: print and fail on missing packages during configure instead of failing later with something like exit code 2, print out what's missing --- hyprpm/src/core/PluginManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index dc3bc548..fb338d25 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -495,6 +495,16 @@ bool CPluginManager::updateHeaders(bool force) { if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); + if (ret.contains("required packages were not found")) { + // missing deps, let the user know. + std::string missing = ret.substr(ret.find("The following required packages were not found:")); + missing = missing.substr(0, missing.find("Call Stack")); + missing = missing.substr(0, missing.find_last_of('\n')); + + std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n"; + return false; + } + // le hack. Wlroots has to generate its build/include ret = execAndGet("cd " + WORKINGDIR + "/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build"); if (m_bVerbose) From bf75723f2742973d4820f3f5378dff8c99333660 Mon Sep 17 00:00:00 2001 From: Mykola Perehudov Date: Sun, 9 Jun 2024 10:43:39 +0300 Subject: [PATCH 0178/2393] helpers: fix misuse of syscalls in sd namespace (#6379) --- src/helpers/SdDaemon.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 497101e4..25e0ca3b 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -21,8 +21,8 @@ namespace Systemd { } int SdNotify(int unsetEnvironment, const char* state) { - int fd = socket(AF_UNIX, SOCK_DGRAM, 0); - if (fd == -1) + int fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (fd < 0) return -errno; constexpr char envVar[] = "NOTIFY_SOCKET"; @@ -47,12 +47,12 @@ namespace Systemd { if (unixAddr.sun_path[0] == '@') unixAddr.sun_path[0] = '\0'; - if (!connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un))) - return 1; + if (connect(fd, (const sockaddr*)&unixAddr, sizeof(struct sockaddr_un)) < 0) + return -errno; // arbitrary value which seems to be enough for s-d messages - size_t stateLen = strnlen(state, 128); - if (write(fd, state, stateLen) >= 0) + ssize_t stateLen = strnlen(state, 128); + if (write(fd, state, stateLen) == stateLen) return 1; return -errno; From 1f71d5f5c1a3fe57dadf534c8b3bcac56fa3259f Mon Sep 17 00:00:00 2001 From: DrummyFloyd Date: Sun, 9 Jun 2024 15:53:05 +0200 Subject: [PATCH 0179/2393] ci: add auto labels on PR (#6369) * ci: add auto labels * ci(labeler): add glob for src/protocols * ci: adapt to vaxerski request --- .github/labeler.yml | 83 +++++++++++++++++++++++++++++++++++ .github/workflows/labeler.yml | 12 +++++ 2 files changed, 95 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/workflows/labeler.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000..a0685fcf --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,83 @@ +assets: + - changed-files: + - any-glob-to-any-file: "assets/**" + +docs: + - changed-files: + - any-glob-to-any-file: "docs/**" + +hyprctl: + - changed-files: + - any-glob-to-any-file: "hyprctl/**" + +hyprpm: + - changed-files: + - any-glob-to-any-file: "hyprpm/**" + +nix: + - changed-files: + - any-glob-to-any-file: "nix/**" + +protocols: + - changed-files: + - any-glob-to-any-file: ["protocols/**", "src/protocols/**"] + +core: + - changed-files: + - any-glob-to-any-file: "src/**" + +config: + - changed-files: + - any-glob-to-any-file: "src/config/**" + +debug: + - changed-files: + - any-glob-to-any-file: "src/debug/**" + +desktop: + - changed-files: + - any-glob-to-any-file: "src/desktop/**" + +devices: + - changed-files: + - any-glob-to-any-file: "src/devices/**" + +events: + - changed-files: + - any-glob-to-any-file: "src/events/**" + +helpers: + - changed-files: + - any-glob-to-any-file: "src/helpers/**" + +hyprerror: + - changed-files: + - any-glob-to-any-file: "src/hyprerror/**" + +init: + - changed-files: + - any-glob-to-any-file: "src/init/**" + +layout: + - changed-files: + - any-glob-to-any-file: "src/layout/**" + +managers: + - changed-files: + - any-glob-to-any-file: "src/managers/**" + +pch: + - changed-files: + - any-glob-to-any-file: "src/pch/**" + +plugins: + - changed-files: + - any-glob-to-any-file: "src/plugins/**" + +render: + - changed-files: + - any-glob-to-any-file: "src/render/**" + +xwayland: + - changed-files: + - any-glob-to-any-file: "src/xwayland/**" diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 00000000..52474c6a --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,12 @@ +name: "Pull Request Labeler" +on: + - pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 From 4168b8c17b12b90873fab1ca73c2981b53f48bf5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Jun 2024 17:23:23 +0200 Subject: [PATCH 0180/2393] seat: fix pointer frame events not being sent correctly fixes #6384 --- src/managers/SeatManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 399ef419..862bd2b5 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -295,11 +295,8 @@ void CSeatManager::sendPointerFrame(WP pResource) { if (!pResource) return; - if (!state.pointerFocusResource) - return; - for (auto& s : seatResources) { - if (s->resource->client() != state.pointerFocusResource->client()) + if (s->resource->client() != pResource->client()) continue; for (auto& p : s->resource->pointers) { From 722b846ac5205ec3e9a2940abfefa273fa4219d4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Jun 2024 21:10:46 +0200 Subject: [PATCH 0181/2393] egl: assume implicit modifiers are available for old drivers fixes #6367 --- src/Compositor.cpp | 6 +++--- src/managers/ProtocolManager.cpp | 9 +++++++-- src/render/OpenGL.cpp | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b0456358..5c0b8eaa 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -403,6 +403,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pPointerManager = std::make_unique(); } break; case STAGE_BASICINIT: { + Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); + g_pHyprOpenGL = std::make_unique(); + Debug::log(LOG, "Creating the ProtocolManager!"); g_pProtocolManager = std::make_unique(); @@ -419,9 +422,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the InputManager!"); g_pInputManager = std::make_unique(); - Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); - g_pHyprOpenGL = std::make_unique(); - Debug::log(LOG, "Creating the HyprRenderer!"); g_pHyprRenderer = std::make_unique(); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index bd435b27..7946a3f7 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -44,6 +44,7 @@ #include "../protocols/core/Shm.hpp" #include "../helpers/Monitor.hpp" +#include "../render/Renderer.hpp" CProtocolManager::CProtocolManager() { @@ -103,8 +104,12 @@ CProtocolManager::CProtocolManager() { PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); - PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); - PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); + + if (g_pHyprOpenGL->getDRMFormats().size() > 0) { + PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); + PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); + } else + Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index d4e8faa6..406ffdd0 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -92,7 +92,7 @@ std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { } if (len <= 0) - return {}; + return {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}; // assume the driver can do linear and implicit. std::vector mods; std::vector external; @@ -190,6 +190,10 @@ void CHyprOpenGLImpl::initDRMFormats() { Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size()); + if (dmaFormats.size() == 0) + Debug::log(WARN, + "EGL: WARNING: No dmabuf formats were found, dmabuf will be disabled. This will degrade performance, but is most likely a driver issue or a very old GPU."); + drmFormats = dmaFormats; } From 121c6ac3eae1601a1498e52a9be7030ebfed242c Mon Sep 17 00:00:00 2001 From: diniamo <55629891+diniamo@users.noreply.github.com> Date: Sun, 9 Jun 2024 21:16:29 +0200 Subject: [PATCH 0182/2393] hyprctl: add --quiet flag (#6380) --- hyprctl/Strings.hpp | 3 +- hyprctl/hyprctl.bash | 36 ++++---- hyprctl/hyprctl.fish | 198 +++++++++++++++++++++--------------------- hyprctl/hyprctl.usage | 1 + hyprctl/hyprctl.zsh | 195 ++++++++++++++++++++--------------------- hyprctl/main.cpp | 48 ++++++---- 6 files changed, 248 insertions(+), 233 deletions(-) diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index 951c6a7f..76e87ecb 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -60,6 +60,7 @@ flags: --batch → Execute a batch of commands, separated by ';' --instance (-i) → use a specific instance. Can be either signature or index in hyprctl instances (0, 1, etc) + --quiet (-q) → Disable the output of hyprctl --help: Can be used to print command's arguments that did not fit into this page @@ -155,4 +156,4 @@ cmd: starting from 0 flags: - See 'hyprctl --help')#"; \ No newline at end of file + See 'hyprctl --help')#"; diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index 0b4e6b86..8386cfbc 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -2,7 +2,7 @@ _hyprctl_cmd_2 () { hyprctl monitors | grep Monitor | awk '{ print $2 }' } -_hyprctl_cmd_1 () { +_hyprctl_cmd_3 () { hyprpm list | grep "Plugin" | awk '{print $4}' } @@ -10,7 +10,7 @@ _hyprctl_cmd_0 () { hyprctl clients | grep class | awk '{print $2}' } -_hyprctl_cmd_3 () { +_hyprctl_cmd_1 () { hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } @@ -23,25 +23,25 @@ _hyprctl () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") declare -A literal_transitions - literal_transitions[0]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [108]=5 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [96]=5 [97]=2 [27]=2 [28]=14 [100]=2 [102]=5)" - literal_transitions[3]="([72]=18 [13]=2 [32]=18 [54]=18 [55]=18 [89]=18 [104]=2 [120]=2 [76]=1 [16]=2 [123]=18 [3]=1 [5]=2 [63]=18 [127]=2 [129]=18 [80]=18 [130]=18 [83]=18 [31]=18 [48]=2 [12]=2 [85]=18 [10]=18 [86]=18 [137]=18)" - literal_transitions[7]="([103]=1 [74]=2 [33]=3 [1]=2 [2]=2 [77]=2 [105]=4 [36]=2 [40]=2 [45]=2 [112]=2 [84]=6 [113]=8 [51]=2 [53]=2 [88]=9 [117]=2 [119]=2 [121]=2 [15]=2 [58]=10 [138]=10 [59]=2 [17]=11 [122]=12 [19]=2 [124]=2 [126]=2 [25]=13 [67]=2 [97]=2 [27]=2 [28]=14 [100]=2)" - literal_transitions[8]="([128]=2 [131]=2 [0]=2 [73]=2 [35]=2 [106]=2 [37]=2 [107]=2 [4]=2 [78]=2 [39]=2 [79]=2 [110]=2 [6]=2 [41]=2 [42]=2 [81]=2 [82]=2 [46]=2 [47]=2 [9]=2 [109]=2 [50]=2 [52]=2 [11]=2 [115]=2 [87]=2 [49]=2 [56]=2 [90]=2 [57]=2 [91]=2 [92]=2 [60]=2 [61]=2 [125]=2 [93]=2 [62]=2 [20]=2 [95]=2 [22]=2 [23]=2 [64]=2 [65]=2 [24]=2 [132]=2 [26]=2 [68]=2 [98]=2 [69]=2 [29]=2 [136]=2 [70]=2 [99]=2)" - literal_transitions[9]="([114]=15 [111]=16)" - literal_transitions[11]="([101]=2)" - literal_transitions[13]="([21]=1 [116]=1 [30]=1 [135]=1 [118]=1 [43]=1 [71]=1)" - literal_transitions[14]="([38]=2)" - literal_transitions[15]="([8]=2 [66]=2 [14]=2 [133]=2)" - literal_transitions[17]="([75]=19)" - literal_transitions[18]="([18]=2 [7]=2)" - literal_transitions[19]="([34]=5 [44]=5)" - literal_transitions[20]="([134]=2 [94]=2)" + literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)" + literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)" + literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)" + literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)" + literal_transitions[9]="([117]=20 [114]=16)" + literal_transitions[11]="([103]=2)" + literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)" + literal_transitions[14]="([39]=2)" + literal_transitions[15]="([138]=2 [96]=2)" + literal_transitions[17]="([18]=2 [7]=2)" + literal_transitions[18]="([76]=19)" + literal_transitions[19]="([34]=4 [45]=4)" + literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)" declare -A match_anything_transitions - match_anything_transitions=([1]=2 [0]=7 [6]=2 [20]=2 [10]=2 [2]=17 [7]=7 [12]=2 [14]=17 [16]=2 [4]=20 [11]=17) + match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18) declare -A subword_transitions local state=0 @@ -108,7 +108,7 @@ _hyprctl () { done fi declare -A commands - commands=([16]=2 [4]=3 [12]=1 [10]=0) + commands=([5]=1 [16]=2 [12]=3 [10]=0) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} local completions=() diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index 6d31b25a..2a75eb12 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -3,7 +3,7 @@ function _hyprctl_3 hyprctl monitors | grep Monitor | awk '{ print $2 }' end -function _hyprctl_2 +function _hyprctl_4 set 1 $argv[1] hyprpm list | grep "Plugin" | awk '{print $4}' end @@ -13,7 +13,7 @@ function _hyprctl_1 hyprctl clients | grep class | awk '{print $2}' end -function _hyprctl_4 +function _hyprctl_2 set 1 $argv[1] hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' end @@ -29,7 +29,7 @@ function _hyprctl set COMP_CWORD (count $COMP_WORDS) end - set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut" + set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" set --local descriptions set descriptions[1] "Focus the next window on a workspace" @@ -54,102 +54,104 @@ function _hyprctl set descriptions[31] "CONFUSED" set descriptions[34] "Set a property of a window" set descriptions[35] "Specify the Hyprland instance" - set descriptions[36] "Toggle the current window's floating state" - set descriptions[37] "Get the list of defined workspace rules" - set descriptions[38] "Move the focused window to a workspace" - set descriptions[40] "Temporarily enable or disable binds:ignore_group_lock" - set descriptions[41] "List all workspaces with their properties" - set descriptions[42] "Swap the active window with the next or previous in a group" - set descriptions[43] "Close a specified window" - set descriptions[44] "WARNING" - set descriptions[45] "Specify the Hyprland instance" - set descriptions[46] "List all registered binds" - set descriptions[47] "Move the active window in a direction or to a monitor" - set descriptions[48] "Change the split ratio" - set descriptions[50] "Prohibit the active window from becoming or being inserted into group" - set descriptions[51] "Change the workspace" - set descriptions[52] "List all current config parsing errors" - set descriptions[53] "Toggle the current active window into a group" - set descriptions[54] "Get the config option status (values)" - set descriptions[57] "Close the active window" - set descriptions[58] "Pass the key to a specified window" - set descriptions[59] "List all decorations and their info" - set descriptions[60] "List all connected keyboards and mice" - set descriptions[61] "Switch focus from current to previously focused window" - set descriptions[62] "Change the current mapping group" - set descriptions[63] "Execute a Global Shortcut using the GlobalShortcuts portal" - set descriptions[65] "Force the renderer to reload all resources and outputs" - set descriptions[66] "Move a selected window" - set descriptions[68] "Print the Hyprland version: flags, commit and branch of build" - set descriptions[69] "Set all monitors' DPMS status" - set descriptions[70] "Resize the active window" - set descriptions[71] "Move the active window into a group" - set descriptions[72] "OK" - set descriptions[74] "Set the current window's floating state to true" - set descriptions[75] "Print tail of the log" - set descriptions[78] "List all layouts available (including plugin ones)" - set descriptions[79] "Move a workspace to a monitor" - set descriptions[80] "Execute a shell command" - set descriptions[82] "Modify the window stack order of the active or specified window" - set descriptions[83] "Toggle the focused window's internal fullscreen state" - set descriptions[85] "Issue a keyword to call a config keyword dynamically" - set descriptions[88] "Pin a window" - set descriptions[89] "Allows adding/removing fake outputs to a specific backend" - set descriptions[91] "Toggle a special workspace on/off" - set descriptions[92] "Toggle the focused window's fullscreen state" - set descriptions[93] "Toggle the current window to always be opaque" - set descriptions[94] "Focus the requested workspace" - set descriptions[96] "Switch to the next window in a group" - set descriptions[97] "Output in JSON format" - set descriptions[98] "List all running Hyprland instances and their info" - set descriptions[99] "Execute a raw shell command" - set descriptions[100] "Exit the compositor with no questions asked" - set descriptions[101] "List all windows with their properties" - set descriptions[103] "Execute a batch of commands separated by ;" - set descriptions[104] "Dismiss all or up to amount of notifications" - set descriptions[106] "Set the xkb layout index for a keyboard" - set descriptions[107] "Move window doesnt switch to the workspace" - set descriptions[108] "Behave as moveintogroup" - set descriptions[109] "Refresh state after issuing the command" - set descriptions[110] "Move the focus in a direction" - set descriptions[111] "Focus the urgent window or the last window" - set descriptions[113] "Get the active workspace name and its properties" - set descriptions[114] "Issue a dispatch to call a keybind dispatcher with an arg" - set descriptions[116] "Center the active window" - set descriptions[117] "HINT" - set descriptions[118] "Interact with hyprpaper if present" - set descriptions[119] "No Icon" - set descriptions[120] "Force reload the config" - set descriptions[122] "Print system info" - set descriptions[123] "Interact with a plugin" - set descriptions[125] "Get the active window name and its properties" - set descriptions[126] "Swap the active workspaces between two monitors" - set descriptions[127] "Print the current random splash" - set descriptions[129] "Lock the focused group" - set descriptions[132] "Lock the groups" - set descriptions[133] "Move the cursor to the corner of the active window" - set descriptions[136] "INFO" - set descriptions[137] "Resize a selected window" - set descriptions[138] "On shortcut X sends shortcut Y to a specified window" - + set descriptions[36] "Disable output" + set descriptions[37] "Toggle the current window's floating state" + set descriptions[38] "Get the list of defined workspace rules" + set descriptions[39] "Move the focused window to a workspace" + set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock" + set descriptions[42] "List all workspaces with their properties" + set descriptions[43] "Swap the active window with the next or previous in a group" + set descriptions[44] "Close a specified window" + set descriptions[45] "WARNING" + set descriptions[46] "Specify the Hyprland instance" + set descriptions[47] "List all registered binds" + set descriptions[48] "Move the active window in a direction or to a monitor" + set descriptions[49] "Change the split ratio" + set descriptions[51] "Prohibit the active window from becoming or being inserted into group" + set descriptions[52] "Change the workspace" + set descriptions[53] "List all current config parsing errors" + set descriptions[54] "Toggle the current active window into a group" + set descriptions[55] "Get the config option status (values)" + set descriptions[58] "Close the active window" + set descriptions[59] "Pass the key to a specified window" + set descriptions[60] "List all decorations and their info" + set descriptions[61] "List all connected keyboards and mice" + set descriptions[62] "Switch focus from current to previously focused window" + set descriptions[63] "Change the current mapping group" + set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal" + set descriptions[66] "Force the renderer to reload all resources and outputs" + set descriptions[67] "Move a selected window" + set descriptions[69] "Print the Hyprland version: flags, commit and branch of build" + set descriptions[70] "Set all monitors' DPMS status" + set descriptions[71] "Resize the active window" + set descriptions[72] "Move the active window into a group" + set descriptions[73] "OK" + set descriptions[75] "Set the current window's floating state to true" + set descriptions[76] "Print tail of the log" + set descriptions[79] "List all layouts available (including plugin ones)" + set descriptions[80] "Move a workspace to a monitor" + set descriptions[81] "Execute a shell command" + set descriptions[83] "Modify the window stack order of the active or specified window" + set descriptions[84] "Toggle the focused window's internal fullscreen state" + set descriptions[86] "Issue a keyword to call a config keyword dynamically" + set descriptions[89] "Disable output" + set descriptions[90] "Pin a window" + set descriptions[91] "Allows adding/removing fake outputs to a specific backend" + set descriptions[93] "Toggle a special workspace on/off" + set descriptions[94] "Toggle the focused window's fullscreen state" + set descriptions[95] "Toggle the current window to always be opaque" + set descriptions[96] "Focus the requested workspace" + set descriptions[98] "Switch to the next window in a group" + set descriptions[99] "Output in JSON format" + set descriptions[100] "List all running Hyprland instances and their info" + set descriptions[101] "Execute a raw shell command" + set descriptions[102] "Exit the compositor with no questions asked" + set descriptions[103] "List all windows with their properties" + set descriptions[105] "Execute a batch of commands separated by ;" + set descriptions[106] "Dismiss all or up to amount of notifications" + set descriptions[108] "Set the xkb layout index for a keyboard" + set descriptions[109] "Move window doesnt switch to the workspace" + set descriptions[110] "Apply a tag to the window" + set descriptions[111] "Behave as moveintogroup" + set descriptions[112] "Refresh state after issuing the command" + set descriptions[113] "Move the focus in a direction" + set descriptions[114] "Focus the urgent window or the last window" + set descriptions[116] "Get the active workspace name and its properties" + set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg" + set descriptions[119] "Center the active window" + set descriptions[120] "HINT" + set descriptions[121] "Interact with hyprpaper if present" + set descriptions[122] "No Icon" + set descriptions[123] "Force reload the config" + set descriptions[125] "Print system info" + set descriptions[126] "Interact with a plugin" + set descriptions[128] "Get the active window name and its properties" + set descriptions[129] "Swap the active workspaces between two monitors" + set descriptions[130] "Print the current random splash" + set descriptions[131] "On shortcut X sends shortcut Y to a specified window" + set descriptions[133] "Lock the focused group" + set descriptions[136] "Lock the groups" + set descriptions[137] "Move the cursor to the corner of the active window" + set descriptions[140] "INFO" + set descriptions[141] "Resize a selected window" set --local literal_transitions - set literal_transitions[1] "set inputs 104 75 34 2 3 78 106 37 109 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 97 98 28 29 101 103; set tos 2 3 4 3 3 3 5 3 6 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 6 3 3 15 3 6" - set literal_transitions[4] "set inputs 73 14 33 55 56 90 105 121 77 17 124 4 6 64 128 130 81 131 84 32 49 13 86 11 87 138; set tos 19 3 19 19 19 19 3 3 2 3 19 2 3 19 3 19 19 19 19 19 3 3 19 19 19 19" - set literal_transitions[8] "set inputs 104 75 34 2 3 78 106 37 41 46 113 85 114 52 54 89 118 120 122 16 59 60 18 123 20 125 127 26 68 98 28 29 101; set tos 2 3 4 3 3 3 5 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" - set literal_transitions[9] "set inputs 129 132 1 74 36 107 38 108 5 79 40 80 111 7 42 43 82 83 47 48 10 110 51 53 12 116 88 50 57 91 58 92 93 61 62 126 94 63 21 96 23 24 65 66 25 133 27 69 99 70 30 137 71 100 138; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" - set literal_transitions[10] "set inputs 115 112; set tos 16 17" - set literal_transitions[12] "set inputs 102; set tos 3" - set literal_transitions[14] "set inputs 22 117 31 136 119 44 72; set tos 2 2 2 2 2 2 2" - set literal_transitions[15] "set inputs 39; set tos 3" - set literal_transitions[16] "set inputs 9 67 15 134; set tos 3 3 3 3" - set literal_transitions[18] "set inputs 76; set tos 20" - set literal_transitions[19] "set inputs 19 8; set tos 3 3" - set literal_transitions[20] "set inputs 35 45; set tos 6 6" - set literal_transitions[21] "set inputs 135 95; set tos 3 3" + set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5" + set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18" + set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" + set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + set literal_transitions[10] "set inputs 118 115; set tos 21 17" + set literal_transitions[12] "set inputs 104; set tos 3" + set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2" + set literal_transitions[15] "set inputs 40; set tos 3" + set literal_transitions[16] "set inputs 139 97; set tos 3 3" + set literal_transitions[18] "set inputs 19 8; set tos 3 3" + set literal_transitions[19] "set inputs 77; set tos 20" + set literal_transitions[20] "set inputs 35 46; set tos 5 5" + set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3" - set --local match_anything_transitions_from 2 1 7 21 11 3 8 13 15 17 5 12 - set --local match_anything_transitions_to 3 8 3 3 3 18 8 3 18 3 21 18 + set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12 + set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19 set --local state 1 set --local word_index 2 @@ -201,8 +203,8 @@ function _hyprctl end end - set command_states 17 5 13 11 - set command_ids 3 4 2 1 + set command_states 6 17 13 11 + set command_ids 2 3 4 1 if contains $state $command_states set --local index (contains --index $state $command_states) set --local function_id $command_ids[$index] diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index 334eefe7..64cbbb80 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -8,6 +8,7 @@ hyprctl []... | (-j) "Output in JSON format" | (-r) "Refresh state after issuing the command" | (--batch) "Execute a batch of commands separated by ;" + | (-q | --quiet) "Disable output" ; ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}}; diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index 82276778..6babd835 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -1,10 +1,8 @@ -#compdef hyprctl - _hyprctl_cmd_2 () { hyprctl monitors | grep Monitor | awk '{ print $2 }' } -_hyprctl_cmd_1 () { +_hyprctl_cmd_3 () { hyprpm list | grep "Plugin" | awk '{print $4}' } @@ -12,12 +10,12 @@ _hyprctl_cmd_0 () { hyprctl clients | grep class | awk '{print $2}' } -_hyprctl_cmd_3 () { +_hyprctl_cmd_1 () { hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } _hyprctl () { - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" "sendshortcut") + local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") local -A descriptions descriptions[1]="Focus the next window on a workspace" @@ -42,101 +40,104 @@ _hyprctl () { descriptions[31]="CONFUSED" descriptions[34]="Set a property of a window" descriptions[35]="Specify the Hyprland instance" - descriptions[36]="Toggle the current window's floating state" - descriptions[37]="Get the list of defined workspace rules" - descriptions[38]="Move the focused window to a workspace" - descriptions[40]="Temporarily enable or disable binds:ignore_group_lock" - descriptions[41]="List all workspaces with their properties" - descriptions[42]="Swap the active window with the next or previous in a group" - descriptions[43]="Close a specified window" - descriptions[44]="WARNING" - descriptions[45]="Specify the Hyprland instance" - descriptions[46]="List all registered binds" - descriptions[47]="Move the active window in a direction or to a monitor" - descriptions[48]="Change the split ratio" - descriptions[50]="Prohibit the active window from becoming or being inserted into group" - descriptions[51]="Change the workspace" - descriptions[52]="List all current config parsing errors" - descriptions[53]="Toggle the current active window into a group" - descriptions[54]="Get the config option status (values)" - descriptions[57]="Close the active window" - descriptions[58]="Pass the key to a specified window" - descriptions[59]="List all decorations and their info" - descriptions[60]="List all connected keyboards and mice" - descriptions[61]="Switch focus from current to previously focused window" - descriptions[62]="Change the current mapping group" - descriptions[63]="Execute a Global Shortcut using the GlobalShortcuts portal" - descriptions[65]="Force the renderer to reload all resources and outputs" - descriptions[66]="Move a selected window" - descriptions[68]="Print the Hyprland version: flags, commit and branch of build" - descriptions[69]="Set all monitors' DPMS status" - descriptions[70]="Resize the active window" - descriptions[71]="Move the active window into a group" - descriptions[72]="OK" - descriptions[74]="Set the current window's floating state to true" - descriptions[75]="Print tail of the log" - descriptions[78]="List all layouts available (including plugin ones)" - descriptions[79]="Move a workspace to a monitor" - descriptions[80]="Execute a shell command" - descriptions[82]="Modify the window stack order of the active or specified window" - descriptions[83]="Toggle the focused window's internal fullscreen state" - descriptions[85]="Issue a keyword to call a config keyword dynamically" - descriptions[88]="Pin a window" - descriptions[89]="Allows adding/removing fake outputs to a specific backend" - descriptions[91]="Toggle a special workspace on/off" - descriptions[92]="Toggle the focused window's fullscreen state" - descriptions[93]="Toggle the current window to always be opaque" - descriptions[94]="Focus the requested workspace" - descriptions[96]="Switch to the next window in a group" - descriptions[97]="Output in JSON format" - descriptions[98]="List all running Hyprland instances and their info" - descriptions[99]="Execute a raw shell command" - descriptions[100]="Exit the compositor with no questions asked" - descriptions[101]="List all windows with their properties" - descriptions[103]="Execute a batch of commands separated by ;" - descriptions[104]="Dismiss all or up to amount of notifications" - descriptions[106]="Set the xkb layout index for a keyboard" - descriptions[107]="Move window doesnt switch to the workspace" - descriptions[108]="Behave as moveintogroup" - descriptions[109]="Refresh state after issuing the command" - descriptions[110]="Move the focus in a direction" - descriptions[111]="Focus the urgent window or the last window" - descriptions[113]="Get the active workspace name and its properties" - descriptions[114]="Issue a dispatch to call a keybind dispatcher with an arg" - descriptions[116]="Center the active window" - descriptions[117]="HINT" - descriptions[118]="Interact with hyprpaper if present" - descriptions[119]="No Icon" - descriptions[120]="Force reload the config" - descriptions[122]="Print system info" - descriptions[123]="Interact with a plugin" - descriptions[125]="Get the active window name and its properties" - descriptions[126]="Swap the active workspaces between two monitors" - descriptions[127]="Print the current random splash" - descriptions[129]="Lock the focused group" - descriptions[132]="Lock the groups" - descriptions[133]="Move the cursor to the corner of the active window" - descriptions[136]="INFO" - descriptions[137]="Resize a selected window" - descriptions[138]="On shortcut X sends shortcut Y to a specified window" + descriptions[36]="Disable output" + descriptions[37]="Toggle the current window's floating state" + descriptions[38]="Get the list of defined workspace rules" + descriptions[39]="Move the focused window to a workspace" + descriptions[41]="Temporarily enable or disable binds:ignore_group_lock" + descriptions[42]="List all workspaces with their properties" + descriptions[43]="Swap the active window with the next or previous in a group" + descriptions[44]="Close a specified window" + descriptions[45]="WARNING" + descriptions[46]="Specify the Hyprland instance" + descriptions[47]="List all registered binds" + descriptions[48]="Move the active window in a direction or to a monitor" + descriptions[49]="Change the split ratio" + descriptions[51]="Prohibit the active window from becoming or being inserted into group" + descriptions[52]="Change the workspace" + descriptions[53]="List all current config parsing errors" + descriptions[54]="Toggle the current active window into a group" + descriptions[55]="Get the config option status (values)" + descriptions[58]="Close the active window" + descriptions[59]="Pass the key to a specified window" + descriptions[60]="List all decorations and their info" + descriptions[61]="List all connected keyboards and mice" + descriptions[62]="Switch focus from current to previously focused window" + descriptions[63]="Change the current mapping group" + descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal" + descriptions[66]="Force the renderer to reload all resources and outputs" + descriptions[67]="Move a selected window" + descriptions[69]="Print the Hyprland version: flags, commit and branch of build" + descriptions[70]="Set all monitors' DPMS status" + descriptions[71]="Resize the active window" + descriptions[72]="Move the active window into a group" + descriptions[73]="OK" + descriptions[75]="Set the current window's floating state to true" + descriptions[76]="Print tail of the log" + descriptions[79]="List all layouts available (including plugin ones)" + descriptions[80]="Move a workspace to a monitor" + descriptions[81]="Execute a shell command" + descriptions[83]="Modify the window stack order of the active or specified window" + descriptions[84]="Toggle the focused window's internal fullscreen state" + descriptions[86]="Issue a keyword to call a config keyword dynamically" + descriptions[89]="Disable output" + descriptions[90]="Pin a window" + descriptions[91]="Allows adding/removing fake outputs to a specific backend" + descriptions[93]="Toggle a special workspace on/off" + descriptions[94]="Toggle the focused window's fullscreen state" + descriptions[95]="Toggle the current window to always be opaque" + descriptions[96]="Focus the requested workspace" + descriptions[98]="Switch to the next window in a group" + descriptions[99]="Output in JSON format" + descriptions[100]="List all running Hyprland instances and their info" + descriptions[101]="Execute a raw shell command" + descriptions[102]="Exit the compositor with no questions asked" + descriptions[103]="List all windows with their properties" + descriptions[105]="Execute a batch of commands separated by ;" + descriptions[106]="Dismiss all or up to amount of notifications" + descriptions[108]="Set the xkb layout index for a keyboard" + descriptions[109]="Move window doesnt switch to the workspace" + descriptions[110]="Apply a tag to the window" + descriptions[111]="Behave as moveintogroup" + descriptions[112]="Refresh state after issuing the command" + descriptions[113]="Move the focus in a direction" + descriptions[114]="Focus the urgent window or the last window" + descriptions[116]="Get the active workspace name and its properties" + descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg" + descriptions[119]="Center the active window" + descriptions[120]="HINT" + descriptions[121]="Interact with hyprpaper if present" + descriptions[122]="No Icon" + descriptions[123]="Force reload the config" + descriptions[125]="Print system info" + descriptions[126]="Interact with a plugin" + descriptions[128]="Get the active window name and its properties" + descriptions[129]="Swap the active workspaces between two monitors" + descriptions[130]="Print the current random splash" + descriptions[131]="On shortcut X sends shortcut Y to a specified window" + descriptions[133]="Lock the focused group" + descriptions[136]="Lock the groups" + descriptions[137]="Move the cursor to the corner of the active window" + descriptions[140]="INFO" + descriptions[141]="Resize a selected window" local -A literal_transitions - literal_transitions[1]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [109]=6 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [97]=6 [98]=3 [28]=3 [29]=15 [101]=3 [103]=6)" - literal_transitions[4]="([73]=19 [14]=3 [33]=19 [55]=19 [56]=19 [90]=19 [105]=3 [121]=3 [77]=2 [17]=3 [124]=19 [4]=2 [6]=3 [64]=19 [128]=3 [130]=19 [81]=19 [131]=19 [84]=19 [32]=19 [49]=3 [13]=3 [86]=19 [11]=19 [87]=19 [138]=19)" - literal_transitions[8]="([104]=2 [75]=3 [34]=4 [2]=3 [3]=3 [78]=3 [106]=5 [37]=3 [41]=3 [46]=3 [113]=3 [85]=7 [114]=9 [52]=3 [54]=3 [89]=10 [118]=3 [120]=3 [122]=3 [16]=3 [59]=11 [60]=3 [18]=12 [123]=13 [20]=3 [125]=3 [127]=3 [26]=14 [68]=3 [98]=3 [28]=3 [29]=15 [101]=3)" - literal_transitions[9]="([129]=3 [132]=3 [1]=3 [74]=3 [36]=3 [107]=3 [38]=3 [108]=3 [5]=3 [79]=3 [40]=3 [80]=3 [111]=3 [7]=3 [42]=3 [43]=3 [82]=3 [83]=3 [47]=3 [48]=3 [10]=3 [110]=3 [51]=3 [53]=3 [12]=3 [116]=3 [88]=3 [50]=3 [57]=3 [91]=3 [58]=3 [92]=3 [93]=3 [61]=3 [62]=3 [126]=3 [94]=3 [63]=3 [21]=3 [96]=3 [23]=3 [24]=3 [65]=3 [66]=3 [25]=3 [133]=3 [27]=3 [69]=3 [99]=3 [70]=3 [30]=3 [137]=3 [71]=3 [100]=3 [138]=3)" - literal_transitions[10]="([115]=16 [112]=17)" - literal_transitions[12]="([102]=3)" - literal_transitions[14]="([22]=2 [117]=2 [31]=2 [136]=2 [119]=2 [44]=2 [72]=2)" - literal_transitions[15]="([39]=3)" - literal_transitions[16]="([9]=3 [67]=3 [15]=3 [134]=3)" - literal_transitions[18]="([76]=20)" - literal_transitions[19]="([19]=3 [8]=3)" - literal_transitions[20]="([35]=6 [45]=6)" - literal_transitions[21]="([135]=3 [95]=3)" + literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)" + literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)" + literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)" + literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)" + literal_transitions[10]="([118]=21 [115]=17)" + literal_transitions[12]="([104]=3)" + literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)" + literal_transitions[15]="([40]=3)" + literal_transitions[16]="([139]=3 [97]=3)" + literal_transitions[18]="([19]=3 [8]=3)" + literal_transitions[19]="([77]=20)" + literal_transitions[20]="([35]=5 [46]=5)" + literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)" local -A match_anything_transitions - match_anything_transitions=([2]=3 [1]=8 [7]=3 [21]=3 [11]=3 [3]=18 [8]=8 [13]=3 [15]=18 [17]=3 [5]=21 [12]=18) + match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19) declare -A subword_transitions @@ -196,7 +197,7 @@ _hyprctl () { fi done fi - local -A commands=([17]=2 [5]=3 [13]=1 [11]=0) + local -A commands=([6]=1 [17]=2 [13]=3 [11]=0) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index bdf354e7..34abe46f 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -30,6 +30,7 @@ #define PAD std::string instanceSignature; +bool quiet = false; struct SInstanceData { std::string id; @@ -39,6 +40,13 @@ struct SInstanceData { bool valid = true; }; +void log(std::string str) { + if (quiet) + return; + + std::cout << str; +} + std::string getRuntimeDir() { const auto XDG = getenv("XDG_RUNTIME_DIR"); @@ -96,17 +104,17 @@ int request(std::string arg, int minArgs = 0) { const auto ARGS = std::count(arg.begin(), arg.end(), ' '); if (ARGS < minArgs) { - std::cout << "Not enough arguments, expected at least " << minArgs; + log("Not enough arguments, expected at least " + minArgs); return -1; } if (SERVERSOCKET < 0) { - std::cout << "Couldn't open a socket (1)"; + log("Couldn't open a socket (1)"); return 1; } if (instanceSignature.empty()) { - std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"; + log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"); return 2; } @@ -120,14 +128,14 @@ int request(std::string arg, int minArgs = 0) { strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { - std::cout << "Couldn't connect to " << socketPath << ". (3)"; + log("Couldn't connect to " + socketPath + ". (3)"); return 3; } auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length()); if (sizeWritten < 0) { - std::cout << "Couldn't write (4)"; + log("Couldn't write (4)"); return 4; } @@ -137,7 +145,7 @@ int request(std::string arg, int minArgs = 0) { sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { - std::cout << "Couldn't read (5)"; + log("Couldn't read (5)"); return 5; } @@ -146,7 +154,7 @@ int request(std::string arg, int minArgs = 0) { while (sizeWritten == 8192) { sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { - std::cout << "Couldn't read (5)"; + log("Couldn't read (5)"); return 5; } reply += std::string(buffer, sizeWritten); @@ -154,7 +162,7 @@ int request(std::string arg, int minArgs = 0) { close(SERVERSOCKET); - std::cout << reply; + log(reply); return 0; } @@ -163,12 +171,12 @@ int requestHyprpaper(std::string arg) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SERVERSOCKET < 0) { - std::cout << "Couldn't open a socket (1)"; + log("Couldn't open a socket (1)"); return 1; } if (instanceSignature.empty()) { - std::cout << "HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"; + log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)"); return 2; } @@ -182,7 +190,7 @@ int requestHyprpaper(std::string arg) { strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { - std::cout << "Couldn't connect to " << socketPath << ". (3)"; + log("Couldn't connect to " + socketPath + ". (3)"); return 3; } @@ -192,7 +200,7 @@ int requestHyprpaper(std::string arg) { auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length()); if (sizeWritten < 0) { - std::cout << "Couldn't write (4)"; + log("Couldn't write (4)"); return 4; } @@ -201,13 +209,13 @@ int requestHyprpaper(std::string arg) { sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { - std::cout << "Couldn't read (5)"; + log("Couldn't read (5)"); return 5; } close(SERVERSOCKET); - std::cout << std::string(buffer); + log(std::string(buffer)); return 0; } @@ -250,7 +258,7 @@ void instancesRequest(bool json) { result += "\n]"; } - std::cout << result << "\n"; + log(result + "\n"); } std::deque splitArgs(int argc, char** argv) { @@ -310,6 +318,8 @@ int main(int argc, char** argv) { } overrideInstance = ARGS[i]; + } else if (ARGS[i] == "-q" || ARGS[i] == "--quiet") { + quiet = true; } else if (ARGS[i] == "--help") { const std::string& cmd = ARGS[0]; @@ -360,7 +370,7 @@ int main(int argc, char** argv) { instanceSignature = overrideInstance; else if (!overrideInstance.empty()) { if (!isNumber(overrideInstance, false)) { - std::cout << "instance invalid\n"; + log("instance invalid\n"); return 1; } @@ -369,7 +379,7 @@ int main(int argc, char** argv) { const auto INSTANCES = instances(); if (INSTANCENO < 0 || static_cast(INSTANCENO) >= INSTANCES.size()) { - std::cout << "no such instance\n"; + log("no such instance\n"); return 1; } @@ -378,7 +388,7 @@ int main(int argc, char** argv) { const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE"); if (!ISIG) { - std::cout << "HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n"; + log("HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n"); return 1; } @@ -419,6 +429,6 @@ int main(int argc, char** argv) { exitStatus = request(fullRequest); } - std::cout << std::endl; + std::cout << std::flush; return exitStatus; } From 1423707dbefc0329e80895451903a77ab684f7ea Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Jun 2024 22:28:51 +0200 Subject: [PATCH 0183/2393] output: remove wl_output globals for mirrored displays ref #6387 --- src/helpers/Monitor.cpp | 5 +++++ src/managers/ProtocolManager.cpp | 30 ++++++++++++++++++++++++++++-- src/managers/ProtocolManager.hpp | 7 +++++++ src/protocols/core/Output.cpp | 4 ++++ src/protocols/core/Output.hpp | 1 + src/render/Renderer.cpp | 5 ++++- 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5962b73d..a30f1057 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -184,6 +184,9 @@ void CMonitor::onConnect(bool noRule) { forceFullFrames = 3; // force 3 full frames to make sure there is no blinking due to double-buffering. // + if (!activeMonitorRule.mirrorOf.empty()) + setMirror(activeMonitorRule.mirrorOf); + g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); EMIT_HOOK_EVENT("monitorAdded", this); @@ -517,6 +520,8 @@ void CMonitor::setMirror(const std::string& mirrorOf) { g_pCompositor->sanityCheckWorkspaces(); } + + events.modeChanged.emit(); } float CMonitor::getDefaultScale() { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 7946a3f7..74cebd0c 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -46,21 +46,47 @@ #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" +void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { + const bool ISMIRROR = pMonitor->isMirror(); + + // onModeChanged we check if the current mirror status matches the global. + // mirrored outputs should have their global removed, as they are not physical parts of the + // layout. + + if (ISMIRROR && PROTO::outputs.contains(pMonitor->szName)) + PROTO::outputs.at(pMonitor->szName)->remove(); + else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) { + if (PROTO::outputs.contains(pMonitor->szName)) + PROTO::outputs.erase(pMonitor->szName); + PROTO::outputs.emplace(pMonitor->szName, + std::make_unique(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); + } +} + CProtocolManager::CProtocolManager() { // Outputs are a bit dumb, we have to agree. - static auto P = g_pHookSystem->hookDynamic("monitorAdded", [](void* self, SCallbackInfo& info, std::any param) { + static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); + + // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after + // this event is emitted iirc. + if (M->isMirror()) + return; + if (PROTO::outputs.contains(M->szName)) PROTO::outputs.erase(M->szName); PROTO::outputs.emplace(M->szName, std::make_unique(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock())); + + m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); }); }); - static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [](void* self, SCallbackInfo& info, std::any param) { + static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); if (!PROTO::outputs.contains(M->szName)) return; PROTO::outputs.at(M->szName)->remove(); + m_mModeChangeListeners.erase(M->szName); }); // Core diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 9af7b928..4f668b46 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -5,6 +5,8 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" +#include "../helpers/memory/WeakPtr.hpp" +#include class CProtocolManager { public: @@ -15,6 +17,11 @@ class CProtocolManager { std::unique_ptr m_pTextInputV1ProtocolManager; std::unique_ptr m_pGlobalShortcutsProtocolManager; std::unique_ptr m_pScreencopyProtocolManager; + + private: + std::unordered_map m_mModeChangeListeners; + + void onMonitorModeChange(CMonitor* pMonitor); }; inline std::unique_ptr g_pProtocolManager; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index a1b0c7b0..90358fa5 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -105,3 +105,7 @@ void CWLOutputProtocol::remove() { defunct = true; removeGlobal(); } + +bool CWLOutputProtocol::isDefunct() { + return defunct; +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 5c274612..b17a8272 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -40,6 +40,7 @@ class CWLOutputProtocol : public IWaylandProtocol { // will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global) void remove(); + bool isDefunct(); // true if above was called private: void destroyResource(CWLOutputResource* resource); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 17f91d48..8fac5869 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1353,7 +1353,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } else g_pHyprRenderer->renderWindow(pMonitor->solitaryClient.lock(), pMonitor, &now, false, RENDER_PASS_MAIN /* solitary = no popups */); - } else { + } else if (!pMonitor->isMirror()) { sendFrameEventsToWorkspace(pMonitor, pMonitor->activeWorkspace, &now); if (pMonitor->activeSpecialWorkspace) sendFrameEventsToWorkspace(pMonitor, pMonitor->activeSpecialWorkspace, &now); @@ -1869,6 +1869,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR !memcmp(&pMonitor->customDrmMode, &RULE->drmMode, sizeof(pMonitor->customDrmMode))) { Debug::log(LOG, "Not applying a new rule to {} because it's already applied!", pMonitor->szName); + + pMonitor->setMirror(RULE->mirrorOf); + return true; } From b16af45c4ac22d4a49de4e2f11e96132c8718844 Mon Sep 17 00:00:00 2001 From: memchr <118117622+memchr@users.noreply.github.com> Date: Mon, 10 Jun 2024 10:15:25 +0000 Subject: [PATCH 0184/2393] build: ProtocolManager missing header LIstener.hpp (#6391) --- src/managers/ProtocolManager.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 4f668b46..52a54253 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -6,6 +6,7 @@ #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" #include "../helpers/memory/WeakPtr.hpp" +#include "../helpers/signal/Listener.hpp" #include class CProtocolManager { From 89a3c9061367bb19c105a651280b3f3f17c66d22 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Mon, 10 Jun 2024 03:16:38 -0700 Subject: [PATCH 0185/2393] wlr-foreign-toplevel: fix fullscreen failing and add output support (#6360) * wlr-foreign-toplevel: fix fullscreen failing and add output support * fix for core protocol rewrite --- src/protocols/ForeignToplevelWlr.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 782fbc0e..8224f495 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -1,6 +1,8 @@ #include "ForeignToplevelWlr.hpp" #include #include "../Compositor.hpp" +#include "protocols/core/Output.hpp" +#include "render/Renderer.hpp" #define LOGM PROTO::foreignToplevelWlr->protoLog @@ -36,7 +38,21 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetWindowFullscreen(PWINDOW, true); + if (output) { + const auto wpMonitor = CWLOutputResource::fromResource(output)->monitor; + + if (!wpMonitor.expired()) { + const auto monitor = wpMonitor.lock(); + + if (PWINDOW->m_pWorkspace != monitor->activeWorkspace) { + g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, monitor->activeWorkspace); + g_pCompositor->setActiveMonitor(monitor.get()); + } + } + } + + g_pCompositor->setWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); + g_pHyprRenderer->damageWindow(PWINDOW); }); resource->setUnsetFullscreen([this](CZwlrForeignToplevelHandleV1* p) { @@ -372,4 +388,4 @@ PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res } return nullptr; -} \ No newline at end of file +} From cef6aad28fcda34644b62e2cf645f9da1ba553ad Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Mon, 10 Jun 2024 06:20:18 -0400 Subject: [PATCH 0186/2393] groupbar: Fix window title rendering (#6392) --- .../decorations/CHyprGroupBarDecoration.cpp | 55 +++++++++++-------- .../decorations/CHyprGroupBarDecoration.hpp | 3 + 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index d96f2c3c..731fce04 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -172,9 +172,11 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { .emplace_back(std::make_unique(m_dwGroupMembers[WINDOWINDEX].lock(), Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) .get(); - - rect.y += (*PHEIGHT / 2.0 - (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) / 2.0) * pMonitor->scale; - rect.height = (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale; + rect.y += ((rect.height - pTitleTex->textHeight) / 2.0) * pMonitor->scale; + rect.height = (pTitleTex->textHeight) * pMonitor->scale; + rect.width = pTitleTex->textWidth * pMonitor->scale; + rect.x += m_fBarWidth / 2.0 - (pTitleTex->textWidth / 2.0) * pMonitor->scale; + rect.round(); g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); } @@ -203,11 +205,11 @@ void CHyprGroupBarDecoration::invalidateTextures() { } CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { - tex = makeShared(); - szContent = pWindow->m_szTitle; - pWindowOwner = pWindow; - const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, bufferSize.x, bufferSize.y); - const auto CAIRO = cairo_create(CAIROSURFACE); + tex = makeShared(); + szContent = pWindow->m_szTitle; + pWindowOwner = pWindow; + const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); + const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE); static auto FALLBACKFONT = CConfigValue("misc:font_family"); static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); @@ -217,14 +219,11 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float const CColor COLOR = CColor(*PTEXTCOLOR); const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; - // clear the pixmap - cairo_save(CAIRO); - cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR); - cairo_paint(CAIRO); - cairo_restore(CAIRO); + cairo_surface_destroy(LAYOUTSURFACE); // draw title using Pango - PangoLayout* layout = pango_cairo_create_layout(CAIRO); + PangoLayout* layout = pango_cairo_create_layout(LAYOUTCAIRO); + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); pango_layout_set_text(layout, szContent.c_str(), -1); PangoFontDescription* fontDesc = pango_font_description_new(); @@ -238,14 +237,23 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float pango_layout_set_width(layout, maxWidth * PANGO_SCALE); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + int layoutWidth, layoutHeight; + PangoRectangle inkRect; + PangoRectangle logicalRect; + pango_layout_get_pixel_extents(layout, &inkRect, &logicalRect); + layoutWidth = inkRect.width; + layoutHeight = inkRect.height; + + const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layoutWidth, layoutHeight); + const auto CAIRO = cairo_create(CAIROSURFACE); + + // clear the pixmap + cairo_save(CAIRO); + cairo_set_operator(CAIRO, CAIRO_OPERATOR_CLEAR); + cairo_paint(CAIRO); + cairo_restore(CAIRO); + cairo_move_to(CAIRO, -inkRect.x, -inkRect.y); cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); - - int layoutWidth, layoutHeight; - pango_layout_get_size(layout, &layoutWidth, &layoutHeight); - const int xOffset = std::round((bufferSize.x / 2.0 - layoutWidth / PANGO_SCALE / 2.0)); - const int yOffset = std::round((bufferSize.y / 2.0 - layoutHeight / PANGO_SCALE / 2.0)); - - cairo_move_to(CAIRO, xOffset, yOffset); pango_cairo_show_layout(CAIRO, layout); g_object_unref(layout); @@ -264,9 +272,12 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); #endif - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bufferSize.x, bufferSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, layoutWidth, layoutHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); // delete cairo + textWidth = layoutWidth; + textHeight = layoutHeight; + cairo_destroy(LAYOUTCAIRO); cairo_destroy(CAIRO); cairo_surface_destroy(CAIROSURFACE); } diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 64870d45..1af24717 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -14,6 +14,9 @@ class CTitleTex { SP tex; std::string szContent; + int textWidth; + int textHeight; + PHLWINDOWREF pWindowOwner; }; From 7ba2c31822b3df9b40b4184550423f23023b55bb Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 10 Jun 2024 15:25:01 +0200 Subject: [PATCH 0187/2393] github: improve the chances of the user specifying bug or regression (#6399) --- .github/ISSUE_TEMPLATE/bug.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 66ce5fa9..285a15a1 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -9,6 +9,17 @@ body: --- + - type: dropdown + id: type + attributes: + label: Bug or Regression? + description: Is this a bug or a regression? + options: + - Bug + - Regression + validations: + required: true + - type: textarea id: ver attributes: @@ -33,17 +44,6 @@ body: validations: required: true - - type: dropdown - id: type - attributes: - label: Bug or Regression? - description: Is this a bug or a regression? - options: - - Bug - - Regression - validations: - required: true - - type: textarea id: desc attributes: From ea2501d4556f84d3de86a4ae2f4b22a474555b9f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 10 Jun 2024 16:22:59 +0200 Subject: [PATCH 0188/2393] props: bump version to 0.41.0 --- props.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/props.json b/props.json index 72a6e5b6..d9bd7cea 100644 --- a/props.json +++ b/props.json @@ -1,3 +1,3 @@ { - "version": "0.40.0" + "version": "0.41.0" } \ No newline at end of file From 811429bfd4a46f33c7788580f72038b0c3c1c2b1 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 10 Jun 2024 20:31:03 +0000 Subject: [PATCH 0189/2393] wayland: consistently check mmap error after 6967a3145044 (#6402) mmap() returns MAP_FAILED on error, not nullptr. --- src/protocols/LinuxDMABUF.cpp | 2 +- src/protocols/core/Shm.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index f7911f6e..cf8f8730 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -38,7 +38,7 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector resource_, int fd_, size_t RESOURCE->resource->buffer = RESOURCE; }); - if (!pool->data) + if (pool->data == MAP_FAILED) resource->error(WL_SHM_ERROR_INVALID_FD, "Couldn't mmap from fd"); } From b17381eb819d784146ec40d81d30a2b33a8a4e64 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Tue, 11 Jun 2024 11:00:50 -0400 Subject: [PATCH 0190/2393] groupbar: Don't apply monitor scale twice to groupbar text (#6411) --- src/render/decorations/CHyprGroupBarDecoration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 731fce04..a87dba31 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -172,10 +172,10 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { .emplace_back(std::make_unique(m_dwGroupMembers[WINDOWINDEX].lock(), Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) .get(); - rect.y += ((rect.height - pTitleTex->textHeight) / 2.0) * pMonitor->scale; - rect.height = (pTitleTex->textHeight) * pMonitor->scale; - rect.width = pTitleTex->textWidth * pMonitor->scale; - rect.x += m_fBarWidth / 2.0 - (pTitleTex->textWidth / 2.0) * pMonitor->scale; + rect.y += (rect.height - pTitleTex->textHeight) / 2.0; + rect.height = pTitleTex->textHeight; + rect.width = pTitleTex->textWidth; + rect.x += (m_fBarWidth * pMonitor->scale) / 2.0 - (pTitleTex->textWidth / 2.0); rect.round(); g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); From 90d00977169e8478b5f4c27ec0a364a7ec11b0aa Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 08:01:25 -0700 Subject: [PATCH 0191/2393] input: fix input regions being ignored on ls-es (#6413) --- src/Compositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5c0b8eaa..5cb7c7be 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1056,7 +1056,7 @@ SP CCompositor::vectorToLayerSurface(const Vector2D& pos, st if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; - auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos()); + auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); if (surf) { if (surf->current.input.empty()) From 809820921d9844e1bc09b843392fd7d277b83f73 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 08:11:15 -0700 Subject: [PATCH 0192/2393] sessionLock: fix focus not being tied to mouse (#6414) --- src/managers/input/InputManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index ff10f303..5ce53472 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -155,6 +155,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { Vector2D surfacePos = Vector2D(-1337, -1337); PHLWINDOW pFoundWindow; PHLLS pFoundLayerSurface; + SSessionLockSurface* pSessionLock = nullptr; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -261,12 +262,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pCompositor->setActiveMonitor(PMONITOR); if (g_pSessionLockManager->isSessionLocked()) { - const auto PSLS = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; + pSessionLock = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; - if (!PSLS) + if (!pSessionLock) return; - foundSurface = PSLS->surface->surface(); + foundSurface = pSessionLock->surface->surface(); surfacePos = PMONITOR->vecPosition; } @@ -455,7 +456,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { restoreCursorIconToApp(); } - if (pFoundWindow) { + if (pSessionLock != nullptr) + g_pCompositor->focusSurface(foundSurface); + else if (pFoundWindow) { // change cursor icon if hovering over border if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) { From 1f46296ea05f9a8e6020ab694b531c91a1abdfa6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 11 Jun 2024 17:12:24 +0200 Subject: [PATCH 0193/2393] deps: update wlroots --- subprojects/wlroots-hyprland | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland index 91de8da4..422207db 160000 --- a/subprojects/wlroots-hyprland +++ b/subprojects/wlroots-hyprland @@ -1 +1 @@ -Subproject commit 91de8da4b6b9b3c5630123d2446cd6de4e80071a +Subproject commit 422207dbcf0949e28042403edab539159282885e From 8c64a4bad710fb18e9b84812bd680a89d1e93661 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:17:45 +0200 Subject: [PATCH 0194/2393] core: move to hyprutils for utils (#6385) * core: move to hyprutils for utils Nix: add hyprutils dep * Meson: add hyprutils dep * flake.lock: update --------- Co-authored-by: Mihai Fufezan --- .github/actions/setup_base/action.yml | 5 + CMakeLists.txt | 2 +- flake.lock | 45 +++- flake.nix | 7 + hyprctl/CMakeLists.txt | 4 + hyprctl/main.cpp | 8 +- hyprctl/meson.build | 3 + hyprpm/CMakeLists.txt | 4 +- hyprpm/src/core/PluginManager.cpp | 24 +- hyprpm/src/meson.build | 1 + nix/default.nix | 2 + nix/overlays.nix | 1 + src/Compositor.cpp | 5 +- src/config/ConfigDataValues.hpp | 2 +- src/config/ConfigManager.cpp | 22 +- src/config/ConfigManager.hpp | 2 +- src/debug/HyprCtl.cpp | 9 +- src/desktop/Popup.hpp | 2 +- src/desktop/Window.cpp | 5 +- src/desktop/Workspace.cpp | 5 +- src/devices/IKeyboard.cpp | 2 +- src/events/Windows.cpp | 7 +- src/helpers/MiscFunctions.cpp | 61 +---- src/helpers/MiscFunctions.hpp | 3 - src/helpers/Monitor.cpp | 5 +- src/helpers/VarList.cpp | 37 --- src/helpers/VarList.hpp | 64 ----- src/helpers/WLClasses.hpp | 2 +- src/helpers/memory/Memory.hpp | 9 + src/helpers/memory/SharedPtr.hpp | 302 ---------------------- src/helpers/memory/WeakPtr.hpp | 190 -------------- src/helpers/signal/Listener.cpp | 21 -- src/helpers/signal/Listener.hpp | 41 --- src/helpers/signal/Signal.cpp | 51 ---- src/helpers/signal/Signal.hpp | 23 +- src/helpers/varlist/VarList.hpp | 5 + src/macros.hpp | 4 +- src/managers/EventManager.hpp | 2 +- src/managers/KeybindManager.cpp | 7 +- src/managers/ProtocolManager.hpp | 4 +- src/managers/SessionLockManager.hpp | 2 +- src/managers/TokenManager.hpp | 2 +- src/managers/eventLoop/EventLoopTimer.hpp | 2 +- src/managers/input/InputManager.hpp | 2 +- src/managers/input/InputMethodPopup.hpp | 2 +- src/managers/input/InputMethodRelay.hpp | 2 +- src/managers/input/TextInput.hpp | 2 +- src/meson.build | 1 + src/plugins/HookSystem.cpp | 2 +- src/protocols/AlphaModifier.hpp | 2 +- src/protocols/FocusGrab.hpp | 2 +- src/protocols/GammaControl.hpp | 2 +- src/protocols/OutputManagement.hpp | 2 +- src/protocols/OutputPower.hpp | 2 +- src/protocols/PointerConstraints.hpp | 2 +- src/protocols/core/Output.hpp | 2 +- src/xwayland/XWM.hpp | 2 +- 57 files changed, 158 insertions(+), 873 deletions(-) delete mode 100644 src/helpers/VarList.cpp delete mode 100644 src/helpers/VarList.hpp create mode 100644 src/helpers/memory/Memory.hpp delete mode 100644 src/helpers/memory/SharedPtr.hpp delete mode 100644 src/helpers/memory/WeakPtr.hpp delete mode 100644 src/helpers/signal/Listener.cpp delete mode 100644 src/helpers/signal/Listener.hpp delete mode 100644 src/helpers/signal/Signal.cpp create mode 100644 src/helpers/varlist/VarList.hpp diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index ea3eecd3..a7b9994c 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -68,6 +68,11 @@ runs: cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --install build + - name: Get hyprutils-git + shell: bash + run: | + git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build + - name: Get Xorg pacman pkgs shell: bash if: inputs.INSTALL_XORG_PKGS == 'true' diff --git a/CMakeLists.txt b/CMakeLists.txt index 43cbb50c..7aa2bf5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.1 ) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index ab886a15..477db69b 100644 --- a/flake.lock +++ b/flake.lock @@ -53,6 +53,9 @@ }, "hyprlang": { "inputs": { + "hyprutils": [ + "hyprutils" + ], "nixpkgs": [ "nixpkgs" ], @@ -61,11 +64,11 @@ ] }, "locked": { - "lastModified": 1716473782, - "narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", + "lastModified": 1717881852, + "narHash": "sha256-XeeVoKHQgfKuXoP6q90sUqKyl7EYy3ol2dVZGM+Jj94=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "87d5d984109c839482b88b4795db073eb9ed446f", + "rev": "ec6938c66253429192274d612912649a0cfe4d28", "type": "github" }, "original": { @@ -74,6 +77,29 @@ "type": "github" } }, + "hyprutils": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1717881334, + "narHash": "sha256-a0inRgJhPL6v9v7RPM/rx1kbXdfe3xJA1c9z0ZkYnh4=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "0693f9398ab693d89c9a0aa3b3d062dd61b7a60e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ @@ -99,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717602782, - "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", + "lastModified": 1717974879, + "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", + "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3", "type": "github" }, "original": { @@ -117,6 +143,7 @@ "inputs": { "hyprcursor": "hyprcursor", "hyprlang": "hyprlang", + "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems", @@ -152,11 +179,11 @@ ] }, "locked": { - "lastModified": 1716290197, - "narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", + "lastModified": 1717918856, + "narHash": "sha256-I38bmPLqamvOfVSArd1hhZtkVRAYBK38fOHZCU1P9Qg=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", + "rev": "72907822c19afc0983c69d59d299204381623725", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 82e3e4bb..c1be8720 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,13 @@ url = "github:hyprwm/hyprlang"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + }; + + hyprutils = { + url = "github:hyprwm/hyprutils"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; }; hyprwayland-scanner = { diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt index 6f70ace8..64b983e6 100644 --- a/hyprctl/CMakeLists.txt +++ b/hyprctl/CMakeLists.txt @@ -5,8 +5,12 @@ project( DESCRIPTION "Control utility for Hyprland" ) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1) + add_executable(hyprctl "main.cpp") +target_link_libraries(hyprctl PUBLIC PkgConfig::deps) + # binary install(TARGETS hyprctl) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 34abe46f..8fb9194c 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +using namespace Hyprutils::String; #include "Strings.hpp" @@ -270,12 +272,6 @@ std::deque splitArgs(int argc, char** argv) { return result; } -bool isNumber(const std::string& str, bool allowfloat) { - if (str.empty()) - return false; - return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); }); -} - int main(int argc, char** argv) { bool parseArgs = true; diff --git a/hyprctl/meson.build b/hyprctl/meson.build index 94e98b4b..5488845f 100644 --- a/hyprctl/meson.build +++ b/hyprctl/meson.build @@ -1,4 +1,7 @@ executable('hyprctl', 'main.cpp', + dependencies: [ + dependency('hyprutils', version: '>= 0.1.1'), + ], install: true ) diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index 8b6a8320..692e8da1 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") set(CMAKE_CXX_STANDARD 23) -pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1) add_executable(hyprpm ${SRCFILES}) -target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus) +target_link_libraries(hyprpm PUBLIC PkgConfig::deps) # binary install(TARGETS hyprpm) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index fb338d25..446d6af3 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -19,24 +19,8 @@ #include -static std::string removeBeginEndSpacesTabs(std::string str) { - if (str.empty()) - return str; - - int countBefore = 0; - while (str[countBefore] == ' ' || str[countBefore] == '\t') { - countBefore++; - } - - int countAfter = 0; - while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) { - countAfter++; - } - - str = str.substr(countBefore, str.length() - countBefore - countAfter); - - return str; -} +#include +using namespace Hyprutils::String; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; @@ -374,7 +358,7 @@ eHeadersErrors CPluginManager::headersValid() { if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) continue; - verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h"; + verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h"; break; } @@ -447,7 +431,7 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. const std::string SHALLOW_DATE = - removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); if (m_bVerbose && bShallow) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); diff --git a/hyprpm/src/meson.build b/hyprpm/src/meson.build index a8644169..e2c512a5 100644 --- a/hyprpm/src/meson.build +++ b/hyprpm/src/meson.build @@ -3,6 +3,7 @@ src = globber.stdout().strip().split('\n') executable('hyprpm', src, dependencies: [ + dependency('hyprutils', version: '>= 0.1.1'), dependency('threads'), dependency('tomlplusplus') ], diff --git a/nix/default.nix b/nix/default.nix index 5da00d72..0493abc1 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,6 +13,7 @@ git, hyprcursor, hyprlang, + hyprutils, hyprwayland-scanner, jq, libGL, @@ -110,6 +111,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov git hyprcursor.dev hyprlang + hyprutils libGL libdrm libdatrie diff --git a/nix/overlays.nix b/nix/overlays.nix index fbd7e9fc..cc66e1b5 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -23,6 +23,7 @@ in { # Dependencies inputs.hyprcursor.overlays.default inputs.hyprlang.overlays.default + inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default self.overlays.xwayland diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5cb7c7be..8b19f010 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -14,7 +14,7 @@ #include // for SdNotify #endif #include -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" @@ -24,6 +24,9 @@ #include "desktop/LayerSurface.hpp" #include "xwayland/XWayland.hpp" +#include +using namespace Hyprutils::String; + #include #include diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index c162bb40..322bd14a 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -1,6 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include enum eConfigValueDataTypes { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e10522d9..6bb24e46 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -3,7 +3,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" #include @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,7 +21,8 @@ #include #include #include -#include +#include +using namespace Hyprutils::String; extern "C" char** environ; @@ -2087,8 +2089,8 @@ bool layerRuleValid(const std::string& RULE) { } std::optional CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); - const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); + const auto VALUE = trim(value.substr(value.find_first_of(',') + 1)); // check rule and value if (RULE.empty() || VALUE.empty()) @@ -2114,8 +2116,8 @@ std::optional CConfigManager::handleWindowRule(const std::string& c } std::optional CConfigManager::handleLayerRule(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); - const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); + const auto VALUE = trim(value.substr(value.find_first_of(',') + 1)); // check rule and value if (RULE.empty() || VALUE.empty()) @@ -2142,7 +2144,7 @@ std::optional CConfigManager::handleLayerRule(const std::string& co } std::optional CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); const auto VALUE = value.substr(value.find_first_of(',') + 1); if (!windowRuleValid(RULE) && RULE != "unset") { @@ -2219,7 +2221,7 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& result = result.substr(0, min - pos); - result = removeBeginEndSpacesTabs(result); + result = trim(result); if (!result.empty() && result.back() == ',') result.pop_back(); @@ -2341,7 +2343,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl std::optional CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { if (value.starts_with("remove,")) { - const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7)); + const auto TOREMOVE = trim(value.substr(7)); if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; })) updateBlurredLS(TOREMOVE, false); return {}; @@ -2358,7 +2360,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin const auto FIRST_DELIM = value.find_first_of(','); std::string name = ""; - auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM)); + auto first_ident = trim(value.substr(0, FIRST_DELIM)); int id = getWorkspaceIDFromString(first_ident, name); auto rules = value.substr(FIRST_DELIM + 1); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index ca22904d..c43cb020 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -15,7 +15,7 @@ #include #include "../helpers/WLClasses.hpp" #include "../helpers/Monitor.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index bdb12e58..6f4d74b7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -16,6 +16,9 @@ #include #include +#include +using namespace Hyprutils::String; + #include "../config/ConfigDataValues.hpp" #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -826,7 +829,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { - auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE); + auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { @@ -1051,7 +1054,7 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { request = ""; } - curitem = removeBeginEndSpacesTabs(curitem); + curitem = trim(curitem); }; nextItem(); @@ -1305,7 +1308,7 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) request = ""; } - curitem = removeBeginEndSpacesTabs(curitem); + curitem = trim(curitem); }; nextItem(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 91e569e7..47e180a8 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -3,7 +3,7 @@ #include #include #include "Subsurface.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CXDGPopupResource; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5d6e32e9..b02a53e0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -12,6 +12,9 @@ #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include +using namespace Hyprutils::String; + PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -687,7 +690,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { CGradientValueData activeBorderGradient = {}; CGradientValueData inactiveBorderGradient = {}; bool active = true; - CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true); + CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true); // Basic form has only two colors, everything else can be parsed as a gradient if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 7a836b3b..ed09fbc0 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -2,6 +2,9 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include +using namespace Hyprutils::String; + PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); workspace->init(workspace); @@ -219,7 +222,7 @@ std::string CWorkspace::getConfigName() { } bool CWorkspace::matchesStaticSelector(const std::string& selector_) { - auto selector = removeBeginEndSpacesTabs(selector_); + auto selector = trim(selector_); if (selector.empty()) return true; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 7e4dd912..cb294d1a 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -1,6 +1,6 @@ #include "IKeyboard.hpp" #include "../defines.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../managers/input/InputManager.hpp" uint32_t IKeyboard::getCapabilities() { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 88b28c87..899318ce 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,6 +12,9 @@ #include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" +#include +using namespace Hyprutils::String; + // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // // \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| // @@ -140,7 +143,7 @@ void Events::listener_mapWindow(void* owner, void* data) { for (auto& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("monitor")) { try { - const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' '))); + const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); if (MONITORSTR == "unset") { PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -235,7 +238,7 @@ void Events::listener_mapWindow(void* owner, void* data) { continue; // `group` is a shorthand of `group set` - if (removeBeginEndSpacesTabs(r.szRule) == "group") { + if (trim(r.szRule) == "group") { PWINDOW->m_eGroupRules |= GROUP_SET; continue; } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 32cd9868..b1d734c8 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -13,6 +13,8 @@ #ifdef HAS_EXECINFO #include #endif +#include +using namespace Hyprutils::String; #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include @@ -195,25 +197,6 @@ std::string escapeJSONStrings(const std::string& str) { return oss.str(); } -std::string removeBeginEndSpacesTabs(std::string str) { - if (str.empty()) - return str; - - int countBefore = 0; - while (str[countBefore] == ' ' || str[countBefore] == '\t') { - countBefore++; - } - - int countAfter = 0; - while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) { - countAfter++; - } - - str = str.substr(countBefore, str.length() - countBefore - countAfter); - - return str; -} - std::optional getPlusMinusKeywordResult(std::string source, float relative) { try { return relative + stof(source); @@ -223,31 +206,6 @@ std::optional getPlusMinusKeywordResult(std::string source, float relativ } } -bool isNumber(const std::string& str, bool allowfloat) { - - std::string copy = str; - if (*copy.begin() == '-') - copy = copy.substr(1); - - if (copy.empty()) - return false; - - bool point = !allowfloat; - for (auto& c : copy) { - if (c == '.') { - if (point) - return false; - point = true; - continue; - } - - if (!std::isdigit(c)) - return false; - } - - return true; -} - bool isDirection(const std::string& arg) { return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b"; } @@ -579,7 +537,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { std::optional cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) { - std::string cmd = removeBeginEndSpacesTabs(dirtyCmd); + std::string cmd = trim(dirtyCmd); if (!cmd.empty()) { std::string rules; @@ -748,7 +706,7 @@ int64_t configStringToInt(const std::string& VALUE) { } else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) { const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6); - if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) { + if (trim(VALUEWITHOUTFUNC).length() != 8) { Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length()); throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)"); } @@ -760,7 +718,7 @@ int64_t configStringToInt(const std::string& VALUE) { } else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) { const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5); - if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) { + if (trim(VALUEWITHOUTFUNC).length() != 6) { Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length()); throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)"); } @@ -822,15 +780,6 @@ double normalizeAngleRad(double ang) { return ang; } -std::string replaceInString(std::string subject, const std::string& search, const std::string& replace) { - size_t pos = 0; - while ((pos = subject.find(search, pos)) != std::string::npos) { - subject.replace(pos, search.length(), replace); - pos += replace.length(); - } - return subject; -} - std::vector getBacktrace() { std::vector callstack; diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 9d34174c..feb0380b 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -17,8 +17,6 @@ std::string absolutePath(const std::string&, const std::str void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void removeWLSignal(wl_listener*); std::string escapeJSONStrings(const std::string& str); -std::string removeBeginEndSpacesTabs(std::string); -bool isNumber(const std::string&, bool allowfloat = false); bool isDirection(const std::string&); bool isDirection(const char&); int getWorkspaceIDFromString(const std::string&, std::string&); @@ -32,7 +30,6 @@ Vector2D configStringToVector2D(const std::string&); std::optional getPlusMinusKeywordResult(std::string in, float relative); void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); double normalizeAngleRad(double ang); -std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a30f1057..027b47bd 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -6,6 +6,8 @@ #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include +using namespace Hyprutils::String; int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); @@ -71,8 +73,7 @@ void CMonitor::onConnect(bool noRule) { std::erase(szDescription, ','); // field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix - szShortDescription = - removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); + szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); std::erase(szShortDescription, ','); if (!wlr_backend_is_drm(output->backend)) diff --git a/src/helpers/VarList.cpp b/src/helpers/VarList.cpp deleted file mode 100644 index 780ea9a0..00000000 --- a/src/helpers/VarList.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "MiscFunctions.hpp" -#include "VarList.hpp" -#include -#include - -CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) { - if (in.empty()) - m_vArgs.emplace_back(""); - - std::string args{in}; - size_t idx = 0; - size_t pos = 0; - std::ranges::replace_if( - args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0); - - for (const auto& s : args | std::views::split(0)) { - if (removeEmpty && s.empty()) - continue; - if (++idx == lastArgNo) { - m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos))); - break; - } - pos += s.size() + 1; - m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data())); - } -} - -std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const { - size_t last = to == 0 ? size() : to; - - std::string rolling; - for (size_t i = from; i < last; ++i) { - rolling += m_vArgs[i] + (i + 1 < last ? joiner : ""); - } - - return rolling; -} \ No newline at end of file diff --git a/src/helpers/VarList.hpp b/src/helpers/VarList.hpp deleted file mode 100644 index d70f2c3f..00000000 --- a/src/helpers/VarList.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#include -#include "../macros.hpp" - -class CVarList { - public: - /** Split string into arg list - @param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args - @param delim if delimiter is 's', use std::isspace - @param removeEmpty remove empty args from argv - */ - CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false); - - ~CVarList() = default; - - size_t size() const { - return m_vArgs.size(); - } - - std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const; - - void map(std::function func) { - for (auto& s : m_vArgs) - func(s); - } - - void append(const std::string arg) { - m_vArgs.emplace_back(arg); - } - - std::string operator[](const size_t& idx) const { - if (idx >= m_vArgs.size()) - return ""; - return m_vArgs[idx]; - } - - // for range-based loops - std::vector::iterator begin() { - return m_vArgs.begin(); - } - std::vector::const_iterator begin() const { - return m_vArgs.begin(); - } - std::vector::iterator end() { - return m_vArgs.end(); - } - std::vector::const_iterator end() const { - return m_vArgs.end(); - } - - bool contains(const std::string& el) { - for (auto& a : m_vArgs) { - if (a == el) - return true; - } - - return false; - } - - private: - std::vector m_vArgs; -}; \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index d5be9f40..247aa8f0 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -7,7 +7,7 @@ #include "../desktop/Popup.hpp" #include "AnimatedVariable.hpp" #include "../desktop/WLSurface.hpp" -#include "signal/Listener.hpp" +#include "signal/Signal.hpp" #include "Region.hpp" class CMonitor; diff --git a/src/helpers/memory/Memory.hpp b/src/helpers/memory/Memory.hpp new file mode 100644 index 00000000..135a84af --- /dev/null +++ b/src/helpers/memory/Memory.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +using namespace Hyprutils::Memory; + +#define SP Hyprutils::Memory::CSharedPointer +#define WP Hyprutils::Memory::CWeakPointer +#define UP std::unique_ptr diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp deleted file mode 100644 index 02900911..00000000 --- a/src/helpers/memory/SharedPtr.hpp +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#define SP CSharedPointer - -/* - This is a custom impl of std::shared_ptr. - It is not thread-safe like the STL one, - but Hyprland is single-threaded anyways. - - It differs a bit from how the STL one works, - namely in the fact that it keeps the T* inside the - control block, and that you can still make a CWeakPtr - or deref an existing one inside the destructor. -*/ -namespace CSharedPointer_ { - - class impl_base { - public: - virtual ~impl_base(){}; - - virtual void inc() noexcept = 0; - virtual void dec() noexcept = 0; - virtual void incWeak() noexcept = 0; - virtual void decWeak() noexcept = 0; - virtual unsigned int ref() noexcept = 0; - virtual unsigned int wref() noexcept = 0; - virtual void destroy() noexcept = 0; - virtual bool destroying() noexcept = 0; - virtual bool dataNonNull() noexcept = 0; - }; - - template - class impl : public impl_base { - public: - impl(T* data) noexcept : _data(data) { - ; - } - - /* strong refcount */ - unsigned int _ref = 0; - /* weak refcount */ - unsigned int _weak = 0; - - T* _data = nullptr; - - friend void swap(impl*& a, impl*& b) { - impl* tmp = a; - a = b; - b = tmp; - } - - /* if the destructor was called, - creating shared_ptrs is no longer valid */ - bool _destroying = false; - - void _destroy() { - if (!_data || _destroying) - return; - - // first, we destroy the data, but keep the pointer. - // this way, weak pointers will still be able to - // reference and use, but no longer create shared ones. - _destroying = true; - __deleter(_data); - // now, we can reset the data and call it a day. - _data = nullptr; - _destroying = false; - } - - std::default_delete __deleter{}; - - // - virtual void inc() noexcept { - _ref++; - } - - virtual void dec() noexcept { - _ref--; - } - - virtual void incWeak() noexcept { - _weak++; - } - - virtual void decWeak() noexcept { - _weak--; - } - - virtual unsigned int ref() noexcept { - return _ref; - } - - virtual unsigned int wref() noexcept { - return _weak; - } - - virtual void destroy() noexcept { - _destroy(); - } - - virtual bool destroying() noexcept { - return _destroying; - } - - virtual bool dataNonNull() noexcept { - return _data; - } - - virtual ~impl() { - destroy(); - } - }; -}; - -template -class CSharedPointer { - public: - template - using validHierarchy = typename std::enable_if&, X>::value, CSharedPointer&>::type; - template - using isConstructible = typename std::enable_if::value>::type; - - /* creates a new shared pointer managing a resource - avoid calling. Could duplicate ownership. Prefer makeShared */ - explicit CSharedPointer(T* object) noexcept { - impl_ = new CSharedPointer_::impl(object); - increment(); - } - - /* creates a shared pointer from a reference */ - template > - CSharedPointer(const CSharedPointer& ref) noexcept { - impl_ = ref.impl_; - increment(); - } - - CSharedPointer(const CSharedPointer& ref) noexcept { - impl_ = ref.impl_; - increment(); - } - - template > - CSharedPointer(CSharedPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - CSharedPointer(CSharedPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - /* allows weakPointer to create from an impl */ - CSharedPointer(CSharedPointer_::impl_base* implementation) noexcept { - impl_ = implementation; - increment(); - } - - /* creates an empty shared pointer with no implementation */ - CSharedPointer() noexcept { - ; // empty - } - - /* creates an empty shared pointer with no implementation */ - CSharedPointer(std::nullptr_t) noexcept { - ; // empty - } - - ~CSharedPointer() { - // we do not decrement here, - // because we want to preserve the pointer - // in case this is the last owner. - if (impl_ && impl_->ref() == 1) - destroyImpl(); - else - decrement(); - } - - template - validHierarchy&> operator=(const CSharedPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrement(); - impl_ = rhs.impl_; - increment(); - return *this; - } - - CSharedPointer& operator=(const CSharedPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrement(); - impl_ = rhs.impl_; - increment(); - return *this; - } - - template - validHierarchy&> operator=(CSharedPointer&& rhs) { - std::swap(impl_, rhs.impl_); - return *this; - } - - CSharedPointer& operator=(CSharedPointer&& rhs) { - std::swap(impl_, rhs.impl_); - return *this; - } - - operator bool() const { - return impl_ && impl_->dataNonNull(); - } - - bool operator==(const CSharedPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const { - return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; - } - - bool operator<(const CSharedPointer& rhs) const { - return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; - } - - T* operator->() const { - return get(); - } - - T& operator*() const { - return *get(); - } - - void reset() { - decrement(); - impl_ = nullptr; - } - - T* get() const { - return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); - } - - unsigned int strongRef() const { - return impl_ ? impl_->ref() : 0; - } - - CSharedPointer_::impl_base* impl_ = nullptr; - - private: - /* - no-op if there is no impl_ - may delete the stored object if ref == 0 - may delete and reset impl_ if ref == 0 and weak == 0 - */ - void decrement() { - if (!impl_) - return; - - impl_->dec(); - - // if ref == 0, we can destroy impl - if (impl_->ref() == 0) - destroyImpl(); - } - /* no-op if there is no impl_ */ - void increment() { - if (!impl_) - return; - - impl_->inc(); - } - - /* destroy the pointed-to object - if able, will also destroy impl */ - void destroyImpl() { - // destroy the impl contents - impl_->destroy(); - - // check for weak refs, if zero, we can also delete impl_ - if (impl_->wref() == 0) { - delete impl_; - impl_ = nullptr; - } - } -}; - -template -static CSharedPointer makeShared(Args&&... args) { - return CSharedPointer(new U(std::forward(args)...)); -} - -template -struct std::hash> { - std::size_t operator()(const CSharedPointer& p) const noexcept { - return std::hash{}(p.impl_); - } -}; diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp deleted file mode 100644 index 872f8e55..00000000 --- a/src/helpers/memory/WeakPtr.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#pragma once - -#include "SharedPtr.hpp" - -#define WP CWeakPointer - -/* - This is a Hyprland implementation of std::weak_ptr. - - See SharedPtr.hpp for more info on how it's different. -*/ - -template -class CWeakPointer { - public: - template - using validHierarchy = typename std::enable_if&, X>::value, CWeakPointer&>::type; - template - using isConstructible = typename std::enable_if::value>::type; - - /* create a weak ptr from a reference */ - template > - CWeakPointer(const CSharedPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - /* create a weak ptr from another weak ptr */ - template > - CWeakPointer(const CWeakPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - CWeakPointer(const CWeakPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - template > - CWeakPointer(CWeakPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - CWeakPointer(CWeakPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - /* create a weak ptr from another weak ptr with assignment */ - template - validHierarchy&> operator=(const CWeakPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - CWeakPointer& operator=(const CWeakPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - /* create a weak ptr from a shared ptr with assignment */ - template - validHierarchy&> operator=(const CSharedPointer& rhs) { - if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - /* create an empty weak ptr */ - CWeakPointer() { - ; - } - - ~CWeakPointer() { - decrementWeak(); - } - - /* expired MAY return true even if the pointer is still stored. - the situation would be e.g. self-weak pointer in a destructor. - for pointer validity, use valid() */ - bool expired() const { - return !impl_ || !impl_->dataNonNull() || impl_->destroying(); - } - - /* this means the pointed-to object is not yet deleted and can still be - referenced, but it might be in the process of being deleted. - check !expired() if you want to check whether it's valid and - assignable to a SP. */ - bool valid() const { - return impl_ && impl_->dataNonNull(); - } - - void reset() { - decrementWeak(); - impl_ = nullptr; - } - - CSharedPointer lock() const { - if (!impl_ || !impl_->dataNonNull() || impl_->destroying()) - return {}; - - return CSharedPointer(impl_); - } - - /* this returns valid() */ - operator bool() const { - return valid(); - } - - bool operator==(const CWeakPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator==(const CSharedPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const { - return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; - } - - bool operator<(const CWeakPointer& rhs) const { - return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; - } - - T* get() const { - return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); - } - - T* operator->() const { - return get(); - } - - CSharedPointer_::impl_base* impl_ = nullptr; - - private: - /* no-op if there is no impl_ */ - void decrementWeak() { - if (!impl_) - return; - - impl_->decWeak(); - - // we need to check for ->destroying, - // because otherwise we could destroy here - // and have a shared_ptr destroy the same thing - // later (in situations where we have a weak_ptr to self) - if (impl_->wref() == 0 && impl_->ref() == 0 && !impl_->destroying()) { - delete impl_; - impl_ = nullptr; - } - } - /* no-op if there is no impl_ */ - void incrementWeak() { - if (!impl_) - return; - - impl_->incWeak(); - } -}; - -template -struct std::hash> { - std::size_t operator()(const CWeakPointer& p) const noexcept { - return std::hash{}(p.impl_); - } -}; diff --git a/src/helpers/signal/Listener.cpp b/src/helpers/signal/Listener.cpp deleted file mode 100644 index 4023477f..00000000 --- a/src/helpers/signal/Listener.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Listener.hpp" -#include "Signal.hpp" - -CSignalListener::CSignalListener(std::function handler) : m_fHandler(handler) { - ; -} - -void CSignalListener::emit(std::any data) { - if (!m_fHandler) - return; - - m_fHandler(data); -} - -CStaticSignalListener::CStaticSignalListener(std::function handler, void* owner) : m_pOwner(owner), m_fHandler(handler) { - ; -} - -void CStaticSignalListener::emit(std::any data) { - m_fHandler(m_pOwner, data); -} diff --git a/src/helpers/signal/Listener.hpp b/src/helpers/signal/Listener.hpp deleted file mode 100644 index e6aa8d73..00000000 --- a/src/helpers/signal/Listener.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../../macros.hpp" - -class CSignal; - -class CSignalListener { - public: - CSignalListener(std::function handler); - - CSignalListener(CSignalListener&&) = delete; - CSignalListener(CSignalListener&) = delete; - CSignalListener(const CSignalListener&) = delete; - CSignalListener(const CSignalListener&&) = delete; - - void emit(std::any data); - - private: - std::function m_fHandler; -}; - -typedef SP CHyprSignalListener; - -class CStaticSignalListener { - public: - CStaticSignalListener(std::function handler, void* owner); - - CStaticSignalListener(CStaticSignalListener&&) = delete; - CStaticSignalListener(CStaticSignalListener&) = delete; - CStaticSignalListener(const CStaticSignalListener&) = delete; - CStaticSignalListener(const CStaticSignalListener&&) = delete; - - void emit(std::any data); - - private: - void* m_pOwner = nullptr; - std::function m_fHandler; -}; \ No newline at end of file diff --git a/src/helpers/signal/Signal.cpp b/src/helpers/signal/Signal.cpp deleted file mode 100644 index fd2d11c8..00000000 --- a/src/helpers/signal/Signal.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "Signal.hpp" -#include - -void CSignal::emit(std::any data) { - bool dirty = false; - - std::vector> listeners; - for (auto& l : m_vListeners) { - if (l.expired()) { - dirty = true; - continue; - } - - listeners.emplace_back(l.lock()); - } - - std::vector statics; - for (auto& l : m_vStaticListeners) { - statics.emplace_back(l.get()); - } - - for (auto& l : listeners) { - // if there is only one lock, it means the event is only held by the listeners - // vector and was removed during our iteration - if (l.strongRef() == 1) { - dirty = true; - continue; - } - l->emit(data); - } - - for (auto& l : statics) { - l->emit(data); - } - - // release SPs - listeners.clear(); - - if (dirty) - std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); -} - -CHyprSignalListener CSignal::registerListener(std::function handler) { - CHyprSignalListener listener = makeShared(handler); - m_vListeners.emplace_back(WP(listener)); - return listener; -} - -void CSignal::registerStaticListener(std::function handler, void* owner) { - m_vStaticListeners.emplace_back(std::make_unique(handler, owner)); -} \ No newline at end of file diff --git a/src/helpers/signal/Signal.hpp b/src/helpers/signal/Signal.hpp index 3d04f7de..9eea3671 100644 --- a/src/helpers/signal/Signal.hpp +++ b/src/helpers/signal/Signal.hpp @@ -1,24 +1,5 @@ #pragma once -#include -#include -#include -#include +#include -#include "Listener.hpp" - -class CSignal { - public: - void emit(std::any data = {}); - - // - [[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener registerListener(std::function handler); - - // this is for static listeners. They die with this signal. - // TODO: can we somehow rid of the void* data and make it a custom this? - void registerStaticListener(std::function handler, void* owner); - - private: - std::vector> m_vListeners; - std::vector> m_vStaticListeners; -}; +using namespace Hyprutils::Signal; diff --git a/src/helpers/varlist/VarList.hpp b/src/helpers/varlist/VarList.hpp new file mode 100644 index 00000000..34629e4c --- /dev/null +++ b/src/helpers/varlist/VarList.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +using namespace Hyprutils::String; diff --git a/src/macros.hpp b/src/macros.hpp index 4c6d621c..cca088d8 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -4,9 +4,7 @@ #include #include -#include "helpers/memory/WeakPtr.hpp" - -#define UP std::unique_ptr +#include "helpers/memory/Memory.hpp" #ifndef NDEBUG #ifdef HYPRLAND_DEBUG diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 94dbab59..383d3246 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -3,7 +3,7 @@ #include #include "../defines.hpp" -#include "../helpers/memory/SharedPtr.hpp" +#include "../helpers/memory/Memory.hpp" struct SHyprIPCEvent { std::string event; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 5811f4a1..49ea39a3 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -6,13 +6,16 @@ #include "KeybindManager.hpp" #include "TokenManager.hpp" #include "debug/Log.hpp" -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include #include #include #include +#include +using namespace Hyprutils::String; + #include #include #include @@ -836,7 +839,7 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { void CKeybindManager::spawn(std::string args) { - args = removeBeginEndSpacesTabs(args); + args = trim(args); std::string RULES = ""; diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 52a54253..91fb82a0 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -5,8 +5,8 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" -#include "../helpers/memory/WeakPtr.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/signal/Signal.hpp" #include class CProtocolManager { diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index ea1b2029..fe4a4434 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -2,7 +2,7 @@ #include "../defines.hpp" #include "../helpers/Timer.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" #include #include diff --git a/src/managers/TokenManager.hpp b/src/managers/TokenManager.hpp index afe8c55b..4587f556 100644 --- a/src/managers/TokenManager.hpp +++ b/src/managers/TokenManager.hpp @@ -5,7 +5,7 @@ #include #include -#include "../helpers/memory/SharedPtr.hpp" +#include "../helpers/memory/Memory.hpp" class CUUIDToken { public: diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index fc0b2522..73f5dc73 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -4,7 +4,7 @@ #include #include -#include "../../helpers/memory/SharedPtr.hpp" +#include "../../helpers/memory/Memory.hpp" class CEventLoopTimer { public: diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 9fdf061c..930f3025 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -6,7 +6,7 @@ #include "../../helpers/WLClasses.hpp" #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include "../../devices/IPointer.hpp" #include "../../devices/ITouch.hpp" #include "../../devices/Tablet.hpp" diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index 9c5491bf..3151aedb 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -4,7 +4,7 @@ #include "../../desktop/WLSurface.hpp" #include "../../macros.hpp" #include "../../helpers/Box.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" class CInputMethodPopupV2; diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index e942add8..e13a1f1c 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -3,7 +3,7 @@ #include #include "../../defines.hpp" #include "../../helpers/WLClasses.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include "TextInput.hpp" #include "InputMethodPopup.hpp" #include diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 30fbb4cc..61a664b9 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -3,7 +3,7 @@ #include "../../helpers/WLListener.hpp" #include "../../macros.hpp" #include "../../helpers/Box.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include struct wl_client; diff --git a/src/meson.build b/src/meson.build index ef00d4e0..ccb1922a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -13,6 +13,7 @@ executable('Hyprland', src, dependency('cairo'), dependency('hyprcursor'), dependency('hyprlang', version: '>= 0.3.2'), + dependency('hyprutils', version: '>= 0.1.1'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 84faec4e..9118456b 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -1,6 +1,6 @@ #include "HookSystem.hpp" #include "../debug/Log.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../managers/TokenManager.hpp" #include "../Compositor.hpp" diff --git a/src/protocols/AlphaModifier.hpp b/src/protocols/AlphaModifier.hpp index d49d1e4e..1bb9cf23 100644 --- a/src/protocols/AlphaModifier.hpp +++ b/src/protocols/AlphaModifier.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "alpha-modifier-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CWLSurfaceResource; diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 80166f9f..a2d545c5 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -6,7 +6,7 @@ #include #include #include -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CFocusGrab; class CSeatGrab; diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 074a51f0..93465b81 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-gamma-control-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 12e324b7..81ae9a71 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/OutputPower.hpp b/src/protocols/OutputPower.hpp index 44788a8f..410742ca 100644 --- a/src/protocols/OutputPower.hpp +++ b/src/protocols/OutputPower.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-output-power-management-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 06bebb02..8a78de99 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -9,7 +9,7 @@ #include "pointer-constraints-unstable-v1.hpp" #include "../helpers/Vector2D.hpp" #include "../helpers/Region.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CWLSurface; class CWLSurfaceResource; diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index b17a8272..46981635 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -5,7 +5,7 @@ #include #include "../WaylandProtocol.hpp" #include "wayland.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index bdf4fac2..7f68454c 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" From 1c388e52fb71b116d728830f31883f0ef0e6cf17 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:18:51 +0200 Subject: [PATCH 0195/2393] session-lock: fix refocus after unlocking (#6423) --- src/protocols/SessionLock.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index ae45b0f1..e7abc7cb 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -114,9 +114,11 @@ CSessionLock::CSessionLock(SP resource_) : resource(resource_ return; } - events.unlockAndDestroy.emit(); - inert = true; PROTO::sessionLock->locked = false; + + events.unlockAndDestroy.emit(); + + inert = true; PROTO::sessionLock->destroyResource(this); }); } From 21b9e31bf432e3d58f408b83e7dd15b653b49494 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 10:35:30 -0700 Subject: [PATCH 0196/2393] layershell: Fix keyboard focus grabs (#4968) (#6394) --- src/desktop/LayerSurface.cpp | 85 +++++++++++++---------------- src/desktop/LayerSurface.hpp | 53 +++++++++--------- src/managers/input/InputManager.cpp | 37 ++++++++++++- src/managers/input/InputManager.hpp | 1 + 4 files changed, 103 insertions(+), 73 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 62cae8f6..0b2e23a3 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -116,8 +116,8 @@ void CLayerSurface::onDestroy() { void CLayerSurface::onMap() { Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); - mapped = true; - keyboardExclusive = layerSurface->current.interactivity; + mapped = true; + interactivity = layerSurface->current.interactivity; // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -133,12 +133,15 @@ void CLayerSurface::onMap() { surface->resource()->enter(PMONITOR->self.lock()); - if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + + if (ISEXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); - const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && - // don't focus if constrained - (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); + const bool GRABSFOCUS = ISEXCLUSIVE || + (layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + // don't focus if constrained + (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())); if (GRABSFOCUS) { // TODO: use the new superb really very cool grab @@ -177,9 +180,6 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); - if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource()); - if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -210,33 +210,8 @@ void CLayerSurface::onUnmap() { return; // refocus if needed - if (WASLASTFOCUS) { - g_pInputManager->releaseAllMouseButtons(); - - Vector2D surfaceCoords; - PHLLS pFoundLayerSurface; - SP foundSurface = nullptr; - - g_pCompositor->m_pLastFocus.reset(); - - // find LS-es to focus - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { - // if there isn't any, focus the last window - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - g_pCompositor->focusWindow(nullptr); - g_pCompositor->focusWindow(PLASTWINDOW); - } else { - // otherwise, full refocus - g_pInputManager->refocus(); - } - } + if (WASLASTFOCUS) + g_pInputManager->refocusLastWindow(PMONITOR); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); @@ -311,18 +286,36 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained - && !keyboardExclusive && mapped) { - g_pCompositor->focusSurface(surface->resource()); + if (mapped) { + const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); + const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; - const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); - g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { - g_pInputManager->refocus(); + if (!WASEXCLUSIVE && ISEXCLUSIVE) + g_pInputManager->m_dExclusiveLSes.push_back(self); + else if (WASEXCLUSIVE && !ISEXCLUSIVE) + std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); + + // if the surface was focused and interactive but now isn't, refocus + if (WASLASTFOCUS && !layerSurface->current.interactivity) { + // moveMouseUnified won't focus non interactive layers but it won't unfocus them either, + // so unfocus the surface here. + g_pCompositor->focusSurface(nullptr); + g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); + } else if (!WASEXCLUSIVE && !WASLASTFOCUS && + (ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) { + // if not focused last and exclusive or accepting input + unconstrained + g_pSeatManager->setGrab(nullptr); + g_pInputManager->releaseAllMouseButtons(); + g_pCompositor->focusSurface(surface->resource()); + + const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); + g_pInputManager->m_bEmptyFocusCursorSet = false; + } } - keyboardExclusive = layerSurface->current.interactivity; + interactivity = layerSurface->current.interactivity; g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); @@ -512,4 +505,4 @@ int CLayerSurface::popupsCount() { int no = -1; // we have one dummy popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; -} \ No newline at end of file +} diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 9fa96d2d..056f66a8 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -34,40 +34,41 @@ class CLayerSurface { WP layerSurface; wl_list link; - bool keyboardExclusive = false; + // the header providing the enum type cannot be imported here + int interactivity = 0; - SP surface; + SP surface; - bool mapped = false; - uint32_t layer = 0; + bool mapped = false; + uint32_t layer = 0; - int monitorID = -1; + int monitorID = -1; - bool fadingOut = false; - bool readyToDelete = false; - bool noProcess = false; - bool noAnimations = false; + bool fadingOut = false; + bool readyToDelete = false; + bool noProcess = false; + bool noAnimations = false; - bool forceBlur = false; - bool forceBlurPopups = false; - int xray = -1; - bool ignoreAlpha = false; - float ignoreAlphaValue = 0.f; - bool dimAround = false; + bool forceBlur = false; + bool forceBlurPopups = false; + int xray = -1; + bool ignoreAlpha = false; + float ignoreAlphaValue = 0.f; + bool dimAround = false; - std::optional animationStyle; + std::optional animationStyle; - PHLLSREF self; + PHLLSREF self; - CBox geometry = {0, 0, 0, 0}; - Vector2D position; - std::string szNamespace = ""; - std::unique_ptr popupHead; + CBox geometry = {0, 0, 0, 0}; + Vector2D position; + std::string szNamespace = ""; + std::unique_ptr popupHead; - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(); private: struct { @@ -83,4 +84,4 @@ class CLayerSurface { bool operator==(const CLayerSurface& rhs) const { return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; } -}; \ No newline at end of file +}; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 5ce53472..3e412b27 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -512,7 +512,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && - allowKeyboardRefocus) { + (allowKeyboardRefocus || pFoundLayerSurface->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)) { g_pCompositor->focusSurface(foundSurface); } @@ -1384,6 +1384,41 @@ void CInputManager::refocus() { mouseMoveUnified(0, true); } +void CInputManager::refocusLastWindow(CMonitor* pMonitor) { + if (!pMonitor) { + refocus(); + return; + } + + Vector2D surfaceCoords; + PHLLS pFoundLayerSurface; + SP foundSurface = nullptr; + + g_pInputManager->releaseAllMouseButtons(); + + // first try for an exclusive layer + if (!m_dExclusiveLSes.empty()) + foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource(); + + // then any surfaces above windows on the same monitor + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + // then the last focused window if we're on the same workspace as it + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + g_pCompositor->focusWindow(PLASTWINDOW); + } else { + // otherwise fall back to a normal refocus. + refocus(); + } +} + void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 930f3025..8050defe 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -104,6 +104,7 @@ class CInputManager { Vector2D getMouseCoordsInternal(); void refocus(); + void refocusLastWindow(CMonitor* pMonitor); void simulateMouseMovement(); void sendMotionEventsToFocused(); From e1b05f8eafd8cd3e7e9197fa1db92391174b9206 Mon Sep 17 00:00:00 2001 From: Moritz G <100203892+Moerliy@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:49:54 +0200 Subject: [PATCH 0197/2393] binds: Add description to key binds (#6358) --------- Co-authored-by: Yusuf Duran --- src/config/ConfigManager.cpp | 39 +++++++++++++++++++-------------- src/debug/HyprCtl.cpp | 14 ++++++++---- src/managers/KeybindManager.hpp | 36 ++++++++++++++++-------------- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6bb24e46..80af063b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -6,6 +6,7 @@ #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" +#include #include #include #include @@ -1957,15 +1958,16 @@ std::optional CConfigManager::handleBind(const std::string& command // bind[fl]=SUPER,G,exec,dmenu_run // flags - bool locked = false; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; - bool multiKey = false; - const auto BINDARGS = command.substr(4); + bool locked = false; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; + bool hasDescription = false; + const auto BINDARGS = command.substr(4); for (auto& arg : BINDARGS) { if (arg == 'l') { @@ -1984,6 +1986,8 @@ std::optional CConfigManager::handleBind(const std::string& command ignoreMods = true; } else if (arg == 's') { multiKey = true; + } else if (arg == 'd') { + hasDescription = true; } else { return "bind: invalid flag"; } @@ -1995,11 +1999,13 @@ std::optional CConfigManager::handleBind(const std::string& command if (mouse && (repeat || release || locked)) return "flag m is exclusive"; - const auto ARGS = CVarList(value, 4); + const int numbArgs = hasDescription ? 5 : 4; + const auto ARGS = CVarList(value, numbArgs); + const int DESCR_OFFSET = hasDescription ? 1 : 0; if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) return "bind: too few args"; - else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) + else if ((ARGS.size() > (size_t)4 + DESCR_OFFSET && !mouse) || (ARGS.size() > (size_t)3 + DESCR_OFFSET && mouse)) return "bind: too many args"; std::set KEYSYMS; @@ -2018,12 +2024,11 @@ std::optional CConfigManager::handleBind(const std::string& command const auto KEY = multiKey ? "" : ARGS[1]; - auto HANDLER = ARGS[2]; + const auto DESCRIPTION = hasDescription ? ARGS[2] : ""; - const auto COMMAND = mouse ? HANDLER : ARGS[3]; + auto HANDLER = ARGS[2 + DESCR_OFFSET]; - if (mouse) - HANDLER = "mouse"; + const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET]; // to lower std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower); @@ -2048,8 +2053,8 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, - repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey}); + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, + release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription}); } return {}; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6f4d74b7..a7e714bd 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1,5 +1,6 @@ #include "HyprCtl.hpp" +#include #include #include #include @@ -28,6 +29,7 @@ using namespace Hyprutils::String; #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" #include "config/ConfigManager.hpp" +#include "helpers/MiscFunctions.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -792,9 +794,11 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { ret += "e"; if (kb.nonConsuming) ret += "n"; + if (kb.hasDescription) + ret += "d"; - ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, - kb.keycode, kb.catchAll, kb.handler, kb.arg); + ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, + kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg); } } else { // json @@ -808,17 +812,19 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "release": {}, "repeat": {}, "non_consuming": {}, + "has_description": {}, "modmask": {}, "submap": "{}", "key": "{}", "keycode": {}, "catch_all": {}, + "description": "{}", "dispatcher": "{}", "arg": "{}" }},)#", kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", - kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler), - escapeJSONStrings(kb.arg)); + kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", + escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 305e563f..ecab6ee1 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -14,23 +14,25 @@ class CPluginSystem; class IKeyboard; struct SKeybind { - std::string key = ""; - std::set sMkKeys = {}; - uint32_t keycode = 0; - bool catchAll = false; - uint32_t modmask = 0; - std::set sMkMods = {}; - std::string handler = ""; - std::string arg = ""; - bool locked = false; - std::string submap = ""; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; - bool multiKey = false; + std::string key = ""; + std::set sMkKeys = {}; + uint32_t keycode = 0; + bool catchAll = false; + uint32_t modmask = 0; + std::set sMkMods = {}; + std::string handler = ""; + std::string arg = ""; + bool locked = false; + std::string submap = ""; + std::string description = ""; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; + bool hasDescription = false; // DO NOT INITIALIZE bool shadowed = false; From b6bf4afb4861c7a7b41c6bf53daadf57a708e352 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:56:35 +0000 Subject: [PATCH 0198/2393] layer: don't close special ws when restoring focus (#6424) modified: src/Compositor.cpp modified: src/Compositor.hpp modified: src/managers/input/InputManager.cpp --- src/Compositor.cpp | 11 +++++++++++ src/Compositor.hpp | 1 + src/managers/input/InputManager.cpp | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8b19f010..7d33889e 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1111,6 +1111,17 @@ bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) { return valid(w) && w->m_bVisible; } +bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { + if (!valid(w)) + return false; + + const auto PMONITOR = getMonitorFromID(w->m_iMonitorID); + if (PMONITOR->activeSpecialWorkspace) + return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID; + + return PMONITOR->activeWorkspace->m_iID == w->m_iID; +} + PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) { for (auto& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 793899ee..458e37a7 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -118,6 +118,7 @@ class CCompositor { PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); + bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); PHLWORKSPACE getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3e412b27..033f4d6d 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1409,7 +1409,7 @@ void CInputManager::refocusLastWindow(CMonitor* pMonitor) { foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisibleNotCovered(g_pCompositor->m_pLastWindow->m_pWorkspace)) { // then the last focused window if we're on the same workspace as it const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); g_pCompositor->focusWindow(PLASTWINDOW); From 8412ffcc42012888757cd00a004871e8bc353cf2 Mon Sep 17 00:00:00 2001 From: Moritz G <100203892+Moerliy@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:02:29 +0200 Subject: [PATCH 0199/2393] keybinds: fix bindm (#6429) * fixed mouse dispatcher * no brakets * move command up --- src/config/ConfigManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 80af063b..e0de33cf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2030,6 +2030,9 @@ std::optional CConfigManager::handleBind(const std::string& command const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET]; + if (mouse) + HANDLER = "mouse"; + // to lower std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower); From 32283ed706291255d8e8b5d1249bbc2394bf532f Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:56:35 +0000 Subject: [PATCH 0200/2393] groupbar: fix groupbar position rounding (#6433) modified: src/render/decorations/CHyprGroupBarDecoration.cpp --- src/render/decorations/CHyprGroupBarDecoration.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index a87dba31..e461ba08 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -119,15 +119,15 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { g_pDecorationPositioner->repositionDeco(this); } - int xoff = 0; - int yoff = 0; + float xoff = 0; + float yoff = 0; for (int i = 0; i < barsToDraw; ++i) { const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i; - CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, - BAR_INDICATOR_HEIGHT}; + CBox rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, + m_fBarWidth, BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -151,8 +151,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); - rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, + rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}; rect.scale(pMonitor->scale); From f687105eff61aebff34669852e7153584286a357 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 16:02:19 +0200 Subject: [PATCH 0201/2393] compositor: update suspended states on moveworkspacetomonitor fixes #6417 --- src/Compositor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7d33889e..20bc82e7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2098,9 +2098,11 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon if (POLDMON) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID); updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace); + updateSuspendedStates(); } updateFullscreenFadeOnWorkspace(pWorkspace); + updateSuspendedStates(); // event g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName}); From 1bae19ce85ae9a25f2dddb6cee8bbd6ed3872ade Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 16:16:27 +0200 Subject: [PATCH 0202/2393] datadevice: only send actions for ver >= 3 fixes #6444 --- src/protocols/core/DataDevice.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index ca044e93..c1de8f83 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -85,8 +85,10 @@ void CWLDataOfferResource::sendData() { if (!source) return; - resource->sendSourceActions(7); - resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + if (resource->version() >= 3) { + resource->sendSourceActions(7); + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + } for (auto& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); From c7e85e26f761fb58db6692649e259589cdf55cf0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 12 Jun 2024 16:49:26 +0200 Subject: [PATCH 0203/2393] seat: fixup touch event handling fixes #6353 --- src/managers/SeatManager.cpp | 50 ++++++++++++++++++------------------ src/managers/SeatManager.hpp | 1 + src/protocols/core/Seat.cpp | 21 +++++++-------- src/protocols/core/Seat.hpp | 2 ++ 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 862bd2b5..c1b13ccb 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -337,34 +337,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double } void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, int32_t id, const Vector2D& local) { - if (state.touchFocus == surf) - return; - listeners.touchSurfaceDestroy.reset(); - if (state.touchFocusResource) { - auto client = state.touchFocusResource->client(); - for (auto& s : seatResources) { - if (s->resource->client() != client) - continue; - - for (auto& t : s->resource->touches) { - if (!t) - continue; - - t->sendUp(timeMs, id); - } - } - } - state.touchFocusResource.reset(); state.touchFocus = surf; - if (!surf) { - events.touchFocusChange.emit(); - return; - } - auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) @@ -381,11 +358,34 @@ void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, i listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); }); - events.touchFocusChange.emit(); + touchLocks++; + + if (touchLocks <= 1) + events.touchFocusChange.emit(); } void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) { - sendTouchDown(nullptr, timeMs, id, {}); + if (!state.touchFocusResource || touchLocks <= 0) + return; + + auto client = state.touchFocusResource->client(); + for (auto& r : seatResources | std::views::reverse) { + if (r->resource->client() != client) + continue; + + state.touchFocusResource = r->resource; + for (auto& t : r->resource->touches) { + if (!t) + continue; + + t->sendUp(timeMs, id); + } + } + + touchLocks--; + + if (touchLocks <= 0) + events.touchFocusChange.emit(); } void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index e74d9ace..1a1df1d5 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -155,6 +155,7 @@ class CSeatManager { } listeners; Vector2D lastLocalCoords; + int touchLocks = 0; // we assume there aint like 20 touch devices at once... friend struct SSeatResourceContainer; friend class CSeatGrab; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 8bf03909..331eb15e 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -25,37 +25,38 @@ void CWLTouchResource::sendDown(SP surface, uint32_t timeMs, if (!owner) return; - if (currentSurface) { - LOGM(WARN, "requested CWLTouchResource::sendDown without sendUp first."); - sendUp(timeMs, id); - } - ASSERT(surface->client() == owner->client()); currentSurface = surface; listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); }); resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + + fingers++; } void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { - if (!owner || !currentSurface) + if (!owner) return; resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); - currentSurface.reset(); - listeners.destroySurface.reset(); + fingers--; + if (fingers <= 0) { + currentSurface.reset(); + listeners.destroySurface.reset(); + fingers = 0; + } } void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { - if (!owner || !currentSurface) + if (!owner) return; resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLTouchResource::sendFrame() { - if (!owner || !currentSurface) + if (!owner) return; resource->sendFrame(); diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 524783f9..625d3a98 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -46,6 +46,8 @@ class CWLTouchResource { SP resource; WP currentSurface; + int fingers = 0; + struct { CHyprSignalListener destroySurface; } listeners; From 9d7d5ec3c8ea3550ca3053a7a26e97231ad6fde9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 17:03:04 +0200 Subject: [PATCH 0204/2393] seatmgr: fix missing nullcheck in updateActiveKeyboardData sometimes we may set a keyboard that's about-to-be-deleted, we might as well check for that additionally avoid setting null keyboards altogether --- src/managers/SeatManager.cpp | 2 +- src/managers/input/InputManager.cpp | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index c1b13ccb..a58bca72 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -94,7 +94,7 @@ void CSeatManager::setKeyboard(SP KEEB) { } void CSeatManager::updateActiveKeyboardData() { - if (keyboard) + if (keyboard && keyboard->wlr()) PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); PROTO::seat->updateKeymap(); } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 033f4d6d..ed8e834c 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1226,12 +1226,20 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { - const auto PNEWKEYBOARD = m_vKeyboards.back(); - g_pSeatManager->setKeyboard(PNEWKEYBOARD); - PNEWKEYBOARD->active = true; - } else { + bool found = false; + for (auto& k : m_vKeyboards | std::views::reverse) { + if (!k->wlr()) + continue; + + g_pSeatManager->setKeyboard(k); + found = true; + break; + } + + if (!found) + g_pSeatManager->setKeyboard(nullptr); + } else g_pSeatManager->setKeyboard(nullptr); - } removeFromHIDs(pKeyboard); } From a99f314106cd2ae45e12e7c4012ab68026cf5522 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 18:39:52 +0200 Subject: [PATCH 0205/2393] input: fallback to main surface if not found on window fixes #6421 --- src/managers/input/InputManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index ed8e834c..3aa8d2ae 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -351,6 +351,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (pFoundWindow) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); + if (!foundSurface) { + foundSurface = pFoundWindow->m_pWLSurface->resource(); + surfacePos = pFoundWindow->m_vRealPosition.value(); + } } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); From 38132ffaf53c843a3ed03be5b305702fde8f5a49 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:28:52 -0500 Subject: [PATCH 0206/2393] renderer: properly software lock cursors with zoom_factor (#6434) --- src/managers/PointerManager.cpp | 14 ++++++++++++++ src/managers/PointerManager.hpp | 2 ++ src/render/Renderer.cpp | 16 +++++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 80a7ee76..bf7b5d0a 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -150,6 +150,20 @@ CPointerManager::CPointerManager() { }); } +void CPointerManager::lockSoftwareAll() { + for (auto& state : monitorStates) + state->softwareLocks++; + + updateCursorBackend(); +} + +void CPointerManager::unlockSoftwareAll() { + for (auto& state : monitorStates) + state->softwareLocks--; + + updateCursorBackend(); +} + void CPointerManager::lockSoftwareForMonitor(SP mon) { auto state = stateFor(mon); state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index b71a79c3..1e386797 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -43,6 +43,8 @@ class CPointerManager { void lockSoftwareForMonitor(SP pMonitor); void unlockSoftwareForMonitor(SP pMonitor); + void lockSoftwareAll(); + void unlockSoftwareAll(); void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8fac5869..48fa92a0 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1253,6 +1253,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { TRACY_GPU_ZONE("Render"); + static bool zoomLock = false; + if (zoomLock && *PZOOMFACTOR == 1.f) { + g_pPointerManager->unlockSoftwareAll(); + zoomLock = false; + } else if (!zoomLock && *PZOOMFACTOR != 1.f) { + g_pPointerManager->lockSoftwareAll(); + zoomLock = true; + } + if (pMonitor == g_pCompositor->getMonitorFromCursor()) g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY); else @@ -1265,10 +1274,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->forceFullFrames = 10; } - bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; - if (lockSoftware) - g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); - CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); @@ -1370,9 +1375,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { endRender(); - if (lockSoftware) - g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); - TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { From 18ee9ece9cec51daa75fbf765d9fa6b72ef898e5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 22:57:06 +0200 Subject: [PATCH 0207/2393] layershell: minor fixes to re-mapping of layers ref #2012 --- src/Compositor.cpp | 4 ++++ src/Compositor.hpp | 1 + src/desktop/LayerSurface.cpp | 19 +++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 20bc82e7..8f36b4ae 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1361,6 +1361,10 @@ void CCompositor::addToFadingOutSafe(PHLLS pLS) { m_vSurfacesFadingOut.emplace_back(pLS); } +void CCompositor::removeFromFadingOutSafe(PHLLS ls) { + std::erase(m_vSurfacesFadingOut, ls); +} + void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 458e37a7..242c3b13 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -156,6 +156,7 @@ class CCompositor { PHLWINDOW getX11Parent(PHLWINDOW); void scheduleFrameForMonitor(CMonitor*); void addToFadingOutSafe(PHLLS); + void removeFromFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLWINDOW); PHLWINDOW getWindowByRegex(const std::string&); void warpCursorTo(const Vector2D&, bool force = false); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 0b2e23a3..2eb66440 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -119,6 +119,10 @@ void CLayerSurface::onMap() { mapped = true; interactivity = layerSurface->current.interactivity; + // this layer might be re-mapped. + fadingOut = false; + g_pCompositor->removeFromFadingOutSafe(self.lock()); + // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -204,8 +208,6 @@ void CLayerSurface::onUnmap() { const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); - surface.reset(); - if (!PMONITOR) return; @@ -221,12 +223,25 @@ void CLayerSurface::onUnmap() { g_pHyprRenderer->damageBox(&geomFixed); g_pInputManager->sendMotionEventsToFocused(); + + g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); } void CLayerSurface::onCommit() { if (!layerSurface) return; + if (!mapped) { + // we're re-mapping if this is the case + if (layerSurface->surface && !layerSurface->surface->current.buffer) { + fadingOut = false; + geometry = {}; + g_pHyprRenderer->arrangeLayersForMonitor(monitorID); + } + + return; + } + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); if (!PMONITOR) From 0e18da8467136806d191f84c88aa7536453869e0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 23:28:52 +0200 Subject: [PATCH 0208/2393] foreign-toplevel: fixup output resource finding fixes #6457 --- src/protocols/ForeignToplevelWlr.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 8224f495..14800393 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -122,25 +122,19 @@ void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { if (lastMonitorID == (int64_t)pMonitor->ID) return; - const auto CLIENT = resource->client(); - - struct wl_resource* outputResource; + const auto CLIENT = resource->client(); 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; + const auto OLDRESOURCE = PROTO::outputs.at(PLASTMONITOR->szName)->outputResourceFrom(CLIENT); - resource->sendOutputLeave(outputResource); - } + if (OLDRESOURCE) + resource->sendOutputLeave(OLDRESOURCE->getResource()->resource()); } - wl_resource_for_each(outputResource, &pMonitor->output->resources) { - if (wl_resource_get_client(outputResource) != CLIENT) - continue; + const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT); - resource->sendOutputEnter(outputResource); - } + if (NEWRESOURCE) + resource->sendOutputEnter(NEWRESOURCE->getResource()->resource()); lastMonitorID = pMonitor->ID; } From a9d7befc36f2890f080d02b8c04b678778ded080 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 23:29:24 +0200 Subject: [PATCH 0209/2393] formats: fixup for legacy_renderer builds --- src/helpers/Format.cpp | 94 ++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 343440b4..9c94f68b 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -93,70 +93,100 @@ inline const std::vector GLES3_FORMATS = { .bytesPerBlock = 2, }, { - .drmFormat = DRM_FORMAT_XBGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_XBGR2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XBGR2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_ABGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_ABGR2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XBGR2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XRGB2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_XRGB2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XRGB2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_ARGB2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_ARGB2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XRGB2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XBGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT, + .drmFormat = DRM_FORMAT_XBGR16161616F, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_HALF_FLOAT, +#else + .glType = GL_HALF_FLOAT_OES, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XBGR16161616F, .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_ABGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT, + .drmFormat = DRM_FORMAT_ABGR16161616F, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_HALF_FLOAT, +#else + .glType = GL_HALF_FLOAT_OES, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XBGR16161616F, .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_XBGR16161616, - .glInternalFormat = GL_RGBA16UI, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = false, - .alphaStripped = DRM_FORMAT_XBGR16161616, - .bytesPerBlock = 8, + .drmFormat = DRM_FORMAT_XBGR16161616, +#ifndef GLES2 + .glFormat = GL_RGBA16UI, +#else + .glFormat = GL_RGBA16_EXT, +#endif + .glType = GL_UNSIGNED_SHORT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_ABGR16161616, - .glInternalFormat = GL_RGBA16UI, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = true, - .alphaStripped = DRM_FORMAT_XBGR16161616, - .bytesPerBlock = 8, + .drmFormat = DRM_FORMAT_ABGR16161616, +#ifndef GLES2 + .glFormat = GL_RGBA16UI, +#else + .glFormat = GL_RGBA16_EXT, +#endif + .glType = GL_UNSIGNED_SHORT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, }, { .drmFormat = DRM_FORMAT_YVYU, From d677ac6f87acf97103327e321f7a05a0ce5774d6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 11:33:20 +0200 Subject: [PATCH 0210/2393] hyprpm: print all types of cmake errors during configure --- hyprpm/src/core/PluginManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 446d6af3..f9e9664a 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -479,13 +479,16 @@ bool CPluginManager::updateHeaders(bool force) { if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); - if (ret.contains("required packages were not found")) { + if (ret.contains("CMake Error at")) { // missing deps, let the user know. - std::string missing = ret.substr(ret.find("The following required packages were not found:")); - missing = missing.substr(0, missing.find("Call Stack")); + std::string missing = ret.substr(ret.find("CMake Error at")); + missing = ret.substr(ret.find_first_of('\n') + 1); + missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find_last_of('\n')); - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n"; + std::cerr << "\n" + << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" + << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n"; return false; } From a54f98c20301a71efe5e73a8fc5e1bcd66f2bd34 Mon Sep 17 00:00:00 2001 From: "Yang, Ying-chao" Date: Thu, 13 Jun 2024 17:33:47 +0800 Subject: [PATCH 0211/2393] virtualkeyboard: check if VirtualKeyboard is valid before accessing client. (#6460) This fixes crash when restarting fcitx (#6378) --- src/protocols/InputMethodV2.cpp | 4 ++-- src/protocols/VirtualKeyboard.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 5d0bd417..24f7ad54 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -81,7 +81,7 @@ SP CInputMethodKeyboardGrabV2::getOwner() { } wl_client* CInputMethodKeyboardGrabV2::client() { - return resource->client(); + return resource->resource() ? resource->client() : nullptr; } CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, SP owner_, SP surface) : resource(resource_), owner(owner_) { @@ -373,4 +373,4 @@ void CInputMethodV2Protocol::onGetIME(CZwpInputMethodManagerV2* mgr, wl_resource LOGM(LOG, "New IME with resource id {}", id); events.newIME.emit(RESOURCE); -} \ No newline at end of file +} diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 89b14c32..009c277c 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -100,7 +100,7 @@ wlr_keyboard* CVirtualKeyboardV1Resource::wlr() { } wl_client* CVirtualKeyboardV1Resource::client() { - return resource->client(); + return resource->resource() ? resource->client() : nullptr; } void CVirtualKeyboardV1Resource::releasePressed() { @@ -151,4 +151,4 @@ void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, LOGM(LOG, "New VKeyboard at id {}", id); events.newKeyboard.emit(RESOURCE); -} \ No newline at end of file +} From 9e781040d9067c2711ec2e9f5b47b76ef70762b3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 11:54:01 +0200 Subject: [PATCH 0212/2393] props: bump version to 0.41.1 --- props.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/props.json b/props.json index d9bd7cea..4af3eb2a 100644 --- a/props.json +++ b/props.json @@ -1,3 +1,3 @@ { - "version": "0.41.0" + "version": "0.41.1" } \ No newline at end of file From e6d10539af1fdca33b10bc3c1dfac16f1cdfe1c8 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 13 Jun 2024 12:08:02 +0200 Subject: [PATCH 0213/2393] core: fix a few small memory leaks on exit (#6470) * renderer: add destructor and destroy event source add destructor and destroy the event source. one less leak on exit of compositor reported by asan. * compositor: cleanup eventloop on exit destruct hyprctl to release the event sources, and properly cleanup the event loop on exit of compositor. less leaks on exit reported by asan * threadmgr: destroy event source on destruction destroy the event source on destruction. * eventloopmgr: reset eventloopmgr on exit aswell reset the eventloopmanager on exit of compositor and free the leaking last idle frame on monitor destroy. --- src/Compositor.cpp | 3 +++ src/events/Monitors.cpp | 3 +++ src/managers/ThreadManager.cpp | 3 ++- src/render/Renderer.cpp | 5 +++++ src/render/Renderer.hpp | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8f36b4ae..2f972335 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -351,6 +351,8 @@ void CCompositor::cleanup() { g_pXWaylandManager.reset(); g_pPointerManager.reset(); g_pSeatManager.reset(); + g_pHyprCtl.reset(); + g_pEventLoopManager.reset(); if (m_sWLRRenderer) wlr_renderer_destroy(m_sWLRRenderer); @@ -364,6 +366,7 @@ 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; diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index e3f8f03a..17b8ef65 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -188,6 +188,9 @@ void Events::listener_monitorDestroy(void* owner, void* data) { Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); + if (pMonitor->output->idle_frame) + wl_event_source_remove(pMonitor->output->idle_frame); + pMonitor->onDisconnect(true); pMonitor->output = nullptr; diff --git a/src/managers/ThreadManager.cpp b/src/managers/ThreadManager.cpp index cd892503..6f8e0c9a 100644 --- a/src/managers/ThreadManager.cpp +++ b/src/managers/ThreadManager.cpp @@ -25,5 +25,6 @@ CThreadManager::CThreadManager() { } CThreadManager::~CThreadManager() { - // + if (m_esConfigTimer) + wl_event_source_remove(m_esConfigTimer); } \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 48fa92a0..4fe35c7e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -90,6 +90,11 @@ CHyprRenderer::CHyprRenderer() { wl_event_source_timer_update(m_pCursorTicker, 500); } +CHyprRenderer::~CHyprRenderer() { + if (m_pCursorTicker) + wl_event_source_remove(m_pCursorTicker); +} + static void renderSurface(SP surface, int x, int y, void* data) { if (!surface->current.buffer || !surface->current.buffer->texture) return; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index f88bfebf..60101e87 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -42,6 +42,7 @@ struct SSessionLockSurface; class CHyprRenderer { public: CHyprRenderer(); + ~CHyprRenderer(); void renderMonitor(CMonitor* pMonitor); void arrangeLayersForMonitor(const int&); From 4842eb83b444418ad3fe1901d645dd02224989e5 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 13 Jun 2024 12:20:14 +0000 Subject: [PATCH 0214/2393] helpers: make shm_open() portable after 8bcccf9f0f0f (#6471) https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html https://man.freebsd.org/shm_open/2 https://www.man7.org/linux/man-pages/man3/shm_open.3.html --- src/helpers/MiscFunctions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b1d734c8..346a3ffa 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -814,7 +814,8 @@ bool envEnabled(const std::string& env) { } std::pair openExclusiveShm() { - std::string name = g_pTokenManager->getRandomUUID(); + // Only absolute paths can be shared across different shm_open() calls + std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); From 5de273a14427cb4a4cad9ac57a22b418bcd4248d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 17:32:32 +0200 Subject: [PATCH 0215/2393] xwayland: drop some spammy logs to trace fixes #6478 --- src/xwayland/XWM.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 7af1d506..247af4b7 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -248,11 +248,11 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ } } } else { - Debug::log(LOG, "[xwm] Unhandled prop {} -> {}", atom, propName); + Debug::log(TRACE, "[xwm] Unhandled prop {} -> {}", atom, propName); return; } - Debug::log(LOG, "[xwm] Handled prop {} -> {}", atom, propName); + Debug::log(TRACE, "[xwm] Handled prop {} -> {}", atom, propName); } void CXWM::handlePropertyNotify(xcb_property_notify_event_t* e) { @@ -354,11 +354,11 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { } else if (e->type == HYPRATOMS["_NET_ACTIVE_WINDOW"]) { XSURF->events.activate.emit(); } else { - Debug::log(LOG, "[xwm] Unhandled message prop {} -> {}", e->type, propName); + Debug::log(TRACE, "[xwm] Unhandled message prop {} -> {}", e->type, propName); return; } - Debug::log(LOG, "[xwm] Handled message prop {} -> {}", e->type, propName); + Debug::log(TRACE, "[xwm] Handled message prop {} -> {}", e->type, propName); } void CXWM::handleFocusIn(xcb_focus_in_event_t* e) { @@ -490,18 +490,18 @@ std::string CXWM::mimeFromAtom(xcb_atom_t atom) { } void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { - Debug::log(LOG, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target); + Debug::log(TRACE, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target); SXSelection& sel = clipboard; if (e->property == XCB_ATOM_NONE) { if (sel.transfer) { - Debug::log(ERR, "[xwm] converting selection failed"); + Debug::log(TRACE, "[xwm] converting selection failed"); sel.transfer.reset(); } } else if (e->target == HYPRATOMS["TARGETS"]) { if (!focusedSurface) { - Debug::log(LOG, "[xwm] denying access to write to clipboard because no X client is in focus"); + Debug::log(TRACE, "[xwm] denying access to write to clipboard because no X client is in focus"); return; } @@ -519,7 +519,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { - Debug::log(LOG, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor, + Debug::log(TRACE, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor, e->selection); SXSelection& sel = clipboard; @@ -542,7 +542,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { } if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient) { - Debug::log(LOG, "[xwm] Ignoring clipboard access: xwayland not in focus"); + Debug::log(TRACE, "[xwm] Ignoring clipboard access: xwayland not in focus"); selectionSendNotify(e, false); return; } @@ -585,7 +585,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { } bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) { - Debug::log(LOG, "[xwm] Selection xfixes notify for {}", e->selection); + Debug::log(TRACE, "[xwm] Selection xfixes notify for {}", e->selection); // IMPORTANT: mind the g_pSeatManager below SXSelection& sel = clipboard; From 8055b1c00a102f5419e40f5eddfb6ee8be693f33 Mon Sep 17 00:00:00 2001 From: phonetic112 <73647246+phonetic112@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:23:23 -0400 Subject: [PATCH 0216/2393] misc: Fix build warnings (#6486) --- hyprpm/src/core/PluginManager.cpp | 7 ++++--- src/helpers/MiscFunctions.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index f9e9664a..e8c6e251 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -24,9 +24,10 @@ using namespace Hyprutils::String; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; - std::array buffer; - std::string result; - const std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); + std::array buffer; + std::string result; + using PcloseType = int (*)(FILE*); + const std::unique_ptr pipe(popen(cmd.c_str(), "r"), static_cast(pclose)); if (!pipe) return ""; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 346a3ffa..821f3231 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -580,9 +580,10 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve // Execute a shell command and get the output std::string execAndGet(const char* cmd) { - std::array buffer; - std::string result; - const std::unique_ptr pipe(popen(cmd, "r"), pclose); + std::array buffer; + std::string result; + using PcloseType = int (*)(FILE*); + const std::unique_ptr pipe(popen(cmd, "r"), static_cast(pclose)); if (!pipe) { Debug::log(ERR, "execAndGet: failed in pipe"); return ""; From 9cd5b3587cb1e3d42b647fa230024cd0153ea9cb Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Fri, 14 Jun 2024 02:52:37 -0700 Subject: [PATCH 0217/2393] layerSurface: fix layer being refocused every commit with on_demand (#6487) * layerSurface: fix layer being refocused every commit with on_demand Fixes #6477 The surface will now only receive focus when its keyboard interactivity is more than the previous keyboard interactivity in the order none -> on_demand -> exclusive. * layerSurface: only kb focus if becoming exclusive --- src/desktop/LayerSurface.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 2eb66440..64eeead1 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -317,9 +317,8 @@ void CLayerSurface::onCommit() { // so unfocus the surface here. g_pCompositor->focusSurface(nullptr); g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); - } else if (!WASEXCLUSIVE && !WASLASTFOCUS && - (ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) { - // if not focused last and exclusive or accepting input + unconstrained + } else if (!WASEXCLUSIVE && ISEXCLUSIVE) { + // if now exclusive and not previously g_pSeatManager->setGrab(nullptr); g_pInputManager->releaseAllMouseButtons(); g_pCompositor->focusSurface(surface->resource()); From b2590b58c51094424a9651d8df37dfab838b5bbb Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:11:40 +0300 Subject: [PATCH 0218/2393] hyprctl: added --follow option to rolliglog (#6325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- Makefile | 2 +- hyprctl/Strings.hpp | 5 ++- hyprctl/main.cpp | 71 ++++++++++++++++++++++++++++++---- src/debug/HyprCtl.cpp | 51 +++++++++++++++++++++++- src/debug/Log.cpp | 4 ++ src/debug/RollingLogFollow.hpp | 65 +++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 src/debug/RollingLogFollow.hpp diff --git a/Makefile b/Makefile index a33f4cb7..493a6784 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ uninstall: pluginenv: @echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n" @exit 1 - + installheaders: @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index 76e87ecb..17725e77 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -38,7 +38,8 @@ commands: plugin ... → Issue a plugin request reload [config-only] → Issue a reload to force reload the config. Pass 'config-only' to disable monitor reload - rollinglog → Prints tail of the log + rollinglog → Prints tail of the log. Also supports -f/--follow + option setcursor → Sets the cursor theme and reloads the cursor manager seterror → Sets the hyprctl error string. Color has @@ -112,7 +113,7 @@ create : remove : Removes virtual output. Pass the output's name, as found in 'hyprctl monitors' - + flags: See 'hyprctl --help')#"; diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 8fb9194c..f5de041b 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -1,9 +1,9 @@ -#include +#include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -22,8 +22,9 @@ #include #include #include -#include +#include #include +#include #include using namespace Hyprutils::String; @@ -100,13 +101,53 @@ std::vector instances() { return result; } -int request(std::string arg, int minArgs = 0) { +static volatile bool sigintReceived = false; +void intHandler(int sig) { + sigintReceived = true; + std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl; +} + +int rollingRead(const int socket) { + sigintReceived = false; + signal(SIGINT, intHandler); + + constexpr size_t BUFFER_SIZE = 8192; + std::array buffer = {0}; + int sizeWritten = 0; + std::cout << "[hyprctl] reading from socket following up log:" << std::endl; + while (!sigintReceived) { + sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); + if (sizeWritten < 0 && errno != EAGAIN) { + if (errno != EINTR) + std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl; + close(socket); + return 5; + } + + if (sizeWritten == 0) + break; + + if (sizeWritten > 0) { + std::cout << std::string(buffer.data(), sizeWritten); + buffer.fill('\0'); + } + + usleep(100000); + } + close(socket); + return 0; +} + +int request(std::string arg, int minArgs = 0, bool needRoll = false) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + auto t = timeval{.tv_sec = 0, .tv_usec = 100000}; + setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)); + const auto ARGS = std::count(arg.begin(), arg.end(), ' '); if (ARGS < minArgs) { - log("Not enough arguments, expected at least " + minArgs); + log(std::format("Not enough arguments in '{}', expected at least {}", arg, minArgs)); return -1; } @@ -141,6 +182,9 @@ int request(std::string arg, int minArgs = 0) { return 4; } + if (needRoll) + return rollingRead(SERVERSOCKET); + std::string reply = ""; char buffer[8192] = {0}; @@ -284,6 +328,7 @@ int main(int argc, char** argv) { std::string fullArgs = ""; const auto ARGS = splitArgs(argc, argv); bool json = false; + bool needRoll = false; std::string overrideInstance = ""; for (std::size_t i = 0; i < ARGS.size(); ++i) { @@ -303,6 +348,9 @@ int main(int argc, char** argv) { fullArgs += "a"; } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) { fullArgs += "c"; + } else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) { + fullArgs += "f"; + needRoll = true; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { @@ -362,6 +410,11 @@ int main(int argc, char** argv) { return 0; } + if (needRoll && !fullRequest.contains("/rollinglog")) { + log("only 'rollinglog' command supports '--follow' option"); + return 1; + } + if (overrideInstance.contains("_")) instanceSignature = overrideInstance; else if (!overrideInstance.empty()) { @@ -421,6 +474,8 @@ int main(int argc, char** argv) { exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/--help")) std::cout << USAGE << std::endl; + else if (fullRequest.contains("/rollinglog") && needRoll) + exitStatus = request(fullRequest, 0, true); else { exitStatus = request(fullRequest); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a7e714bd..70b886f2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -28,6 +28,7 @@ using namespace Hyprutils::String; #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "debug/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" @@ -1732,6 +1733,46 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) { return getReply(input); } +bool successWrite(int fd, const std::string& data, bool needLog = true) { + if (write(fd, data.c_str(), data.length()) > 0) + return true; + + if (errno == EAGAIN) + return true; + + if (needLog) + Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); + + return false; +} + +void runWritingDebugLogThread(const int conn) { + using namespace std::chrono_literals; + Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn); + //will be finished, when reading side close connection + std::thread([conn]() { + while (Debug::RollingLogFollow::Get().IsRunning()) { + if (Debug::RollingLogFollow::Get().isEmpty(conn)) { + std::this_thread::sleep_for(1000ms); + continue; + } + + auto line = Debug::RollingLogFollow::Get().GetLog(conn); + if (!successWrite(conn, line)) + // We cannot write, when connection is closed. So thread will successfully exit by itself + break; + + std::this_thread::sleep_for(100ms); + } + close(conn); + Debug::RollingLogFollow::Get().StopFor(conn); + }).detach(); +} + +bool isFollowUpRollingLogRequest(const std::string& request) { + return request.contains("rollinglog") && request.contains("f"); +} + int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; @@ -1775,9 +1816,15 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) { reply = "Err: " + std::string(e.what()); } - write(ACCEPTEDCONNECTION, reply.c_str(), reply.length()); + successWrite(ACCEPTEDCONNECTION, reply); - close(ACCEPTEDCONNECTION); + if (isFollowUpRollingLogRequest(request)) { + Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket."); + Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION); + runWritingDebugLogThread(ACCEPTEDCONNECTION); + Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo()); + } else + close(ACCEPTEDCONNECTION); if (g_pConfigManager->m_bWantsMonitorReload) g_pConfigManager->ensureMonitorStatus(); diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 8b82c852..7547204a 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -1,6 +1,7 @@ #include "Log.hpp" #include "../defines.hpp" #include "../Compositor.hpp" +#include "RollingLogFollow.hpp" #include #include @@ -73,6 +74,9 @@ void Debug::log(LogLevel level, std::string str) { if (rollingLog.size() > ROLLING_LOG_SIZE) rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); + if (RollingLogFollow::Get().IsRunning()) + RollingLogFollow::Get().AddLog(str); + if (!disableLogs || !**disableLogs) { // log to a file std::ofstream ofs; diff --git a/src/debug/RollingLogFollow.hpp b/src/debug/RollingLogFollow.hpp new file mode 100644 index 00000000..5ff018af --- /dev/null +++ b/src/debug/RollingLogFollow.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +namespace Debug { + struct RollingLogFollow { + std::unordered_map socketToRollingLogFollowQueue; + std::shared_mutex m; + bool running = false; + static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; + + // Returns true if the queue is empty for the given socket + bool isEmpty(int socket) { + std::shared_lock r(m); + return socketToRollingLogFollowQueue[socket].empty(); + } + + std::string DebugInfo() { + std::shared_lock r(m); + return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size()); + } + + std::string GetLog(int socket) { + std::unique_lock w(m); + + const std::string ret = socketToRollingLogFollowQueue[socket]; + socketToRollingLogFollowQueue[socket] = ""; + + return ret; + }; + + void AddLog(std::string log) { + std::unique_lock w(m); + running = true; + std::vector to_erase; + for (const auto& p : socketToRollingLogFollowQueue) + socketToRollingLogFollowQueue[p.first] += log + "\n"; + } + + bool IsRunning() { + std::shared_lock r(m); + return running; + } + + void StopFor(int socket) { + std::unique_lock w(m); + socketToRollingLogFollowQueue.erase(socket); + if (socketToRollingLogFollowQueue.empty()) + running = false; + } + + void StartFor(int socket) { + std::unique_lock w(m); + socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); + running = true; + } + + static RollingLogFollow& Get() { + static RollingLogFollow instance; + static std::mutex gm; + std::lock_guard lock(gm); + return instance; + }; + }; +} From a9d53a2252f7ec084e2487d18777e2df01c8c351 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:45:32 +0300 Subject: [PATCH 0219/2393] vrr: add option to fix mouse breaking vrr (#6483) * option to fix mouse breaking vrr * skip damage on mouse move * remove this-> & cleanup * add cursor:min_refresh_rate to avoid cursor freezing * run clang-format --------- Co-authored-by: UjinT34 --- src/config/ConfigManager.cpp | 2 ++ src/helpers/Monitor.cpp | 18 ++++++++++++++++++ src/helpers/Monitor.hpp | 1 + src/managers/PointerManager.cpp | 2 +- src/managers/input/InputManager.cpp | 6 ++++-- src/render/Renderer.cpp | 5 +++-- src/render/Renderer.hpp | 2 +- 7 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e0de33cf..f63ff552 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -522,6 +522,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 027b47bd..58687e09 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -362,6 +362,24 @@ void CMonitor::addDamage(const CBox* box) { g_pCompositor->scheduleFrameForMonitor(this); } +bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { + static auto PNOBREAK = CConfigValue("cursor:no_break_fs_vrr"); + static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); + + // skip scheduling extra frames for fullsreen apps with vrr + bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && + activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; + + // keep requested minimum refresh rate + if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { + // damage whole screen because some previous cursor box damages were skipped + wlr_damage_ring_add_whole(&damage); + return false; + } + + return shouldSkip; +} + bool CMonitor::isMirror() { return pMirrorOf != nullptr; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 4bfbf53c..c59e00ac 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -158,6 +158,7 @@ class CMonitor { void addDamage(const pixman_region32_t* rg); void addDamage(const CRegion* rg); void addDamage(const CBox* box); + bool shouldSkipScheduleFrameOnMouseEvent(); void setMirror(const std::string&); bool isMirror(); bool matchesStaticSelector(const std::string& selector) const; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index bf7b5d0a..3a28ea8d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -675,7 +675,7 @@ void CPointerManager::damageIfSoftware() { continue; if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { - g_pHyprRenderer->damageBox(&b); + g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3aa8d2ae..81a46f97 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -187,7 +187,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (*PZOOMFACTOR != 1.f) g_pHyprRenderer->damageMonitor(PMONITOR); - if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0) + bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); + + if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(PMONITOR); PHLWINDOW forcedFocus = m_pForcedFocus.lock(); @@ -370,7 +372,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); - if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0) + if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); // grabs diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4fe35c7e..19b646a4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1763,7 +1763,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { Debug::log(LOG, "Damage: Monitor {}", pMonitor->szName); } -void CHyprRenderer::damageBox(CBox* pBox) { +void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { if (g_pCompositor->m_bUnsafeState) return; @@ -1773,7 +1773,8 @@ void CHyprRenderer::damageBox(CBox* pBox) { CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; damageBox.scale(m->scale); - m->addDamage(&damageBox); + if (!skipFrameSchedule) + m->addDamage(&damageBox); } static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 60101e87..6adca72a 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -48,7 +48,7 @@ class CHyprRenderer { void arrangeLayersForMonitor(const int&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*); + void damageBox(CBox*, bool skipFrameSchedule = false); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageRegion(const CRegion&); void damageMonitor(CMonitor*); From a357fa3e0a60b4f96a1924e0d9753d23001ab00e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 16:45:41 +0200 Subject: [PATCH 0220/2393] window: use effective damage for tearing re-schedules fixes #6377 --- src/events/Windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 899318ce..becff152 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -803,7 +803,7 @@ void Events::listener_commitWindow(void* owner, void* data) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { - CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage}; + CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; if (!damageBox.empty()) { if (PMONITOR->tearingState.busy) { From 12ce06f39b2194685ddeadf656ebf2d334836992 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 19:10:12 +0200 Subject: [PATCH 0221/2393] format: fix flipped r/b channels on legacy_renderer We don't wanna use an extension, but for gles2 there is no other option. fixes #6465 --- src/helpers/Format.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 9c94f68b..65828519 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -11,9 +11,13 @@ */ inline const std::vector GLES3_FORMATS = { { - .drmFormat = DRM_FORMAT_ARGB8888, - .flipRB = true, - .glFormat = GL_RGBA, + .drmFormat = DRM_FORMAT_ARGB8888, + .flipRB = true, +#ifndef GLES2 + .glFormat = GL_RGBA, +#else + .glFormat = GL_BGRA_EXT, +#endif .glType = GL_UNSIGNED_BYTE, .withAlpha = true, .alphaStripped = DRM_FORMAT_XRGB8888, @@ -22,7 +26,11 @@ inline const std::vector GLES3_FORMATS = { { .drmFormat = DRM_FORMAT_XRGB8888, .flipRB = true, - .glFormat = GL_RGBA, +#ifndef GLES2 + .glFormat = GL_RGBA, +#else + .glFormat = GL_BGRA_EXT, +#endif .glType = GL_UNSIGNED_BYTE, .withAlpha = false, .alphaStripped = DRM_FORMAT_XRGB8888, From 2f278dc883f3e4e84fb1d18154132f8f4efe42cf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 21:59:21 +0200 Subject: [PATCH 0222/2393] egl: fixup format modifier lookups with implicit modifiers ref #6485 --- src/helpers/Format.cpp | 4 ++-- src/render/OpenGL.cpp | 32 ++++++++++++++++++++++---------- src/render/OpenGL.hpp | 4 +++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 65828519..08c3ca63 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -24,8 +24,8 @@ inline const std::vector GLES3_FORMATS = { .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XRGB8888, - .flipRB = true, + .drmFormat = DRM_FORMAT_XRGB8888, + .flipRB = true, #ifndef GLES2 .glFormat = GL_RGBA, #else diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 406ffdd0..5d8d6b83 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -79,20 +79,20 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } -std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { +std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { // TODO: return std::expected when clang supports it if (!m_sExts.EXT_image_dma_buf_import_modifiers) - return {}; + return std::nullopt; EGLint len = 0; if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { Debug::log(ERR, "EGL: Failed to query mods"); - return {}; + return std::nullopt; } if (len <= 0) - return {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}; // assume the driver can do linear and implicit. + return std::vector{}; std::vector mods; std::vector external; @@ -103,13 +103,21 @@ std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); std::vector result; + bool linearIsExternal = false; for (size_t i = 0; i < mods.size(); ++i) { - if (external.at(i)) + if (external.at(i)) { + if (mods.at(i) == DRM_FORMAT_MOD_LINEAR) + linearIsExternal = true; continue; + } result.push_back(mods.at(i)); } + // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) + if (!linearIsExternal && std::find(mods.begin(), mods.end(), DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) + mods.push_back(DRM_FORMAT_MOD_LINEAR); + return result; } @@ -147,15 +155,19 @@ void CHyprOpenGLImpl::initDRMFormats() { for (auto& fmt : formats) { std::vector mods; - if (!DISABLE_MODS) - mods = getModsForFormat(fmt); - else + if (!DISABLE_MODS) { + auto ret = getModsForFormat(fmt); + if (!ret.has_value()) + continue; + + mods = *ret; + } else mods = {DRM_FORMAT_MOD_LINEAR}; m_bHasModifiers = m_bHasModifiers || mods.size() > 0; - if (mods.size() == 0) - continue; + // EGL can always do implicit modifiers. + mods.push_back(DRM_FORMAT_MOD_INVALID); dmaFormats.push_back(SDRMFormat{ .format = fmt, diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index db0f8ea1..c6e173e5 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -238,7 +238,9 @@ class CHyprOpenGLImpl { void createBGTextureForMonitor(CMonitor*); void initShaders(); void initDRMFormats(); - std::vector getModsForFormat(EGLint format); + + // + std::optional> getModsForFormat(EGLint format); // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); From cb63398f079b4b4324c04e2e41ba17983d66487c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 14 Jun 2024 20:00:53 +0000 Subject: [PATCH 0223/2393] [gha] Nix: update inputs --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 477db69b..94fc9d90 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1717181720, - "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", + "lastModified": 1718368322, + "narHash": "sha256-VfMg3RsnRLQzbq0hFIh1dCM09b5C/F/qPFUOgU/CRi0=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", + "rev": "dd3a853c8239d1c3f3f37de7d2b8ae4b4f3840df", "type": "github" }, "original": { @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1717881334, - "narHash": "sha256-a0inRgJhPL6v9v7RPM/rx1kbXdfe3xJA1c9z0ZkYnh4=", + "lastModified": 1718271409, + "narHash": "sha256-8KvVqtApNt4FWTdn1TqVvw00rpqyG9UuUPA2ilPVD1U=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "0693f9398ab693d89c9a0aa3b3d062dd61b7a60e", + "rev": "8e10e0626fb26a14b859b3811b6ed7932400c86e", "type": "github" }, "original": { @@ -110,11 +110,11 @@ ] }, "locked": { - "lastModified": 1717784906, - "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", + "lastModified": 1718119275, + "narHash": "sha256-nqDYXATNkyGXVmNMkT19fT4sjtSPBDS1LLOxa3Fueo4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", + "rev": "1419520d5f7f38d35e05504da5c1b38212a38525", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717974879, - "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=", + "lastModified": 1718318537, + "narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3", + "rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420", "type": "github" }, "original": { @@ -179,11 +179,11 @@ ] }, "locked": { - "lastModified": 1717918856, - "narHash": "sha256-I38bmPLqamvOfVSArd1hhZtkVRAYBK38fOHZCU1P9Qg=", + "lastModified": 1718272114, + "narHash": "sha256-KsX7sAwkEFpXiwyjt0HGTnnrUU58wW1jlzj5IA/LRz8=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "72907822c19afc0983c69d59d299204381623725", + "rev": "24be4a26f0706e456fca1b61b8c79f7486a9e86d", "type": "github" }, "original": { From df0c014ba0c9c665df51fe7750ab9d7288b57478 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:06:02 +0200 Subject: [PATCH 0224/2393] xwayland: use safeRemove for removing files fixes #6514 --- src/xwayland/Server.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 26010cfb..e2dab412 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -155,6 +155,14 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) { return g_pXWayland->pServer->ready(fd, mask); } +static bool safeRemove(const std::string& path) { + try { + return std::filesystem::remove(path); + } catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); } + + return false; +} + bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= 32; ++i) { auto LOCK = std::format("/tmp/.X{}-lock", i); @@ -162,7 +170,7 @@ bool CXWaylandServer::tryOpenSockets() { if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { // we managed to open the lock if (!openSockets(xFDs, i)) { - std::filesystem::remove(LOCK); + safeRemove(LOCK); close(fd); continue; } @@ -170,7 +178,7 @@ bool CXWaylandServer::tryOpenSockets() { const auto PIDSTR = std::format("{}", getpid()); if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { - std::filesystem::remove(LOCK); + safeRemove(LOCK); close(fd); continue; } @@ -197,7 +205,7 @@ bool CXWaylandServer::tryOpenSockets() { } catch (...) { continue; } if (kill(pid, 0) != 0 && errno == ESRCH) { - if (!std::filesystem::remove(LOCK)) + if (!safeRemove(LOCK)) continue; i--; @@ -228,7 +236,7 @@ CXWaylandServer::~CXWaylandServer() { close(xFDs[1]); auto LOCK = std::format("/tmp/.X{}-lock", display); - std::filesystem::remove(LOCK); + safeRemove(LOCK); std::string path; #ifdef __linux__ @@ -236,7 +244,7 @@ CXWaylandServer::~CXWaylandServer() { #else path = std::format("/tmp/.X11-unix/X{}_", display); #endif - std::filesystem::remove(path); + safeRemove(path); } void CXWaylandServer::die() { From 32aca887522063cf728357af247ca6f20d93eb97 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:20:00 +0200 Subject: [PATCH 0225/2393] keybinds: add custom event dispatcher fixes #3439 --- src/managers/KeybindManager.cpp | 5 +++++ src/managers/KeybindManager.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 49ea39a3..eb07850c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -114,6 +114,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup; m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock; m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; + m_mDispatchers["event"] = event; m_mDispatchers["global"] = global; m_tScrollTimer.reset(); @@ -2680,3 +2681,7 @@ void CKeybindManager::moveGroupWindow(std::string args) { PLASTWINDOW->updateWindowDecos(); } + +void CKeybindManager::event(std::string args) { + g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); +} diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index ecab6ee1..2a256760 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -205,6 +205,7 @@ class CKeybindManager { static void setIgnoreGroupLock(std::string); static void denyWindowFromGroup(std::string); static void global(std::string); + static void event(std::string); friend class CCompositor; friend class CInputManager; From fb82f6bcd7d829a3ab2d2cb7d9a27f3837abfb80 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:31:35 +0200 Subject: [PATCH 0226/2393] animations: fix overriding direction for slide fixes #6512 --- src/managers/AnimationManager.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f8cb0184..74fe4117 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -6,6 +6,7 @@ #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "eventLoop/EventLoopManager.hpp" +#include "../helpers/varlist/VarList.hpp" int wlTick(SP self, void* data) { if (g_pAnimationManager) @@ -396,6 +397,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle; transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower); + CVarList animList(ANIMSTYLE, 0, 's'); + // if the window is not being animated, that means the layout set a fixed size for it, don't animate. if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated()) return; @@ -407,12 +410,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (pWindow->m_sAdditionalConfigData.animationStyle != "") { // the window has config'd special anim if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) { - if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) { - // has a direction - animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close); - } else { - animationSlide(pWindow, "", close); - } + CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's'); + animationSlide(pWindow, animList2[1], close); } else { // anim popin, fallback @@ -429,9 +428,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { animationPopin(pWindow, close, minPerc / 100.f); } } else { - if (ANIMSTYLE == "slide") { - animationSlide(pWindow, "", close); - } else { + if (animList[0] == "slide") + animationSlide(pWindow, animList[1], close); + else { // anim popin, fallback float minPerc = 0.f; @@ -451,9 +450,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { - if (style == "slide") { + if (style.starts_with("slide")) return ""; - } else if (style.starts_with("popin")) { + else if (style.starts_with("popin")) { // try parsing float minPerc = 0.f; if (style.find("%") != std::string::npos) { From 46ef6653be90f1a3e2a8cecc1fd9112dc3c6f464 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:33:21 +0200 Subject: [PATCH 0227/2393] data-device: abort drag on unaccepted offers fixes #6509 --- src/protocols/core/DataDevice.cpp | 28 ++++++++++++++++++++++++++-- src/protocols/core/DataDevice.hpp | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index c1de8f83..86b372bf 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,13 +13,17 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetDestroy([this](CWlDataOffer* r) { - if (!dead) + if (!dead && (recvd || accepted)) PROTO::data->completeDrag(); + else + PROTO::data->abortDrag(); PROTO::data->destroyResource(this); }); resource->setOnDestroy([this](CWlDataOffer* r) { - if (!dead) + if (!dead && (recvd || accepted)) PROTO::data->completeDrag(); + else + PROTO::data->abortDrag(); PROTO::data->destroyResource(this); }); @@ -592,6 +596,11 @@ void CWLDataDeviceProtocol::dropDrag() { return; } + if (!wasDragSuccessful()) { + abortDrag(); + return; + } + dnd.currentSource->sendDndDropPerformed(); dnd.focusedDevice->sendDrop(); dnd.focusedDevice->sendLeave(); @@ -603,6 +612,21 @@ void CWLDataDeviceProtocol::dropDrag() { dnd.overriddenCursor = false; } +bool CWLDataDeviceProtocol::wasDragSuccessful() { + if (!dnd.focusedDevice || !dnd.currentSource) + return false; + + for (auto& o : m_vOffers) { + if (o->dead || !o->source || !o->source->hasDnd()) + continue; + + if (o->recvd || o->accepted) + return true; + } + + return false; +} + void CWLDataDeviceProtocol::completeDrag() { resetDndState(); diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index f31725ee..5b31559f 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -175,6 +175,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { void dropDrag(); void completeDrag(); void resetDndState(); + bool wasDragSuccessful(); // SP dataDeviceForClient(wl_client*); From 6c24dc0bb147d60cc5c7e44cc3e257a737ead828 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:43:39 +0200 Subject: [PATCH 0228/2393] xdg-shell: fixup xdg-positioner's pointForAnchor with non-corner points fixes #6157 --- src/protocols/XDGShell.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index dcbc6162..49b7b417 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -507,12 +507,12 @@ CXDGPositionerRules::CXDGPositionerRules(SP positioner) state = positioner->state; } -static Vector2D pointForAnchor(const CBox& box, xdgPositionerAnchor anchor) { +static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) { switch (anchor) { - case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F, 0}; - case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F, box.size().y}; - case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F}; - case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F}; + case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, 0}; + case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, box.size().y}; + case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F - predictionSize.y / 2.F}; + case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.F}; case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos(); case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y}; case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0}; @@ -527,7 +527,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord); - CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.anchor) + state.offset, state.requestedSize}; + CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.requestedSize, state.anchor) + state.offset, state.requestedSize}; bool success = predictedBox.inside(constraint); From 77f44bfcab6c3e553d26a776c011613efbfe6cfd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:56:44 +0200 Subject: [PATCH 0229/2393] output: avoid crashes when binding a defunct wl_output global ref #6508 --- src/protocols/core/Output.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 90358fa5..10daa15e 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -9,6 +9,9 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni pClient = resource->client(); + if (!monitor) + return; + resource->setOnDestroy([this](CWlOutput* r) { if (monitor && PROTO::outputs.contains(monitor->szName)) PROTO::outputs.at(monitor->szName)->destroyResource(this); @@ -69,6 +72,9 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, } void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + if (defunct) + Debug::log(WARN, "[wl_output] Binding a wl_output that's inert?? Possible client bug."); + const auto RESOURCE = m_vOutputs.emplace_back(makeShared(makeShared(client, ver, id), monitor.lock())); if (!RESOURCE->good()) { From 91fe58f8f278d126852877eadc87c50ca7b9b78d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 18:20:09 +0200 Subject: [PATCH 0230/2393] window: improve swallowing functionality cleanups, fixes, etc. ref #6095 --- src/desktop/Window.cpp | 55 +++++++++++++++++++++++++++++++++ src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 69 +++++------------------------------------- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b02a53e0..d153b344 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1540,3 +1540,58 @@ void CWindow::warpCursor() { else g_pCompositor->warpCursorTo(middle()); } + +PHLWINDOW CWindow::getSwallower() { + static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); + static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); + static auto PSWALLOW = CConfigValue("misc:enable_swallow"); + + if (!*PSWALLOW || (*PSWALLOWREGEX).empty()) + return nullptr; + + // check parent + std::vector candidates; + pid_t currentPid = getPID(); + // walk up the tree until we find someone, 25 iterations max. + for (size_t i = 0; i < 25; ++i) { + currentPid = getPPIDof(currentPid); + + if (!currentPid) + break; + + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->isHidden()) + continue; + + if (w->getPID() == currentPid) + candidates.push_back(w); + } + } + + if (!(*PSWALLOWREGEX).empty()) + std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); }); + + if (candidates.size() <= 0) + return nullptr; + + if (!(*PSWALLOWEXREGEX).empty()) + std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); }); + + if (candidates.size() <= 0) + return nullptr; + + if (candidates.size() == 1) + return candidates.at(0); + + // walk up the focus history and find the last focused + for (auto& w : g_pCompositor->m_vWindowFocusHistory) { + if (!w) + continue; + + if (std::find(candidates.begin(), candidates.end(), w.lock()) != candidates.end()) + return w.lock(); + } + + // if none are found (??) then just return the first one + return candidates.at(0); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 85c74622..16bf297c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -450,6 +450,7 @@ class CWindow { std::string fetchTitle(); std::string fetchClass(); void warpCursor(); + PHLWINDOW getSwallower(); // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index becff152..d37ba12b 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -44,7 +44,6 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); static auto PSWALLOW = CConfigValue("misc:enable_swallow"); static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); - static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); @@ -527,71 +526,17 @@ void Events::listener_mapWindow(void* owner, void* data) { // verify swallowing if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) { - // don't swallow ourselves - std::regex rgx(*PSWALLOWREGEX); - if (!std::regex_match(PWINDOW->m_szClass, rgx)) { - // check parent - int ppid = getPPIDof(PWINDOW->getPID()); + const auto SWALLOWER = PWINDOW->getSwallower(); - int curppid = 0; + if (SWALLOWER) { + // swallow + PWINDOW->m_pSwallowed = SWALLOWER; - for (int i = 0; i < 5; ++i) { - curppid = getPPIDof(ppid); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); - if (curppid < 10) { - break; - } + SWALLOWER->setHidden(true); - ppid = curppid; - } - - if (ppid) { - // get window by pid - std::vector found; - PHLWINDOW finalFound; - for (auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden()) - continue; - - if (w->getPID() == ppid) { - found.push_back(w); - } - } - - if (found.size() > 1) { - for (auto& w : found) { - // try get the focus, otherwise we'll ignore to avoid swallowing incorrect windows - if (w == PFOCUSEDWINDOWPREV) { - finalFound = w; - break; - } - } - } else if (found.size() == 1) { - finalFound = found[0]; - } - - if (finalFound) { - bool valid = std::regex_match(PWINDOW->m_szClass, rgx); - - if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) { - std::regex exc(*PSWALLOWEXREGEX); - - valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc); - } - - // check if it's the window we want & not exempt from getting swallowed - if (valid) { - // swallow - PWINDOW->m_pSwallowed = finalFound; - - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound); - - finalFound->setHidden(true); - - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); - } - } - } + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); } } From 89f795da98cc53faf7e3a683d8c189aa24986267 Mon Sep 17 00:00:00 2001 From: memchr Date: Sat, 15 Jun 2024 19:17:38 +0000 Subject: [PATCH 0231/2393] master: refine master layout new window handling (#6479) * ## Open window relative to active window `new_on_active`: - `none` (default): - `before`: above of the focused window - `after`: below the focused window If the focused window is the solo master window, or the new window replaces master, this option has no effect and new_on_top are respected. ## Refine new window status control **BREAKING CHANGE**: new_is_master removed in favour of new variable `new_status`: - `slave` (default): new window open as slave - `master`: new window open as master - `inherit`: new window inherit status from active window, i.e. when the focused window is master, new window will become new master, otherwise new window are added to slaves * refactor: rename a few variables --- src/config/ConfigManager.cpp | 3 +- src/layout/MasterLayout.cpp | 54 +++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f63ff552..1b069f5d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -431,8 +431,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:special_scale_factor", {1.f}); m_pConfig->addConfigValue("master:mfact", {0.55f}); - m_pConfig->addConfigValue("master:new_is_master", Hyprlang::INT{1}); + m_pConfig->addConfigValue("master:new_status", {"slave"}); m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); + m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:orientation", {"left"}); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index af0182e1..c5784c74 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -76,17 +76,31 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire if (pWindow->m_bIsFloating) return; - static auto PNEWTOP = CConfigValue("master:new_on_top"); + static auto PNEWONACTIVE = CConfigValue("master:new_on_active"); + static auto PNEWONTOP = CConfigValue("master:new_on_top"); + static auto PNEWSTATUS = CConfigValue("master:new_status"); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); + const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before"; + const bool BNEWISMASTER = *PNEWSTATUS == "master"; + + const auto PNODE = [&]() { + if (*PNEWONACTIVE != "none" && !BNEWISMASTER) { + const auto pLastNode = getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()); + if (pLastNode && !(pLastNode->isMaster && (getMastersOnWorkspace(pWindow->workspaceID()) == 1 || *PNEWSTATUS == "slave"))) { + auto it = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *pLastNode); + if (!BNEWBEFOREACTIVE) + ++it; + return &(*m_lMasterNodesData.emplace(it)); + } + } + return *PNEWONTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); + }(); PNODE->workspaceID = pWindow->workspaceID(); PNODE->pWindow = pWindow; - static auto PNEWISMASTER = CConfigValue("master:new_is_master"); - const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID); static auto PMFACT = CConfigValue("master:mfact"); float lastSplitPercent = *PMFACT; @@ -186,13 +200,27 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire } } - if ((*PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) || - forceDropAsMaster) { - for (auto& nd : m_lMasterNodesData) { - if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { - nd.isMaster = false; - lastSplitPercent = nd.percMaster; - break; + if ((BNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) // + || WINDOWSONWORKSPACE == 1 // + || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) // + || forceDropAsMaster // + || (*PNEWSTATUS == "inherit" && OPENINGON && OPENINGON->isMaster && g_pInputManager->dragMode != MBIND_MOVE)) { + + if (BNEWBEFOREACTIVE) { + for (auto& nd : m_lMasterNodesData | std::views::reverse) { + if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { + nd.isMaster = false; + lastSplitPercent = nd.percMaster; + break; + } + } + } else { + for (auto& nd : m_lMasterNodesData) { + if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { + nd.isMaster = false; + lastSplitPercent = nd.percMaster; + break; + } } } @@ -1440,7 +1468,7 @@ void CHyprMasterLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { } Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { - static auto PNEWISMASTER = CConfigValue("master:new_is_master"); + static auto PNEWSTATUS = CConfigValue("master:new_status"); if (!g_pCompositor->m_pLastMonitor) return {}; @@ -1454,7 +1482,7 @@ Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { if (!MASTER) // wtf return {}; - if (*PNEWISMASTER) { + if (*PNEWSTATUS == "master") { return MASTER->size; } else { const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID); From 908bec1564e4fe448a2a8a7371bbb0621c62b11a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 21:24:26 +0200 Subject: [PATCH 0232/2393] wl_seat: send repeat data from current keyboard on bind ref #6515 --- src/protocols/core/Seat.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 331eb15e..8f9174f5 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -200,10 +200,13 @@ CWLKeyboardResource::CWLKeyboardResource(SP resource_, SPsetRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); - static auto REPEAT = CConfigValue("input:repeat_rate"); - static auto DELAY = CConfigValue("input:repeat_delay"); + if (!g_pSeatManager->keyboard) { + LOGM(ERR, "No keyboard on bound wl_keyboard??"); + return; + } + sendKeymap(g_pSeatManager->keyboard.lock()); - repeatInfo(*REPEAT, *DELAY); + repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay); } bool CWLKeyboardResource::good() { From 1f5fd7e64a1c0e8d1815bdd6d168193bf9c28d6d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 21:46:36 +0200 Subject: [PATCH 0233/2393] hyprpm: add --no-shallow --- hyprpm/src/core/PluginManager.cpp | 2 +- hyprpm/src/core/PluginManager.hpp | 3 ++- hyprpm/src/main.cpp | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index e8c6e251..848b9cab 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -427,7 +427,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); - const bool bShallow = HLVER.branch == "main" || HLVER.branch == ""; + const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow; // let us give a bit of leg-room for shallowing // due to timezones, etc. diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index a87240e3..13ea5b12 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -58,7 +58,8 @@ class CPluginManager { bool hasDeps(); - bool m_bVerbose = false; + bool m_bVerbose = false; + bool m_bNoShallow = false; // will delete recursively if exists!! bool createSafeDirectory(const std::string& path); diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 38b32c83..4f00f708 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -26,6 +26,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┣ --help | -h → Show this menu ┣ --verbose | -v → Enable too much logging ┣ --force | -f → Force an operation ignoring checks (e.g. update -f) +┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources ┗ )#"; @@ -41,7 +42,7 @@ int main(int argc, char** argv, char** envp) { } std::vector command; - bool notify = false, verbose = false, force = false; + bool notify = false, verbose = false, force = false, noShallow = false; for (int i = 1; i < argc; ++i) { if (ARGS[i].starts_with("-")) { @@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) { notify = true; } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { verbose = true; + } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { + noShallow = true; } else if (ARGS[i] == "--force" || ARGS[i] == "-f") { force = true; std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; @@ -69,8 +72,9 @@ int main(int argc, char** argv, char** envp) { return 0; } - g_pPluginManager = std::make_unique(); - g_pPluginManager->m_bVerbose = verbose; + g_pPluginManager = std::make_unique(); + g_pPluginManager->m_bVerbose = verbose; + g_pPluginManager->m_bNoShallow = noShallow; if (command[0] == "add") { if (command.size() < 2) { From 2566d818848b58b114071f199ffe944609376270 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 12:38:09 +0200 Subject: [PATCH 0234/2393] xwayland: fixup unfocus atom conditions ref #6468 --- src/xwayland/XSurface.cpp | 2 +- src/xwayland/XWM.cpp | 25 +++++++++++++++++-------- src/xwayland/XWM.hpp | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 07cac832..5d25e0e8 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -179,7 +179,7 @@ void CXWaylandSurface::configure(const CBox& box) { void CXWaylandSurface::activate(bool activate) { if (overrideRedirect && !activate) return; - g_pXWayland->pWM->activateSurface(self.lock()); + g_pXWayland->pWM->activateSurface(self.lock(), activate); } void CXWaylandSurface::setFullscreen(bool fs) { diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 247af4b7..719adcb9 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -394,11 +394,16 @@ void CXWM::focusWindow(SP surf) { if (surf == focusedSurface) return; - auto oldSurf = focusedSurface.lock(); focusedSurface = surf; - if (oldSurf) - sendState(oldSurf); + // send state to all surfaces, sometimes we might lose some + // that could still stick with the focused atom + for (auto& s : mappedSurfaces) { + if (!s) + continue; + + sendState(s.lock()); + } if (!surf) { xcb_set_input_focus_checked(connection, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_NONE, XCB_CURRENT_TIME); @@ -868,13 +873,17 @@ void CXWM::createWMWindow() { xcb_set_selection_owner(connection, wmWindow, HYPRATOMS["_NET_WM_CM_S0"], XCB_CURRENT_TIME); } -void CXWM::activateSurface(SP surf) { - if (surf == focusedSurface || (surf && surf->overrideRedirect)) +void CXWM::activateSurface(SP surf, bool activate) { + if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE); - - focusWindow(surf); + if (!activate || !surf) { + setActiveWindow((uint32_t)XCB_WINDOW_NONE); + focusWindow(nullptr); + } else { + setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE); + focusWindow(surf); + } xcb_flush(connection); } diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 7f68454c..6456c71b 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -79,7 +79,7 @@ class CXWM { void setActiveWindow(xcb_window_t window); void sendState(SP surf); void focusWindow(SP surf); - void activateSurface(SP surf); + void activateSurface(SP surf, bool activate); bool isWMWindow(xcb_window_t w); void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); From 3eaf35f1e2d984bea89ab1d8a5abbef66243aa5d Mon Sep 17 00:00:00 2001 From: memchr Date: Sun, 16 Jun 2024 13:44:13 +0000 Subject: [PATCH 0235/2393] hyprland.conf: update master section (#6537) --- example/hyprland.conf | 2 +- src/config/defaultConfig.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index f0ee8b25..f69309c2 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -125,7 +125,7 @@ dwindle { # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more master { - new_is_master = true + new_status = master } # https://wiki.hyprland.org/Configuring/Variables/#misc diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index dd7df126..98b617d0 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -138,7 +138,7 @@ dwindle { # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more master { - new_is_master = true + new_status = master } # https://wiki.hyprland.org/Configuring/Variables/#misc From 1b5444494d26624804de8f479da3cffb5d480dc6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 16:23:35 +0200 Subject: [PATCH 0236/2393] seat/dnd: unfocus pointer from surfaces on dnd start GTK is speshyal and requires this for functioning properly. Ugh. It's technically not required by spec, f you gtk. Ref #6509 --- src/managers/SeatManager.cpp | 5 +++++ src/protocols/core/DataDevice.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index a58bca72..fc14f0fc 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -191,6 +191,11 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocus == surf) return; + if (PROTO::data->dndActive() && surf) { + Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd"); + return; + } + if (!mouse || !mouse->wlr()) { Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); return; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 86b372bf..03c51852 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -542,6 +542,11 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource } }); + // unfocus the pointer from the surface, this is part of """standard""" wayland procedure and gtk will freak out if this isn't happening. + // BTW, the spec does NOT require this explicitly... + // Fuck you gtk. + g_pSeatManager->setPointerFocus(nullptr, {}); + // make a new offer, etc updateDrag(); } @@ -638,7 +643,7 @@ void CWLDataDeviceProtocol::completeDrag() { dnd.focusedDevice.reset(); dnd.currentSource.reset(); - g_pSeatManager->resendEnterEvents(); + g_pInputManager->simulateMouseMovement(); } void CWLDataDeviceProtocol::abortDrag() { @@ -657,7 +662,7 @@ void CWLDataDeviceProtocol::abortDrag() { dnd.focusedDevice.reset(); dnd.currentSource.reset(); - g_pSeatManager->resendEnterEvents(); + g_pInputManager->simulateMouseMovement(); } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { From 43c75f17eb9ce89f90ef443a3ae740a1bdd55d31 Mon Sep 17 00:00:00 2001 From: memchr Date: Sun, 16 Jun 2024 14:42:32 +0000 Subject: [PATCH 0237/2393] input: add cursor:warp_on_changeworkspace (#6480) * input: add cursor:warp_on_changeworkspace If enabled, warp the cursor to the last focused window on the workspace in the `changeworkspace' dispatcher, except if the cursor is currently on the WLR top layer. Respect persistent warps. * warp_on_change_workspace: check if focused layer is a window. --- src/config/ConfigManager.cpp | 1 + src/managers/KeybindManager.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1b069f5d..56fdae25 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -529,6 +529,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY}); m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index eb07850c..14fadf02 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1,6 +1,7 @@ #include "../config/ConfigValue.hpp" #include "../devices/IKeyboard.hpp" #include "../managers/SeatManager.hpp" +#include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "KeybindManager.hpp" @@ -1087,6 +1088,8 @@ void CKeybindManager::changeworkspace(std::string args) { if (!PMONITORWORKSPACEOWNER) return; + updateRelativeCursorCoords(); + g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER); if (BISWORKSPACECURRENT) { @@ -1115,6 +1118,16 @@ void CKeybindManager::changeworkspace(std::string args) { else g_pInputManager->simulateMouseMovement(); } + + const static auto PWARPONWORKSPACECHANGE = CConfigValue("cursor:warp_on_change_workspace"); + + if (*PWARPONWORKSPACECHANGE) { + auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); + auto HLSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); + + if (PLAST && (!HLSurface || HLSurface->getWindow())) + PLAST->warpCursor(); + } } void CKeybindManager::fullscreenActive(std::string args) { From 648ac8a00b0d68a9e3a86e928b30a490870dbed6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 16:46:15 +0200 Subject: [PATCH 0238/2393] xdg-shell: properly check for resource version for TILED and SUSPENDED states fixes #6535 --- src/protocols/XDGShell.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 49b7b417..dddc3bca 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -136,10 +136,12 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPversion() >= 2) { + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM); + } resource->setSetTitle([this](CXdgToplevel* r, const char* t) { state.title = t; @@ -261,6 +263,9 @@ uint32_t CXDGToplevelResource::setActive(bool active) { } uint32_t CXDGToplevelResource::setSuspeneded(bool sus) { + if (resource->version() < 6) + return owner->scheduleConfigure(); // SUSPENDED is since 6 + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != pendingApply.states.end(); if (sus == set) From d0a6fa7aa6c3a9d94611130a9213de19a8754d67 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 17:04:10 +0200 Subject: [PATCH 0239/2393] wl_seat: accomodate for apps late-binding seat resources Sends enter events when an app binds wl_keyboard or wl_pointer later than it should. Fixes some buggy apps. Fixes #6131 --- src/protocols/core/Seat.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 8f9174f5..be05955c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -98,6 +98,9 @@ CWLPointerResource::CWLPointerResource(SP resource_, SPonSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY}); }); + + if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client()) + sendEnter(g_pSeatManager->state.pointerFocus.lock(), {-1, -1} /* Coords don't really matter that much, they will be updated next move */); } bool CWLPointerResource::good() { @@ -207,6 +210,9 @@ CWLKeyboardResource::CWLKeyboardResource(SP resource_, SPkeyboard.lock()); repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay); + + if (g_pSeatManager->state.keyboardFocus && g_pSeatManager->state.keyboardFocus->client() == resource->client()) + sendEnter(g_pSeatManager->state.keyboardFocus.lock()); } bool CWLKeyboardResource::good() { From 2031af82fa029aa098357339d502b53c371919d4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 17:41:16 +0200 Subject: [PATCH 0240/2393] wl_data_device: send drop_performed in completeDrag ref #6509 --- src/protocols/core/DataDevice.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 03c51852..e54d3633 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -606,15 +606,15 @@ void CWLDataDeviceProtocol::dropDrag() { return; } - dnd.currentSource->sendDndDropPerformed(); dnd.focusedDevice->sendDrop(); - dnd.focusedDevice->sendLeave(); resetDndState(); if (dnd.overriddenCursor) g_pInputManager->unsetCursorImage(); dnd.overriddenCursor = false; + + g_pInputManager->simulateMouseMovement(); } bool CWLDataDeviceProtocol::wasDragSuccessful() { @@ -638,6 +638,7 @@ void CWLDataDeviceProtocol::completeDrag() { if (!dnd.focusedDevice || !dnd.currentSource) return; + dnd.currentSource->sendDndDropPerformed(); dnd.currentSource->sendDndFinished(); dnd.focusedDevice.reset(); @@ -681,5 +682,5 @@ void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { } bool CWLDataDeviceProtocol::dndActive() { - return dnd.currentSource; + return dnd.currentSource && dnd.mouseButton /* test a member of the state to ensure it's also present */; } From 069a21a34ef062bb278cf70f153cfdd0bfec9df2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 19:52:07 +0200 Subject: [PATCH 0241/2393] xwayland: force default plain mime atoms on known types ref #6247 --- src/xwayland/XDataSource.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 98e0701b..f4059ee1 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -49,10 +49,16 @@ std::vector CXDataSource::mimes() { void CXDataSource::send(const std::string& mime, uint32_t fd) { xcb_atom_t mimeAtom = 0; - for (size_t i = 0; i < mimeTypes.size(); ++i) { - if (mimeTypes.at(i) == mime) { - mimeAtom = mimeAtoms.at(i); - break; + if (mime == "text/plain") + mimeAtom = HYPRATOMS["TEXT"]; + else if (mime == "text/plain;charset=utf-8") + mimeAtom = HYPRATOMS["UTF8_STRING"]; + else { + for (size_t i = 0; i < mimeTypes.size(); ++i) { + if (mimeTypes.at(i) == mime) { + mimeAtom = mimeAtoms.at(i); + break; + } } } From 738530e62ee48f7326cd5a610b90b47344b701f1 Mon Sep 17 00:00:00 2001 From: Dashie Date: Sun, 16 Jun 2024 20:01:08 +0200 Subject: [PATCH 0242/2393] xdg-shell: Continue transform of popup until size fits (#6521) --- src/protocols/XDGShell.cpp | 47 ++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index dddc3bca..c16ebb9d 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -539,30 +539,33 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa if (success) return predictedBox.translate(-parentCoord - constraint.pos()); + CBox test = predictedBox; + if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) { // attempt to flip - const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; - const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; + const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + auto countEdges = [constraint](const CBox& test) -> int { + int edgeCount = 0; + edgeCount += test.x < constraint.x ? 1 : 0; + edgeCount += test.x + test.w > constraint.x + constraint.w ? 1 : 0; + edgeCount += test.y < constraint.y ? 1 : 0; + edgeCount += test.y + test.h > constraint.y + constraint.h ? 1 : 0; + return edgeCount; + }; + int edgeCount = countEdges(test); - CBox test = predictedBox; - success = true; - if (flipX && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}).expand(-1).inside(constraint)) + if (flipX && edgeCount > countEdges(test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}))) test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}); - else if (flipY && test.copy().translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint)) + if (flipY && edgeCount > countEdges(test.copy().translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}))) test.translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}); - else if (flipX && flipY && test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h}).expand(-1).inside(constraint)) - test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, -predictedBox.h - state.anchorRect.h}); - else - success = false; + + success = test.copy().expand(-1).inside(constraint); if (success) return test.translate(-parentCoord - constraint.pos()); } - // if flips fail, we will slide and remember. - // if the positioner is allowed to resize, then resize the slid thing. - CBox test = predictedBox; - // for slide and resize, defines the padding around the edge for the positioned // surface. constexpr int EDGE_PADDING = 4; @@ -575,10 +578,10 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa //const bool gravityLeft = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT; //const bool gravityTop = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_TOP || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_RIGHT; - const bool leftEdgeOut = predictedBox.x < constraint.x; - const bool topEdgeOut = predictedBox.y < constraint.y; - const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; - const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; + const bool leftEdgeOut = test.x < constraint.x; + const bool topEdgeOut = test.y < constraint.y; + const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w; + const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h; // TODO: this isn't truly conformant. if (leftEdgeOut && slideX) @@ -600,10 +603,10 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa const bool resizeX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; const bool resizeY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; - const bool leftEdgeOut = predictedBox.x < constraint.x; - const bool topEdgeOut = predictedBox.y < constraint.y; - const bool rightEdgeOut = predictedBox.x + predictedBox.w > constraint.x + constraint.w; - const bool bottomEdgeOut = predictedBox.y + predictedBox.h > constraint.y + constraint.h; + const bool leftEdgeOut = test.x < constraint.x; + const bool topEdgeOut = test.y < constraint.y; + const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w; + const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h; // TODO: this isn't truly conformant. if (leftEdgeOut && resizeX) { From 172ee1cadaabd3ba4df330f9cdd02fb520b59e71 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 20:36:55 +0200 Subject: [PATCH 0243/2393] data-device: minor fixups ref #6543 firefox needs a re-enter after a dnd don't destroy dnd on an offer destroy, it's not valid --- src/protocols/core/DataDevice.cpp | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index e54d3633..986d1176 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -12,20 +12,8 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetDestroy([this](CWlDataOffer* r) { - if (!dead && (recvd || accepted)) - PROTO::data->completeDrag(); - else - PROTO::data->abortDrag(); - PROTO::data->destroyResource(this); - }); - resource->setOnDestroy([this](CWlDataOffer* r) { - if (!dead && (recvd || accepted)) - PROTO::data->completeDrag(); - else - PROTO::data->abortDrag(); - PROTO::data->destroyResource(this); - }); + resource->setDestroy([this](CWlDataOffer* r) { PROTO::data->destroyResource(this); }); + resource->setOnDestroy([this](CWlDataOffer* r) { PROTO::data->destroyResource(this); }); resource->setAccept([this](CWlDataOffer* r, uint32_t serial, const char* mime) { if (!source) { @@ -210,7 +198,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : reso pClient = resource->client(); - resource->setSetSelection([this](CWlDataDevice* r, wl_resource* sourceR, uint32_t serial) { + resource->setSetSelection([](CWlDataDevice* r, wl_resource* sourceR, uint32_t serial) { auto source = sourceR ? CWLDataSourceResource::fromResource(sourceR) : CSharedPointer{}; if (!source) { LOGM(LOG, "Reset selection received"); @@ -226,7 +214,7 @@ CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : reso g_pSeatManager->setCurrentSelection(source); }); - resource->setStartDrag([this](CWlDataDevice* r, wl_resource* sourceR, wl_resource* origin, wl_resource* icon, uint32_t serial) { + resource->setStartDrag([](CWlDataDevice* r, wl_resource* sourceR, wl_resource* origin, wl_resource* icon, uint32_t serial) { auto source = CWLDataSourceResource::fromResource(sourceR); if (!source) { LOGM(ERR, "No source in drag"); @@ -615,6 +603,7 @@ void CWLDataDeviceProtocol::dropDrag() { dnd.overriddenCursor = false; g_pInputManager->simulateMouseMovement(); + g_pSeatManager->resendEnterEvents(); } bool CWLDataDeviceProtocol::wasDragSuccessful() { @@ -645,6 +634,7 @@ void CWLDataDeviceProtocol::completeDrag() { dnd.currentSource.reset(); g_pInputManager->simulateMouseMovement(); + g_pSeatManager->resendEnterEvents(); } void CWLDataDeviceProtocol::abortDrag() { @@ -664,6 +654,7 @@ void CWLDataDeviceProtocol::abortDrag() { dnd.currentSource.reset(); g_pInputManager->simulateMouseMovement(); + g_pSeatManager->resendEnterEvents(); } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { From d5ef10abf429355246abcda65fe4c15d886fad7c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 20:56:50 +0200 Subject: [PATCH 0244/2393] data-device: properly abort drag on missing device sometimes there is no focused device (e.g. when dnd'ing on nothing or xwayland) in which case abort would fail to send cancelled to the source. ref #6543 --- src/protocols/core/DataDevice.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 986d1176..2d50ff15 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -644,11 +644,13 @@ void CWLDataDeviceProtocol::abortDrag() { g_pInputManager->unsetCursorImage(); dnd.overriddenCursor = false; - if (!dnd.focusedDevice || !dnd.currentSource) + if (!dnd.focusedDevice && !dnd.currentSource) return; - dnd.focusedDevice->sendLeave(); - dnd.currentSource->cancelled(); + if (dnd.focusedDevice) + dnd.focusedDevice->sendLeave(); + if (dnd.currentSource) + dnd.currentSource->cancelled(); dnd.focusedDevice.reset(); dnd.currentSource.reset(); From b15be9c77de593581007de53b2bbca97d121900a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 21:34:17 +0200 Subject: [PATCH 0245/2393] xwayland: do not set a new data source if it has no MIMEs ref #6247 --- src/xwayland/XWM.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 719adcb9..7b57de0f 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1034,16 +1034,16 @@ void CXWM::initSelection() { } void CXWM::setClipboardToWayland(SXSelection& sel) { - sel.dataSource = makeShared(sel); - if (sel.dataSource->mimes().empty()) { + auto source = makeShared(sel); + if (source->mimes().empty()) { Debug::log(ERR, "[xwm] can't set clipboard: no MIMEs"); - sel.dataSource.reset(); + return; } - if (sel.dataSource) { - Debug::log(LOG, "[xwm] X clipboard at {:x} takes clipboard", (uintptr_t)sel.dataSource.get()); - g_pSeatManager->setCurrentSelection(sel.dataSource); - } + sel.dataSource = source; + + Debug::log(LOG, "[xwm] X clipboard at {:x} takes clipboard", (uintptr_t)sel.dataSource.get()); + g_pSeatManager->setCurrentSelection(sel.dataSource); } void CXWM::getTransferData(SXSelection& sel) { From 9cb3bf1cac1a38fbac3942a60415d7050ffcd2cb Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 17 Jun 2024 13:03:59 +0300 Subject: [PATCH 0246/2393] Nix: tidy up derivation --- nix/default.nix | 55 ++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 0493abc1..6b5068bc 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,6 +11,7 @@ expat, fribidi, git, + hwdata, hyprcursor, hyprlang, hyprutils, @@ -18,26 +19,28 @@ jq, libGL, libdatrie, + libdisplay-info, libdrm, libexecinfo, libinput, + libliftoff, libselinux, libsepol, libthai, libuuid, libxkbcommon, mesa, + meson, pango, pciutils, pcre2, python3, + seatd, systemd, tomlplusplus, - udis86, wayland, wayland-protocols, wayland-scanner, - wlroots, xorg, xwayland, debug ? false, @@ -76,23 +79,21 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov sed -i "s#@PREFIX@/##g" hyprland.pc.in ''; + COMMITS = commit; DATE = date; + DIRTY = lib.optionalString (commit == "") "dirty"; HASH = commit; - DIRTY = if commit == "" then "dirty" else ""; - nativeBuildInputs = lib.concatLists [ - [ - hyprwayland-scanner - jq - makeWrapper - cmake - ninja - pkg-config - python3 - wayland-scanner - ] - # introduce this later so that cmake takes precedence - wlroots.nativeBuildInputs + nativeBuildInputs = [ + hyprwayland-scanner + jq + makeWrapper + cmake + meson # for wlroots + ninja + pkg-config + python3 # for udis86 + wayland-scanner ]; outputs = [ @@ -102,14 +103,13 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov ]; buildInputs = lib.concatLists [ - wlroots.buildInputs - udis86.buildInputs [ cairo expat fribidi git - hyprcursor.dev + hwdata + hyprcursor hyprlang hyprutils libGL @@ -128,12 +128,18 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov tomlplusplus wayland wayland-protocols + # for wlroots + seatd + libdisplay-info + libliftoff ] (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ xorg.libxcb xorg.libXdmcp xorg.xcbutil + xorg.xcbutilerrors + xorg.xcbutilrenderutil xorg.xcbutilwm xwayland ]) @@ -145,6 +151,9 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov then "Debug" else "RelWithDebInfo"; + # we want as much debug info as possible + dontStrip = true; + cmakeFlags = [ (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) @@ -164,11 +173,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov passthru.providedSessions = ["hyprland"]; - meta = with lib; { + meta = { homepage = "https://github.com/hyprwm/Hyprland"; - description = "A dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; - license = licenses.bsd3; - platforms = wlroots.meta.platforms; + description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; + license = lib.licenses.bsd3; + platforms = lib.platforms.linux; mainProgram = "Hyprland"; }; } From 14ab0ecc5eb3c437dd62f92629fc29e33679043b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 17 Jun 2024 13:14:26 +0300 Subject: [PATCH 0247/2393] Nix: don't strip in debug builds Strip in Release builds, as the non-stripped binary is almost 500MB. --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index 6b5068bc..a2302688 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -152,7 +152,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov else "RelWithDebInfo"; # we want as much debug info as possible - dontStrip = true; + dontStrip = debug; cmakeFlags = [ (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) From 1360677478e867034713e5d43d7a8a8f6bf1343d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 17 Jun 2024 12:42:32 +0200 Subject: [PATCH 0248/2393] subcompositor/renderer: fixup handling of subsurfaces below the main one some apps (notably vlc 4) place a subsurface below the main surface (which is kinda cursed) but we have to accomodate for that --- src/helpers/WLClasses.hpp | 3 ++ src/protocols/core/Compositor.cpp | 25 ++++++++++++--- src/protocols/core/Subcompositor.cpp | 48 ++++++++++++++++++++++------ src/protocols/core/Subcompositor.hpp | 2 ++ src/render/Renderer.cpp | 12 ++++++- 5 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 247aa8f0..bcd6bf10 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -51,6 +51,9 @@ struct SRenderData { PHLWINDOW pWindow; bool popup = false; + + // counts how many surfaces this pass has rendered + int surfaceCounter = 0; }; struct SSwipeGesture { diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index db6e3258..165da6ee 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -277,8 +277,26 @@ void CWLSurfaceResource::resetRole() { } void CWLSurfaceResource::bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data) { - for (auto& n : nodes) { + std::vector> nodes2; + + // first, gather all nodes below + for (auto& n : nodes) { + std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); + // subsurfaces is sorted lowest -> highest + for (auto& c : n->subsurfaces) { + if (c->zIndex >= 0) + break; + nodes2.push_back(c->surface.lock()); + } + } + + if (!nodes2.empty()) + bfHelper(nodes2, fn, data); + + nodes2.clear(); + + for (auto& n : nodes) { Vector2D offset = {}; if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { auto subsurface = (CWLSubsurfaceResource*)n->role.get(); @@ -288,11 +306,10 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std fn(n, offset, data); } - std::vector> nodes2; - for (auto& n : nodes) { - std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); for (auto& c : n->subsurfaces) { + if (c->zIndex < 0) + continue; nodes2.push_back(c->surface.lock()); } } diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index d407636c..cbc4063a 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -23,15 +23,29 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPsubsurfaces, self.lock()); + auto pushAboveIndex = [this](int idx) -> void { + for (auto& c : parent->subsurfaces) { + if (c->zIndex >= idx) + c->zIndex++; + } + }; + + std::erase_if(parent->subsurfaces, [this](const auto& e) { return e == self || !e; }); auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); if (it == parent->subsurfaces.end()) { - LOGM(ERR, "Invalid surface reference in placeAbove"); - parent->subsurfaces.emplace_back(self.lock()); - } else - parent->subsurfaces.insert(it, self.lock()); + LOGM(ERR, "Invalid surface reference in placeAbove, likely parent"); + pushAboveIndex(1); + parent->subsurfaces.emplace_back(self); + zIndex = 1; + } else { + pushAboveIndex((*it)->zIndex); + zIndex = (*it)->zIndex; + parent->subsurfaces.emplace_back(self); + } + + std::sort(parent->subsurfaces.begin(), parent->subsurfaces.end(), [](const auto& a, const auto& b) { return a->zIndex < b->zIndex; }); }); resource->setPlaceBelow([this](CWlSubsurface* r, wl_resource* surf) { @@ -40,15 +54,29 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPsubsurfaces, self.lock()); + auto pushBelowIndex = [this](int idx) -> void { + for (auto& c : parent->subsurfaces) { + if (c->zIndex <= idx) + c->zIndex--; + } + }; + + std::erase_if(parent->subsurfaces, [this](const auto& e) { return e == self || !e; }); auto it = std::find(parent->subsurfaces.begin(), parent->subsurfaces.end(), SURF); if (it == parent->subsurfaces.end()) { - LOGM(ERR, "Invalid surface reference in placeBelow"); - parent->subsurfaces.emplace_back(self.lock()); - } else - parent->subsurfaces.insert(it--, self.lock()); + LOGM(ERR, "Invalid surface reference in placeBelow, likely parent"); + pushBelowIndex(-1); + parent->subsurfaces.emplace_back(self); + zIndex = -1; + } else { + pushBelowIndex((*it)->zIndex); + zIndex = (*it)->zIndex; + parent->subsurfaces.emplace_back(self); + } + + std::sort(parent->subsurfaces.begin(), parent->subsurfaces.end(), [](const auto& a, const auto& b) { return a->zIndex < b->zIndex; }); }); listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { diff --git a/src/protocols/core/Subcompositor.hpp b/src/protocols/core/Subcompositor.hpp index abcfbf6d..824f0ffc 100644 --- a/src/protocols/core/Subcompositor.hpp +++ b/src/protocols/core/Subcompositor.hpp @@ -35,6 +35,8 @@ class CWLSubsurfaceResource : public ISurfaceRole { WP self; + int zIndex = 1; // by default, it's above + struct { CSignal destroy; } events; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 19b646a4..f56fb5d6 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -209,7 +209,10 @@ static void renderSurface(SP surface, int x, int y, void* da else g_pHyprOpenGL->blend(true); - if (RDATA->surface && surface == RDATA->surface) { + // FIXME: This is wrong and will bug the blur out as shit if the first surface + // is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back + // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) + if (RDATA->surfaceCounter == 0) { if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else @@ -235,6 +238,9 @@ static void renderSurface(SP surface, int x, int y, void* da g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = NEARESTNEIGHBORSET; + + // up the counter so that we dont blur any surfaces above this one + RDATA->surfaceCounter++; } bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { @@ -602,6 +608,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec renderdata.blur = false; } + renderdata.surfaceCounter = 0; pWindow->m_pWLSurface->resource()->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); @@ -658,6 +665,8 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; + renderdata.surfaceCounter = 0; + pWindow->m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) @@ -743,6 +752,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time renderdata.dontRound = true; renderdata.popup = true; renderdata.blur = pLayer->forceBlurPopups; + renderdata.surfaceCounter = 0; if (popups) { pLayer->popupHead->breadthfirst( [](CPopup* popup, void* data) { From 785d0628876a4782759b13c25fa644c12f340356 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 17 Jun 2024 16:07:32 +0200 Subject: [PATCH 0249/2393] seat: track pressed pointer buttons releases them on leave, unless there is a dnd going on --- src/protocols/core/Seat.cpp | 26 ++++++++++++++++++++++++++ src/protocols/core/Seat.hpp | 2 ++ 2 files changed, 28 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index be05955c..f578292a 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -1,5 +1,6 @@ #include "Seat.hpp" #include "Compositor.hpp" +#include "DataDevice.hpp" #include "../../devices/IKeyboard.hpp" #include "../../managers/SeatManager.hpp" #include "../../config/ConfigValue.hpp" @@ -128,6 +129,18 @@ void CWLPointerResource::sendLeave() { if (!owner || !currentSurface) return; + // release all buttons unless we have a dnd going on in which case + // the events shall be lost. + if (!PROTO::data->dndActive()) { + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + for (auto& b : pressedButtons) { + sendButton(now.tv_sec * 1000 + now.tv_nsec / 1000000, b, WL_POINTER_BUTTON_STATE_RELEASED); + } + } + + pressedButtons.clear(); + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); currentSurface.reset(); listeners.destroySurface.reset(); @@ -144,6 +157,19 @@ void CWLPointerResource::sendButton(uint32_t timeMs, uint32_t button, wl_pointer if (!owner || !currentSurface) return; + if (state == WL_POINTER_BUTTON_STATE_RELEASED && std::find(pressedButtons.begin(), pressedButtons.end(), button) == pressedButtons.end()) { + LOGM(ERR, "sendButton release on a non-pressed button"); + return; + } else if (state == WL_POINTER_BUTTON_STATE_PRESSED && std::find(pressedButtons.begin(), pressedButtons.end(), button) != pressedButtons.end()) { + LOGM(ERR, "sendButton press on a non-pressed button"); + return; + } + + if (state == WL_POINTER_BUTTON_STATE_RELEASED) + std::erase(pressedButtons, button); + else if (state == WL_POINTER_BUTTON_STATE_PRESSED) + pressedButtons.emplace_back(button); + resource->sendButton(g_pSeatManager->nextSerial(owner.lock()), timeMs, button, state); } diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 625d3a98..0b563b8f 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -76,6 +76,8 @@ class CWLPointerResource { SP resource; WP currentSurface; + std::vector pressedButtons; + struct { CHyprSignalListener destroySurface; } listeners; From a9c7a0830fd9a8b9fc4065f1cd654efd1326691a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 17 Jun 2024 16:14:45 +0200 Subject: [PATCH 0250/2393] data-device: minor fixes send leave after drop, improve checks in completeDrag --- src/protocols/core/DataDevice.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 2d50ff15..9634d569 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -540,7 +540,7 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource } void CWLDataDeviceProtocol::updateDrag() { - if (!dnd.currentSource) + if (!dndActive()) return; if (dnd.focusedDevice) @@ -595,15 +595,13 @@ void CWLDataDeviceProtocol::dropDrag() { } dnd.focusedDevice->sendDrop(); + dnd.focusedDevice->sendLeave(); resetDndState(); if (dnd.overriddenCursor) g_pInputManager->unsetCursorImage(); dnd.overriddenCursor = false; - - g_pInputManager->simulateMouseMovement(); - g_pSeatManager->resendEnterEvents(); } bool CWLDataDeviceProtocol::wasDragSuccessful() { @@ -624,11 +622,13 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() { void CWLDataDeviceProtocol::completeDrag() { resetDndState(); - if (!dnd.focusedDevice || !dnd.currentSource) + if (!dnd.focusedDevice && !dnd.currentSource) return; - dnd.currentSource->sendDndDropPerformed(); - dnd.currentSource->sendDndFinished(); + if (dnd.currentSource) { + dnd.currentSource->sendDndDropPerformed(); + dnd.currentSource->sendDndFinished(); + } dnd.focusedDevice.reset(); dnd.currentSource.reset(); From 28ce0e0f804de50f75eab797bc404c1be0b54442 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 17 Jun 2024 17:37:36 +0200 Subject: [PATCH 0251/2393] misc: a few compiler level performance optimisations (#6559) * window: use const references instead of copies use const references instead of wasteful copies and make the = operator check for self assignment and return early. also use const in all the other operators. * listener: pass std::function as const reference instead of copies pass the std::functions as const references. * config: dont unnecessarily convert to c_str getHyprlangConfigValuePtr wants an std::string and we already have an std::string, dont convert it to a c_str only for it to be converted back to an std::string. * buffer: pass attributes as const reference pass attributes as const reference instead of copies. --- src/config/ConfigValue.hpp | 2 +- src/desktop/Window.hpp | 30 +++++++++++++++++------------- src/helpers/WLListener.cpp | 4 ++-- src/helpers/WLListener.hpp | 4 ++-- src/protocols/types/DMABuffer.cpp | 2 +- src/protocols/types/DMABuffer.hpp | 2 +- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/config/ConfigValue.hpp b/src/config/ConfigValue.hpp index 72accd67..fc8abb4b 100644 --- a/src/config/ConfigValue.hpp +++ b/src/config/ConfigValue.hpp @@ -11,7 +11,7 @@ template class CConfigValue { public: CConfigValue(const std::string& val) { - const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val.c_str()); + const auto PVHYPRLANG = g_pConfigManager->getHyprlangConfigValuePtr(val); p_ = PVHYPRLANG->getDataStaticPtr(); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 16bf297c..3f387d31 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -62,18 +62,22 @@ class IWindowTransformer; template class CWindowOverridableVar { public: - CWindowOverridableVar(T val) { + CWindowOverridableVar(T const& val) { value = val; } ~CWindowOverridableVar() = default; - CWindowOverridableVar& operator=(CWindowOverridableVar other) { - if (locked) + CWindowOverridableVar& operator=(CWindowOverridableVar const& other) { + // Self-assignment check + if (this == &other) return *this; - locked = other.locked; - value = other.value; + // Check if the current object is locked + if (!locked) { + locked = other.locked; + value = other.value; + } return *this; } @@ -85,36 +89,36 @@ class CWindowOverridableVar { return other; } - void forceSetIgnoreLocked(T val, bool lock = false) { + void forceSetIgnoreLocked(T const& val, bool lock = false) { value = val; locked = lock; } - T operator*(T& other) { + T operator*(T const& other) { return value * other; } - T operator+(T& other) { + T operator+(T const& other) { return value + other; } - bool operator==(T& other) { + bool operator==(T const& other) { return other == value; } - bool operator>=(T& other) { + bool operator>=(T const& other) { return value >= other; } - bool operator<=(T& other) { + bool operator<=(T const& other) { return value <= other; } - bool operator>(T& other) { + bool operator>(T const& other) { return value > other; } - bool operator<(T& other) { + bool operator<(T const& other) { return value < other; } diff --git a/src/helpers/WLListener.cpp b/src/helpers/WLListener.cpp index 978ff034..2ea5c0b6 100644 --- a/src/helpers/WLListener.cpp +++ b/src/helpers/WLListener.cpp @@ -18,7 +18,7 @@ void handleWrapped(wl_listener* listener, void* data) { g_pWatchdog->endWatching(); } -CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function callback, void* pOwner) { +CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function const& callback, void* pOwner) { initCallback(pSignal, callback, pOwner); } @@ -44,7 +44,7 @@ bool CHyprWLListener::isConnected() { return !wl_list_empty(&m_swWrapper.m_sListener.link); } -void CHyprWLListener::initCallback(wl_signal* pSignal, std::function callback, void* pOwner, std::string author) { +void CHyprWLListener::initCallback(wl_signal* pSignal, std::function const& callback, void* pOwner, std::string author) { if (isConnected()) { Debug::log(ERR, "Tried to connect a listener twice?!"); return; diff --git a/src/helpers/WLListener.hpp b/src/helpers/WLListener.hpp index d5d925b0..621458e6 100644 --- a/src/helpers/WLListener.hpp +++ b/src/helpers/WLListener.hpp @@ -6,7 +6,7 @@ class CHyprWLListener { public: - CHyprWLListener(wl_signal*, std::function, void* owner); + CHyprWLListener(wl_signal*, std::function const&, void* owner); CHyprWLListener(); ~CHyprWLListener(); @@ -15,7 +15,7 @@ class CHyprWLListener { CHyprWLListener& operator=(const CHyprWLListener&) = delete; CHyprWLListener& operator=(CHyprWLListener&&) = delete; - void initCallback(wl_signal*, std::function, void* owner, std::string author = ""); + void initCallback(wl_signal*, std::function const&, void* owner, std::string author = ""); void removeCallback(); diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index f26328e9..7c3a9886 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -3,7 +3,7 @@ #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" -CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) : attrs(attrs_) { +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) { g_pHyprRenderer->makeEGLCurrent(); listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp index dac89493..d07840b7 100644 --- a/src/protocols/types/DMABuffer.hpp +++ b/src/protocols/types/DMABuffer.hpp @@ -4,7 +4,7 @@ class CDMABuffer : public IWLBuffer { public: - CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs_); + CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_); virtual ~CDMABuffer(); virtual eBufferCapability caps(); From d1340bd1d8eedd274283e0cb2568a3ed67b58c81 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 17 Jun 2024 17:53:44 +0200 Subject: [PATCH 0252/2393] keybinds: ignore missing keysyms if no other methods match fixes #6548 --- src/managers/KeybindManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 14fadf02..875ba239 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -636,6 +636,12 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (found || key.submapAtPress != m_szCurrentSelectedSubmap) continue; } else { + // in this case, we only have the keysym to go off. + // if the keysym failed resolving, we can't do anything. It's likely missing + // from the keymap. + if (key.keysym == 0) + return false; + // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); From 236150b3c5227bbfbe46d2610c739a386afdca1f Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 18 Jun 2024 17:06:14 +0200 Subject: [PATCH 0253/2393] github: reword bug or regression (#6520) --- .github/ISSUE_TEMPLATE/bug.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 285a15a1..e3e97bef 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -5,18 +5,21 @@ body: - type: markdown attributes: value: | - Before opening a new issue, take a moment to search through the current open ones. + ## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists. --- - type: dropdown id: type attributes: - label: Bug or Regression? - description: Is this a bug or a regression? + label: Regression? + description: | + Regression means that something used to work but no longer does. + **BEFORE CONTINUING**, please check if this bug is a regression or not, and if it is, we need you to bisect with the help of the wiki: https://wiki.hyprland.org/Crashes-and-Bugs/#bisecting-an-issue + multiple: true options: - - Bug - - Regression + - "Yes" + - "No" validations: required: true From b98e0876d3b54b7625bacf14e3546dd2d0e600d0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Jun 2024 21:38:33 +0200 Subject: [PATCH 0254/2393] hyprctl: avoid using select() move to poll() ref #6584 --- src/debug/HyprCtl.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 70b886f2..e212ed1c 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -1784,13 +1785,17 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) { std::array readBuffer; - fd_set fdset; - FD_ZERO(&fdset); - FD_SET(ACCEPTEDCONNECTION, &fdset); - timeval timeout = {.tv_sec = 0, .tv_usec = 5000}; - auto success = select(ACCEPTEDCONNECTION + 1, &fdset, nullptr, nullptr, &timeout); + // + pollfd pollfds[1] = { + { + .fd = ACCEPTEDCONNECTION, + .events = POLLIN, + }, + }; - if (success <= 0) { + int ret = poll(pollfds, 1, 5000); + + if (ret <= 0) { close(ACCEPTEDCONNECTION); return 0; } From e0e3c4c6ae15af88ac5fd5ab959adfe45a2e1dca Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Jun 2024 21:52:55 +0200 Subject: [PATCH 0255/2393] compositor: bump nofile rlimits on launch ref #6584 --- src/Compositor.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2f972335..af46b0ff 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -29,6 +29,7 @@ using namespace Hyprutils::String; #include #include +#include int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -70,6 +71,46 @@ void handleUserSignal(int sig) { } } +static void bumpNofile() { + unsigned long limit = 1024; + + try { + std::ifstream f("/proc/sys/fs/nr_open"); + if (!f.good()) + limit = 1073741816; + else { + std::string content((std::istreambuf_iterator(f)), (std::istreambuf_iterator())); + f.close(); + + limit = std::stoll(content); + } + + } catch (...) { limit = 1073741816; } + + struct rlimit rlimit_; + if (!getrlimit(RLIMIT_NOFILE, &rlimit_)) + Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", rlimit_.rlim_cur, rlimit_.rlim_max); + + if (rlimit_.rlim_max <= 1024) + rlimit_.rlim_max = limit; + + unsigned long oldHardLimit = rlimit_.rlim_max; + + rlimit_.rlim_max = limit; + + if (setrlimit(RLIMIT_NOFILE, &rlimit_) < 0) { + Debug::log(LOG, "Failed bumping NOFILE limits higher, retrying with previous hard."); + rlimit_.rlim_max = oldHardLimit; + rlimit_.rlim_cur = std::clamp((unsigned long)limit, 1UL, (unsigned long)rlimit_.rlim_max); + + if (setrlimit(RLIMIT_NOFILE, &rlimit_) < 0) + Debug::log(LOG, "Failed bumping NOFILE limits higher for the second time."); + } + + if (!getrlimit(RLIMIT_NOFILE, &rlimit_)) + Debug::log(LOG, "New rlimit: soft -> {}, hard -> {}", rlimit_.rlim_cur, rlimit_.rlim_max); +} + CCompositor::CCompositor() { m_iHyprlandPID = getpid(); @@ -131,6 +172,8 @@ CCompositor::CCompositor() { setRandomSplash(); Debug::log(LOG, "\nCurrent splash: {}\n\n", m_szCurrentSplash); + + bumpNofile(); } CCompositor::~CCompositor() { From 6e5804b53de753f24953d9d647940df66bc68f6d Mon Sep 17 00:00:00 2001 From: random2907 <81547183+random2907@users.noreply.github.com> Date: Wed, 19 Jun 2024 11:50:49 +0530 Subject: [PATCH 0256/2393] hyprctl: fix zsh completion (#6467) Co-authored-by: random2907 --- hyprctl/hyprctl.zsh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index 6babd835..1a4cc187 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -1,3 +1,5 @@ +#compdef hyprctl + _hyprctl_cmd_2 () { hyprctl monitors | grep Monitor | awk '{ print $2 }' } From fb15b7aa2a9bba0f0693f84d0c65d386942583f8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 19 Jun 2024 16:20:06 +0200 Subject: [PATCH 0257/2393] core: Move to hyprutils for Math Moves CRegion, CBox and Vector2D over to hyprutils. Requires hyprutils>=0.1.4 --- CMakeLists.txt | 2 +- src/Compositor.cpp | 3 +- src/SharedDefs.hpp | 29 +-- src/config/ConfigManager.cpp | 3 +- src/debug/HyprNotificationOverlay.cpp | 2 +- src/desktop/LayerSurface.cpp | 4 +- src/desktop/WLSurface.cpp | 2 +- src/desktop/WLSurface.hpp | 2 +- src/desktop/Window.cpp | 10 +- src/desktop/Window.hpp | 136 +++++------ src/desktop/Workspace.cpp | 16 +- src/devices/IKeyboard.hpp | 2 +- src/devices/IPointer.hpp | 2 +- src/devices/ITouch.hpp | 2 +- src/devices/Tablet.hpp | 4 +- src/helpers/AnimatedVariable.hpp | 2 +- src/helpers/BezierCurve.hpp | 2 +- src/helpers/Box.cpp | 179 -------------- src/helpers/Box.hpp | 92 -------- src/helpers/Format.hpp | 2 +- src/helpers/MiscFunctions.cpp | 2 +- src/helpers/MiscFunctions.hpp | 2 +- src/helpers/Monitor.cpp | 4 +- src/helpers/Monitor.hpp | 2 +- src/helpers/Region.cpp | 183 --------------- src/helpers/Region.hpp | 69 ------ src/helpers/Vector2D.cpp | 58 ----- src/helpers/Vector2D.hpp | 133 ----------- src/helpers/WLClasses.hpp | 2 +- src/helpers/math/Math.cpp | 220 ++++++++++++++++++ src/helpers/math/Math.hpp | 11 + src/includes.hpp | 2 - src/layout/DwindleLayout.cpp | 12 +- src/layout/IHyprLayout.cpp | 4 +- src/layout/MasterLayout.cpp | 4 +- src/macros.hpp | 7 + src/managers/AnimationManager.cpp | 18 +- src/managers/CursorManager.cpp | 9 +- src/managers/CursorManager.hpp | 2 +- src/managers/PointerManager.cpp | 2 +- src/managers/PointerManager.hpp | 4 +- src/managers/SeatManager.hpp | 2 +- src/managers/input/InputMethodPopup.hpp | 2 +- src/managers/input/Swipe.cpp | 40 ++-- src/managers/input/TextInput.hpp | 2 +- src/protocols/LayerShell.cpp | 2 +- src/protocols/LayerShell.hpp | 2 +- src/protocols/PointerConstraints.hpp | 4 +- src/protocols/PointerGestures.hpp | 2 +- src/protocols/RelativePointer.hpp | 2 +- src/protocols/Screencopy.cpp | 9 +- src/protocols/Tablet.hpp | 2 +- src/protocols/TextInputV3.hpp | 2 +- src/protocols/ToplevelExport.cpp | 2 +- src/protocols/XDGShell.cpp | 20 +- src/protocols/XDGShell.hpp | 4 +- src/protocols/core/Compositor.cpp | 2 +- src/protocols/core/Compositor.hpp | 2 +- src/protocols/core/DataDevice.hpp | 2 +- src/protocols/core/Seat.hpp | 2 +- src/protocols/core/Shm.hpp | 2 +- src/render/OpenGL.cpp | 38 +-- src/render/OpenGL.hpp | 2 +- src/render/Renderer.cpp | 16 +- src/render/Renderer.hpp | 2 +- src/render/Texture.cpp | 2 +- src/render/Texture.hpp | 2 +- .../decorations/CHyprBorderDecoration.hpp | 16 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.hpp | 14 +- .../decorations/CHyprGroupBarDecoration.hpp | 2 +- .../decorations/DecorationPositioner.cpp | 30 +-- .../decorations/DecorationPositioner.hpp | 28 +-- .../decorations/IHyprWindowDecoration.hpp | 2 +- src/xwayland/XSurface.hpp | 2 +- src/xwayland/XWM.cpp | 2 +- 76 files changed, 509 insertions(+), 1004 deletions(-) delete mode 100644 src/helpers/Box.cpp delete mode 100644 src/helpers/Box.hpp delete mode 100644 src/helpers/Region.cpp delete mode 100644 src/helpers/Region.hpp delete mode 100644 src/helpers/Vector2D.cpp delete mode 100644 src/helpers/Vector2D.hpp create mode 100644 src/helpers/math/Math.cpp create mode 100644 src/helpers/math/Math.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aa2bf5c..632621ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.1 + hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.4 ) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index af46b0ff..7777a55f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1434,8 +1434,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (!PMONITOR) return nullptr; // ?? - const auto WINDOWIDEALBB = pWindow->m_bIsFullscreen ? wlr_box{(int)PMONITOR->vecPosition.x, (int)PMONITOR->vecPosition.y, (int)PMONITOR->vecSize.x, (int)PMONITOR->vecSize.y} : - pWindow->getWindowIdealBoundingBoxIgnoreReserved(); + const auto WINDOWIDEALBB = pWindow->m_bIsFullscreen ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index 1b4876bb..2a1546c6 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -1,7 +1,11 @@ #pragma once -#include "helpers/Vector2D.hpp" +#include "helpers/math/Math.hpp" #include +#include +#include + +using namespace Hyprutils::Math; enum eIcons { ICON_WARNING = 0, @@ -37,29 +41,6 @@ struct SCallbackInfo { bool cancelled = false; /* on cancellable events, will cancel the event. */ }; -struct SWindowDecorationExtents { - Vector2D topLeft; - Vector2D bottomRight; - - // - SWindowDecorationExtents operator*(const double& scale) const { - return SWindowDecorationExtents{topLeft * scale, bottomRight * scale}; - } - - SWindowDecorationExtents round() { - return {topLeft.round(), bottomRight.round()}; - } - - bool operator==(const SWindowDecorationExtents& other) const { - return topLeft == other.topLeft && bottomRight == other.bottomRight; - } - - void addExtents(const SWindowDecorationExtents& other) { - topLeft = topLeft.getComponentMax(other.topLeft); - bottomRight = bottomRight.getComponentMax(other.bottomRight); - } -}; - enum eHyprCtlOutputFormat { FORMAT_NORMAL = 0, FORMAT_JSON diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 56fdae25..17bbe465 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -982,7 +982,8 @@ float CConfigManager::getDeviceFloat(const std::string& dev, const std::string& } Vector2D CConfigManager::getDeviceVec(const std::string& dev, const std::string& v, const std::string& fallback) { - return std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue()); + auto vec = std::any_cast(getConfigValueSafeDevice(dev, v, fallback)->getValue()); + return {vec.x, vec.y}; } std::string CConfigManager::getDeviceString(const std::string& dev, const std::string& v, const std::string& fallback) { diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index aec3853e..3f8bb579 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -131,7 +131,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { textW /= PANGO_SCALE; textH /= PANGO_SCALE; - const auto NOTIFSIZE = Vector2D{textW + 20 + iconW + 2 * ICONPADFORNOTIF, textH + 10}; + const auto NOTIFSIZE = Vector2D{textW + 20.0 + iconW + 2 * ICONPADFORNOTIF, textH + 10.0}; // draw rects cairo_set_source_rgba(m_pCairo, notif->color.r, notif->color.g, notif->color.b, notif->color.a); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 64eeead1..9a891531 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -412,9 +412,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) { } const std::array edgePoints = { - PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0}, + PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, 0.0}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x / 2, PMONITOR->vecSize.y}, - PMONITOR->vecPosition + Vector2D{0, PMONITOR->vecSize.y}, + PMONITOR->vecPosition + Vector2D{0.0, PMONITOR->vecSize.y}, PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, }; diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index c7a09b40..97335d27 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -86,7 +86,7 @@ CRegion CWLSurface::logicalDamage() const { return {}; CRegion damage = m_pResource->accumulateCurrentBufferDamage(); - damage.transform(m_pResource->current.transform, m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); + damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); damage.scale(1.0 / m_pResource->current.scale); const auto VPSIZE = getViewporterCorrectedSize(); diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 4ba381a9..447f4582 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -1,7 +1,7 @@ #pragma once #include "../defines.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" class CSubsurface; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index d153b344..e67a3357 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -104,7 +104,7 @@ CWindow::~CWindow() { std::erase_if(g_pHyprOpenGL->m_mWindowFramebuffers, [&](const auto& other) { return !other.first.lock() || other.first.lock().get() == this; }); } -SWindowDecorationExtents CWindow::getFullWindowExtents() { +SBoxExtents CWindow::getFullWindowExtents() { if (m_bFadingOut) return m_eOriginalClosedExtents; @@ -116,9 +116,9 @@ SWindowDecorationExtents CWindow::getFullWindowExtents() { {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; } - SWindowDecorationExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; + SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; - const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock()); + const auto EXTENTS = g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock()); if (EXTENTS.topLeft.x > maxExtents.topLeft.x) maxExtents.topLeft.x = EXTENTS.topLeft.x; @@ -224,7 +224,7 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) { return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } - SWindowDecorationExtents EXTENTS = {{0, 0}, {0, 0}}; + SBoxExtents EXTENTS = {{0, 0}, {0, 0}}; if (properties & RESERVED_EXTENTS) EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock())); if (properties & INPUT_EXTENTS) @@ -242,7 +242,7 @@ CBox CWindow::getWindowMainSurfaceBox() { return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; } -SWindowDecorationExtents CWindow::getFullWindowReservedArea() { +SBoxExtents CWindow::getFullWindowReservedArea() { return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 3f387d31..6bfdbc50 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -6,7 +6,7 @@ #include "../config/ConfigDataValues.hpp" #include "../defines.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/TagKeeper.hpp" #include "../macros.hpp" @@ -310,7 +310,7 @@ class CWindow { bool m_bReadyToDelete = false; Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedSize; // drawing the closing animations - SWindowDecorationExtents m_eOriginalClosedExtents; + SBoxExtents m_eOriginalClosedExtents; bool m_bAnimatingIn = false; // For pinned (sticky) windows @@ -386,75 +386,75 @@ class CWindow { } // methods - CBox getFullWindowBoundingBox(); - SWindowDecorationExtents getFullWindowExtents(); - CBox getWindowBoxUnified(uint64_t props); - CBox getWindowMainSurfaceBox(); - CBox getWindowIdealBoundingBoxIgnoreReserved(); - void addWindowDeco(std::unique_ptr deco); - void updateWindowDecos(); - void removeWindowDeco(IHyprWindowDecoration* deco); - void uncacheWindowDecos(); - bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); - pid_t getPID(); - IHyprWindowDecoration* getDecorationByType(eDecorationType); - void removeDecorationByType(eDecorationType); - void updateToplevel(); - void updateSurfaceScaleTransformDetails(bool force = false); - void moveToWorkspace(PHLWORKSPACE); - PHLWINDOW X11TransientFor(); - void onUnmap(); - void onMap(); - void setHidden(bool hidden); - bool isHidden(); - void applyDynamicRule(const SWindowRule& r); - void updateDynamicRules(); - SWindowDecorationExtents getFullWindowReservedArea(); - Vector2D middle(); - bool opaque(); - float rounding(); - bool canBeTorn(); - bool shouldSendFullscreenState(); - void setSuspended(bool suspend); - bool visibleOnMonitor(CMonitor* pMonitor); - int workspaceID(); - bool onSpecialWorkspace(); - void activate(bool force = false); - int surfacesCount(); + CBox getFullWindowBoundingBox(); + SBoxExtents getFullWindowExtents(); + CBox getWindowBoxUnified(uint64_t props); + CBox getWindowMainSurfaceBox(); + CBox getWindowIdealBoundingBoxIgnoreReserved(); + void addWindowDeco(std::unique_ptr deco); + void updateWindowDecos(); + void removeWindowDeco(IHyprWindowDecoration* deco); + void uncacheWindowDecos(); + bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); + pid_t getPID(); + IHyprWindowDecoration* getDecorationByType(eDecorationType); + void removeDecorationByType(eDecorationType); + void updateToplevel(); + void updateSurfaceScaleTransformDetails(bool force = false); + void moveToWorkspace(PHLWORKSPACE); + PHLWINDOW X11TransientFor(); + void onUnmap(); + void onMap(); + void setHidden(bool hidden); + bool isHidden(); + void applyDynamicRule(const SWindowRule& r); + void updateDynamicRules(); + SBoxExtents getFullWindowReservedArea(); + Vector2D middle(); + bool opaque(); + float rounding(); + bool canBeTorn(); + bool shouldSendFullscreenState(); + void setSuspended(bool suspend); + bool visibleOnMonitor(CMonitor* pMonitor); + int workspaceID(); + bool onSpecialWorkspace(); + void activate(bool force = false); + int surfacesCount(); - int getRealBorderSize(); - void updateSpecialRenderData(); - void updateSpecialRenderData(const struct SWorkspaceRule&); + int getRealBorderSize(); + void updateSpecialRenderData(); + void updateSpecialRenderData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(void* ptr); - bool isInCurvedCorner(double x, double y); - bool hasPopupAt(const Vector2D& pos); - int popupsCount(); + void onBorderAngleAnimEnd(void* ptr); + bool isInCurvedCorner(double x, double y); + bool hasPopupAt(const Vector2D& pos); + int popupsCount(); - void applyGroupRules(); - void createGroup(); - void destroyGroup(); - PHLWINDOW getGroupHead(); - PHLWINDOW getGroupTail(); - PHLWINDOW getGroupCurrent(); - PHLWINDOW getGroupPrevious(); - PHLWINDOW getGroupWindowByIndex(int); - int getGroupSize(); - bool canBeGroupedInto(PHLWINDOW pWindow); - void setGroupCurrent(PHLWINDOW pWindow); - void insertWindowToGroup(PHLWINDOW pWindow); - void updateGroupOutputs(); - void switchWithWindowInGroup(PHLWINDOW pWindow); - void setAnimationsToMove(); - void onWorkspaceAnimUpdate(); - void onUpdateState(); - void onUpdateMeta(); - void onX11Configure(CBox box); - void onResourceChangeX11(); - std::string fetchTitle(); - std::string fetchClass(); - void warpCursor(); - PHLWINDOW getSwallower(); + void applyGroupRules(); + void createGroup(); + void destroyGroup(); + PHLWINDOW getGroupHead(); + PHLWINDOW getGroupTail(); + PHLWINDOW getGroupCurrent(); + PHLWINDOW getGroupPrevious(); + PHLWINDOW getGroupWindowByIndex(int); + int getGroupSize(); + bool canBeGroupedInto(PHLWINDOW pWindow); + void setGroupCurrent(PHLWINDOW pWindow); + void insertWindowToGroup(PHLWINDOW pWindow); + void updateGroupOutputs(); + void switchWithWindowInGroup(PHLWINDOW pWindow); + void setAnimationsToMove(); + void onWorkspaceAnimUpdate(); + void onUpdateState(); + void onUpdateMeta(); + void onX11Configure(CBox box); + void onResourceChangeX11(); + std::string fetchTitle(); + std::string fetchClass(); + void warpCursor(); + PHLWINDOW getSwallower(); // listeners void onAck(uint32_t serial); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index ed09fbc0..04685bd5 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -104,24 +104,24 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { if (ANIMSTYLE.starts_with("slidefadevert")) { if (in) { m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D(0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); + m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); m_fAlpha = 1.f; m_vRenderOffset = Vector2D(0, 0); } else { m_fAlpha.setValueAndWarp(1.f); m_fAlpha = 0.f; - m_vRenderOffset = Vector2D(0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); + m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); } } else { if (in) { m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0)); + m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); m_fAlpha = 1.f; m_vRenderOffset = Vector2D(0, 0); } else { m_fAlpha.setValueAndWarp(1.f); m_fAlpha = 0.f; - m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0); + m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); } } } else if (ANIMSTYLE == "fade") { @@ -142,10 +142,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(0, left ? YDISTANCE : -YDISTANCE)); + m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(0, left ? -YDISTANCE : YDISTANCE); + m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); } } else { // fallback is slide @@ -155,10 +155,10 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0)); + m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0); + m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); } } diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index ec58ff5b..b1757a18 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -3,7 +3,7 @@ #include "IHID.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" #include diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index e2347c95..b2995b2f 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -3,7 +3,7 @@ #include "IHID.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" struct wlr_pointer; diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index 5929be02..b9cbf2ae 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -3,7 +3,7 @@ #include "IHID.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" struct wlr_touch; diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index 1805f3ba..ada2cf89 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -3,8 +3,8 @@ #include "IHID.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" -#include "../helpers/Vector2D.hpp" -#include "../helpers/Box.hpp" +#include "../helpers/math/Math.hpp" +#include "../helpers/math/Math.hpp" struct wlr_tablet; struct wlr_tablet_tool; diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index 5c63032e..073cf65b 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "Vector2D.hpp" +#include "math/Math.hpp" #include "Color.hpp" #include "../defines.hpp" #include "../debug/Log.hpp" diff --git a/src/helpers/BezierCurve.hpp b/src/helpers/BezierCurve.hpp index fb11d52b..54af46a6 100644 --- a/src/helpers/BezierCurve.hpp +++ b/src/helpers/BezierCurve.hpp @@ -3,7 +3,7 @@ #include #include #include -#include "Vector2D.hpp" +#include "math/Math.hpp" constexpr int BAKEDPOINTS = 255; constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS; diff --git a/src/helpers/Box.cpp b/src/helpers/Box.cpp deleted file mode 100644 index 4b7f5726..00000000 --- a/src/helpers/Box.cpp +++ /dev/null @@ -1,179 +0,0 @@ -#include "Box.hpp" - -#include -#include - -wlr_box CBox::wlr() { - CBox rounded = roundInternal(); - m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h}; - return m_bWlrBox; -} - -wlr_box* CBox::pWlr() { - CBox rounded = roundInternal(); - m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h}; - return &m_bWlrBox; -} - -CBox& CBox::scale(double scale) { - x *= scale; - y *= scale; - w *= scale; - h *= scale; - - return *this; -} - -CBox& CBox::scale(const Vector2D& scale) { - x *= scale.x; - y *= scale.y; - w *= scale.x; - h *= scale.y; - - return *this; -} - -CBox& CBox::translate(const Vector2D& vec) { - x += vec.x; - y += vec.y; - - return *this; -} - -Vector2D CBox::middle() const { - return Vector2D{x + w / 2.0, y + h / 2.0}; -} - -bool CBox::containsPoint(const Vector2D& vec) const { - return VECINRECT(vec, x, y, x + w, y + h); -} - -bool CBox::empty() const { - return w == 0 || h == 0; -} - -CBox& CBox::applyFromWlr() { - x = m_bWlrBox.x; - y = m_bWlrBox.y; - w = m_bWlrBox.width; - h = m_bWlrBox.height; - - return *this; -} - -CBox& CBox::round() { - float newW = x + w - std::round(x); - float newH = y + h - std::round(y); - x = std::round(x); - y = std::round(y); - w = std::round(newW); - h = std::round(newH); - - return *this; -} - -CBox& CBox::transform(const wl_output_transform t, double w, double h) { - wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h); - applyFromWlr(); - - return *this; -} - -CBox& CBox::addExtents(const SWindowDecorationExtents& e) { - x -= e.topLeft.x; - y -= e.topLeft.y; - w += e.topLeft.x + e.bottomRight.x; - h += e.topLeft.y + e.bottomRight.y; - - return *this; -} - -CBox& CBox::scaleFromCenter(double scale) { - double oldW = w, oldH = h; - - w *= scale; - h *= scale; - - x -= (w - oldW) / 2.0; - y -= (h - oldH) / 2.0; - - return *this; -} - -CBox& CBox::expand(const double& value) { - x -= value; - y -= value; - w += value * 2.0; - h += value * 2.0; - - if (w <= 0 || h <= 0) { - w = 0; - h = 0; - } - - return *this; -} - -CBox& CBox::noNegativeSize() { - w = std::clamp(w, 0.0, std::numeric_limits::infinity()); - h = std::clamp(h, 0.0, std::numeric_limits::infinity()); - - return *this; -} - -CBox CBox::intersection(const CBox& other) const { - const float newX = std::max(x, other.x); - const float newY = std::max(y, other.y); - const float newBottom = std::min(y + h, other.y + other.h); - const float newRight = std::min(x + w, other.x + other.w); - float newW = newRight - newX; - float newH = newBottom - newY; - - if (newW <= 0 || newH <= 0) { - newW = 0; - newH = 0; - } - - return {newX, newY, newW, newH}; -} - -bool CBox::overlaps(const CBox& other) const { - return (other.x + other.w >= x) && (x + w >= other.x) && (other.y + other.h >= y) && (y + h >= other.y); -} - -bool CBox::inside(const CBox& bound) const { - return bound.x < x && bound.y < y && x + w < bound.x + bound.w && y + h < bound.y + bound.h; -} - -CBox CBox::roundInternal() { - float newW = x + w - std::floor(x); - float newH = y + h - std::floor(y); - - return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)}; -} - -CBox CBox::copy() const { - return CBox{*this}; -} - -Vector2D CBox::pos() const { - return {x, y}; -} - -Vector2D CBox::size() const { - return {w, h}; -} - -Vector2D CBox::closestPoint(const Vector2D& vec) const { - if (containsPoint(vec)) - return vec; - - Vector2D nv = vec; - nv.x = std::clamp(nv.x, x, x + w); - nv.y = std::clamp(nv.y, y, y + h); - return nv; -} - -SWindowDecorationExtents CBox::extentsFrom(const CBox& small) { - return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}}; -} diff --git a/src/helpers/Box.hpp b/src/helpers/Box.hpp deleted file mode 100644 index 57df2154..00000000 --- a/src/helpers/Box.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include "Vector2D.hpp" -#include "../SharedDefs.hpp" -#include "../includes.hpp" - -class CBox { - public: - CBox(double x_, double y_, double w_, double h_) { - x = x_; - y = y_; - w = w_; - h = h_; - } - - CBox() { - w = 0; - h = 0; - } - - CBox(const wlr_box& box) { - x = box.x; - y = box.y; - w = box.width; - h = box.height; - } - - CBox(const double d) { - x = d; - y = d; - w = d; - h = d; - } - - CBox(const Vector2D& pos, const Vector2D& size) { - x = pos.x; - y = pos.y; - w = size.x; - h = size.y; - } - - wlr_box wlr(); - wlr_box* pWlr(); - - CBox& applyFromWlr(); - CBox& scale(double scale); - CBox& scaleFromCenter(double scale); - CBox& scale(const Vector2D& scale); - CBox& translate(const Vector2D& vec); - CBox& round(); - CBox& transform(const wl_output_transform t, double w, double h); - CBox& addExtents(const SWindowDecorationExtents& e); - CBox& expand(const double& value); - CBox& noNegativeSize(); - - CBox copy() const; - CBox intersection(const CBox& other) const; - bool overlaps(const CBox& other) const; - bool inside(const CBox& bound) const; - - SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box - - Vector2D middle() const; - Vector2D pos() const; - Vector2D size() const; - Vector2D closestPoint(const Vector2D& vec) const; - - bool containsPoint(const Vector2D& vec) const; - bool empty() const; - - double x = 0, y = 0; - union { - double w; - double width; - }; - union { - double h; - double height; - }; - - double rot = 0; /* rad, ccw */ - - // - bool operator==(const CBox& rhs) const { - return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; - } - - private: - CBox roundInternal(); - - wlr_box m_bWlrBox; -}; diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp index b86f44dd..a1ef53f5 100644 --- a/src/helpers/Format.hpp +++ b/src/helpers/Format.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "Vector2D.hpp" +#include "math/Math.hpp" typedef uint32_t DRMFormat; typedef uint32_t SHMFormat; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 821f3231..654ccf35 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -762,7 +762,7 @@ Vector2D configStringToVector2D(const std::string& VALUE) { if (std::getline(iss, token)) throw std::invalid_argument("Invalid string format"); - return Vector2D(x, y); + return Vector2D((double)x, (double)y); } double normalizeAngleRad(double ang) { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index feb0380b..111abba0 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "Vector2D.hpp" +#include "math/Math.hpp" #include #include diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 58687e09..da6da873 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -358,7 +358,9 @@ void CMonitor::addDamage(const CBox* box) { g_pCompositor->scheduleFrameForMonitor(this); } - if (wlr_damage_ring_add_box(&damage, const_cast(box)->pWlr())) + wlr_box damageBox = {(int)box->x, (int)box->y, (int)box->w, (int)box->h}; + + if (wlr_damage_ring_add_box(&damage, &damageBox)) g_pCompositor->scheduleFrameForMonitor(this); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index c59e00ac..b8902197 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -8,7 +8,7 @@ #include #include #include "Timer.hpp" -#include "Region.hpp" +#include "math/Math.hpp" #include #include "signal/Signal.hpp" diff --git a/src/helpers/Region.cpp b/src/helpers/Region.cpp deleted file mode 100644 index 9e572b34..00000000 --- a/src/helpers/Region.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "Region.hpp" -extern "C" { -#include -#include -} - -constexpr const int64_t MAX_REGION_SIDE = 10000000; - -CRegion::CRegion() { - pixman_region32_init(&m_rRegion); -} - -CRegion::CRegion(const pixman_region32_t* const ref) { - pixman_region32_init(&m_rRegion); - pixman_region32_copy(&m_rRegion, ref); -} - -CRegion::CRegion(double x, double y, double w, double h) { - pixman_region32_init_rect(&m_rRegion, x, y, w, h); -} - -CRegion::CRegion(wlr_box* box) { - pixman_region32_init_rect(&m_rRegion, box->x, box->y, box->width, box->height); -} - -CRegion::CRegion(const CBox& box) { - pixman_region32_init_rect(&m_rRegion, box.x, box.y, box.w, box.h); -} - -CRegion::CRegion(pixman_box32_t* box) { - pixman_region32_init_rect(&m_rRegion, box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1); -} - -CRegion::CRegion(const CRegion& other) { - pixman_region32_init(&m_rRegion); - pixman_region32_copy(&m_rRegion, const_cast(&other)->pixman()); -} - -CRegion::CRegion(CRegion&& other) { - pixman_region32_init(&m_rRegion); - pixman_region32_copy(&m_rRegion, other.pixman()); -} - -CRegion::~CRegion() { - pixman_region32_fini(&m_rRegion); -} - -CRegion& CRegion::clear() { - pixman_region32_clear(&m_rRegion); - return *this; -} - -CRegion& CRegion::set(const CRegion& other) { - pixman_region32_copy(&m_rRegion, const_cast(&other)->pixman()); - return *this; -} - -CRegion& CRegion::add(const CRegion& other) { - pixman_region32_union(&m_rRegion, &m_rRegion, const_cast(&other)->pixman()); - return *this; -} - -CRegion& CRegion::add(double x, double y, double w, double h) { - pixman_region32_union_rect(&m_rRegion, &m_rRegion, x, y, w, h); - return *this; -} - -CRegion& CRegion::add(const CBox& other) { - pixman_region32_union_rect(&m_rRegion, &m_rRegion, other.x, other.y, other.w, other.h); - return *this; -} - -CRegion& CRegion::subtract(const CRegion& other) { - pixman_region32_subtract(&m_rRegion, &m_rRegion, const_cast(&other)->pixman()); - return *this; -} - -CRegion& CRegion::intersect(const CRegion& other) { - pixman_region32_intersect(&m_rRegion, &m_rRegion, const_cast(&other)->pixman()); - return *this; -} - -CRegion& CRegion::intersect(double x, double y, double w, double h) { - pixman_region32_intersect_rect(&m_rRegion, &m_rRegion, x, y, w, h); - return *this; -} - -CRegion& CRegion::invert(pixman_box32_t* box) { - pixman_region32_inverse(&m_rRegion, &m_rRegion, box); - return *this; -} - -CRegion& CRegion::invert(const CBox& box) { - pixman_box32 pixmanBox = {box.x, box.y, box.w + box.x, box.h + box.y}; - return this->invert(&pixmanBox); -} - -CRegion& CRegion::translate(const Vector2D& vec) { - pixman_region32_translate(&m_rRegion, vec.x, vec.y); - return *this; -} - -CRegion& CRegion::transform(const wl_output_transform t, double w, double h) { - wlr_region_transform(&m_rRegion, &m_rRegion, t, w, h); - return *this; -} - -CRegion& CRegion::rationalize() { - intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2}); - return *this; -} - -CRegion CRegion::copy() const { - return CRegion(*this); -} - -CRegion& CRegion::scale(float scale) { - wlr_region_scale(&m_rRegion, &m_rRegion, scale); - return *this; -} - -CRegion& CRegion::scale(const Vector2D& scale) { - wlr_region_scale_xy(&m_rRegion, &m_rRegion, scale.x, scale.y); - return *this; -} - -std::vector CRegion::getRects() const { - std::vector result; - - int rectsNum = 0; - const auto RECTSARR = pixman_region32_rectangles(&m_rRegion, &rectsNum); - - result.assign(RECTSARR, RECTSARR + rectsNum); - - return result; -} - -CBox CRegion::getExtents() { - pixman_box32_t* box = pixman_region32_extents(&m_rRegion); - return {box->x1, box->y1, box->x2 - box->x1, box->y2 - box->y1}; -} - -bool CRegion::containsPoint(const Vector2D& vec) const { - return pixman_region32_contains_point(&m_rRegion, vec.x, vec.y, nullptr); -} - -bool CRegion::empty() const { - return !pixman_region32_not_empty(&m_rRegion); -} - -Vector2D CRegion::closestPoint(const Vector2D& vec) const { - if (containsPoint(vec)) - return vec; - - double bestDist = __FLT_MAX__; - Vector2D leader = vec; - - for (auto& box : getRects()) { - double x = 0, y = 0; - - if (vec.x >= box.x2) - x = box.x2 - 1; - else if (vec.x < box.x1) - x = box.x1; - else - x = vec.x; - - if (vec.y >= box.y2) - y = box.y2 - 1; - else if (vec.y < box.y1) - y = box.y1; - else - y = vec.y; - - double distance = pow(x, 2) + pow(y, 2); - if (distance < bestDist) { - bestDist = distance; - leader = {x, y}; - } - } - - return leader; -} \ No newline at end of file diff --git a/src/helpers/Region.hpp b/src/helpers/Region.hpp deleted file mode 100644 index 42693c21..00000000 --- a/src/helpers/Region.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once -#include -#include -#include "Vector2D.hpp" -#include "Box.hpp" - -struct wlr_box; - -class CRegion { - public: - /* Create an empty region */ - CRegion(); - /* Create from a reference. Copies, does not own. */ - CRegion(const pixman_region32_t* const ref); - /* Create from a box */ - CRegion(double x, double y, double w, double h); - /* Create from a wlr_box */ - CRegion(wlr_box* box); - /* Create from a CBox */ - CRegion(const CBox& box); - /* Create from a pixman_box32_t */ - CRegion(pixman_box32_t* box); - - CRegion(const CRegion&); - CRegion(CRegion&&); - - ~CRegion(); - - CRegion& operator=(CRegion&& other) { - pixman_region32_copy(&m_rRegion, other.pixman()); - return *this; - } - - CRegion& operator=(CRegion& other) { - pixman_region32_copy(&m_rRegion, other.pixman()); - return *this; - } - - CRegion& clear(); - CRegion& set(const CRegion& other); - CRegion& add(const CRegion& other); - CRegion& add(double x, double y, double w, double h); - CRegion& add(const CBox& other); - CRegion& subtract(const CRegion& other); - CRegion& intersect(const CRegion& other); - CRegion& intersect(double x, double y, double w, double h); - CRegion& translate(const Vector2D& vec); - CRegion& transform(const wl_output_transform t, double w, double h); - CRegion& invert(pixman_box32_t* box); - CRegion& invert(const CBox& box); - CRegion& scale(float scale); - CRegion& scale(const Vector2D& scale); - CRegion& rationalize(); - CBox getExtents(); - bool containsPoint(const Vector2D& vec) const; - bool empty() const; - Vector2D closestPoint(const Vector2D& vec) const; - CRegion copy() const; - - std::vector getRects() const; - - // - pixman_region32_t* pixman() { - return &m_rRegion; - } - - private: - pixman_region32_t m_rRegion; -}; diff --git a/src/helpers/Vector2D.cpp b/src/helpers/Vector2D.cpp deleted file mode 100644 index 6f96d686..00000000 --- a/src/helpers/Vector2D.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "Vector2D.hpp" -#include -#include - -Vector2D::Vector2D(double xx, double yy) { - x = xx; - y = yy; -} - -Vector2D::Vector2D() { - x = 0; - y = 0; -} - -Vector2D::Vector2D(const Hyprlang::VEC2& ref) { - x = ref.x; - y = ref.y; -} - -Vector2D::~Vector2D() {} - -double Vector2D::normalize() { - // get max abs - const auto max = std::abs(x) > std::abs(y) ? std::abs(x) : std::abs(y); - - x /= max; - y /= max; - - return max; -} - -Vector2D Vector2D::floor() const { - return Vector2D(std::floor(x), std::floor(y)); -} - -Vector2D Vector2D::round() const { - return Vector2D(std::round(x), std::round(y)); -} - -Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const { - return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y)); -} - -double Vector2D::distance(const Vector2D& other) const { - return std::sqrt(distanceSq(other)); -} - -double Vector2D::distanceSq(const Vector2D& other) const { - return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y); -} - -double Vector2D::size() const { - return std::sqrt(x * x + y * y); -} - -Vector2D Vector2D::getComponentMax(const Vector2D& other) const { - return Vector2D(std::max(this->x, other.x), std::max(this->y, other.y)); -} diff --git a/src/helpers/Vector2D.hpp b/src/helpers/Vector2D.hpp deleted file mode 100644 index 0f1440c3..00000000 --- a/src/helpers/Vector2D.hpp +++ /dev/null @@ -1,133 +0,0 @@ -#pragma once - -#include -#include -#include "../macros.hpp" -#include - -class Vector2D { - public: - Vector2D(double, double); - Vector2D(); - ~Vector2D(); - Vector2D(const Hyprlang::VEC2&); - - double x = 0; - double y = 0; - - // returns the scale - double normalize(); - - Vector2D operator+(const Vector2D& a) const { - return Vector2D(this->x + a.x, this->y + a.y); - } - Vector2D operator-(const Vector2D& a) const { - return Vector2D(this->x - a.x, this->y - a.y); - } - Vector2D operator-() const { - return Vector2D(-this->x, -this->y); - } - Vector2D operator*(const double& a) const { - return Vector2D(this->x * a, this->y * a); - } - Vector2D operator/(const double& a) const { - return Vector2D(this->x / a, this->y / a); - } - - bool operator==(const Vector2D& a) const { - return a.x == x && a.y == y; - } - - bool operator!=(const Vector2D& a) const { - return a.x != x || a.y != y; - } - - Vector2D operator*(const Vector2D& a) const { - return Vector2D(this->x * a.x, this->y * a.y); - } - - Vector2D operator/(const Vector2D& a) const { - return Vector2D(this->x / a.x, this->y / a.y); - } - - bool operator>(const Vector2D& a) const { - return this->x > a.x && this->y > a.y; - } - - bool operator<(const Vector2D& a) const { - return this->x < a.x && this->y < a.y; - } - Vector2D& operator+=(const Vector2D& a) { - this->x += a.x; - this->y += a.y; - return *this; - } - Vector2D& operator-=(const Vector2D& a) { - this->x -= a.x; - this->y -= a.y; - return *this; - } - Vector2D& operator*=(const Vector2D& a) { - this->x *= a.x; - this->y *= a.y; - return *this; - } - Vector2D& operator/=(const Vector2D& a) { - this->x /= a.x; - this->y /= a.y; - return *this; - } - Vector2D& operator*=(const double& a) { - this->x *= a; - this->y *= a; - return *this; - } - Vector2D& operator/=(const double& a) { - this->x /= a; - this->y /= a; - return *this; - } - - double distance(const Vector2D& other) const; - double distanceSq(const Vector2D& other) const; - double size() const; - Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const; - - Vector2D floor() const; - Vector2D round() const; - - Vector2D getComponentMax(const Vector2D& other) const; -}; - -/** - format specification - - 'j', as json array - - 'X', same as std::format("{}x{}", vec.x, vec.y) - - number, floating point precision, use `0` to format as integer -*/ -template -struct std::formatter : std::formatter { - bool formatJson = false; - bool formatX = false; - std::string precision = ""; - FORMAT_PARSE(FORMAT_FLAG('j', formatJson) // - FORMAT_FLAG('X', formatX) // - FORMAT_NUMBER(precision), - Vector2D) - - template - auto format(const Vector2D& vec, FormatContext& ctx) const { - std::string formatString = precision.empty() ? "{}" : std::format("{{:.{}f}}", precision); - - if (formatJson) - formatString = std::format("[{0}, {0}]", formatString); - else if (formatX) - formatString = std::format("{0}x{0}", formatString); - else - formatString = std::format("[Vector2D: x: {0}, y: {0}]", formatString); - try { - string buf = std::vformat(formatString, std::make_format_args(vec.x, vec.y)); - return std::format_to(ctx.out(), "{}", buf); - } catch (std::format_error& e) { return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y); } - } -}; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index bcd6bf10..6b25e76d 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -8,7 +8,7 @@ #include "AnimatedVariable.hpp" #include "../desktop/WLSurface.hpp" #include "signal/Signal.hpp" -#include "Region.hpp" +#include "math/Math.hpp" class CMonitor; class IPointer; diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp new file mode 100644 index 00000000..df4f1bb5 --- /dev/null +++ b/src/helpers/math/Math.cpp @@ -0,0 +1,220 @@ +#include "Math.hpp" +#include + +Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { + switch (t) { + case WL_OUTPUT_TRANSFORM_NORMAL: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; + case WL_OUTPUT_TRANSFORM_180: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_180; + case WL_OUTPUT_TRANSFORM_90: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_90; + case WL_OUTPUT_TRANSFORM_270: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_270; + case WL_OUTPUT_TRANSFORM_FLIPPED: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_180; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_270; + case WL_OUTPUT_TRANSFORM_FLIPPED_90: return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_FLIPPED_90; + default: break; + } + return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; +} + +static void matrixIdentity(float mat[9]) { + static const float identity[9] = { + 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + }; + memcpy(mat, identity, sizeof(identity)); +} + +static void matrixMultiply(float mat[9], const float a[9], const float b[9]) { + float product[9]; + + product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; + product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7]; + product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8]; + + product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6]; + product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7]; + product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8]; + + product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6]; + product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7]; + product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8]; + + memcpy(mat, product, sizeof(product)); +} + +static void matrixTranspose(float mat[9], const float a[9]) { + float transposition[9] = { + a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8], + }; + memcpy(mat, transposition, sizeof(transposition)); +} + +static void matrixTranslate(float mat[9], float x, float y) { + float translate[9] = { + 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, translate); +} + +static void matrixScale(float mat[9], float x, float y) { + float scale[9] = { + x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, scale); +} + +static void matrixRotate(float mat[9], float rad) { + float rotate[9] = { + cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, + }; + wlr_matrix_multiply(mat, mat, rotate); +} + +static std::unordered_map> transforms = { + {HYPRUTILS_TRANSFORM_NORMAL, + { + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_90, + { + 0.0f, + 1.0f, + 0.0f, + -1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_180, + { + -1.0f, + 0.0f, + 0.0f, + 0.0f, + -1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_270, + { + 0.0f, + -1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_FLIPPED, + { + -1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_FLIPPED_90, + { + 0.0f, + 1.0f, + 0.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_FLIPPED_180, + { + 1.0f, + 0.0f, + 0.0f, + 0.0f, + -1.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, + {HYPRUTILS_TRANSFORM_FLIPPED_270, + { + 0.0f, + -1.0f, + 0.0f, + -1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + 1.0f, + }}, +}; + +static void matrixTransform(float mat[9], eTransform transform) { + matrixMultiply(mat, mat, transforms.at(transform).data()); +} + +static void matrixProjection(float mat[9], int width, int height, eTransform transform) { + memset(mat, 0, sizeof(*mat) * 9); + + const float* t = transforms.at(transform).data(); + float x = 2.0f / width; + float y = 2.0f / height; + + // Rotation + reflection + mat[0] = x * t[0]; + mat[1] = x * t[1]; + mat[3] = y * -t[3]; + mat[4] = y * -t[4]; + + // Translation + mat[2] = -copysign(1.0f, mat[0] + mat[1]); + mat[5] = -copysign(1.0f, mat[3] + mat[4]); + + // Identity + mat[8] = 1.0f; +} + +void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) { + double x = box.x; + double y = box.y; + double width = box.width; + double height = box.height; + + matrixIdentity(mat); + matrixTranslate(mat, x, y); + + if (rotation != 0) { + matrixTranslate(mat, width / 2, height / 2); + matrixRotate(mat, rotation); + matrixTranslate(mat, -width / 2, -height / 2); + } + + wlr_matrix_scale(mat, width, height); + + if (transform != HYPRUTILS_TRANSFORM_NORMAL) { + matrixTranslate(mat, 0.5, 0.5); + matrixTransform(mat, transform); + matrixTranslate(mat, -0.5, -0.5); + } + + matrixMultiply(mat, projection, mat); +} diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp new file mode 100644 index 00000000..4aa65c93 --- /dev/null +++ b/src/helpers/math/Math.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +// includes box and vector as well +#include + +using namespace Hyprutils::Math; + +eTransform wlTransformToHyprutils(wl_output_transform t); +void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); diff --git a/src/includes.hpp b/src/includes.hpp index dbae7635..87bd21f8 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -110,6 +110,4 @@ extern "C" { #define XWAYLAND true #endif -#include "helpers/Vector2D.hpp" -#include "helpers/Box.hpp" #include "SharedDefs.hpp" diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 172a157b..cbeaa420 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -180,9 +180,9 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for auto calcPos = PWINDOW->m_vPosition; auto calcSize = PWINDOW->m_vSize; - const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut.left : gapsIn.left, DISPLAYTOP ? gapsOut.top : gapsIn.top); + const auto OFFSETTOPLEFT = Vector2D((double)(DISPLAYLEFT ? gapsOut.left : gapsIn.left), (double)(DISPLAYTOP ? gapsOut.top : gapsIn.top)); - const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut.right : gapsIn.right, DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom); + const auto OFFSETBOTTOMRIGHT = Vector2D((double)(DISPLAYRIGHT ? gapsOut.right : gapsIn.right), (double)(DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom)); calcPos = calcPos + OFFSETTOPLEFT; calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; @@ -912,11 +912,11 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, switch (dir[0]) { case 't': - case 'u': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.f, -1}; break; + case 'u': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.0, -1.0}; break; case 'd': - case 'b': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.f, pWindow->m_vSize.y + 1}; break; - case 'l': focalPoint = pWindow->m_vPosition + Vector2D{-1, pWindow->m_vSize.y / 2.f}; break; - case 'r': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x + 1, pWindow->m_vSize.y / 2.f}; break; + case 'b': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x / 2.0, pWindow->m_vSize.y + 1.0}; break; + case 'l': focalPoint = pWindow->m_vPosition + Vector2D{-1.0, pWindow->m_vSize.y / 2.0}; break; + case 'r': focalPoint = pWindow->m_vPosition + Vector2D{pWindow->m_vSize.x + 1.0, pWindow->m_vSize.y / 2.0}; break; default: UNREACHABLE(); } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index b4270bb8..c6a7a66c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -428,9 +428,9 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (m_eGrabbedCorner == CORNER_TOPLEFT) newPos = newPos - newSize + m_vBeginDragSizeXY; else if (m_eGrabbedCorner == CORNER_TOPRIGHT) - newPos = newPos + Vector2D(0, (m_vBeginDragSizeXY - newSize).y); + newPos = newPos + Vector2D(0.0, (m_vBeginDragSizeXY - newSize).y); else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) - newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0); + newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); CBox wb = {newPos, newSize}; wb.round(); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index c5784c74..965c0ed7 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -689,9 +689,9 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { auto calcPos = PWINDOW->m_vPosition; auto calcSize = PWINDOW->m_vSize; - const auto OFFSETTOPLEFT = Vector2D(DISPLAYLEFT ? gapsOut.left : gapsIn.left, DISPLAYTOP ? gapsOut.top : gapsIn.top); + const auto OFFSETTOPLEFT = Vector2D((double)(DISPLAYLEFT ? gapsOut.left : gapsIn.left), (double)(DISPLAYTOP ? gapsOut.top : gapsIn.top)); - const auto OFFSETBOTTOMRIGHT = Vector2D(DISPLAYRIGHT ? gapsOut.right : gapsIn.right, DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom); + const auto OFFSETBOTTOMRIGHT = Vector2D((double)(DISPLAYRIGHT ? gapsOut.right : gapsIn.right), (double)(DISPLAYBOTTOM ? gapsOut.bottom : gapsIn.bottom)); calcPos = calcPos + OFFSETTOPLEFT; calcSize = calcSize - OFFSETTOPLEFT - OFFSETBOTTOMRIGHT; diff --git a/src/macros.hpp b/src/macros.hpp index cca088d8..cacfdfea 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -98,3 +98,10 @@ ([]() constexpr -> std::string { return std::string(__FILE__).substr(std::string(__FILE__).find_last_of('/') + 1); })(), err); \ } \ } + +#define HYPRUTILS_FORWARD(ns, name) \ + namespace Hyprutils { \ + namespace ns { \ + class name; \ + } \ + } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 74fe4117..9d6668c9 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -25,7 +25,7 @@ int wlTick(SP self, void* data) { } CAnimationManager::CAnimationManager() { - std::vector points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)}; + std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; m_mBezierCurves["default"].setup(&points); m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); @@ -36,7 +36,7 @@ void CAnimationManager::removeAllBeziers() { m_mBezierCurves.clear(); // add the default one - std::vector points = {Vector2D(0, 0.75f), Vector2D(0.15f, 1.f)}; + std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; m_mBezierCurves["default"].setup(&points); } @@ -336,9 +336,9 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo if (force == "bottom") posOffset = Vector2D(GOALPOS.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y); else if (force == "left") - posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0); + posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); else if (force == "right") - posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0); + posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); else posOffset = Vector2D(GOALPOS.x, PMONITOR->vecPosition.y - GOALSIZE.y); @@ -360,16 +360,16 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo if (DISPLAYBOTTOM && DISPLAYTOP) { if (DISPLAYLEFT && DISPLAYRIGHT) { - posOffset = GOALPOS + Vector2D(0, GOALSIZE.y); + posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); } else if (DISPLAYLEFT) { - posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0); + posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); } else { - posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0); + posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); } } else if (DISPLAYTOP) { - posOffset = GOALPOS - Vector2D(0, GOALSIZE.y); + posOffset = GOALPOS - Vector2D(0.0, GOALSIZE.y); } else if (DISPLAYBOTTOM) { - posOffset = GOALPOS + Vector2D(0, GOALSIZE.y); + posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); } else { if (MIDPOINT.y > PMONITOR->vecPosition.y + PMONITOR->vecSize.y / 2.f) posOffset = Vector2D(GOALPOS.x, PMONITOR->vecPosition.y + PMONITOR->vecSize.y); diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 4430d0f4..daa4f4be 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -149,9 +149,10 @@ void CCursorManager::setXCursor(const std::string& name) { auto image = xcursor->images[0]; - m_vCursorBuffers.emplace_back(std::make_unique(image->buffer, Vector2D{image->width, image->height}, Vector2D{image->hotspot_x, image->hotspot_y})); + m_vCursorBuffers.emplace_back( + std::make_unique(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y})); - g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{image->hotspot_x, image->hotspot_y} / scale, scale); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale); if (m_vCursorBuffers.size() > 1) wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); @@ -256,8 +257,8 @@ void CCursorManager::setXWaylandCursor() { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); } else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) { - g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {XCURSOR->images[0]->width, XCURSOR->images[0]->height}, - {XCURSOR->images[0]->hotspot_x, XCURSOR->images[0]->hotspot_y}); + g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height}, + {(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y}); } else Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 6fbff636..f983efbb 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -4,7 +4,7 @@ #include #include #include "../includes.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" struct wlr_buffer; struct wlr_xcursor_manager; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3a28ea8d..05059669 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -577,7 +577,7 @@ Vector2D CPointerManager::transformedHotspot(SP pMonitor) { return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}} - .transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) + .transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) .pos(); } diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 1e386797..c3673e16 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -3,8 +3,8 @@ #include "../devices/IPointer.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" -#include "../helpers/Box.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" +#include "../helpers/math/Math.hpp" #include "../desktop/WLSurface.hpp" #include diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 1a1df1d5..43ebe8b5 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -5,7 +5,7 @@ #include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/signal/Signal.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" #include "../protocols/types/DataDevice.hpp" #include diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index 3151aedb..f6e5c8be 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -3,7 +3,7 @@ #include "../../helpers/WLListener.hpp" #include "../../desktop/WLSurface.hpp" #include "../../macros.hpp" -#include "../../helpers/Box.hpp" +#include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" class CInputMethodPopupV2; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index a605fea7..ead7c5b8 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -109,16 +109,16 @@ void CInputManager::endWorkspaceSwipe() { if (PWORKSPACEL) { if (VERTANIMS) - PWORKSPACEL->m_vRenderOffset = Vector2D{0, -YDISTANCE}; + PWORKSPACEL->m_vRenderOffset = Vector2D{0.0, -YDISTANCE}; else - PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0}; + PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0.0}; } } else if (PWORKSPACER) { // to right if (VERTANIMS) - PWORKSPACER->m_vRenderOffset = Vector2D{0, YDISTANCE}; + PWORKSPACER->m_vRenderOffset = Vector2D{0.0, YDISTANCE}; else - PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0}; + PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0.0}; } m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); @@ -141,9 +141,9 @@ void CInputManager::endWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, YDISTANCE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0.0); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -167,9 +167,9 @@ void CInputManager::endWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0, -YDISTANCE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, -YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0.0); m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -269,9 +269,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); return; @@ -293,11 +293,11 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0)); + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft); @@ -309,9 +309,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); return; @@ -333,11 +333,11 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0)); + PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 61a664b9..79e08af9 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -2,7 +2,7 @@ #include "../../helpers/WLListener.hpp" #include "../../macros.hpp" -#include "../../helpers/Box.hpp" +#include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" #include diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index d4b105cb..fd66ba5e 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -82,7 +82,7 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPsetSetSize([this](CZwlrLayerSurfaceV1* r, uint32_t x, uint32_t y) { pending.committed |= STATE_SIZE; - pending.desiredSize = {x, y}; + pending.desiredSize = {(int)x, (int)y}; }); resource->setSetAnchor([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 7fa14447..6d29248a 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -6,7 +6,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-layer-shell-unstable-v1.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" #include "types/SurfaceRole.hpp" diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 8a78de99..faf28b32 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -7,8 +7,8 @@ #include #include "WaylandProtocol.hpp" #include "pointer-constraints-unstable-v1.hpp" -#include "../helpers/Vector2D.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" class CWLSurface; diff --git a/src/protocols/PointerGestures.hpp b/src/protocols/PointerGestures.hpp index 33c2bace..f907a49f 100644 --- a/src/protocols/PointerGestures.hpp +++ b/src/protocols/PointerGestures.hpp @@ -4,7 +4,7 @@ #include #include "WaylandProtocol.hpp" #include "pointer-gestures-unstable-v1.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" class CPointerGestureSwipe { public: diff --git a/src/protocols/RelativePointer.hpp b/src/protocols/RelativePointer.hpp index 93446e85..453ce157 100644 --- a/src/protocols/RelativePointer.hpp +++ b/src/protocols/RelativePointer.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "relative-pointer-unstable-v1.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" class CRelativePointer { public: diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 0c4eac86..8a6285a1 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -279,7 +279,7 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r } int ow, oh; wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); - PFRAME->box.transform(PFRAME->pMonitor->transform, ow, oh).scale(PFRAME->pMonitor->scale).round(); + PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -556,9 +556,10 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) return false; - CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} - .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. - .transform(wlr_output_transform_invert(frame->pMonitor->output->transform), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); + CBox monbox = + CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} + .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. + .transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index c61395c9..58f13c1a 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "tablet-v2.hpp" -#include "../helpers/Vector2D.hpp" +#include "../helpers/math/Math.hpp" class CTablet; class CTabletTool; diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index 3959e72b..9f6284dc 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -7,7 +7,7 @@ #include "WaylandProtocol.hpp" #include "text-input-unstable-v3.hpp" #include "../helpers/signal/Signal.hpp" -#include "../helpers/Box.hpp" +#include "../helpers/math/Math.hpp" class CWLSurfaceResource; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 80f9defa..287538b5 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -202,7 +202,7 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; int ow, oh; wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); - PFRAME->box.transform(PMONITOR->transform, ow, oh).round(); + PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index c16ebb9d..9c56df93 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -514,13 +514,13 @@ CXDGPositionerRules::CXDGPositionerRules(SP positioner) static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) { switch (anchor) { - case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, 0}; - case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, box.size().y}; - case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F - predictionSize.y / 2.F}; - case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.F}; + case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, 0.0}; + case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, box.size().y}; + case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0.0, box.size().y / 2.0 - predictionSize.y / 2.0}; + case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.0}; case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos(); - case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y}; - case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0}; + case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0.0, box.size().y}; + case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0.0}; case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y}; default: return box.pos(); } @@ -555,10 +555,10 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa }; int edgeCount = countEdges(test); - if (flipX && edgeCount > countEdges(test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}))) - test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0}); - if (flipY && edgeCount > countEdges(test.copy().translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}))) - test.translate(Vector2D{0, -predictedBox.h - state.anchorRect.h}); + if (flipX && edgeCount > countEdges(test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0}))) + test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0}); + if (flipY && edgeCount > countEdges(test.copy().translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h}))) + test.translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h}); success = test.copy().expand(-1).inside(constraint); diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index d60db86a..da551718 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -6,8 +6,8 @@ #include #include "WaylandProtocol.hpp" #include "xdg-shell.hpp" -#include "../helpers/Vector2D.hpp" -#include "../helpers/Box.hpp" +#include "../helpers/math/Math.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" #include "types/SurfaceRole.hpp" diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 165da6ee..4bce3f58 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -421,7 +421,7 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; - return surfaceDamage.scale(current.scale).transform(wlr_output_transform_invert(current.transform), trc.x, trc.y).add(current.bufferDamage); + return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(wlr_output_transform_invert(current.transform)), trc.x, trc.y).add(current.bufferDamage); } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index f50144bf..2f276719 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -14,7 +14,7 @@ #include "../WaylandProtocol.hpp" #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -#include "../../helpers/Region.hpp" +#include "../../helpers/math/Math.hpp" #include "../types/Buffer.hpp" #include "../types/SurfaceRole.hpp" diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 5b31559f..22bb9376 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -15,7 +15,7 @@ #include #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -#include "../../helpers/Vector2D.hpp" +#include "../../helpers/math/Math.hpp" #include "../types/DataDevice.hpp" class CWLDataDeviceResource; diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 0b563b8f..09b36056 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -15,7 +15,7 @@ #include #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -#include "../../helpers/Vector2D.hpp" +#include "../../helpers/math/Math.hpp" constexpr const char* HL_SEAT_NAME = "Hyprland"; diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 687e2031..70a8b208 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -13,7 +13,7 @@ #include "../WaylandProtocol.hpp" #include "wayland.hpp" #include "../types/Buffer.hpp" -#include "../../helpers/Vector2D.hpp" +#include "../../helpers/math/Math.hpp" class CWLSHMPoolResource; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 5d8d6b83..3178ab8c 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -916,7 +916,7 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) { int w, h; wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h); - const auto TR = wlr_output_transform_invert(m_RenderData.pMonitor->transform); + const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); newBox.transform(TR, w, h); } @@ -1006,8 +1006,8 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion box = &newBox; float matrix[9]; - wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1025,7 +1025,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); CBox transformedBox = *box; - transformedBox.transform(wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1097,9 +1097,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB static auto PDT = CConfigValue("debug:damage_tracking"); // get transform - const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); + const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1185,7 +1185,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB } CBox transformedBox = newBox; - transformedBox.transform(wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1260,9 +1260,9 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); + const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1314,9 +1314,9 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform); + const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; - wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1372,10 +1372,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glDisable(GL_STENCIL_TEST); // get transforms for the full monitor - const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform); + const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); float matrix[9]; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.monitorProjection.data()); + projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1870,8 +1870,8 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in round += round == 0 ? 0 : scaledBorderSize; float matrix[9]; - wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -1896,7 +1896,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); CBox transformedBox = *box; - transformedBox.transform(wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -2176,8 +2176,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const const auto col = color; float matrix[9]; - wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here float glMatrix[9]; wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); @@ -2258,7 +2258,7 @@ void CHyprOpenGLImpl::renderMirrored() { CBox monbox = {0, 0, mirrored->vecTransformedSize.x * scale, mirrored->vecTransformedSize.y * scale}; // transform box as it will be drawn on a transformed projection - monbox.transform(mirrored->transform, mirrored->vecTransformedSize.x * scale, mirrored->vecTransformedSize.y * scale); + monbox.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecTransformedSize.x * scale, mirrored->vecTransformedSize.y * scale); monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2; monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index c6e173e5..814b80fe 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -4,7 +4,7 @@ #include "../helpers/Monitor.hpp" #include "../helpers/Color.hpp" #include "../helpers/Timer.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" #include "../helpers/Format.hpp" #include #include diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f56fb5d6..d44f4cd5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,6 +1,6 @@ #include "Renderer.hpp" #include "../Compositor.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" #include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -1508,15 +1508,15 @@ void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { // taken from Sway. // this is just too much of a spaghetti for me to understand -static void applyExclusive(wlr_box& usableArea, uint32_t anchor, int32_t exclusive, int32_t marginTop, int32_t marginRight, int32_t marginBottom, int32_t marginLeft) { +static void applyExclusive(CBox& usableArea, uint32_t anchor, int32_t exclusive, int32_t marginTop, int32_t marginRight, int32_t marginBottom, int32_t marginLeft) { if (exclusive <= 0) { return; } struct { uint32_t singular_anchor; uint32_t anchor_triplet; - int* positive_axis; - int* negative_axis; + double* positive_axis; + double* negative_axis; int margin; } edges[] = { // Top @@ -1640,9 +1640,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgeometry = box; - applyExclusive(*usableArea->pWlr(), PSTATE->anchor, PSTATE->exclusive, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); - - usableArea->applyFromWlr(); + applyExclusive(*usableArea, PSTATE->anchor, PSTATE->exclusive, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); if (Vector2D{box.width, box.height} != OLDSIZE) ls->layerSurface->configure(box.size()); @@ -1820,7 +1818,7 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; wlr_region_scale(transformed.pixman(), transformed.pixman(), scale); - transformed.transform(mirrored->transform, mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale); + transformed.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale); transformed.translate(Vector2D(monbox.x, monbox.y)); mirror->addDamage(&transformed); @@ -2234,7 +2232,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (pMonitor->createdByUser) { CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; - transformedBox.transform(wlr_output_transform_invert(pMonitor->output->transform), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 6adca72a..8f404c88 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -6,7 +6,7 @@ #include "OpenGL.hpp" #include "Renderbuffer.hpp" #include "../helpers/Timer.hpp" -#include "../helpers/Region.hpp" +#include "../helpers/math/Math.hpp" struct SMonitorRule; class CWorkspace; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index aef8e4ac..5560db97 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -55,7 +55,7 @@ CTexture::CTexture(wlr_texture* tex) { else m_iType = TEXTURE_EXTERNAL; - m_vSize = Vector2D(tex->width, tex->height); + m_vSize = Vector2D((int)tex->width, (int)tex->height); } CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index fa1ca4fe..c80e943d 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -4,7 +4,7 @@ class IWLBuffer; struct SDMABUFAttrs; -class CRegion; +HYPRUTILS_FORWARD(Math, CRegion); enum TEXTURETYPE { TEXTURE_INVALID, // Invalid diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index 3fa0946e..8ad3263e 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -26,16 +26,16 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { virtual std::string getDisplayName(); private: - SWindowDecorationExtents m_seExtents; - SWindowDecorationExtents m_seReportedExtents; + SBoxExtents m_seExtents; + SBoxExtents m_seReportedExtents; - PHLWINDOWREF m_pWindow; + PHLWINDOWREF m_pWindow; - Vector2D m_vLastWindowPos; - Vector2D m_vLastWindowSize; + Vector2D m_vLastWindowPos; + Vector2D m_vLastWindowSize; - CBox m_bAssignedGeometry = {0}; + CBox m_bAssignedGeometry = {0}; - CBox assignedBoxGlobal(); - bool doesntWantBorders(); + CBox assignedBoxGlobal(); + bool doesntWantBorders(); }; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index fba279cc..6893d78c 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -130,7 +130,7 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { const float SHADOWSCALE = std::clamp(*PSHADOWSCALE, 0.f, 1.f); // scale the box in relation to the center of the box - fullBox.scaleFromCenter(SHADOWSCALE).translate(*PSHADOWOFFSET); + fullBox.scaleFromCenter(SHADOWSCALE).translate({(*PSHADOWOFFSET).x, (*PSHADOWOFFSET).y}); updateWindow(PWINDOW); m_vLastWindowPos += WORKSPACEOFFSET; diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 06319cb7..ecd5a47b 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -26,14 +26,14 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { virtual std::string getDisplayName(); private: - SWindowDecorationExtents m_seExtents; - SWindowDecorationExtents m_seReportedExtents; + SBoxExtents m_seExtents; + SBoxExtents m_seReportedExtents; - PHLWINDOWREF m_pWindow; + PHLWINDOWREF m_pWindow; - Vector2D m_vLastWindowPos; - Vector2D m_vLastWindowSize; + Vector2D m_vLastWindowPos; + Vector2D m_vLastWindowSize; - CBox m_bLastWindowBox = {0}; - CBox m_bLastWindowBoxWithDecos = {0}; + CBox m_bLastWindowBox = {0}; + CBox m_bLastWindowBoxWithDecos = {0}; }; diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 1af24717..bfb15d5c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -48,7 +48,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { virtual std::string getDisplayName(); private: - SWindowDecorationExtents m_seExtents; + SBoxExtents m_seExtents; CBox m_bAssignedBox = {0}; diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 17f6d913..d66a5760 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -33,11 +33,11 @@ Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, PHLWINDOW pW if (EDGESNO == 1) { if (TOP) - return wb.pos() + Vector2D{wb.size().x / 2.0, 0}; + return wb.pos() + Vector2D{wb.size().x / 2.0, 0.0}; else if (BOTTOM) return wb.pos() + Vector2D{wb.size().x / 2.0, wb.size().y}; else if (LEFT) - return wb.pos() + Vector2D{0, wb.size().y / 2.0}; + return wb.pos() + Vector2D{0.0, wb.size().y / 2.0}; else if (RIGHT) return wb.pos() + Vector2D{wb.size().x, wb.size().y / 2.0}; UNREACHABLE(); @@ -45,11 +45,11 @@ Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, PHLWINDOW pW if (TOP && LEFT) return wb.pos(); if (TOP && RIGHT) - return wb.pos() + Vector2D{wb.size().x, 0}; + return wb.pos() + Vector2D{wb.size().x, 0.0}; if (BOTTOM && RIGHT) return wb.pos() + wb.size(); if (BOTTOM && LEFT) - return wb.pos() + Vector2D{0, wb.size().y}; + return wb.pos() + Vector2D{0.0, wb.size().y}; UNREACHABLE(); } UNREACHABLE(); @@ -234,26 +234,26 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { } else if (LEFT) { pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, -stickyOffsetYT}; pos.x -= desiredSize; - size = {desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT}; + size = {(double)desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT}; if (SOLID) stickyOffsetXL += desiredSize; } else if (RIGHT) { - pos = wb.pos() + Vector2D{wb.size().x, 0} - EDGEPOINT + Vector2D{stickyOffsetXR, -stickyOffsetYT}; - size = {desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT}; + pos = wb.pos() + Vector2D{wb.size().x, 0.0} - EDGEPOINT + Vector2D{stickyOffsetXR, -stickyOffsetYT}; + size = {(double)desiredSize, wb.size().y + stickyOffsetYB + stickyOffsetYT}; if (SOLID) stickyOffsetXR += desiredSize; } else if (TOP) { pos = wb.pos() - EDGEPOINT - Vector2D{stickyOffsetXL, stickyOffsetYT}; pos.y -= desiredSize; - size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, desiredSize}; + size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, (double)desiredSize}; if (SOLID) stickyOffsetYT += desiredSize; } else { - pos = wb.pos() + Vector2D{0, wb.size().y} - EDGEPOINT - Vector2D{stickyOffsetXL, stickyOffsetYB}; - size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, desiredSize}; + pos = wb.pos() + Vector2D{0.0, wb.size().y} - EDGEPOINT - Vector2D{stickyOffsetXL, stickyOffsetYB}; + size = {wb.size().x + stickyOffsetXL + stickyOffsetXR, (double)desiredSize}; if (SOLID) stickyOffsetYB += desiredSize; @@ -271,7 +271,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { } } - if (WINDOWDATA->extents != SWindowDecorationExtents{{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}) { + if (WINDOWDATA->extents != SBoxExtents{{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}) { WINDOWDATA->extents = {{stickyOffsetXL + reservedXL, stickyOffsetYT + reservedYT}, {stickyOffsetXR + reservedXR, stickyOffsetYB + reservedYB}}; g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); } @@ -286,14 +286,14 @@ void CDecorationPositioner::onWindowMap(PHLWINDOW pWindow) { m_mWindowDatas[pWindow] = {}; } -SWindowDecorationExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOW pWindow) { +SBoxExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOW pWindow) { try { const auto E = m_mWindowDatas.at(pWindow); return E.reserved; } catch (std::out_of_range& e) { return {}; } } -SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly) { +SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly) { CBox accum = pWindow->getWindowMainSurfaceBox(); for (auto& data : m_vWindowPositioningDatas) { @@ -317,7 +317,7 @@ SWindowDecorationExtents CDecorationPositioner::getWindowDecorationExtents(PHLWI decoBox.translate(EDGEPOINT); } - SWindowDecorationExtents extentsToAdd; + SBoxExtents extentsToAdd; if (decoBox.x < accum.x) extentsToAdd.topLeft.x = accum.x - decoBox.x; @@ -355,7 +355,7 @@ CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { decoBox.translate(EDGEPOINT); } - SWindowDecorationExtents extentsToAdd; + SBoxExtents extentsToAdd; if (decoBox.x < accum.x) extentsToAdd.topLeft.x = accum.x - decoBox.x; diff --git a/src/render/decorations/DecorationPositioner.hpp b/src/render/decorations/DecorationPositioner.hpp index 880dc3f8..27e56f0b 100644 --- a/src/render/decorations/DecorationPositioner.hpp +++ b/src/render/decorations/DecorationPositioner.hpp @@ -3,7 +3,7 @@ #include #include #include -#include "../../helpers/Box.hpp" +#include "../../helpers/math/Math.hpp" #include "../../desktop/DesktopTypes.hpp" class CWindow; @@ -37,7 +37,7 @@ struct SDecorationPositioningInfo { eDecorationPositioningPolicy policy = DECORATION_POSITION_ABSOLUTE; uint32_t edges = 0; // enum eDecorationEdges uint32_t priority = 10; // priority, decos will be evaluated high -> low - SWindowDecorationExtents desiredExtents; + SBoxExtents desiredExtents; bool reserved = false; // if true, geometry will use reserved area }; @@ -62,14 +62,14 @@ class CDecorationPositioner { Vector2D getEdgeDefinedPoint(uint32_t edges, PHLWINDOW pWindow); // called on resize, or insert/removal of a new deco - void onWindowUpdate(PHLWINDOW pWindow); - void uncacheDecoration(IHyprWindowDecoration* deco); - SWindowDecorationExtents getWindowDecorationReserved(PHLWINDOW pWindow); - SWindowDecorationExtents getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly = false); - CBox getBoxWithIncludedDecos(PHLWINDOW pWindow); - void repositionDeco(IHyprWindowDecoration* deco); - CBox getWindowDecorationBox(IHyprWindowDecoration* deco); - void forceRecalcFor(PHLWINDOW pWindow); + void onWindowUpdate(PHLWINDOW pWindow); + void uncacheDecoration(IHyprWindowDecoration* deco); + SBoxExtents getWindowDecorationReserved(PHLWINDOW pWindow); + SBoxExtents getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly = false); + CBox getBoxWithIncludedDecos(PHLWINDOW pWindow); + void repositionDeco(IHyprWindowDecoration* deco); + CBox getWindowDecorationBox(IHyprWindowDecoration* deco); + void forceRecalcFor(PHLWINDOW pWindow); private: struct SWindowPositioningData { @@ -81,10 +81,10 @@ class CDecorationPositioner { }; struct SWindowData { - Vector2D lastWindowSize = {}; - SWindowDecorationExtents reserved = {}; - SWindowDecorationExtents extents = {}; - bool needsRecalc = false; + Vector2D lastWindowSize = {}; + SBoxExtents reserved = {}; + SBoxExtents extents = {}; + bool needsRecalc = false; }; std::map m_mWindowDatas; diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 2346106f..a58560f3 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -2,7 +2,7 @@ #include #include "../../defines.hpp" -#include "../../helpers/Region.hpp" +#include "../../helpers/math/Math.hpp" #include "DecorationPositioner.hpp" enum eDecorationType { diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 0cdac1d5..4e31e88d 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -2,7 +2,7 @@ #include "../helpers/WLListener.hpp" #include "../helpers/signal/Signal.hpp" -#include "../helpers/Box.hpp" +#include "../helpers/math/Math.hpp" #include class CWLSurfaceResource; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 7b57de0f..aa38910f 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1,4 +1,4 @@ -#include "helpers/Vector2D.hpp" +#include "helpers/math/Math.hpp" #ifndef NO_XWAYLAND #include "XWayland.hpp" From 20a465f69d342c5caead27df696d228492ea02e8 Mon Sep 17 00:00:00 2001 From: Lucas Reis Date: Wed, 19 Jun 2024 10:24:28 -0400 Subject: [PATCH 0258/2393] pointer: use software rendering when monitor is mirrored (#6587) * pointer_manager: add lock/unlock software wrappers that receive the raw pointer * monitor: lock/unlock software pointer rendering when adding/removing mirrored screens * use relative path in includes --- src/helpers/Monitor.cpp | 10 ++++++++++ src/managers/PointerManager.cpp | 18 ++++++++++++++++++ src/managers/PointerManager.hpp | 2 ++ 3 files changed, 30 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index da6da873..e99e16ef 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -6,6 +6,7 @@ #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include "../managers/PointerManager.hpp" #include using namespace Hyprutils::String; @@ -248,6 +249,9 @@ void CMonitor::onDisconnect(bool destroy) { // remove mirror if (pMirrorOf) { pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); + + // unlock software for mirrored monitor + g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); pMirrorOf = nullptr; } @@ -471,6 +475,9 @@ void CMonitor::setMirror(const std::string& mirrorOf) { if (pMirrorOf) { pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); + + // unlock software for mirrored monitor + g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); } pMirrorOf = nullptr; @@ -540,6 +547,9 @@ void CMonitor::setMirror(const std::string& mirrorOf) { g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get()); g_pCompositor->sanityCheckWorkspaces(); + + // Software lock mirrored monitor + g_pPointerManager->lockSoftwareForMonitor(PMIRRORMON); } events.modeChanged.emit(); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 05059669..d3da5eff 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -164,6 +164,15 @@ void CPointerManager::unlockSoftwareAll() { updateCursorBackend(); } +void CPointerManager::lockSoftwareForMonitor(CMonitor* Monitor) { + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->ID == Monitor->ID) { + lockSoftwareForMonitor(m); + return; + } + } +} + void CPointerManager::lockSoftwareForMonitor(SP mon) { auto state = stateFor(mon); state->softwareLocks++; @@ -172,6 +181,15 @@ void CPointerManager::lockSoftwareForMonitor(SP mon) { updateCursorBackend(); } +void CPointerManager::unlockSoftwareForMonitor(CMonitor* Monitor) { + for (auto& m : g_pCompositor->m_vMonitors) { + if (m->ID == Monitor->ID) { + unlockSoftwareForMonitor(m); + return; + } + } +} + void CPointerManager::unlockSoftwareForMonitor(SP mon) { auto state = stateFor(mon); state->softwareLocks--; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index c3673e16..545b76fb 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -43,6 +43,8 @@ class CPointerManager { void lockSoftwareForMonitor(SP pMonitor); void unlockSoftwareForMonitor(SP pMonitor); + void lockSoftwareForMonitor(CMonitor* pMonitor); + void unlockSoftwareForMonitor(CMonitor* pMonitor); void lockSoftwareAll(); void unlockSoftwareAll(); From 6d21014a50d8e7863b1b25cb5ed19bb1fcba1583 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 19 Jun 2024 16:28:54 +0200 Subject: [PATCH 0259/2393] core: fix no-pch build --- src/plugins/PluginAPI.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index 83db5f85..4dcf4ba5 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -29,6 +29,7 @@ Feel like the API is missing something you'd like to use in your plugin? Open an #include #include #include +#include typedef struct { std::string name; From 65f04f265c268d9752d6c2534c2b078d0e54a150 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 19 Jun 2024 18:36:50 +0300 Subject: [PATCH 0260/2393] flake.lock: update --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 94fc9d90..cb1f7875 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1718368322, - "narHash": "sha256-VfMg3RsnRLQzbq0hFIh1dCM09b5C/F/qPFUOgU/CRi0=", + "lastModified": 1718450675, + "narHash": "sha256-jpsns6buS4bK+1sF8sL8AaixAiCRjA+nldTKvcwmvUs=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "dd3a853c8239d1c3f3f37de7d2b8ae4b4f3840df", + "rev": "66d5b46ff94efbfa6fa3d1d1b66735f1779c34a6", "type": "github" }, "original": { @@ -38,11 +38,11 @@ ] }, "locked": { - "lastModified": 1691753796, - "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=", + "lastModified": 1714869498, + "narHash": "sha256-vbLVOWvQqo4n1yvkg/Q70VTlPbMmTiCQfNTgcWDCfJM=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03", + "rev": "e06482e0e611130cd1929f75e8c1cf679e57d161", "type": "github" }, "original": { @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1718271409, - "narHash": "sha256-8KvVqtApNt4FWTdn1TqVvw00rpqyG9UuUPA2ilPVD1U=", + "lastModified": 1718804078, + "narHash": "sha256-CqRZne63BpYlPd/i8lXV0UInUt59oKogiwdVtBRHt60=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8e10e0626fb26a14b859b3811b6ed7932400c86e", + "rev": "4f1351295c55a8f51219b25aa4a6497a067989d0", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1718318537, - "narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=", + "lastModified": 1718530797, + "narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420", + "rev": "b60ebf54c15553b393d144357375ea956f89e9a9", "type": "github" }, "original": { @@ -179,11 +179,11 @@ ] }, "locked": { - "lastModified": 1718272114, - "narHash": "sha256-KsX7sAwkEFpXiwyjt0HGTnnrUU58wW1jlzj5IA/LRz8=", + "lastModified": 1718619174, + "narHash": "sha256-FWW68AVYmB91ZDQnhLMBNCUUTCjb1ZpO2k2KIytHtkA=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "24be4a26f0706e456fca1b61b8c79f7486a9e86d", + "rev": "c7894aa54f9a7dbd16df5cd24d420c8af22d5623", "type": "github" }, "original": { From def5fcb2128304392e9e76bcc081d088b316a197 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 19 Jun 2024 18:25:20 +0200 Subject: [PATCH 0261/2393] damageRing: move to hyprland impl A small wlroots utility we were still using. --- src/helpers/DamageRing.cpp | 52 ++++++++++++++++++++++++++++++++++++++ src/helpers/DamageRing.hpp | 22 ++++++++++++++++ src/helpers/Monitor.cpp | 18 +++++-------- src/helpers/Monitor.hpp | 40 ++++++++++++++--------------- src/includes.hpp | 1 - src/render/Renderer.cpp | 16 +++++++----- 6 files changed, 111 insertions(+), 38 deletions(-) create mode 100644 src/helpers/DamageRing.cpp create mode 100644 src/helpers/DamageRing.hpp diff --git a/src/helpers/DamageRing.cpp b/src/helpers/DamageRing.cpp new file mode 100644 index 00000000..093e7ca6 --- /dev/null +++ b/src/helpers/DamageRing.cpp @@ -0,0 +1,52 @@ +#include "DamageRing.hpp" + +void CDamageRing::setSize(const Vector2D& size_) { + if (size_ == size) + return; + + size = size_; + + damageEntire(); +} + +bool CDamageRing::damage(const CRegion& rg) { + CRegion clipped = rg.copy().intersect(CBox{{}, size}); + if (clipped.empty()) + return false; + + current.add(clipped); + return true; +} + +void CDamageRing::damageEntire() { + damage(CBox{{}, size}); +} + +void CDamageRing::rotate() { + previousIdx = (previousIdx + DAMAGE_RING_PREVIOUS_LEN - 1) % DAMAGE_RING_PREVIOUS_LEN; + + previous[previousIdx] = current; + current.clear(); +} + +CRegion CDamageRing::getBufferDamage(int age) { + if (age <= 0 || age > DAMAGE_RING_PREVIOUS_LEN + 1) + return CBox{{}, size}; + + CRegion damage = current; + + for (int i = 0; i < age - 1; ++i) { + int j = (previousIdx + i) % DAMAGE_RING_PREVIOUS_LEN; + damage.add(previous.at(j)); + } + + // don't return a ludicrous amount of rects + if (damage.getRects().size() > 8) + return damage.getExtents(); + + return damage; +} + +bool CDamageRing::hasChanged() { + return !current.empty(); +} diff --git a/src/helpers/DamageRing.hpp b/src/helpers/DamageRing.hpp new file mode 100644 index 00000000..ae85c453 --- /dev/null +++ b/src/helpers/DamageRing.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "./math/Math.hpp" +#include + +constexpr static int DAMAGE_RING_PREVIOUS_LEN = 2; + +class CDamageRing { + public: + void setSize(const Vector2D& size_); + bool damage(const CRegion& rg); + void damageEntire(); + void rotate(); + CRegion getBufferDamage(int age); + bool hasChanged(); + + private: + Vector2D size; + CRegion current; + std::array previous; + size_t previousIdx = 0; +}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e99e16ef..7ebd2539 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -17,12 +17,10 @@ int ratHandler(void* data) { } CMonitor::CMonitor() : state(this) { - wlr_damage_ring_init(&damage); + ; } CMonitor::~CMonitor() { - wlr_damage_ring_finish(&damage); - hyprListener_monitorDestroy.removeCallback(); hyprListener_monitorFrame.removeCallback(); hyprListener_monitorStateRequest.removeCallback(); @@ -162,7 +160,7 @@ void CMonitor::onConnect(bool noRule) { if (!state.commit()) Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); - wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y); + damage.setSize(vecTransformedSize); Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output); @@ -345,9 +343,9 @@ void CMonitor::onDisconnect(bool destroy) { void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); g_pCompositor->scheduleFrameForMonitor(this); - } else if (wlr_damage_ring_add(&damage, rg)) + } else if (damage.damage(rg)) g_pCompositor->scheduleFrameForMonitor(this); } @@ -358,13 +356,11 @@ void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CBox* box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); g_pCompositor->scheduleFrameForMonitor(this); } - wlr_box damageBox = {(int)box->x, (int)box->y, (int)box->w, (int)box->h}; - - if (wlr_damage_ring_add_box(&damage, &damageBox)) + if (damage.damage(*box)) g_pCompositor->scheduleFrameForMonitor(this); } @@ -379,7 +375,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { // damage whole screen because some previous cursor box damages were skipped - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); return false; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index b8902197..8a2acdaf 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -11,6 +11,7 @@ #include "math/Math.hpp" #include #include "signal/Signal.hpp" +#include "DamageRing.hpp" // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs { @@ -60,33 +61,32 @@ class CMonitor { CMonitor(); ~CMonitor(); - Vector2D vecPosition = Vector2D(-1, -1); // means unset - Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset - Vector2D vecSize = Vector2D(0, 0); - Vector2D vecPixelSize = Vector2D(0, 0); - Vector2D vecTransformedSize = Vector2D(0, 0); + Vector2D vecPosition = Vector2D(-1, -1); // means unset + Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset + Vector2D vecSize = Vector2D(0, 0); + Vector2D vecPixelSize = Vector2D(0, 0); + Vector2D vecTransformedSize = Vector2D(0, 0); - bool primary = false; + bool primary = false; - uint64_t ID = -1; - PHLWORKSPACE activeWorkspace = nullptr; - PHLWORKSPACE activeSpecialWorkspace = nullptr; - float setScale = 1; // scale set by cfg - float scale = 1; // real scale + uint64_t ID = -1; + PHLWORKSPACE activeWorkspace = nullptr; + PHLWORKSPACE activeSpecialWorkspace = nullptr; + float setScale = 1; // scale set by cfg + float scale = 1; // real scale - std::string szName = ""; - std::string szDescription = ""; - std::string szShortDescription = ""; + std::string szName = ""; + std::string szDescription = ""; + std::string szShortDescription = ""; - Vector2D vecReservedTopLeft = Vector2D(0, 0); - Vector2D vecReservedBottomRight = Vector2D(0, 0); + Vector2D vecReservedTopLeft = Vector2D(0, 0); + Vector2D vecReservedBottomRight = Vector2D(0, 0); - drmModeModeInfo customDrmMode = {}; + drmModeModeInfo customDrmMode = {}; - CMonitorState state; + CMonitorState state; + CDamageRing damage; - // WLR stuff - wlr_damage_ring damage; wlr_output* output = nullptr; float refreshRate = 60; int framesToSkip = 0; diff --git a/src/includes.hpp b/src/includes.hpp index 87bd21f8..afec078a 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -53,7 +53,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d44f4cd5..b783ab81 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1246,7 +1246,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { clock_gettime(CLOCK_MONOTONIC, &now); // check the damage - bool hasChanged = pMonitor->output->needs_frame || pixman_region32_not_empty(&pMonitor->damage.current); + bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged(); if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) return; @@ -1414,7 +1414,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->state.wlr()->tearing_page_flip = shouldTear; if (!pMonitor->state.commit()) { - wlr_damage_ring_add_whole(&pMonitor->damage); + pMonitor->damage.damageEntire(); return; } @@ -2245,7 +2245,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // updato wlroots g_pCompositor->arrangeMonitors(); - wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + pMonitor->damage.setSize(pMonitor->vecTransformedSize); // Set scale for all surfaces on this monitor, needed for some clients // but not on unsafe state to avoid crashes @@ -2609,13 +2609,15 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return true; } + int bufferAge = 0; + if (!buffer) { if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) { Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName); return false; } - m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, nullptr); + m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge); if (!m_pCurrentWlrBuffer) { Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName); return false; @@ -2634,8 +2636,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return false; } - if (mode == RENDER_MODE_NORMAL) - wlr_damage_ring_rotate_buffer(&pMonitor->damage, m_pCurrentWlrBuffer, damage.pixman()); + if (mode == RENDER_MODE_NORMAL) { + damage = pMonitor->damage.getBufferDamage(bufferAge); + pMonitor->damage.rotate(); + } m_pCurrentRenderbuffer->bind(); if (simple) From c1e21719a2fff2fa9549f00053ac40173da54af9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 19 Jun 2024 18:36:40 +0200 Subject: [PATCH 0262/2393] core: avoid bumping hard rlimits, restore on fork ref #6584 --- src/Compositor.cpp | 63 ++++++++++++++------------------- src/Compositor.hpp | 8 +++-- src/managers/KeybindManager.cpp | 1 + 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7777a55f..7a1d035d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -71,44 +71,35 @@ void handleUserSignal(int sig) { } } -static void bumpNofile() { - unsigned long limit = 1024; - - try { - std::ifstream f("/proc/sys/fs/nr_open"); - if (!f.good()) - limit = 1073741816; - else { - std::string content((std::istreambuf_iterator(f)), (std::istreambuf_iterator())); - f.close(); - - limit = std::stoll(content); - } - - } catch (...) { limit = 1073741816; } - - struct rlimit rlimit_; - if (!getrlimit(RLIMIT_NOFILE, &rlimit_)) - Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", rlimit_.rlim_cur, rlimit_.rlim_max); - - if (rlimit_.rlim_max <= 1024) - rlimit_.rlim_max = limit; - - unsigned long oldHardLimit = rlimit_.rlim_max; - - rlimit_.rlim_max = limit; - - if (setrlimit(RLIMIT_NOFILE, &rlimit_) < 0) { - Debug::log(LOG, "Failed bumping NOFILE limits higher, retrying with previous hard."); - rlimit_.rlim_max = oldHardLimit; - rlimit_.rlim_cur = std::clamp((unsigned long)limit, 1UL, (unsigned long)rlimit_.rlim_max); - - if (setrlimit(RLIMIT_NOFILE, &rlimit_) < 0) - Debug::log(LOG, "Failed bumping NOFILE limits higher for the second time."); +void CCompositor::bumpNofile() { + if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile)) + Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max); + else { + Debug::log(ERR, "Failed to get NOFILE rlimits"); + m_sOriginalNofile.rlim_max = 0; + return; } - if (!getrlimit(RLIMIT_NOFILE, &rlimit_)) - Debug::log(LOG, "New rlimit: soft -> {}, hard -> {}", rlimit_.rlim_cur, rlimit_.rlim_max); + rlimit newLimit = m_sOriginalNofile; + + newLimit.rlim_cur = newLimit.rlim_max; + + if (setrlimit(RLIMIT_NOFILE, &newLimit) < 0) { + Debug::log(ERR, "Failed bumping NOFILE limits higher"); + m_sOriginalNofile.rlim_max = 0; + return; + } + + if (!getrlimit(RLIMIT_NOFILE, &newLimit)) + Debug::log(LOG, "New rlimit: soft -> {}, hard -> {}", newLimit.rlim_cur, newLimit.rlim_max); +} + +void CCompositor::restoreNofile() { + if (m_sOriginalNofile.rlim_max <= 0) + return; + + if (setrlimit(RLIMIT_NOFILE, &m_sOriginalNofile) < 0) + Debug::log(ERR, "Failed restoring NOFILE limits"); } CCompositor::CCompositor() { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 242c3b13..5a1d8a64 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "defines.hpp" #include "debug/Log.hpp" @@ -81,6 +82,8 @@ class CCompositor { void cleanup(); void createLockFile(); void removeLockFile(); + void bumpNofile(); + void restoreNofile(); WP m_pLastFocus; PHLWINDOWREF m_pLastWindow; @@ -190,8 +193,9 @@ class CCompositor { void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); - uint64_t m_iHyprlandPID = 0; - wl_event_source* m_critSigSource = nullptr; + uint64_t m_iHyprlandPID = 0; + wl_event_source* m_critSigSource = nullptr; + rlimit m_sOriginalNofile = {0}; }; inline std::unique_ptr g_pCompositor; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 875ba239..80af767c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -890,6 +890,7 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { } if (child == 0) { // run in child + g_pCompositor->restoreNofile(); sigset_t set; sigemptyset(&set); From d6de248b0d434a382a7036ff04b3f9b367668cb0 Mon Sep 17 00:00:00 2001 From: Przegryw321 <65826466+Przegryw321@users.noreply.github.com> Date: Wed, 19 Jun 2024 23:19:18 +0200 Subject: [PATCH 0263/2393] window: expose pseudotiled state and add param to dispatcher (#6583) * Show pseudotiled state of window in hyprctl clients * Add a window as an optional argument for the pseudo dispatcher * change formatting --- src/debug/HyprCtl.cpp | 31 ++++++++++++++++--------------- src/managers/KeybindManager.cpp | 16 +++++++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index e212ed1c..b0a0c477 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -210,6 +210,7 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "name": "{}" }}, "floating": {}, + "pseudo": {}, "monitor": {}, "class": "{}", "title": "{}", @@ -228,22 +229,22 @@ static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { }},)#", (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, - escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (int64_t)w->m_iMonitorID, - escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), - ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (w->m_bIsFullscreen ? "true" : "false"), - (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), - getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), + (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), + escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), + (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), + w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } else { - return std::format("Window {:x} -> {}:\n\tmapped: {}\n\thidden: {}\n\tat: {},{}\n\tsize: {},{}\n\tworkspace: {} ({})\n\tfloating: {}\n\tmonitor: {}\n\tclass: {}\n\ttitle: " - "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " - "{}\n\txwayland: {}\n\tpinned: " - "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", - (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, - (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, - (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, - w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, - (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), (int)w->m_bFakeFullscreenState, getGroupedData(w, format), - getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + 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: " + "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " + "{}\n\txwayland: {}\n\tpinned: " + "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", + (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, + (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), + (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), + (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), + (int)w->m_bFakeFullscreenState, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 80af767c..e5db8918 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -5,6 +5,7 @@ #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "KeybindManager.hpp" +#include "Compositor.hpp" #include "TokenManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" @@ -1017,15 +1018,20 @@ void CKeybindManager::centerWindow(std::string args) { } void CKeybindManager::toggleActivePseudo(std::string args) { - const auto ACTIVEWINDOW = g_pCompositor->m_pLastWindow.lock(); + PHLWINDOW PWINDOW = nullptr; - if (!ACTIVEWINDOW) + if (args != "active" && args.length() > 1) + PWINDOW = g_pCompositor->getWindowByRegex(args); + else + PWINDOW = g_pCompositor->m_pLastWindow.lock(); + + if (!PWINDOW) return; - ACTIVEWINDOW->m_bIsPseudotiled = !ACTIVEWINDOW->m_bIsPseudotiled; + PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled; - if (!ACTIVEWINDOW->m_bIsFullscreen) - g_pLayoutManager->getCurrentLayout()->recalculateWindow(ACTIVEWINDOW); + if (!PWINDOW->m_bIsFullscreen) + g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); } void CKeybindManager::changeworkspace(std::string args) { From fabc30df52ab5d2c369fc8acd4ff909a6ba3b8ac Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 20 Jun 2024 00:15:18 +0200 Subject: [PATCH 0264/2393] format: include macros for unreachable --- src/helpers/Format.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 08c3ca63..5251002c 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -2,6 +2,7 @@ #include #include "../includes.hpp" #include "debug/Log.hpp" +#include "../macros.hpp" /* DRM formats are LE, while OGL is BE. The two primary formats From 8cf2ca196620bc4431cbab83bfa25314e1e80ad7 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 21 Jun 2024 15:56:25 +0200 Subject: [PATCH 0265/2393] math: include cstring for memset fixup name too --- src/helpers/math/Math.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp index df4f1bb5..560f29c9 100644 --- a/src/helpers/math/Math.cpp +++ b/src/helpers/math/Math.cpp @@ -1,5 +1,6 @@ #include "Math.hpp" #include +#include Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { switch (t) { @@ -52,21 +53,21 @@ static void matrixTranslate(float mat[9], float x, float y) { float translate[9] = { 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, }; - wlr_matrix_multiply(mat, mat, translate); + matrixMultiply(mat, mat, translate); } static void matrixScale(float mat[9], float x, float y) { float scale[9] = { x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, }; - wlr_matrix_multiply(mat, mat, scale); + matrixMultiply(mat, mat, scale); } static void matrixRotate(float mat[9], float rad) { float rotate[9] = { cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, }; - wlr_matrix_multiply(mat, mat, rotate); + matrixMultiply(mat, mat, rotate); } static std::unordered_map> transforms = { @@ -208,7 +209,7 @@ void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, c matrixTranslate(mat, -width / 2, -height / 2); } - wlr_matrix_scale(mat, width, height); + matrixScale(mat, width, height); if (transform != HYPRUTILS_TRANSFORM_NORMAL) { matrixTranslate(mat, 0.5, 0.5); From 4a8b13ea4f8e5111390471c9212d10d4d032e837 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 21 Jun 2024 19:25:34 +0200 Subject: [PATCH 0266/2393] renderer: shrink occlusion rect if blur is used if we are blurring, we cannot be sure whether the occluded region won't be included in the expanded damage. If it is, we'd get dark shimmers. fixes #6547 --- src/render/Renderer.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b783ab81..4fc751ff 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2451,9 +2451,14 @@ void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pW } void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace) { - CRegion rg; + CRegion rg; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + + static auto PBLUR = CConfigValue("decoration:blur:enabled"); + static auto PBLURSIZE = CConfigValue("decoration:blur:size"); + static auto PBLURPASSES = CConfigValue("decoration:blur:passes"); + const auto BLURRADIUS = *PBLUR ? (*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)) : 0; for (auto& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != pWorkspace) @@ -2468,7 +2473,8 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork CBox box = {POS.x, POS.y, SIZE.x, SIZE.y}; - box.scale(PMONITOR->scale); + box.scale(PMONITOR->scale).expand(-BLURRADIUS); + g_pHyprOpenGL->m_RenderData.renderModif.applyToBox(box); rg.add(box); From fa022901cf2c9acdae9e9a24a68b9148d44f8627 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sat, 22 Jun 2024 00:40:45 +0200 Subject: [PATCH 0267/2393] surface: add virtual destructor to surfacerole to avoid undefined behaviour (#6620) * surfacerole: add virtual destructor all classes that will be derived from should have a virtual destructor otherwise deleting an instance via pointer to a base class is undefined behaviour, layershell/xdgshell hits this with std::default_delete in the new sharedptr implentation. * includes: fix missing includes fix missing includes for no precompiled headers builds, and remove a redefiniton of a macro already defined in macros.hpp --- src/managers/CursorManager.hpp | 1 + src/protocols/types/SurfaceRole.hpp | 1 + src/xwayland/XSurface.hpp | 1 + src/xwayland/XWM.hpp | 1 + src/xwayland/XWayland.hpp | 5 ++--- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index f983efbb..3ee98ca6 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -5,6 +5,7 @@ #include #include "../includes.hpp" #include "../helpers/math/Math.hpp" +#include "../helpers/memory/Memory.hpp" struct wlr_buffer; struct wlr_xcursor_manager; diff --git a/src/protocols/types/SurfaceRole.hpp b/src/protocols/types/SurfaceRole.hpp index 05c0ea66..faaf70ee 100644 --- a/src/protocols/types/SurfaceRole.hpp +++ b/src/protocols/types/SurfaceRole.hpp @@ -11,4 +11,5 @@ enum eSurfaceRole { class ISurfaceRole { public: virtual eSurfaceRole role() = 0; + virtual ~ISurfaceRole() = default; }; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 4e31e88d..61eee984 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -2,6 +2,7 @@ #include "../helpers/WLListener.hpp" #include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" #include "../helpers/math/Math.hpp" #include diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 6456c71b..88606416 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,6 +1,7 @@ #pragma once #include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index c7981251..d1cc4421 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -2,6 +2,7 @@ #include #include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" #include "XSurface.hpp" @@ -29,10 +30,8 @@ class CXWayland { } events; }; -inline std::unique_ptr g_pXWayland; +inline std::unique_ptr g_pXWayland; -#define HYPRATOM(name) \ - { name, 0 } inline std::unordered_map HYPRATOMS = { HYPRATOM("_NET_SUPPORTED"), HYPRATOM("_NET_SUPPORTING_WM_CHECK"), From 4778afe2e6b4a6f8c7d218ccd8fe7e0bd4d2ee9c Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 21 Jun 2024 17:41:23 -0500 Subject: [PATCH 0268/2393] hyprctl: make recv timeout bigger and give error message if it does timeout (#6621) --- hyprctl/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index f5de041b..2bd325e3 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -141,7 +141,7 @@ int rollingRead(const int socket) { int request(std::string arg, int minArgs = 0, bool needRoll = false) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); - auto t = timeval{.tv_sec = 0, .tv_usec = 100000}; + auto t = timeval{.tv_sec = 1, .tv_usec = 0}; setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)); const auto ARGS = std::count(arg.begin(), arg.end(), ' '); @@ -191,6 +191,8 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) { sizeWritten = read(SERVERSOCKET, buffer, 8192); if (sizeWritten < 0) { + if (errno == EWOULDBLOCK) + log("Hyprland IPC didn't respond in time\n"); log("Couldn't read (5)"); return 5; } From 0b924f541c744f96d32c9a0d98dcfd90205bab4c Mon Sep 17 00:00:00 2001 From: MariuszTrybus Date: Sat, 22 Jun 2024 17:05:05 +0200 Subject: [PATCH 0269/2393] constraints: Lock surface region when region is empty (#6627) * Pointer constraints: Lock surface region when region is empty * Format code --- src/protocols/PointerConstraints.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index c7b78a5b..a17fa6cd 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -165,8 +165,15 @@ SP CPointerConstraint::owner() { } CRegion CPointerConstraint::logicConstraintRegion() { - CRegion rg = region; - const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); + CRegion rg = region; + const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); + + // if region wasn't set in pointer-constraints request take surface region + if (rg.empty() && SURFBOX.has_value()) { + rg.set(SURFBOX.value()); + return rg; + } + const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{}; rg.translate(CONSTRAINTPOS); return rg; From 7f09646ab8b5b6d9f835681d0af5d7a0dc29d8f1 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Sun, 23 Jun 2024 00:52:42 +0300 Subject: [PATCH 0270/2393] core: add ability to select previous workspace per monitor (#6598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- src/Compositor.cpp | 3 +- src/config/ConfigManager.cpp | 13 +++-- src/desktop/Workspace.cpp | 20 ++++++-- src/desktop/Workspace.hpp | 34 ++++++------- src/events/Windows.cpp | 3 +- src/helpers/MiscFunctions.cpp | 90 ++++++++++++++++----------------- src/helpers/MiscFunctions.hpp | 9 +++- src/helpers/Monitor.cpp | 25 +++++---- src/macros.hpp | 3 +- src/managers/KeybindManager.cpp | 88 +++++++++++++++----------------- src/managers/input/Swipe.cpp | 12 ++--- 11 files changed, 154 insertions(+), 146 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7a1d035d..c607dfb6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1648,8 +1648,7 @@ PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) { } try { - std::string name = ""; - return getWorkspaceByID(getWorkspaceIDFromString(str, name)); + return getWorkspaceByID(getWorkspaceIDNameFromString(str).id); } catch (std::exception& e) { Debug::log(ERR, "Error in getWorkspaceByString, invalid id"); } return nullptr; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 17bbe465..6a1c896c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1815,14 +1815,13 @@ std::optional CConfigManager::handleMonitor(const std::string& comm newrule.vrr = std::stoi(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "workspace") { - std::string name = ""; - int wsId = getWorkspaceIDFromString(ARGS[argno + 1], name); + const auto& [id, name] = getWorkspaceIDNameFromString(ARGS[argno + 1]); SWorkspaceRule wsRule; wsRule.monitor = newrule.name; wsRule.workspaceString = ARGS[argno + 1]; + wsRule.workspaceId = id; wsRule.workspaceName = name; - wsRule.workspaceId = wsId; m_dWorkspaceRules.emplace_back(wsRule); argno++; @@ -2370,11 +2369,11 @@ std::optional CConfigManager::handleBlurLS(const std::string& comma std::optional CConfigManager::handleWorkspaceRules(const std::string& command, const std::string& value) { // This can either be the monitor or the workspace identifier - const auto FIRST_DELIM = value.find_first_of(','); + const auto FIRST_DELIM = value.find_first_of(','); - std::string name = ""; - auto first_ident = trim(value.substr(0, FIRST_DELIM)); - int id = getWorkspaceIDFromString(first_ident, name); + auto first_ident = trim(value.substr(0, FIRST_DELIM)); + + const auto& [id, name] = getWorkspaceIDNameFromString(first_ident); auto rules = value.substr(FIRST_DELIM + 1); SWorkspaceRule wsRule; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 04685bd5..34db914e 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -57,6 +57,13 @@ void CWorkspace::init(PHLWORKSPACE self) { EMIT_HOOK_EVENT("createWorkspace", this); } +SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const { + if (perMonitor) + return m_sPrevWorkspacePerMonitor; + + return m_sPrevWorkspace; +} + CWorkspace::~CWorkspace() { m_vRenderOffset.unregister(); @@ -196,7 +203,7 @@ PHLWINDOW CWorkspace::getLastFocusedWindow() { void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { if (!prev) { - m_sPrevWorkspace.iID = -1; + m_sPrevWorkspace.id = -1; m_sPrevWorkspace.name = ""; return; } @@ -206,8 +213,13 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { return; } - m_sPrevWorkspace.iID = prev->m_iID; + m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.name = prev->m_szName; + + if (prev->m_iMonitorID == m_iMonitorID) { + m_sPrevWorkspacePerMonitor.id = prev->m_iID; + m_sPrevWorkspacePerMonitor.name = prev->m_szName; + } } std::string CWorkspace::getConfigName() { @@ -228,9 +240,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { return true; if (isNumber(selector)) { - - std::string wsname = ""; - int wsid = getWorkspaceIDFromString(selector, wsname); + const auto& [wsid, wsname] = getWorkspaceIDNameFromString(selector); if (wsid == WORKSPACE_INVALID) return false; diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 17431215..ab3907aa 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -4,6 +4,7 @@ #include #include "../defines.hpp" #include "DesktopTypes.hpp" +#include "helpers/MiscFunctions.hpp" enum eFullscreenMode : int8_t { FULLSCREEN_INVALID = -1, @@ -25,17 +26,14 @@ class CWorkspace { int m_iID = -1; std::string m_szName = ""; uint64_t m_iMonitorID = -1; - // Previous workspace ID is stored during a workspace change, allowing travel + // Previous workspace ID and name is stored during a workspace change, allowing travel // to the previous workspace. - struct SPrevWorkspaceData { - int iID = -1; - std::string name = ""; - } m_sPrevWorkspace; + SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; - bool m_bHasFullscreenWindow = false; - eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; + bool m_bHasFullscreenWindow = false; + eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; - wl_array m_wlrCoordinateArr; + wl_array m_wlrCoordinateArr; // for animations CAnimatedVariable m_vRenderOffset; @@ -63,21 +61,23 @@ class CWorkspace { bool m_bPersistent = false; // Inert: destroyed and invalid. If this is true, release the ptr you have. - bool inert(); + bool inert(); - void startAnim(bool in, bool left, bool instant = false); - void setActive(bool on); + void startAnim(bool in, bool left, bool instant = false); + void setActive(bool on); - void moveToMonitor(const int&); + void moveToMonitor(const int&); - PHLWINDOW getLastFocusedWindow(); - void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); + PHLWINDOW getLastFocusedWindow(); + void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); - std::string getConfigName(); + std::string getConfigName(); - bool matchesStaticSelector(const std::string& selector); + bool matchesStaticSelector(const std::string& selector); - void markInert(); + void markInert(); + + SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const; private: void init(PHLWORKSPACE self); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index d37ba12b..bb1197e5 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -293,8 +293,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (WORKSPACEARGS[WORKSPACEARGS.size() - 1].starts_with("silent")) workspaceSilent = true; - std::string requestedWorkspaceName; - const int REQUESTEDWORKSPACEID = getWorkspaceIDFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0), requestedWorkspaceName); + const auto& [REQUESTEDWORKSPACEID, requestedWorkspaceName] = getWorkspaceIDNameFromString(WORKSPACEARGS.join(" ", 0, workspaceSilent ? WORKSPACEARGS.size() - 1 : 0)); if (REQUESTEDWORKSPACEID != WORKSPACE_INVALID) { auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 654ccf35..aa034254 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -214,37 +214,36 @@ bool isDirection(const char& arg) { return arg == 'l' || arg == 'r' || arg == 'u' || arg == 'd' || arg == 't' || arg == 'b'; } -int getWorkspaceIDFromString(const std::string& in, std::string& outName) { - int result = WORKSPACE_INVALID; +SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { + SWorkspaceIDName result = {WORKSPACE_INVALID, ""}; + if (in.starts_with("special")) { - outName = "special:special"; + result.name = "special:special"; if (in.length() > 8) { const auto NAME = in.substr(8); + const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME); - const auto WS = g_pCompositor->getWorkspaceByName("special:" + NAME); - - outName = "special:" + NAME; - - return WS ? WS->m_iID : g_pCompositor->getNewSpecialID(); + return {WS ? WS->m_iID : g_pCompositor->getNewSpecialID(), "special:" + NAME}; } - return SPECIAL_WORKSPACE_START; + result.id = SPECIAL_WORKSPACE_START; + return result; } else if (in.starts_with("name:")) { const auto WORKSPACENAME = in.substr(in.find_first_of(':') + 1); const auto WORKSPACE = g_pCompositor->getWorkspaceByName(WORKSPACENAME); if (!WORKSPACE) { - result = g_pCompositor->getNextAvailableNamedWorkspace(); + result.id = g_pCompositor->getNextAvailableNamedWorkspace(); } else { - result = WORKSPACE->m_iID; + result.id = WORKSPACE->m_iID; } - outName = WORKSPACENAME; + result.name = WORKSPACENAME; } else if (in.starts_with("empty")) { const bool same_mon = in.substr(5).contains("m"); const bool next = in.substr(5).contains("n"); if ((same_mon || next) && !g_pCompositor->m_pLastMonitor) { Debug::log(ERR, "Empty monitor workspace on monitor null!"); - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; } std::set invalidWSes; @@ -259,41 +258,42 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; while (++id < INT_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); - if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) - return id; + if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) { + result.id = id; + return result; + } } } else if (in.starts_with("prev")) { if (!g_pCompositor->m_pLastMonitor) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; if (!valid(PWORKSPACE)) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; - const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.iID); + const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.id); if (!PLASTWORKSPACE) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; - outName = PLASTWORKSPACE->m_szName; - return PLASTWORKSPACE->m_iID; + return {PLASTWORKSPACE->m_iID, PLASTWORKSPACE->m_szName}; } else { if (in[0] == 'r' && (in[1] == '-' || in[1] == '+' || in[1] == '~') && isNumber(in.substr(2))) { bool absolute = in[1] == '~'; if (!g_pCompositor->m_pLastMonitor) { Debug::log(ERR, "Relative monitor workspace on monitor null!"); - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; } const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(absolute ? 2 : 1), 0); if (!PLUSMINUSRESULT.has_value()) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; - result = (int)PLUSMINUSRESULT.value(); + result.id = (int)PLUSMINUSRESULT.value(); - int remains = (int)result; + int remains = (int)result.id; std::set invalidWSes; @@ -330,13 +330,13 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { // traverse valid workspaces until we reach the remains if ((size_t)remains < namedWSes.size()) { - result = namedWSes[remains]; + result.id = namedWSes[remains]; } else { remains -= namedWSes.size(); - result = 0; + result.id = 0; while (remains >= 0) { - result++; - if (!invalidWSes.contains(result)) { + result.id++; + if (!invalidWSes.contains(result.id)) { remains--; } } @@ -430,14 +430,14 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { finalWSID = curID; } } - result = finalWSID; + result.id = finalWSID; } - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result); + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(result.id); if (PWORKSPACE) - outName = g_pCompositor->getWorkspaceByID(result)->m_szName; + result.name = g_pCompositor->getWorkspaceByID(result.id)->m_szName; else - outName = std::to_string(result); + result.name = std::to_string(result.id); } else if ((in[0] == 'm' || in[0] == 'e') && (in[1] == '-' || in[1] == '+' || in[1] == '~') && isNumber(in.substr(2))) { bool onAllMonitors = in[0] == 'e'; @@ -445,19 +445,19 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { if (!g_pCompositor->m_pLastMonitor) { Debug::log(ERR, "Relative monitor workspace on monitor null!"); - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; } // monitor relative const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in.substr(absolute ? 2 : 1), 0); if (!PLUSMINUSRESULT.has_value()) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; - result = (int)PLUSMINUSRESULT.value(); + result.id = (int)PLUSMINUSRESULT.value(); // result now has +/- what we should move on mon - int remains = (int)result; + int remains = (int)result.id; std::vector validWSes; for (auto& ws : g_pCompositor->m_vWorkspaces) { @@ -505,30 +505,30 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { } } - result = validWSes[currentItem]; - outName = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName; + result.id = validWSes[currentItem]; + result.name = g_pCompositor->getWorkspaceByID(validWSes[currentItem])->m_szName; } else { if (in[0] == '+' || in[0] == '-') { if (g_pCompositor->m_pLastMonitor) { const auto PLUSMINUSRESULT = getPlusMinusKeywordResult(in, g_pCompositor->m_pLastMonitor->activeWorkspaceID()); if (!PLUSMINUSRESULT.has_value()) - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; - result = std::max((int)PLUSMINUSRESULT.value(), 1); + result.id = std::max((int)PLUSMINUSRESULT.value(), 1); } else { Debug::log(ERR, "Relative workspace on no mon!"); - return WORKSPACE_INVALID; + return {WORKSPACE_INVALID}; } } else if (isNumber(in)) - result = std::max(std::stoi(in), 1); + result.id = std::max(std::stoi(in), 1); else { // maybe name const auto PWORKSPACE = g_pCompositor->getWorkspaceByName(in); if (PWORKSPACE) - result = PWORKSPACE->m_iID; + result.id = PWORKSPACE->m_iID; } - outName = std::to_string(result); + result.name = std::to_string(result.id); } } diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 111abba0..33be7965 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -13,13 +13,18 @@ struct SCallstackFrameInfo { std::string desc; }; +struct SWorkspaceIDName { + int id = -1; + std::string name; +}; + std::string absolutePath(const std::string&, const std::string&); void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void removeWLSignal(wl_listener*); std::string escapeJSONStrings(const std::string& str); bool isDirection(const std::string&); bool isDirection(const char&); -int getWorkspaceIDFromString(const std::string&, std::string&); +SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&); std::optional cleanCmdForWorkspace(const std::string&, std::string); float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); void logSystemInfo(); @@ -42,4 +47,4 @@ template // because any suck format specifier will cause a compilation error // this is actually what std::format in stdlib does return std::vformat(fmt.get(), std::make_format_args(args...)); -} \ No newline at end of file +} diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 7ebd2539..199b1c5d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -415,20 +415,25 @@ int CMonitor::findAvailableDefaultWS() { void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { // Workspace std::string newDefaultWorkspaceName = ""; - int64_t WORKSPACEID = g_pConfigManager->getDefaultWorkspaceFor(szName).empty() ? - findAvailableDefaultWS() : - getWorkspaceIDFromString(g_pConfigManager->getDefaultWorkspaceFor(szName), newDefaultWorkspaceName); + int64_t wsID = WORKSPACE_INVALID; + if (g_pConfigManager->getDefaultWorkspaceFor(szName).empty()) + wsID = findAvailableDefaultWS(); + else { + const auto ws = getWorkspaceIDNameFromString(g_pConfigManager->getDefaultWorkspaceFor(szName)); + wsID = ws.id; + newDefaultWorkspaceName = ws.name; + } - if (WORKSPACEID == WORKSPACE_INVALID || (WORKSPACEID >= SPECIAL_WORKSPACE_START && WORKSPACEID <= -2)) { - WORKSPACEID = g_pCompositor->m_vWorkspaces.size() + 1; - newDefaultWorkspaceName = std::to_string(WORKSPACEID); + if (wsID == WORKSPACE_INVALID || (wsID >= SPECIAL_WORKSPACE_START && wsID <= -2)) { + wsID = g_pCompositor->m_vWorkspaces.size() + 1; + newDefaultWorkspaceName = std::to_string(wsID); Debug::log(LOG, "Invalid workspace= directive name in monitor parsing, workspace name \"{}\" is invalid.", g_pConfigManager->getDefaultWorkspaceFor(szName)); } - auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); + auto PNEWWORKSPACE = g_pCompositor->getWorkspaceByID(wsID); - Debug::log(LOG, "New monitor: WORKSPACEID {}, exists: {}", WORKSPACEID, (int)(PNEWWORKSPACE != nullptr)); + Debug::log(LOG, "New monitor: WORKSPACEID {}, exists: {}", wsID, (int)(PNEWWORKSPACE != nullptr)); if (PNEWWORKSPACE) { // workspace exists, move it to the newly connected monitor @@ -438,9 +443,9 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { PNEWWORKSPACE->startAnim(true, true, true); } else { if (newDefaultWorkspaceName == "") - newDefaultWorkspaceName = std::to_string(WORKSPACEID); + newDefaultWorkspaceName = std::to_string(wsID); - PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(WORKSPACEID, ID, newDefaultWorkspaceName)); + PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, ID, newDefaultWorkspaceName)); } activeWorkspace = PNEWWORKSPACE; diff --git a/src/macros.hpp b/src/macros.hpp index cacfdfea..67f6301b 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -24,7 +24,8 @@ #define STRVAL_EMPTY "[[EMPTY]]" -#define WORKSPACE_INVALID -1L +#define WORKSPACE_INVALID -1L +#define WORKSPACE_NOT_CHANGED -101 #define LISTENER(name) \ void listener_##name(wl_listener*, void*); \ diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e5db8918..bfcea3da 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1034,10 +1034,26 @@ void CKeybindManager::toggleActivePseudo(std::string args) { g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); } -void CKeybindManager::changeworkspace(std::string args) { - int workspaceToChangeTo = 0; - std::string workspaceName = ""; +SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCURRENTWORKSPACE) { + if (!args.starts_with("previous")) { + return getWorkspaceIDNameFromString(args); + } + const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); + // Do nothing if there's no previous workspace, otherwise switch to it. + if (PPREVWS.id == -1) { + Debug::log(LOG, "No previous workspace to change to"); + return {WORKSPACE_NOT_CHANGED, ""}; + } + + const auto ID = PCURRENTWORKSPACE->m_iID; + if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) + return {ID, PWORKSPACETOCHANGETO->m_szName}; + + return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; +} + +void CKeybindManager::changeworkspace(std::string args) { // Workspace_back_and_forth being enabled means that an attempt to switch to // the current workspace will instead switch to the previous. static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); @@ -1050,43 +1066,31 @@ void CKeybindManager::changeworkspace(std::string args) { return; const auto PCURRENTWORKSPACE = PMONITOR->activeWorkspace; - const bool EXPLICITPREVIOUS = args.starts_with("previous"); - - if (args.starts_with("previous")) { - // Do nothing if there's no previous workspace, otherwise switch to it. - if (PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1) { - Debug::log(LOG, "No previous workspace to change to"); - return; - } else { - workspaceToChangeTo = PCURRENTWORKSPACE->m_iID; - - if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PCURRENTWORKSPACE->m_sPrevWorkspace.iID); PWORKSPACETOCHANGETO) - workspaceName = PWORKSPACETOCHANGETO->m_szName; - else - workspaceName = - PCURRENTWORKSPACE->m_sPrevWorkspace.name.empty() ? std::to_string(PCURRENTWORKSPACE->m_sPrevWorkspace.iID) : PCURRENTWORKSPACE->m_sPrevWorkspace.name; - } - } else { - workspaceToChangeTo = getWorkspaceIDFromString(args, workspaceName); - } + const bool EXPLICITPREVIOUS = args.contains("previous"); + const auto& [workspaceToChangeTo, workspaceName] = getWorkspaceToChangeFromArgs(args, PCURRENTWORKSPACE); if (workspaceToChangeTo == WORKSPACE_INVALID) { Debug::log(ERR, "Error in changeworkspace, invalid value"); return; } - const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; + if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) { + return; + } - if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PCURRENTWORKSPACE->m_sPrevWorkspace.iID == -1)) + const auto PREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); + + const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; + if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PREVWS.id == -1)) return; g_pInputManager->unconstrainMouse(); g_pInputManager->m_bEmptyFocusCursorSet = false; - auto pWorkspaceToChangeTo = g_pCompositor->getWorkspaceByID(BISWORKSPACECURRENT ? PCURRENTWORKSPACE->m_sPrevWorkspace.iID : workspaceToChangeTo); + auto pWorkspaceToChangeTo = g_pCompositor->getWorkspaceByID(BISWORKSPACECURRENT ? PREVWS.id : workspaceToChangeTo); if (!pWorkspaceToChangeTo) - pWorkspaceToChangeTo = g_pCompositor->createNewWorkspace(BISWORKSPACECURRENT ? PCURRENTWORKSPACE->m_sPrevWorkspace.iID : workspaceToChangeTo, PMONITOR->ID, - BISWORKSPACECURRENT ? PCURRENTWORKSPACE->m_sPrevWorkspace.name : workspaceName); + pWorkspaceToChangeTo = + g_pCompositor->createNewWorkspace(BISWORKSPACECURRENT ? PREVWS.id : workspaceToChangeTo, PMONITOR->ID, BISWORKSPACECURRENT ? PREVWS.name : workspaceName); if (!BISWORKSPACECURRENT && pWorkspaceToChangeTo->m_bIsSpecialWorkspace) { PMONITOR->setSpecialWorkspace(pWorkspaceToChangeTo); @@ -1169,10 +1173,7 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { if (!PWINDOW) return; - // hack - std::string workspaceName; - const auto WORKSPACEID = getWorkspaceIDFromString(args, workspaceName); - + const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace"); return; @@ -1233,10 +1234,7 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { if (!PWINDOW) return; - std::string workspaceName = ""; - - const int WORKSPACEID = getWorkspaceIDFromString(args, workspaceName); - + const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value"); return; @@ -1702,8 +1700,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { return; } - std::string workspaceName; - const int WORKSPACEID = getWorkspaceIDFromString(workspace, workspaceName); + const int WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); @@ -1721,9 +1718,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { } void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { - std::string workspaceName; - int workspaceID = getWorkspaceIDFromString(args, workspaceName); - + int workspaceID = getWorkspaceIDNameFromString(args).id; if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); return; @@ -1746,14 +1741,13 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { } static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); + const auto PREVWS = pWorkspace->getPrevWorkspaceIDName(false); - if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspaceID() == workspaceID && pWorkspace->m_sPrevWorkspace.iID != -1) { - const int PREVWORKSPACEID = pWorkspace->m_sPrevWorkspace.iID; - const auto PREVWORKSPACENAME = pWorkspace->m_sPrevWorkspace.name; + if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspaceID() == workspaceID && PREVWS.id != -1) { // Workspace to focus is previous workspace - pWorkspace = g_pCompositor->getWorkspaceByID(PREVWORKSPACEID); + pWorkspace = g_pCompositor->getWorkspaceByID(PREVWS.id); if (!pWorkspace) - pWorkspace = g_pCompositor->createNewWorkspace(PREVWORKSPACEID, PCURRMONITOR->ID, PREVWORKSPACENAME); + pWorkspace = g_pCompositor->createNewWorkspace(PREVWS.id, PCURRMONITOR->ID, PREVWS.name); workspaceID = pWorkspace->m_iID; } @@ -1776,9 +1770,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { } void CKeybindManager::toggleSpecialWorkspace(std::string args) { - std::string workspaceName = ""; - int workspaceID = getWorkspaceIDFromString("special:" + args, workspaceName); - + const auto& [workspaceID, workspaceName] = getWorkspaceIDNameFromString("special:" + args); if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) { Debug::log(ERR, "Invalid workspace passed to special"); return; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index ead7c5b8..775881cd 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -63,10 +63,9 @@ void CInputManager::endWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); // commit - std::string wsname = ""; - auto workspaceIDLeft = getWorkspaceIDFromString((*PSWIPEUSER ? "r-1" : "m-1"), wsname); - auto workspaceIDRight = getWorkspaceIDFromString((*PSWIPEUSER ? "r+1" : "m+1"), wsname); - const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); + auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; + auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; + const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); // If we've been swiping off the right end with PSWIPENEW enabled, there is // no workspace there yet, and we need to choose an ID for a new one now. @@ -232,9 +231,8 @@ void CInputManager::updateWorkspaceSwipe(double delta) { m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(d)) / (m_sActiveSwipe.speedPoints + 1); m_sActiveSwipe.speedPoints++; - std::string wsname = ""; - auto workspaceIDLeft = getWorkspaceIDFromString((*PSWIPEUSER ? "r-1" : "m-1"), wsname); - auto workspaceIDRight = getWorkspaceIDFromString((*PSWIPEUSER ? "r+1" : "m+1"), wsname); + auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; + auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_sActiveSwipe.pWorkspaceBegin->m_iID) && !*PSWIPENEW) { m_sActiveSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe From 315f16d501f38d6bc743fca359d13b655c4a970d Mon Sep 17 00:00:00 2001 From: John Titor <50095635+JohnRTitor@users.noreply.github.com> Date: Sun, 23 Jun 2024 12:43:17 +0530 Subject: [PATCH 0271/2393] dbus: import PATH XDG_DATA_DIRS variables into systemd and dbus session --- src/Compositor.cpp | 8 ++++---- src/config/ConfigManager.cpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c607dfb6..2ed1a951 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -311,10 +311,10 @@ void CCompositor::cleanEnvironment() { if (m_sWLRSession) { const auto CMD = #ifdef USES_SYSTEMD - "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash " + "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "dbus-update-activation-environment 2>/dev/null && " #endif - "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME"; + "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; g_pKeybindManager->spawn(CMD); } } @@ -569,10 +569,10 @@ void CCompositor::startCompositor() { if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) { const auto CMD = #ifdef USES_SYSTEMD - "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash " + "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "dbus-update-activation-environment 2>/dev/null && " #endif - "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME"; + "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; g_pKeybindManager->spawn(CMD); } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6a1c896c..a4a80944 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1282,10 +1282,10 @@ void CConfigManager::dispatchExecOnce() { if (g_pCompositor->m_sWLRSession) handleRawExec("", #ifdef USES_SYSTEMD - "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME && hash " + "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " "dbus-update-activation-environment 2>/dev/null && " #endif - "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME"); + "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"); firstExecDispatched = true; From e09addf8dede9a8e7f2dd0e5bb414d3a0d5dc471 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 23 Jun 2024 16:43:53 +0300 Subject: [PATCH 0272/2393] Workspace.hpp: fix include --- src/desktop/Workspace.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index ab3907aa..bb5cd441 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -4,7 +4,7 @@ #include #include "../defines.hpp" #include "DesktopTypes.hpp" -#include "helpers/MiscFunctions.hpp" +#include "../helpers/MiscFunctions.hpp" enum eFullscreenMode : int8_t { FULLSCREEN_INVALID = -1, From 8a68199a0ceb2894a5d9cc300961c38123ac0312 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 23 Jun 2024 19:49:48 +0200 Subject: [PATCH 0273/2393] foreign-toplevel-wlr: fix out-of-range for missing monitor resources fixes #6635 --- src/protocols/ForeignToplevelWlr.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 14800393..2b378386 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -124,17 +124,19 @@ void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { const auto CLIENT = resource->client(); - if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR) { + if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR && PROTO::outputs.contains(PLASTMONITOR->szName)) { const auto OLDRESOURCE = PROTO::outputs.at(PLASTMONITOR->szName)->outputResourceFrom(CLIENT); if (OLDRESOURCE) resource->sendOutputLeave(OLDRESOURCE->getResource()->resource()); } - const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT); + if (PROTO::outputs.contains(pMonitor->szName)) { + const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT); - if (NEWRESOURCE) - resource->sendOutputEnter(NEWRESOURCE->getResource()->resource()); + if (NEWRESOURCE) + resource->sendOutputEnter(NEWRESOURCE->getResource()->resource()); + } lastMonitorID = pMonitor->ID; } From cff0123ce62a1f721d3aa2ac0fb58019787a7778 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 24 Jun 2024 23:29:26 +0200 Subject: [PATCH 0274/2393] wl-compositor: don't send enter to defunct output globals --- src/protocols/core/Compositor.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 4bce3f58..691267b0 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -221,6 +221,11 @@ void CWLSurfaceResource::enter(SP monitor) { return; } + if (PROTO::outputs.at(monitor->szName)->isDefunct()) { + LOGM(ERR, "enter() called on a defunct output global"); + return; + } + auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); if (!output || !output->getResource() || !output->getResource()->resource()) { From 4dd2b5902e770eeaf84820eccfebb5451aedb6a5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 24 Jun 2024 23:58:10 +0200 Subject: [PATCH 0275/2393] hyprctl: add a newline after log() --- hyprctl/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 2bd325e3..45fe9142 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -47,7 +47,7 @@ void log(std::string str) { if (quiet) return; - std::cout << str; + std::cout << str << "\n"; } std::string getRuntimeDir() { From eef207ce0a46c13dafa8fab3a462e62c8a3c04f1 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 25 Jun 2024 03:55:54 -0700 Subject: [PATCH 0276/2393] output: fix cursors disappearing after dpms (#6659) --- src/managers/KeybindManager.cpp | 3 +++ src/managers/PointerManager.hpp | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index bfcea3da..37159ca8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -5,6 +5,7 @@ #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "KeybindManager.hpp" +#include "PointerManager.hpp" #include "Compositor.hpp" #include "TokenManager.hpp" #include "debug/Log.hpp" @@ -2280,6 +2281,8 @@ void CKeybindManager::dpms(std::string arg) { } g_pCompositor->m_bDPMSStateON = enable; + + g_pPointerManager->recheckEnteredOutputs(); } void CKeybindManager::swapnext(std::string arg) { diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 545b76fb..da639340 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -59,6 +59,8 @@ class CPointerManager { Vector2D position(); Vector2D cursorSizeLogical(); + void recheckEnteredOutputs(); + private: void recheckPointerPosition(); void onMonitorLayoutChange(); @@ -67,7 +69,6 @@ class CPointerManager { void onCursorMoved(); bool hasCursor(); void damageIfSoftware(); - void recheckEnteredOutputs(); // closest valid point to a given one Vector2D closestValid(const Vector2D& pos); From 784c0b5ccb9b99bde66bd45bb94af5f195980f2e Mon Sep 17 00:00:00 2001 From: Gregory <56975502+Trimutex@users.noreply.github.com> Date: Tue, 25 Jun 2024 06:46:49 -0500 Subject: [PATCH 0277/2393] keybinds: fix mouse pass (#6652) * keybinds: fix mouse pass * keybinds: keep mouse and keyboard focus separate after pass bind --- src/managers/KeybindManager.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 37159ca8..c5a35012 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2025,8 +2025,9 @@ void CKeybindManager::pass(std::string regexp) { return; } - const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; - const auto LASTSRF = g_pCompositor->m_pLastFocus.lock(); + const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; + const auto LASTMOUSESURF = g_pSeatManager->state.pointerFocus.lock(); + const auto LASTKBSURF = g_pSeatManager->state.keyboardFocus.lock(); // pass all mf shit if (!XWTOXW) { @@ -2078,9 +2079,9 @@ void CKeybindManager::pass(std::string regexp) { const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); if (g_pKeybindManager->m_uLastCode != 0) - g_pSeatManager->setKeyboardFocus(LASTSRF); + g_pSeatManager->setKeyboardFocus(LASTKBSURF); else - g_pSeatManager->setPointerFocus(PWINDOW->m_pWLSurface->resource(), SL); + g_pSeatManager->setPointerFocus(LASTMOUSESURF, SL); } void CKeybindManager::sendshortcut(std::string args) { From 8121e66f34eb9247cd202590370bf91f8c3ec447 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 13:50:54 +0200 Subject: [PATCH 0278/2393] cmake: bump hyprutils dep to 0.1.5 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 632621ac..e8f203b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.4 + hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.5 ) find_package(hyprwayland-scanner 0.3.10 REQUIRED) From 4f7113972e9803a41329125e5e8f77fe5281fb22 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 13:53:41 +0200 Subject: [PATCH 0279/2393] props: bump version to 0.41.2 --- props.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/props.json b/props.json index 4af3eb2a..2ff7562e 100644 --- a/props.json +++ b/props.json @@ -1,3 +1,3 @@ { - "version": "0.41.1" + "version": "0.41.2" } \ No newline at end of file From 918d8340afd652b011b937d29d5eea0be08467f5 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 25 Jun 2024 15:06:02 +0300 Subject: [PATCH 0280/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index cb1f7875..c1f37d2e 100644 --- a/flake.lock +++ b/flake.lock @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1718804078, - "narHash": "sha256-CqRZne63BpYlPd/i8lXV0UInUt59oKogiwdVtBRHt60=", + "lastModified": 1719316102, + "narHash": "sha256-dmRz128j/lJmMuTYeCYPfSBRHHQO3VeH4PbmoyAhHzw=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "4f1351295c55a8f51219b25aa4a6497a067989d0", + "rev": "1f6bbec5954f623ff8d68e567bddcce97cd2f085", "type": "github" }, "original": { @@ -110,11 +110,11 @@ ] }, "locked": { - "lastModified": 1718119275, - "narHash": "sha256-nqDYXATNkyGXVmNMkT19fT4sjtSPBDS1LLOxa3Fueo4=", + "lastModified": 1719067853, + "narHash": "sha256-mAnZG/eQy72Fp1ImGtqCgUrDumnR1rMZv2E/zgP4U74=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "1419520d5f7f38d35e05504da5c1b38212a38525", + "rev": "914f083741e694092ee60a39d31f693d0a6dc734", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1718530797, - "narHash": "sha256-pup6cYwtgvzDpvpSCFh1TEUjw2zkNpk8iolbKnyFmmU=", + "lastModified": 1719075281, + "narHash": "sha256-CyyxvOwFf12I91PBWz43iGT1kjsf5oi6ax7CrvaMyAo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b60ebf54c15553b393d144357375ea956f89e9a9", + "rev": "a71e967ef3694799d0c418c98332f7ff4cc5f6af", "type": "github" }, "original": { From 1d70962892a6e3e1cacd3663b390bbdf81426984 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 16:05:39 +0200 Subject: [PATCH 0281/2393] core: move to steady_clock where applicable avoid issues when system clock gets desynchronized or changed --- src/events/Monitors.cpp | 4 ++-- src/helpers/AnimatedVariable.cpp | 4 ++-- src/helpers/AnimatedVariable.hpp | 6 +++--- src/helpers/Timer.cpp | 8 ++++---- src/helpers/Timer.hpp | 6 +++--- src/managers/AnimationManager.cpp | 2 +- src/managers/TokenManager.cpp | 8 ++++---- src/managers/TokenManager.hpp | 6 +++--- src/managers/eventLoop/EventLoopTimer.cpp | 12 ++++++------ src/managers/eventLoop/EventLoopTimer.hpp | 6 +++--- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 17b8ef65..2536e1f7 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -19,7 +19,7 @@ static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static auto firstMonitorAdded = std::chrono::system_clock::now(); + static auto firstMonitorAdded = std::chrono::steady_clock::now(); static bool cursorDefaultDone = false; static bool firstLaunch = true; @@ -37,7 +37,7 @@ static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitor return; // after 10s, don't set cursor to default monitor - auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded); + auto timePassedSec = std::chrono::duration_cast(std::chrono::steady_clock::now() - firstMonitorAdded); if (timePassedSec.count() > 10) { cursorDefaultDone = true; return; diff --git a/src/helpers/AnimatedVariable.cpp b/src/helpers/AnimatedVariable.cpp index bdfb4b77..117cd25b 100644 --- a/src/helpers/AnimatedVariable.cpp +++ b/src/helpers/AnimatedVariable.cpp @@ -57,11 +57,11 @@ void CBaseAnimatedVariable::registerVar() { int CBaseAnimatedVariable::getDurationLeftMs() { return std::max( - (int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast(std::chrono::system_clock::now() - animationBegin).count(), 0); + (int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast(std::chrono::steady_clock::now() - animationBegin).count(), 0); } float CBaseAnimatedVariable::getPercent() { - const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::system_clock::now() - animationBegin).count(); + const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::steady_clock::now() - animationBegin).count(); return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f); } diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index 073cf65b..6310afb7 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -155,7 +155,7 @@ class CBaseAnimatedVariable { bool m_bIsRegistered = false; bool m_bIsBeingAnimated = false; - std::chrono::system_clock::time_point animationBegin; + std::chrono::steady_clock::time_point animationBegin; AVARDAMAGEPOLICY m_eDamagePolicy = AVARDAMAGE_NONE; ANIMATEDVARTYPE m_Type; @@ -253,7 +253,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable { return *this; m_Goal = v; - animationBegin = std::chrono::system_clock::now(); + animationBegin = std::chrono::steady_clock::now(); m_Begun = m_Value; onAnimationBegin(); @@ -267,7 +267,7 @@ class CAnimatedVariable : public CBaseAnimatedVariable { return; m_Value = v; - animationBegin = std::chrono::system_clock::now(); + animationBegin = std::chrono::steady_clock::now(); m_Begun = m_Value; onAnimationBegin(); diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp index 6847567a..ec530df4 100644 --- a/src/helpers/Timer.cpp +++ b/src/helpers/Timer.cpp @@ -1,11 +1,11 @@ #include "Timer.hpp" void CTimer::reset() { - m_tpLastReset = std::chrono::system_clock::now(); + m_tpLastReset = std::chrono::steady_clock::now(); } -std::chrono::system_clock::duration CTimer::getDuration() { - return std::chrono::system_clock::now() - m_tpLastReset; +std::chrono::steady_clock::duration CTimer::getDuration() { + return std::chrono::steady_clock::now() - m_tpLastReset; } int CTimer::getMillis() { @@ -16,6 +16,6 @@ float CTimer::getSeconds() { return std::chrono::duration_cast(getDuration()).count() / 1000.f; } -const std::chrono::system_clock::time_point& CTimer::chrono() const { +const std::chrono::steady_clock::time_point& CTimer::chrono() const { return m_tpLastReset; } \ No newline at end of file diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp index e55f4ebf..a6d1aeed 100644 --- a/src/helpers/Timer.hpp +++ b/src/helpers/Timer.hpp @@ -7,10 +7,10 @@ class CTimer { void reset(); float getSeconds(); int getMillis(); - const std::chrono::system_clock::time_point& chrono() const; + const std::chrono::steady_clock::time_point& chrono() const; private: - std::chrono::system_clock::time_point m_tpLastReset; + std::chrono::steady_clock::time_point m_tpLastReset; - std::chrono::system_clock::duration getDuration(); + std::chrono::steady_clock::duration getDuration(); }; \ No newline at end of file diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 9d6668c9..1fec375e 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -552,7 +552,7 @@ void CAnimationManager::scheduleTick() { float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate); - const float SINCEPRES = std::chrono::duration_cast(std::chrono::system_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; + const float SINCEPRES = std::chrono::duration_cast(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it diff --git a/src/managers/TokenManager.cpp b/src/managers/TokenManager.cpp index 451baac1..cee97c1c 100644 --- a/src/managers/TokenManager.cpp +++ b/src/managers/TokenManager.cpp @@ -2,8 +2,8 @@ #include #include -CUUIDToken::CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::system_clock::duration expires) : data(data_), uuid(uuid_) { - expiresAt = std::chrono::system_clock::now() + expires; +CUUIDToken::CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::steady_clock::duration expires) : data(data_), uuid(uuid_) { + expiresAt = std::chrono::steady_clock::now() + expires; } std::string CUUIDToken::getUUID() { @@ -23,7 +23,7 @@ std::string CTokenManager::getRandomUUID() { return uuid; } -std::string CTokenManager::registerNewToken(std::any data, std::chrono::system_clock::duration expires) { +std::string CTokenManager::registerNewToken(std::any data, std::chrono::steady_clock::duration expires) { std::string uuid = getRandomUUID(); m_mTokens[uuid] = makeShared(uuid, data, expires); @@ -33,7 +33,7 @@ std::string CTokenManager::registerNewToken(std::any data, std::chrono::system_c SP CTokenManager::getToken(const std::string& uuid) { // cleanup expired tokens - const auto NOW = std::chrono::system_clock::now(); + const auto NOW = std::chrono::steady_clock::now(); std::erase_if(m_mTokens, [this, &NOW](const auto& el) { return el.second->expiresAt < NOW; }); if (!m_mTokens.contains(uuid)) diff --git a/src/managers/TokenManager.hpp b/src/managers/TokenManager.hpp index 4587f556..92638e9b 100644 --- a/src/managers/TokenManager.hpp +++ b/src/managers/TokenManager.hpp @@ -9,7 +9,7 @@ class CUUIDToken { public: - CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::system_clock::duration expires); + CUUIDToken(const std::string& uuid_, std::any data_, std::chrono::steady_clock::duration expires); std::string getUUID(); @@ -18,14 +18,14 @@ class CUUIDToken { private: std::string uuid; - std::chrono::system_clock::time_point expiresAt; + std::chrono::steady_clock::time_point expiresAt; friend class CTokenManager; }; class CTokenManager { public: - std::string registerNewToken(std::any data, std::chrono::system_clock::duration expires); + std::string registerNewToken(std::any data, std::chrono::steady_clock::duration expires); std::string getRandomUUID(); SP getToken(const std::string& uuid); diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp index dbb405e5..d3cfdf8d 100644 --- a/src/managers/eventLoop/EventLoopTimer.cpp +++ b/src/managers/eventLoop/EventLoopTimer.cpp @@ -2,23 +2,23 @@ #include #include "EventLoopManager.hpp" -CEventLoopTimer::CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_) : +CEventLoopTimer::CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_) : cb(cb_), data(data_) { if (!timeout.has_value()) expires.reset(); else - expires = std::chrono::system_clock::now() + *timeout; + expires = std::chrono::steady_clock::now() + *timeout; } -void CEventLoopTimer::updateTimeout(std::optional timeout) { +void CEventLoopTimer::updateTimeout(std::optional timeout) { if (!timeout.has_value()) { expires.reset(); g_pEventLoopManager->nudgeTimers(); return; } - expires = std::chrono::system_clock::now() + *timeout; + expires = std::chrono::steady_clock::now() + *timeout; g_pEventLoopManager->nudgeTimers(); } @@ -26,7 +26,7 @@ void CEventLoopTimer::updateTimeout(std::optional *expires; + return std::chrono::steady_clock::now() > *expires; } void CEventLoopTimer::cancel() { @@ -47,5 +47,5 @@ float CEventLoopTimer::leftUs() { if (!expires.has_value()) return std::numeric_limits::max(); - return std::chrono::duration_cast(*expires - std::chrono::system_clock::now()).count(); + return std::chrono::duration_cast(*expires - std::chrono::steady_clock::now()).count(); } diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index 73f5dc73..ad7d3986 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -8,11 +8,11 @@ class CEventLoopTimer { public: - CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_); + CEventLoopTimer(std::optional timeout, std::function self, void* data)> cb_, void* data_); // if not specified, disarms. // if specified, arms. - void updateTimeout(std::optional timeout); + void updateTimeout(std::optional timeout); void cancel(); bool passed(); @@ -26,6 +26,6 @@ class CEventLoopTimer { private: std::function self, void* data)> cb; void* data = nullptr; - std::optional expires; + std::optional expires; bool wasCancelled = false; }; From 3ba3d20ad35f904cdafdd664b0acd1671924597a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 18:44:54 +0200 Subject: [PATCH 0282/2393] pointer: round position when rendering software cursors otherwise the image gets resampled and gets blurry --- src/managers/PointerManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index d3da5eff..2b34f380 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -576,6 +576,8 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* return; box.scale(pMonitor->scale); + box.x = std::round(box.x); + box.y = std::round(box.y); g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); From 95782de966ec9e182d49b2f032b74a1101f423e8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 20:04:02 +0200 Subject: [PATCH 0283/2393] renderer: don't use the surface counter in popup iterations fixes #6663 --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4fc751ff..3ea5197e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -212,7 +212,7 @@ static void renderSurface(SP surface, int x, int y, void* da // FIXME: This is wrong and will bug the blur out as shit if the first surface // is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) - if (RDATA->surfaceCounter == 0) { + if (RDATA->surfaceCounter == 0 && !RDATA->popup) { if (RDATA->blur) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else From c338acbb7dc64a735dadd0ae54f3b17d85a2a467 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 25 Jun 2024 22:46:36 +0200 Subject: [PATCH 0284/2393] ime-relay: fix crash on nullptr surface focus --- src/managers/input/InputMethodRelay.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 92ab14d8..f1fe6421 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -143,6 +143,9 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { ti->leave(); } + if (!pSurface) + return; + for (auto& ti : m_vTextInputs) { if (!ti->isV3()) continue; From e4d09aa3a9de9a9e71c10bf4b6800585b3db9a4c Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 25 Jun 2024 14:22:38 -0700 Subject: [PATCH 0285/2393] sessionLock: focus lock on creation based on mouse position (#6658) * sessionLock: focus lock on creation based on mouse position * sessionLock: immediately unfocus any focused surfaces on lock --- src/managers/SessionLockManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 3bec1c4b..b4695e0e 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -10,7 +10,7 @@ SSessionLockSurface::SSessionLockSurface(SP surface_) : sur listeners.map = surface_->events.map.registerListener([this](std::any data) { mapped = true; - g_pCompositor->focusSurface(surface->surface()); + g_pInputManager->simulateMouseMovement(); const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); @@ -78,6 +78,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { }); pLock->sendLocked(); + g_pCompositor->focusSurface(nullptr); } bool CSessionLockManager::isSessionLocked() { From f2dc48d92f340efe6d4264b92d38378c18a3e1ea Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Thu, 27 Jun 2024 16:07:56 +0300 Subject: [PATCH 0286/2393] keybinds: never switch to another monitor with per_monitor (#6665) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- src/managers/KeybindManager.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c5a35012..005ce392 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1040,7 +1040,8 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU return getWorkspaceIDNameFromString(args); } - const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); + const bool PER_MON = args.contains("_per_monitor"); + const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(PER_MON); // Do nothing if there's no previous workspace, otherwise switch to it. if (PPREVWS.id == -1) { Debug::log(LOG, "No previous workspace to change to"); @@ -1048,8 +1049,11 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU } const auto ID = PCURRENTWORKSPACE->m_iID; - if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) + if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) { + if (PER_MON && PCURRENTWORKSPACE->m_iMonitorID != PWORKSPACETOCHANGETO->m_iMonitorID) + return {WORKSPACE_NOT_CHANGED, ""}; return {ID, PWORKSPACETOCHANGETO->m_szName}; + } return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; } @@ -1678,7 +1682,6 @@ void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { // get the current workspace const auto PCURRENTWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; - if (!PCURRENTWORKSPACE) { Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!"); return; From ac11771348146087eb577d20162ec10a81358a7e Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 28 Jun 2024 22:24:32 +0200 Subject: [PATCH 0287/2393] core: fix a few ubsan issues reported at exit of hyprland (#6699) * watchdog: dont detach and cause race condition instead of detaching and causing a race condition on destruction where the thread is alive and watchdog has been destroyed, check if its joinable and join it on destruction. causes heap use after free on exit of compositor. * render: add checks for compositor shutting down avoid member call on null pointer, if the g_pHyprRenderer is destroyed we can call the member makeEGLCurrent on it, causes undefined behaviour on destruction of the compositor/hyprrenderer. found with ubsan. --- src/helpers/Watchdog.cpp | 6 +++--- src/render/Renderbuffer.cpp | 2 +- src/render/Texture.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp index afb8a946..b9f654da 100644 --- a/src/helpers/Watchdog.cpp +++ b/src/helpers/Watchdog.cpp @@ -7,7 +7,9 @@ CWatchdog::~CWatchdog() { m_bExitThread = true; m_bNotified = true; m_cvWatchdogCondition.notify_all(); - m_pWatchdog.reset(); + + if (m_pWatchdog && m_pWatchdog->joinable()) + m_pWatchdog->join(); } CWatchdog::CWatchdog() { @@ -33,8 +35,6 @@ CWatchdog::CWatchdog() { m_bNotified = false; } }); - - m_pWatchdog->detach(); } void CWatchdog::startWatching() { diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 694485c2..b55a921b 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -6,7 +6,7 @@ #include CRenderbuffer::~CRenderbuffer() { - if (!g_pCompositor) + if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) return; g_pHyprRenderer->makeEGLCurrent(); diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 5560db97..46c501a0 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -9,7 +9,7 @@ CTexture::CTexture() { } CTexture::~CTexture() { - if (m_bNonOwning) + if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) return; g_pHyprRenderer->makeEGLCurrent(); From d16c6aa1db52a0ee60ca1f53a9aa9ed1a2537ff2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 29 Jun 2024 00:18:18 +0200 Subject: [PATCH 0288/2393] pointer-constraint: set lifetime correctly ref #6679 --- src/protocols/PointerConstraints.cpp | 8 ++++---- src/protocols/PointerConstraints.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index a17fa6cd..fd15242d 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -7,8 +7,8 @@ #define LOGM PROTO::constraints->protoLog -CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : - resourceL(resource_), locked(true) { +CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : + resourceL(resource_), locked(true), lifetime(lifetime_) { if (!resource_->resource()) return; @@ -46,8 +46,8 @@ CPointerConstraint::CPointerConstraint(SP resource_, SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime) : - resourceC(resource_), locked(false) { +CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : + resourceC(resource_), locked(false), lifetime(lifetime_) { if (!resource_->resource()) return; diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index faf28b32..35d60632 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -16,8 +16,8 @@ class CWLSurfaceResource; class CPointerConstraint { public: - CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); - CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime); + CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime_); + CPointerConstraint(SP resource_, SP surf, wl_resource* region, zwpPointerConstraintsV1Lifetime lifetime_); ~CPointerConstraint(); bool good(); From 9c5dd59d4b1927b7d88e8e3c2e260eb01d95794b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 29 Jun 2024 00:23:02 +0200 Subject: [PATCH 0289/2393] input: fix capabilities enum types passed hyprland down to the seat protocol impl expects IHID capabilities, not WL_ ones ref #6702 #6196 --- src/managers/input/InputManager.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 81a46f97..b3621520 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1473,14 +1473,7 @@ void CInputManager::updateCapabilities() { if (h.expired()) continue; - auto cap = h->getCapabilities(); - - if (cap & HID_INPUT_CAPABILITY_KEYBOARD) - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - if (cap & HID_INPUT_CAPABILITY_POINTER) - caps |= WL_SEAT_CAPABILITY_POINTER; - if (cap & HID_INPUT_CAPABILITY_TOUCH) - caps |= WL_SEAT_CAPABILITY_TOUCH; + caps |= h->getCapabilities(); } g_pSeatManager->updateCapabilities(caps); From 1f43a5c859bfdf3dc6e880610e21cd9434a4e47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AF=E3=82=8C=E3=81=AA=E3=82=88?= <123649644+harenayo@users.noreply.github.com> Date: Sun, 30 Jun 2024 03:04:48 +0900 Subject: [PATCH 0290/2393] session: fix activate events being always treated as on (#6696) * Fix listener_sessionActive to handle an event correctly when the session get inactivated * Remove log --- src/events/Misc.cpp | 25 ++++++++++++++++++------- src/managers/KeybindManager.cpp | 13 +------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index 6580d93e..32f894ec 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -30,14 +30,25 @@ void Events::listener_RendererDestroy(wl_listener* listener, void* data) { } void Events::listener_sessionActive(wl_listener* listener, void* data) { - Debug::log(LOG, "Session got activated!"); + if (g_pCompositor->m_sWLRSession->active) { + Debug::log(LOG, "Session got activated!"); - g_pCompositor->m_bSessionActive = true; + g_pCompositor->m_bSessionActive = true; - for (auto& m : g_pCompositor->m_vMonitors) { - g_pCompositor->scheduleFrameForMonitor(m.get()); - g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); + for (auto& m : g_pCompositor->m_vMonitors) { + g_pCompositor->scheduleFrameForMonitor(m.get()); + g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); + } + + g_pConfigManager->m_bWantsMonitorReload = true; + } else { + Debug::log(LOG, "Session got inactivated!"); + + g_pCompositor->m_bSessionActive = false; + + for (auto& m : g_pCompositor->m_vMonitors) { + m->noFrameSchedule = true; + m->framesToSkip = 1; + } } - - g_pConfigManager->m_bWantsMonitorReload = true; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 005ce392..f66b4457 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -810,18 +810,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY); - if (!wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY)) - return true; // probably same session - - g_pCompositor->m_bSessionActive = false; - - for (auto& m : g_pCompositor->m_vMonitors) { - m->noFrameSchedule = true; - m->framesToSkip = 1; - } - - Debug::log(LOG, "Switched to VT {}, destroyed all render data, frames to skip for each: 2", TTY); - + wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY); return true; } From 718afe271ecebfe6711453b9cfee90fa49a7e761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=AF=E3=82=8C=E3=81=AA=E3=82=88?= <123649644+harenayo@users.noreply.github.com> Date: Sun, 30 Jun 2024 03:05:07 +0900 Subject: [PATCH 0291/2393] seat: don't send keyboard data without a keyboard cap (#6697) * Fix #6279: prevent sending keymap or repeat info events by keyboards without keyboard capability * Remove brackets --- src/protocols/core/Seat.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index f578292a..464a901c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -2,6 +2,7 @@ #include "Compositor.hpp" #include "DataDevice.hpp" #include "../../devices/IKeyboard.hpp" +#include "../../devices/IHID.hpp" #include "../../managers/SeatManager.hpp" #include "../../config/ConfigValue.hpp" #include @@ -451,12 +452,18 @@ void CWLSeatProtocol::updateCapabilities(uint32_t caps) { } void CWLSeatProtocol::updateKeymap() { + if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + for (auto& k : m_vKeyboards) { k->sendKeymap(g_pSeatManager->keyboard.lock()); } } void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) { + if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + for (auto& k : m_vKeyboards) { k->repeatInfo(rate, delayMs); } From 8ff9410d2cd39fc1c677799a29f7a063743c0dc9 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 30 Jun 2024 13:15:59 +0200 Subject: [PATCH 0292/2393] inputmgr: ensure we dont divide by zero (#6713) some weird combination of scrolling/nesting hyprland and closing a window i managed to divide by zero here, reported by ubsan. add a check to ensure we dont hit UB. --- src/managers/input/InputManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index b3621520..9180e9cd 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -798,7 +798,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { } } } - double deltaDiscrete = factor * e.deltaDiscrete / std::abs(e.deltaDiscrete); + double deltaDiscrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0; g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete), std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } From 4d6f96f74f9fa6e7b69790fa569ffe60267f8017 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sun, 30 Jun 2024 14:16:41 +0300 Subject: [PATCH 0293/2393] debug: add Nvidia driver info (#6715) * add nvidia driver info to systeminfo * check file exists --- src/debug/HyprCtl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b0a0c477..571aa6d1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -912,7 +912,10 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif - result += "GPU information: \n" + GPUINFO + "\n\n"; + result += "GPU information: \n" + GPUINFO; + if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) + result += execAndGet("cat /proc/driver/nvidia/version | grep NVRM"); + result += "\n\n"; result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; From d7ea1b7785f31e9fd6477490309721a19a835592 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 1 Jul 2024 00:26:08 +0200 Subject: [PATCH 0294/2393] xwayland: break cyclic loop of parents (#6722) in X11 some surfaces is a parent of itself and creates a cyclic loop when trying to find its parent. check for old parent and break if its beginning to roll over. --- src/desktop/Window.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e67a3357..560e5103 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -444,9 +444,11 @@ PHLWINDOW CWindow::X11TransientFor() { if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) return nullptr; - auto s = m_pXWaylandSurface->parent; + auto s = m_pXWaylandSurface->parent; + auto oldParent = s; while (s) { - if (!s->parent) + // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created? + if (!s->parent || s->parent == oldParent) break; s = s->parent; } From e58fd3bfb09f329e3a1bd10c42f31f95e8299a98 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 2 Jul 2024 05:14:27 -0500 Subject: [PATCH 0295/2393] meson: fix wlroots-hyprland dep checks (for libliftoff patch to work) (#6736) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8f203b4..d41dd6e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ ExternalProject_Add( wlroots-hyprland PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland - CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $,-Db_sanitize=address,-Db_sanitize=none> + CONFIGURE_COMMAND meson setup --reconfigure --clearcache build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $,-Db_sanitize=address,-Db_sanitize=none> BUILD_COMMAND ninja -C build BUILD_ALWAYS true BUILD_IN_SOURCE true From 2fa57f2dc4909be697d003a22ce6870039e4db9b Mon Sep 17 00:00:00 2001 From: drendog <53359960+drendog@users.noreply.github.com> Date: Tue, 2 Jul 2024 12:17:48 +0200 Subject: [PATCH 0296/2393] pointer: change min cursor padding to 0 (#6027) * fix: change min cursor padding to 0 * chore: set default hotspot padding to 0 * fix: adjusting clamp after getting closest point to fix getting off limit point * fix: deal with floating point to clamp to prev value * refactor: max coords to vector * fix: remove box closestPoint adjustment due its fix on hyprutils --- src/config/ConfigManager.cpp | 2 +- src/managers/PointerManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a4a80944..ff9d3a6d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -525,7 +525,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); - m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 2b34f380..8b4ba0ee 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -612,7 +612,7 @@ CBox CPointerManager::getCursorBoxGlobal() { Vector2D CPointerManager::closestValid(const Vector2D& pos) { static auto PADDING = CConfigValue("cursor:hotspot_padding"); - auto CURSOR_PADDING = std::clamp((int)*PADDING, 1, 100); // 1px + auto CURSOR_PADDING = std::clamp((int)*PADDING, 0, 100); CBox hotBox = {{pos.x - CURSOR_PADDING, pos.y - CURSOR_PADDING}, {2 * CURSOR_PADDING, 2 * CURSOR_PADDING}}; // From 6247a6b537fd1c05ecf35420529fab1adf83143e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 2 Jul 2024 18:40:21 +0200 Subject: [PATCH 0297/2393] renderer: don't skip back background on preBlurQueued fixes #6332 --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 3ea5197e..8d98a182 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -864,7 +864,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC // TODO: check better with solitary after MR for tearing. const auto PFULLWINDOW = pWorkspace ? g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID) : nullptr; if (!pWorkspace->m_bHasFullscreenWindow || pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL || !PFULLWINDOW || PFULLWINDOW->m_vRealSize.isBeingAnimated() || - !PFULLWINDOW->opaque() || pWorkspace->m_vRenderOffset.value() != Vector2D{}) { + !PFULLWINDOW->opaque() || pWorkspace->m_vRenderOffset.value() != Vector2D{} || g_pHyprOpenGL->preBlurQueued()) { if (!g_pHyprOpenGL->m_RenderData.pCurrentMonData->blurFBShouldRender) setOccludedForBackLayers(g_pHyprOpenGL->m_RenderData.damage, pWorkspace); From 8bb75a223db3ea9471d05d74fbed3328334a9f78 Mon Sep 17 00:00:00 2001 From: Lincoln Yuji Date: Tue, 2 Jul 2024 16:04:14 -0300 Subject: [PATCH 0298/2393] hyprctl completions: Use only awk rather than grep + awk Using "awk '//{ print $n }'" is more minimal and slightly faster than using "grep '' | awk '{ print $n }'". Signed-off-by: Lincoln Yuji --- hyprctl/hyprctl.bash | 6 +++--- hyprctl/hyprctl.fish | 6 +++--- hyprctl/hyprctl.zsh | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index 8386cfbc..c69cca21 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -1,13 +1,13 @@ _hyprctl_cmd_2 () { - hyprctl monitors | grep Monitor | awk '{ print $2 }' + hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | grep "Plugin" | awk '{print $4}' + hyprpm list | awk '/Plugin/{ print $4 }' } _hyprctl_cmd_0 () { - hyprctl clients | grep class | awk '{print $2}' + hyprctl clients | awk '/class/{ print $2 }' } _hyprctl_cmd_1 () { diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index 2a75eb12..c5c03e49 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -1,16 +1,16 @@ function _hyprctl_3 set 1 $argv[1] - hyprctl monitors | grep Monitor | awk '{ print $2 }' + hyprctl monitors | awk '/Monitor/{ print $2 }' end function _hyprctl_4 set 1 $argv[1] - hyprpm list | grep "Plugin" | awk '{print $4}' + hyprpm list | awk '/Plugin/{ print $4 }' end function _hyprctl_1 set 1 $argv[1] - hyprctl clients | grep class | awk '{print $2}' + hyprctl clients | awk '/class/{ print $2 }' end function _hyprctl_2 diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index 1a4cc187..aeac9663 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -1,15 +1,15 @@ #compdef hyprctl _hyprctl_cmd_2 () { - hyprctl monitors | grep Monitor | awk '{ print $2 }' + hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | grep "Plugin" | awk '{print $4}' + hyprpm list | awk '/Plugin/{ print $4 }' } _hyprctl_cmd_0 () { - hyprctl clients | grep class | awk '{print $2}' + hyprctl clients | awk '/class/{ print $2 }' } _hyprctl_cmd_1 () { From e894d5e964994e988ef75de4d95e98c9503235e1 Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Wed, 3 Jul 2024 15:40:18 -0400 Subject: [PATCH 0299/2393] tablet: Send .frame() on .proximity_out() (#6761) Co-authored-by: Agent_00Ming --- src/protocols/Tablet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 393dfd38..518ea5bd 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -599,10 +599,10 @@ void CTabletV2Protocol::proximityOut(SP tool) { if (t->tool != tool || !t->current) continue; - t->current = false; t->lastSurf.reset(); t->resource->sendProximityOut(); t->sendFrame(); + t->current = false; } } From 0a6e83005f1910b5c1ec78476fcffc05af47833a Mon Sep 17 00:00:00 2001 From: Lincoln Yuji de Oliveira <63720047+Lincoln-Yuji@users.noreply.github.com> Date: Thu, 4 Jul 2024 08:21:07 -0300 Subject: [PATCH 0300/2393] Completions: use only awk (#6763) --- hyprctl/hyprctl.usage | 6 +++--- hyprpm/hyprpm.bash | 2 +- hyprpm/hyprpm.fish | 2 +- hyprpm/hyprpm.usage | 2 +- hyprpm/hyprpm.zsh | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index 64cbbb80..298d253e 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -11,11 +11,11 @@ hyprctl []... | (-q | --quiet) "Disable output" ; - ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}}; + ::= {{{ hyprctl clients | awk '/class/{print $2}' }}}; - ::= {{{ hyprpm list | grep "Plugin" | awk '{print $4}' }}}; + ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}}; - ::= {{{ hyprctl monitors | grep Monitor | awk '{ print $2 }' }}}; + ::= {{{ hyprctl monitors | awk '/Monitor/{ print $2 }' }}}; ::= {{{ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' }}}; diff --git a/hyprpm/hyprpm.bash b/hyprpm/hyprpm.bash index 6989f7c1..ffc33e19 100644 --- a/hyprpm/hyprpm.bash +++ b/hyprpm/hyprpm.bash @@ -1,5 +1,5 @@ _hyprpm_cmd_0 () { - hyprpm list | grep Plugin | awk '{print $4}' + hyprpm list | awk '/Plugin/{print $4}' } _hyprpm () { diff --git a/hyprpm/hyprpm.fish b/hyprpm/hyprpm.fish index 81a1c59e..7be4f224 100644 --- a/hyprpm/hyprpm.fish +++ b/hyprpm/hyprpm.fish @@ -1,6 +1,6 @@ function _hyprpm_1 set 1 $argv[1] - hyprpm list | grep Plugin | awk '{print $4}' + hyprpm list | awk '/Plugin/{print $4}' end function _hyprpm diff --git a/hyprpm/hyprpm.usage b/hyprpm/hyprpm.usage index f321faf6..369c9d2b 100644 --- a/hyprpm/hyprpm.usage +++ b/hyprpm/hyprpm.usage @@ -16,4 +16,4 @@ hyprpm []... | (reload) "Reload all plugins" ; - ::= {{{ hyprpm list | grep Plugin | awk '{print $4}' }}}; + ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}}; diff --git a/hyprpm/hyprpm.zsh b/hyprpm/hyprpm.zsh index e355a1fa..854e8426 100644 --- a/hyprpm/hyprpm.zsh +++ b/hyprpm/hyprpm.zsh @@ -1,7 +1,7 @@ #compdef hyprpm _hyprpm_cmd_0 () { - hyprpm list | grep Plugin | awk '{print $4}' + hyprpm list | awk '/Plugin/{print $4}' } _hyprpm () { From 0502c3f62b1a562e7649ac72bd208b4a89d4f3f4 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Fri, 5 Jul 2024 20:46:38 +0000 Subject: [PATCH 0301/2393] keybinds: fix movewindow float to 0 (#6777) modified: src/managers/KeybindManager.cpp --- src/managers/KeybindManager.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f66b4457..cfc77c10 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1374,20 +1374,21 @@ void CKeybindManager::moveActiveTo(std::string args) { return; if (PLASTWINDOW->m_bIsFloating) { - Vector2D vPos; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID); - const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); + std::optional vPosx, vPosy; + const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID); + const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); switch (arg) { - case 'l': vPos.x = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break; - case 'r': vPos.x = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; + case 'l': vPosx = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break; + case 'r': vPosx = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; case 't': - case 'u': vPos.y = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break; + case 'u': vPosy = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break; case 'b': - case 'd': vPos.y = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; + case 'd': vPosy = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; } - PLASTWINDOW->m_vRealPosition = Vector2D(vPos.x != 0 ? vPos.x : PLASTWINDOW->m_vRealPosition.goal().x, vPos.y != 0 ? vPos.y : PLASTWINDOW->m_vRealPosition.goal().y); + PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition.goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition.goal().y)); + return; } From cc98594c3aed0b542e03818371a4636f549f80e1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 5 Jul 2024 23:05:03 +0200 Subject: [PATCH 0302/2393] pointer: update geometry after unplug events fixes #6700 fixes #6740 --- src/Compositor.cpp | 4 +-- src/managers/PointerManager.cpp | 5 +-- src/managers/eventLoop/EventLoopManager.cpp | 38 ++++++++++++++++----- src/managers/eventLoop/EventLoopManager.hpp | 14 ++++++-- 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2ed1a951..f0a2887a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -413,7 +413,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { switch (stage) { case STAGE_PRIORITY: { Debug::log(LOG, "Creating the EventLoopManager!"); - g_pEventLoopManager = std::make_unique(); + g_pEventLoopManager = std::make_unique(m_sWLDisplay, m_sWLEventLoop); Debug::log(LOG, "Creating the HookSystem!"); g_pHookSystem = std::make_unique(); @@ -604,7 +604,7 @@ void CCompositor::startCompositor() { // This blocks until we are done. Debug::log(LOG, "Hyprland is ready, running the event loop!"); - g_pEventLoopManager->enterLoop(m_sWLDisplay, m_sWLEventLoop); + g_pEventLoopManager->enterLoop(); } CMonitor* CCompositor::getMonitorFromID(const int& id) { diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 8b4ba0ee..e34aa54b 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -4,6 +4,7 @@ #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/core/Compositor.hpp" +#include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" #include #include @@ -139,8 +140,8 @@ CPointerManager::CPointerManager() { onMonitorLayoutChange(); - PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); - PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr); + PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( [this](void* owner, std::any data) { if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 1193ffb8..0d1b0223 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -9,8 +9,10 @@ #define TIMESPEC_NSEC_PER_SEC 1000000000L -CEventLoopManager::CEventLoopManager() { - m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { + m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + m_sWayland.loop = wlEventLoop; + m_sWayland.display = display; } CEventLoopManager::~CEventLoopManager() { @@ -23,13 +25,10 @@ static int timerWrite(int fd, uint32_t mask, void* data) { return 1; } -void CEventLoopManager::enterLoop(wl_display* display, wl_event_loop* wlEventLoop) { - m_sWayland.loop = wlEventLoop; - m_sWayland.display = display; +void CEventLoopManager::enterLoop() { + m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); - m_sWayland.eventSource = wl_event_loop_add_fd(wlEventLoop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); - - wl_display_run(display); + wl_display_run(m_sWayland.display); Debug::log(LOG, "Kicked off the event loop! :("); } @@ -86,4 +85,25 @@ void CEventLoopManager::nudgeTimers() { itimerspec ts = {.it_value = now}; timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr); -} \ No newline at end of file +} + +void CEventLoopManager::doLater(const std::function& fn) { + m_sIdle.fns.emplace_back(fn); + + if (m_sIdle.eventSource) + return; + + m_sIdle.eventSource = wl_event_loop_add_idle( + m_sWayland.loop, + [](void* data) { + auto IDLE = (CEventLoopManager::SIdleData*)data; + auto cpy = IDLE->fns; + IDLE->fns.clear(); + IDLE->eventSource = nullptr; + for (auto& c : cpy) { + if (c) + c(); + } + }, + &m_sIdle); +} diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 7a4fa19e..0b2f9578 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -9,10 +9,10 @@ class CEventLoopManager { public: - CEventLoopManager(); + CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop); ~CEventLoopManager(); - void enterLoop(wl_display* display, wl_event_loop* wlEventLoop); + void enterLoop(); // Note: will remove the timer if the ptr is lost. void addTimer(SP timer); @@ -23,6 +23,14 @@ class CEventLoopManager { // recalculates timers void nudgeTimers(); + // schedules a function to run later, aka in a wayland idle event. + void doLater(const std::function& fn); + + struct SIdleData { + wl_event_source* eventSource = nullptr; + std::vector> fns; + }; + private: struct { wl_event_loop* loop = nullptr; @@ -34,6 +42,8 @@ class CEventLoopManager { std::vector> timers; int timerfd = -1; } m_sTimers; + + SIdleData m_sIdle; }; inline std::unique_ptr g_pEventLoopManager; \ No newline at end of file From ede1e63f69e0356eaef10e3da30b86862df38e8c Mon Sep 17 00:00:00 2001 From: Maximilian Seidler Date: Fri, 5 Jul 2024 22:58:47 +0200 Subject: [PATCH 0303/2393] config: don't crash when getenv HOME returns null --- src/config/ConfigManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ff9d3a6d..12f3ac22 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -633,7 +633,12 @@ std::string CConfigManager::getConfigDir() { if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute()) return xdgConfigHome; - return getenv("HOME") + std::string("/.config"); + static const char* home = getenv("HOME"); + + if (!home) + throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME is set in the environment. Cannot determine config directory."); + + return home + std::string("/.config"); } std::string CConfigManager::getMainConfigPath() { From 19fb13e6cf7c9125b471780156fc423118914fb7 Mon Sep 17 00:00:00 2001 From: Yusuf <37774475+Yusuf-Duran@users.noreply.github.com> Date: Sun, 7 Jul 2024 17:52:56 +0200 Subject: [PATCH 0304/2393] internal: Add functions to hyprctl header (#6745) * add functions to hyprctl header * refactor monitor json into own function and add it to header * format hyprctl.hpp * move functions to namespace * move helper functions to class --- src/debug/HyprCtl.cpp | 76 +++++++++++++++++++++++-------------------- src/debug/HyprCtl.hpp | 4 +++ 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 571aa6d1..f96c071a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -70,26 +70,13 @@ static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFor return result; } -std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { - CVarList vars(request, 0, ' '); - auto allMonitors = false; +std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m, eHyprCtlOutputFormat format) { + std::string result; + if (!m->output || m->ID == -1ull) + return ""; - if (vars.size() > 2) - return "too many args"; - - if (vars.size() == 2 && vars[1] == "all") - allMonitors = true; - - std::string result = ""; - if (format == eHyprCtlOutputFormat::FORMAT_JSON) { - result += "["; - - for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { - if (!m->output || m->ID == -1ull) - continue; - - result += std::format( - R"#({{ + result += std::format( + R"#({{ "id": {}, "name": "{}", "description": "{}", @@ -120,14 +107,33 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { "currentFormat": "{}", "availableModes": [{}] }},)#", - m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""), - escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, - (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), - (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), - escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, - (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), - (m->dpmsStatus ? "true" : "false"), (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), - (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""), + escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, + m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), + m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, + (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, + (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), + (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), + (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + return result; +} + +std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { + CVarList vars(request, 0, ' '); + auto allMonitors = false; + + if (vars.size() > 2) + return "too many args"; + + if (vars.size() == 2 && vars[1] == "all") + allMonitors = true; + + std::string result = ""; + if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + result += "["; + + for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { + result += CHyprCtl::getMonitorData(m, format); } trimTrailingComma(result); @@ -188,7 +194,7 @@ static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) { return result.str(); } -static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { +std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { auto getFocusHistoryID = [](PHLWINDOW wnd) -> int { for (size_t i = 0; i < g_pCompositor->m_vWindowFocusHistory.size(); ++i) { if (g_pCompositor->m_vWindowFocusHistory[i].lock() == wnd) @@ -257,7 +263,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; - result += getWindowData(w, format); + result += CHyprCtl::getWindowData(w, format); } trimTrailingComma(result); @@ -268,13 +274,13 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; - result += getWindowData(w, format); + result += CHyprCtl::getWindowData(w, format); } } return result; } -static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { +std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { const auto PLASTW = w->getLastFocusedWindow(); const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID); if (format == eHyprCtlOutputFormat::FORMAT_JSON) { @@ -354,7 +360,7 @@ std::string activeWorkspaceRequest(eHyprCtlOutputFormat format, std::string requ if (!valid(w)) return "internal error"; - return getWorkspaceData(w, format); + return CHyprCtl::getWorkspaceData(w, format); } std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) { @@ -363,7 +369,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; for (auto& w : g_pCompositor->m_vWorkspaces) { - result += getWorkspaceData(w, format); + result += CHyprCtl::getWorkspaceData(w, format); result += ","; } @@ -371,7 +377,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) result += "]"; } else { for (auto& w : g_pCompositor->m_vWorkspaces) { - result += getWorkspaceData(w, format); + result += CHyprCtl::getWorkspaceData(w, format); } } @@ -404,7 +410,7 @@ std::string activeWindowRequest(eHyprCtlOutputFormat format, std::string request if (!validMapped(PWINDOW)) return format == eHyprCtlOutputFormat::FORMAT_JSON ? "{}" : "Invalid"; - auto result = getWindowData(PWINDOW, format); + auto result = CHyprCtl::getWindowData(PWINDOW, format); if (format == eHyprCtlOutputFormat::FORMAT_JSON) result.pop_back(); diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index 21a2c5f8..ccbd40cd 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -22,6 +22,10 @@ class CHyprCtl { bool sysInfoConfig = false; } m_sCurrentRequestParams; + static std::string getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format); + static std::string getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format); + static std::string getMonitorData(Hyprutils::Memory::CSharedPointer m, eHyprCtlOutputFormat format); + private: void startHyprCtlSocket(); From 22138ac259b2f4253be29311f6b60fbd675074b4 Mon Sep 17 00:00:00 2001 From: Virt <41426325+VirtCode@users.noreply.github.com> Date: Sun, 7 Jul 2024 21:27:18 +0200 Subject: [PATCH 0305/2393] workspaces: don't try to reopen special workspaces (#6802) --- src/helpers/Monitor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 199b1c5d..20c2e81e 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -652,6 +652,9 @@ void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, b } void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { + if (activeSpecialWorkspace == pWorkspace) + return; + g_pHyprRenderer->damageMonitor(this); if (!pWorkspace) { From 648f824b9e9ba58cc49962b0c58fc90892da2bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= Date: Mon, 8 Jul 2024 15:30:10 +0100 Subject: [PATCH 0306/2393] flake.lock: update --- flake.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index c1f37d2e..d3f40397 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1718450675, - "narHash": "sha256-jpsns6buS4bK+1sF8sL8AaixAiCRjA+nldTKvcwmvUs=", + "lastModified": 1720108799, + "narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "66d5b46ff94efbfa6fa3d1d1b66735f1779c34a6", + "rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486", "type": "github" }, "original": { @@ -38,11 +38,11 @@ ] }, "locked": { - "lastModified": 1714869498, - "narHash": "sha256-vbLVOWvQqo4n1yvkg/Q70VTlPbMmTiCQfNTgcWDCfJM=", + "lastModified": 1718746314, + "narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "e06482e0e611130cd1929f75e8c1cf679e57d161", + "rev": "1b61f0093afff20ab44d88ad707aed8bf2215290", "type": "github" }, "original": { @@ -64,11 +64,11 @@ ] }, "locked": { - "lastModified": 1717881852, - "narHash": "sha256-XeeVoKHQgfKuXoP6q90sUqKyl7EYy3ol2dVZGM+Jj94=", + "lastModified": 1720381373, + "narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "ec6938c66253429192274d612912649a0cfe4d28", + "rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb", "type": "github" }, "original": { @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1719316102, - "narHash": "sha256-dmRz128j/lJmMuTYeCYPfSBRHHQO3VeH4PbmoyAhHzw=", + "lastModified": 1720203444, + "narHash": "sha256-lq2dPPPcwMHTLsFrQ2pRp4c2LwDZWoqzSyjuPdeJCP4=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "1f6bbec5954f623ff8d68e567bddcce97cd2f085", + "rev": "a8c3a135701a7b64db0a88ec353a392f402d2a87", "type": "github" }, "original": { @@ -110,11 +110,11 @@ ] }, "locked": { - "lastModified": 1719067853, - "narHash": "sha256-mAnZG/eQy72Fp1ImGtqCgUrDumnR1rMZv2E/zgP4U74=", + "lastModified": 1720215857, + "narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "914f083741e694092ee60a39d31f693d0a6dc734", + "rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1719075281, - "narHash": "sha256-CyyxvOwFf12I91PBWz43iGT1kjsf5oi6ax7CrvaMyAo=", + "lastModified": 1720031269, + "narHash": "sha256-rwz8NJZV+387rnWpTYcXaRNvzUSnnF9aHONoJIYmiUQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a71e967ef3694799d0c418c98332f7ff4cc5f6af", + "rev": "9f4128e00b0ae8ec65918efeba59db998750ead6", "type": "github" }, "original": { @@ -179,11 +179,11 @@ ] }, "locked": { - "lastModified": 1718619174, - "narHash": "sha256-FWW68AVYmB91ZDQnhLMBNCUUTCjb1ZpO2k2KIytHtkA=", + "lastModified": 1720194466, + "narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "c7894aa54f9a7dbd16df5cd24d420c8af22d5623", + "rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6", "type": "github" }, "original": { From b03f41efec14273cf25c42d4cef326acc36cb319 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:46:42 -0500 Subject: [PATCH 0307/2393] xwayland: fix setting title prop (#6809) * fix setting xwayland title prop * add window title types --- src/xwayland/XWM.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index aa38910f..b34d0cfe 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -153,7 +153,7 @@ static bool lookupParentExists(SP XSURF, SP } void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply) { - std::string propName = "?"; + std::string propName = std::format("{}?", atom); for (auto& ha : HYPRATOMS) { if (ha.second != atom) continue; @@ -172,8 +172,10 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ XSURF->state.appid.pop_back(); XSURF->events.metadataChanged.emit(); } else if (atom == XCB_ATOM_WM_NAME || atom == HYPRATOMS["_NET_WM_NAME"]) { - size_t len = xcb_get_property_value_length(reply); - char* string = (char*)xcb_get_property_value(reply); + size_t len = xcb_get_property_value_length(reply); + char* string = (char*)xcb_get_property_value(reply); + if (reply->type != HYPRATOMS["UTF8_STRING"] && reply->type != HYPRATOMS["TEXT"] && reply->type != XCB_ATOM_STRING) + return; XSURF->state.title = std::string{string, len}; XSURF->events.metadataChanged.emit(); } else if (atom == HYPRATOMS["_NET_WM_WINDOW_TYPE"]) { @@ -520,7 +522,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); - return true; + return false; } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { From a443902abca6549839910720b80bd01faf10f387 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 11 Jul 2024 14:10:42 +0000 Subject: [PATCH 0308/2393] core: Improve handling of window properties (#6776) * add mWindowProperties modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp * support int values modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp * create m_sWindowData modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/DwindleLayout.cpp modified: src/layout/IHyprLayout.cpp modified: src/layout/MasterLayout.cpp modified: src/managers/AnimationManager.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/XWaylandManager.cpp modified: src/render/OpenGL.cpp modified: src/render/Renderer.cpp modified: src/render/decorations/CHyprBorderDecoration.cpp modified: src/render/decorations/CHyprDropShadowDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.cpp * simplify some properties modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/managers/KeybindManager.cpp * store multiple values in CWindowOverridableVar modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/IHyprLayout.cpp modified: src/managers/AnimationManager.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/XWaylandManager.cpp modified: src/render/OpenGL.cpp modified: src/render/Renderer.cpp modified: src/render/decorations/CHyprBorderDecoration.cpp modified: src/render/decorations/CHyprDropShadowDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.cpp * clean up modified: src/Compositor.cpp modified: src/Compositor.hpp modified: src/config/ConfigManager.cpp modified: src/config/ConfigManager.hpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/DwindleLayout.cpp modified: src/layout/IHyprLayout.cpp modified: src/layout/IHyprLayout.hpp modified: src/layout/MasterLayout.cpp modified: src/managers/KeybindManager.cpp * use SET_PROP priority for exec rules modified: src/config/ConfigManager.hpp modified: src/desktop/Window.cpp * add default value modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/IHyprLayout.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/XWaylandManager.cpp modified: src/render/OpenGL.cpp modified: src/render/Renderer.cpp modified: src/render/decorations/CHyprBorderDecoration.cpp modified: src/render/decorations/CHyprDropShadowDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.cpp * add setprop toggle modified: src/config/ConfigManager.hpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp * add setprop toggle modified: src/debug/HyprCtl.cpp * make window rules functional modified: src/config/ConfigManager.cpp modified: src/desktop/Window.cpp * minor fixes modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.hpp * properly clean layout data modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/DwindleLayout.cpp modified: src/layout/IHyprLayout.cpp modified: src/layout/IHyprLayout.hpp modified: src/layout/MasterLayout.cpp * remove newline modified: src/events/Windows.cpp * fixes modified: src/config/ConfigManager.hpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp * use CamelCase modified: src/Compositor.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/layout/IHyprLayout.cpp modified: src/managers/AnimationManager.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/XWaylandManager.cpp modified: src/render/OpenGL.cpp modified: src/render/Renderer.cpp modified: src/render/decorations/CHyprBorderDecoration.cpp modified: src/render/decorations/CHyprDropShadowDecoration.cpp modified: src/render/decorations/CHyprGroupBarDecoration.cpp --- src/Compositor.cpp | 43 ++-- src/Compositor.hpp | 2 +- src/config/ConfigManager.cpp | 29 +-- src/config/ConfigManager.hpp | 68 ++++-- src/debug/HyprCtl.cpp | 126 ++++------- src/desktop/Window.cpp | 210 +++++++----------- src/desktop/Window.hpp | 176 +++++++-------- src/events/Windows.cpp | 22 +- src/layout/DwindleLayout.cpp | 14 +- src/layout/IHyprLayout.cpp | 16 +- src/layout/MasterLayout.cpp | 14 +- src/managers/AnimationManager.cpp | 13 +- src/managers/KeybindManager.cpp | 7 +- src/managers/XWaylandManager.cpp | 3 +- src/render/OpenGL.cpp | 16 +- src/render/Renderer.cpp | 12 +- .../decorations/CHyprBorderDecoration.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 7 +- .../decorations/CHyprGroupBarDecoration.cpp | 4 +- 19 files changed, 364 insertions(+), 420 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f0a2887a..2abc1144 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -702,7 +702,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); - if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { + if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) return w; @@ -731,7 +731,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); - if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && + if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) @@ -784,7 +784,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && - !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) { + !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (w->hasPopupAt(pos)) return w; } @@ -796,7 +796,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && - !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) + !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) return w; } @@ -940,7 +940,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface return; } - if (pWindow->m_sAdditionalConfigData.noFocus) { + if (pWindow->m_sWindowData.noFocus.valueOrDefault()) { Debug::log(LOG, "Ignoring focus to nofocus window!"); return; } @@ -1579,7 +1579,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) return w; } @@ -1587,7 +1587,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) return w; } @@ -1608,7 +1608,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) return w; } @@ -1616,7 +1616,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sAdditionalConfigData.noFocus)) + if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) return w; } @@ -1804,13 +1804,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { if (pWindow == m_pLastWindow) { const auto* const ACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL); - setBorderColor(pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying().m_vColors.empty() ? *ACTIVECOLOR : - pWindow->m_sSpecialRenderData.activeBorderColor.toUnderlying()); + setBorderColor(pWindow->m_sWindowData.activeBorderColor.valueOr(*ACTIVECOLOR)); } else { const auto* const INACTIVECOLOR = !pWindow->m_sGroupData.pNextWindow.lock() ? (!pWindow->m_sGroupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL); - setBorderColor(pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying().m_vColors.empty() ? *INACTIVECOLOR : - pWindow->m_sSpecialRenderData.inactiveBorderColor.toUnderlying()); + setBorderColor(pWindow->m_sWindowData.inactiveBorderColor.valueOr(*INACTIVECOLOR)); } } @@ -1821,23 +1819,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // opacity const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { - pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() != -1 ? - (pWindow->m_sSpecialRenderData.alphaFullscreenOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() : - pWindow->m_sSpecialRenderData.alphaFullscreen.toUnderlying() * *PFULLSCREENALPHA) : - *PFULLSCREENALPHA; + pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { if (pWindow == m_pLastWindow) - pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alpha.toUnderlying() : - pWindow->m_sSpecialRenderData.alpha.toUnderlying() * *PACTIVEALPHA; + pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA); else - pWindow->m_fActiveInactiveAlpha = pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() != -1 ? - (pWindow->m_sSpecialRenderData.alphaInactiveOverride.toUnderlying() ? pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() : - pWindow->m_sSpecialRenderData.alphaInactive.toUnderlying() * *PINACTIVEALPHA) : - *PINACTIVEALPHA; + pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA); } // dim - if (pWindow == m_pLastWindow.lock() || pWindow->m_sAdditionalConfigData.forceNoDim || !*PDIMENABLED) { + if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) { pWindow->m_fDimPercent = 0; } else { pWindow->m_fDimPercent = *PDIMSTRENGTH; @@ -2268,7 +2259,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) { } } -void CCompositor::updateWorkspaceSpecialRenderData(const int& id) { +void CCompositor::updateWorkspaceWindowData(const int& id) { const auto PWORKSPACE = getWorkspaceByID(id); const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; @@ -2276,7 +2267,7 @@ void CCompositor::updateWorkspaceSpecialRenderData(const int& id) { if (w->workspaceID() != id) continue; - w->updateSpecialRenderData(WORKSPACERULE); + w->updateWindowData(WORKSPACERULE); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 5a1d8a64..17db2c8b 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -127,7 +127,7 @@ class CCompositor { PHLWORKSPACE getWorkspaceByString(const std::string&); void sanityCheckWorkspaces(); void updateWorkspaceWindowDecos(const int&); - void updateWorkspaceSpecialRenderData(const int&); + void updateWorkspaceWindowData(const int&); int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); PHLWINDOW getUrgentWindow(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 12f3ac22..01fac7cf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -844,7 +844,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (w->inert()) continue; g_pCompositor->updateWorkspaceWindows(w->m_iID); - g_pCompositor->updateWorkspaceSpecialRenderData(w->m_iID); + g_pCompositor->updateWorkspaceWindowData(w->m_iID); } // Update window border colors @@ -1058,14 +1058,14 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1, mergedRule.gapsOut = rule2.gapsOut; if (rule2.borderSize.has_value()) mergedRule.borderSize = rule2.borderSize; - if (rule2.border.has_value()) - mergedRule.border = rule2.border; - if (rule2.rounding.has_value()) - mergedRule.rounding = rule2.rounding; + if (rule2.noBorder.has_value()) + mergedRule.noBorder = rule2.noBorder; + if (rule2.noRounding.has_value()) + mergedRule.noRounding = rule2.noRounding; if (rule2.decorate.has_value()) mergedRule.decorate = rule2.decorate; - if (rule2.shadow.has_value()) - mergedRule.shadow = rule2.shadow; + if (rule2.noShadow.has_value()) + mergedRule.noShadow = rule2.noShadow; if (rule2.onCreatedEmptyRunCmd.has_value()) mergedRule.onCreatedEmptyRunCmd = rule2.onCreatedEmptyRunCmd; if (rule2.defaultName.has_value()) @@ -2086,16 +2086,17 @@ std::optional CConfigManager::handleUnbind(const std::string& comma bool windowRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{ - "dimaround", "fakefullscreen", "float", "focusonactivate", "forceinput", "forcergbx", "fullscreen", "immediate", - "keepaspectratio", "maximize", "nearestneighbor", "noanim", "noblur", "noborder", "nodim", "nofocus", - "noinitialfocus", "nomaxsize", "noshadow", "opaque", "pin", "stayfocused", "tile", "windowdance", + "fakefullscreen", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", }; static const auto rulesPrefix = std::vector{ "animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", }; - return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); + const auto VALS = CVarList(RULE, 2, ' '); + return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }) || + (g_pConfigManager->mbWindowProperties.find(VALS[0]) != g_pConfigManager->mbWindowProperties.end()) || + (g_pConfigManager->miWindowProperties.find(VALS[0]) != g_pConfigManager->miWindowProperties.end()); } bool layerRuleValid(const std::string& RULE) { @@ -2421,11 +2422,11 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin wsRule.borderSize = std::stoi(rule.substr(delim + 11)); } catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); } else if ((delim = rule.find("border:")) != std::string::npos) - wsRule.border = configStringToInt(rule.substr(delim + 7)); + wsRule.noBorder = !configStringToInt(rule.substr(delim + 7)); else if ((delim = rule.find("shadow:")) != std::string::npos) - wsRule.shadow = configStringToInt(rule.substr(delim + 7)); + wsRule.noShadow = !configStringToInt(rule.substr(delim + 7)); else if ((delim = rule.find("rounding:")) != std::string::npos) - wsRule.rounding = configStringToInt(rule.substr(delim + 9)); + wsRule.noRounding = !configStringToInt(rule.substr(delim + 9)); else if ((delim = rule.find("decorate:")) != std::string::npos) wsRule.decorate = configStringToInt(rule.substr(delim + 9)); else if ((delim = rule.find("monitor:")) != std::string::npos) diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index c43cb020..10021187 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -39,10 +39,10 @@ struct SWorkspaceRule { std::optional gapsIn; std::optional gapsOut; std::optional borderSize; - std::optional border; - std::optional rounding; - std::optional decorate; - std::optional shadow; + std::optional decorate; + std::optional noRounding; + std::optional noBorder; + std::optional noShadow; std::optional onCreatedEmptyRunCmd; std::optional defaultName; std::map layoutopts; @@ -148,25 +148,49 @@ class CConfigManager { std::string getErrors(); // keywords - std::optional handleRawExec(const std::string&, const std::string&); - std::optional handleExecOnce(const std::string&, const std::string&); - std::optional handleMonitor(const std::string&, const std::string&); - std::optional handleBind(const std::string&, const std::string&); - std::optional handleUnbind(const std::string&, const std::string&); - std::optional handleWindowRule(const std::string&, const std::string&); - std::optional handleLayerRule(const std::string&, const std::string&); - std::optional handleWindowRuleV2(const std::string&, const std::string&); - std::optional handleWorkspaceRules(const std::string&, const std::string&); - std::optional handleBezier(const std::string&, const std::string&); - std::optional handleAnimation(const std::string&, const std::string&); - std::optional handleSource(const std::string&, const std::string&); - std::optional handleSubmap(const std::string&, const std::string&); - std::optional handleBlurLS(const std::string&, const std::string&); - std::optional handleBindWS(const std::string&, const std::string&); - std::optional handleEnv(const std::string&, const std::string&); - std::optional handlePlugin(const std::string&, const std::string&); + std::optional handleRawExec(const std::string&, const std::string&); + std::optional handleExecOnce(const std::string&, const std::string&); + std::optional handleMonitor(const std::string&, const std::string&); + std::optional handleBind(const std::string&, const std::string&); + std::optional handleUnbind(const std::string&, const std::string&); + std::optional handleWindowRule(const std::string&, const std::string&); + std::optional handleLayerRule(const std::string&, const std::string&); + std::optional handleWindowRuleV2(const std::string&, const std::string&); + std::optional handleWorkspaceRules(const std::string&, const std::string&); + std::optional handleBezier(const std::string&, const std::string&); + std::optional handleAnimation(const std::string&, const std::string&); + std::optional handleSource(const std::string&, const std::string&); + std::optional handleSubmap(const std::string&, const std::string&); + std::optional handleBlurLS(const std::string&, const std::string&); + std::optional handleBindWS(const std::string&, const std::string&); + std::optional handleEnv(const std::string&, const std::string&); + std::optional handlePlugin(const std::string&, const std::string&); - std::string configCurrentPath; + std::string configCurrentPath; + + std::unordered_map*(PHLWINDOW)>> mbWindowProperties = { + {"allowsinput", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.allowsInput; }}, + {"dimaround", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.dimAround; }}, + {"decorate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.decorate; }}, + {"focusonactivate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.focusOnActivate; }}, + {"keepaspectratio", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.keepAspectRatio; }}, + {"nearestneighbor", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.nearestNeighbor; }}, + {"noanim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noAnim; }}, + {"noblur", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBlur; }}, + {"noborder", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noBorder; }}, + {"nodim", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noDim; }}, + {"nofocus", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noFocus; }}, + {"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }}, + {"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }}, + {"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }}, + {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }}, + {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }}, + {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }}, + {"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }}, + }; + + std::unordered_map*(PHLWINDOW)>> miWindowProperties = { + {"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}}; private: std::unique_ptr m_pConfig; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f96c071a..08d2bb57 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -317,10 +317,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : ""; const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; - const std::string border = (bool)(r.border) ? std::format(",\n \"border\": {}", boolToString(r.border.value())) : ""; - const std::string rounding = (bool)(r.rounding) ? std::format(",\n \"rounding\": {}", boolToString(r.rounding.value())) : ""; + const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; + const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; - const std::string shadow = (bool)(r.shadow) ? std::format(",\n \"shadow\": {}", boolToString(r.shadow.value())) : ""; + const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; std::string result = std::format(R"#({{ "workspaceString": "{}"{}{}{}{}{}{}{}{} @@ -339,10 +339,10 @@ static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputF std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : std::format("\tgapsOut: \n"); const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : ""); - const std::string border = std::format("\tborder: {}\n", (bool)(r.border) ? boolToString(r.border.value()) : ""); - const std::string rounding = std::format("\trounding: {}\n", (bool)(r.rounding) ? boolToString(r.rounding.value()) : ""); + const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : ""); + const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : ""); const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : ""); - const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.shadow) ? boolToString(r.shadow.value()) : ""); + const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : ""); std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); @@ -1202,74 +1202,44 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { const auto PROP = vars[2]; const auto VAL = vars[3]; - auto noFocus = PWINDOW->m_sAdditionalConfigData.noFocus; - - bool lock = false; - - if (request.ends_with("lock")) - lock = true; + bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault(); try { if (PROP == "animationstyle") { - PWINDOW->m_sAdditionalConfigData.animationStyle = VAL; - } else if (PROP == "rounding") { - PWINDOW->m_sAdditionalConfigData.rounding.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forcenoblur") { - PWINDOW->m_sAdditionalConfigData.forceNoBlur.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forceopaque") { - PWINDOW->m_sAdditionalConfigData.forceOpaque.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forceopaqueoverriden") { - PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forceallowsinput") { - PWINDOW->m_sAdditionalConfigData.forceAllowsInput.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forcenoanims") { - PWINDOW->m_sAdditionalConfigData.forceNoAnims.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forcenoborder") { - PWINDOW->m_sAdditionalConfigData.forceNoBorder.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forcenoshadow") { - PWINDOW->m_sAdditionalConfigData.forceNoShadow.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "forcenodim") { - PWINDOW->m_sAdditionalConfigData.forceNoDim.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "nofocus") { - PWINDOW->m_sAdditionalConfigData.noFocus.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "windowdancecompat") { - PWINDOW->m_sAdditionalConfigData.windowDanceCompat.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "nomaxsize") { - PWINDOW->m_sAdditionalConfigData.noMaxSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP); } else if (PROP == "maxsize") { - PWINDOW->m_sAdditionalConfigData.maxSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); - if (lock) { - PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), - std::min((double)PWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - PWINDOW->setHidden(false); - } + PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP); + PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x), + std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y)); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); + PWINDOW->setHidden(false); } else if (PROP == "minsize") { - PWINDOW->m_sAdditionalConfigData.minSize.forceSetIgnoreLocked(configStringToVector2D(VAL + " " + vars[4]), lock); - if (lock) { - PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().x, PWINDOW->m_vRealSize.goal().x), - std::max((double)PWINDOW->m_sAdditionalConfigData.minSize.toUnderlying().y, PWINDOW->m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - PWINDOW->setHidden(false); - } - } else if (PROP == "dimaround") { - PWINDOW->m_sAdditionalConfigData.dimAround.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "alphaoverride") { - PWINDOW->m_sSpecialRenderData.alphaOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP); + PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x), + std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y)); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); + PWINDOW->setHidden(false); } else if (PROP == "alpha") { - PWINDOW->m_sSpecialRenderData.alpha.forceSetIgnoreLocked(std::stof(VAL), lock); - } else if (PROP == "alphainactiveoverride") { - PWINDOW->m_sSpecialRenderData.alphaInactiveOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); } else if (PROP == "alphainactive") { - PWINDOW->m_sSpecialRenderData.alphaInactive.forceSetIgnoreLocked(std::stof(VAL), lock); - } else if (PROP == "alphafullscreenoverride") { - PWINDOW->m_sSpecialRenderData.alphaFullscreenOverride.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sWindowData.alphaInactive = + CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); } else if (PROP == "alphafullscreen") { - PWINDOW->m_sSpecialRenderData.alphaFullscreen.forceSetIgnoreLocked(std::stof(VAL), lock); + PWINDOW->m_sWindowData.alphaFullscreen = + CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); + } else if (PROP == "alphaoverride") { + PWINDOW->m_sWindowData.alpha = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + } else if (PROP == "alphainactiveoverride") { + PWINDOW->m_sWindowData.alphaInactive = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + } else if (PROP == "alphafullscreenoverride") { + PWINDOW->m_sWindowData.alphaFullscreen = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { CGradientValueData colorData = {}; if (vars.size() > 4) { - for (int i = 3; i < static_cast(lock ? vars.size() - 1 : vars.size()); ++i) { + for (int i = 3; i < static_cast(vars.size()); ++i) { const auto TOKEN = vars[i]; if (TOKEN.ends_with("deg")) colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); @@ -1280,19 +1250,22 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { colorData.m_vColors.push_back(configStringToInt(VAL)); if (PROP == "activebordercolor") - PWINDOW->m_sSpecialRenderData.activeBorderColor.forceSetIgnoreLocked(colorData, lock); + PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); else - PWINDOW->m_sSpecialRenderData.inactiveBorderColor.forceSetIgnoreLocked(colorData, lock); - } else if (PROP == "forcergbx") { - PWINDOW->m_sAdditionalConfigData.forceRGBX.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "bordersize") { - PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "keepaspectratio") { - PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "immediate") { - PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock); - } else if (PROP == "nearestneighbor") { - PWINDOW->m_sAdditionalConfigData.nearestNeighbor.forceSetIgnoreLocked(configStringToInt(VAL), lock); + PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); + } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) { + auto pWindowDataElement = search->second(PWINDOW); + if (VAL == "toggle") + *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP); + else if (VAL == "unset") + pWindowDataElement->unset(PRIORITY_SET_PROP); + else + *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP); + } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) { + if (VAL == "unset") + search->second(PWINDOW)->unset(PRIORITY_SET_PROP); + else + *(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP); } else { return "prop not found"; } @@ -1300,7 +1273,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { g_pCompositor->updateAllWindowsAnimatedDecorationValues(); - if (!(PWINDOW->m_sAdditionalConfigData.noFocus.toUnderlying() == noFocus.toUnderlying())) { + if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) { g_pCompositor->focusWindow(nullptr); g_pCompositor->focusWindow(PWINDOW); g_pCompositor->focusWindow(PLASTWINDOW); @@ -1848,7 +1821,6 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) { } void CHyprCtl::startHyprCtlSocket() { - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); if (m_iSocketFD < 0) { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 560e5103..2dc5846b 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -110,7 +110,7 @@ SBoxExtents CWindow::getFullWindowExtents() { const int BORDERSIZE = getRealBorderSize(); - if (m_sAdditionalConfigData.dimAround) { + if (m_sWindowData.dimAround.valueOrDefault()) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; @@ -170,7 +170,7 @@ SBoxExtents CWindow::getFullWindowExtents() { } CBox CWindow::getFullWindowBoundingBox() { - if (m_sAdditionalConfigData.dimAround) { + if (m_sWindowData.dimAround.valueOrDefault()) { if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } @@ -218,7 +218,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { } CBox CWindow::getWindowBoxUnified(uint64_t properties) { - if (m_sAdditionalConfigData.dimAround) { + if (m_sWindowData.dimAround.valueOrDefault()) { const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); if (PMONITOR) return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; @@ -411,11 +411,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { setAnimationsToMove(); g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); - g_pCompositor->updateWorkspaceSpecialRenderData(OLDWORKSPACE->m_iID); + g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID); g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); + g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -524,7 +524,7 @@ void CWindow::onUnmap() { PMONITOR->solitaryClient.reset(); g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); + g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -607,38 +607,15 @@ bool CWindow::isHidden() { } void CWindow::applyDynamicRule(const SWindowRule& r) { - if (r.szRule == "noblur") { - m_sAdditionalConfigData.forceNoBlur = true; - } else if (r.szRule == "noborder") { - m_sAdditionalConfigData.forceNoBorder = true; - } else if (r.szRule == "noshadow") { - m_sAdditionalConfigData.forceNoShadow = true; - } else if (r.szRule == "nodim") { - m_sAdditionalConfigData.forceNoDim = true; - } else if (r.szRule == "forcergbx") { - m_sAdditionalConfigData.forceRGBX = true; - } else if (r.szRule == "opaque") { - if (!m_sAdditionalConfigData.forceOpaqueOverridden) - m_sAdditionalConfigData.forceOpaque = true; - } else if (r.szRule == "immediate") { - m_sAdditionalConfigData.forceTearing = true; - } else if (r.szRule == "nearestneighbor") { - m_sAdditionalConfigData.nearestNeighbor = true; - } else if (r.szRule.starts_with("tag")) { + const eOverridePriority priority = r.szValue == "execRule" ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE; + const CVarList VARS(r.szRule, 0, ' '); + if (r.szRule.starts_with("tag")) { CVarList vars{r.szRule, 0, 's', true}; if (vars.size() == 2 && vars[0] == "tag") m_tags.applyTag(vars[1], true); else Debug::log(ERR, "Tag rule invalid: {}", r.szRule); - } else if (r.szRule.starts_with("rounding")) { - try { - m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); - } catch (std::exception& e) { Debug::log(ERR, "Rounding rule \"{}\" failed with: {}", r.szRule, e.what()); } - } else if (r.szRule.starts_with("bordersize")) { - try { - m_sAdditionalConfigData.borderSize = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1)); - } catch (std::exception& e) { Debug::log(ERR, "Bordersize rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("opacity")) { try { CVarList vars(r.szRule, 0, ' '); @@ -651,21 +628,18 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { if (r == "override") { if (opacityIDX == 1) - m_sSpecialRenderData.alphaOverride = true; + m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{m_sWindowData.alpha.value().m_fAlpha, true}, priority); else if (opacityIDX == 2) - m_sSpecialRenderData.alphaInactiveOverride = true; + m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaInactive.value().m_fAlpha, true}, priority); else if (opacityIDX == 3) - m_sSpecialRenderData.alphaFullscreenOverride = true; + m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{m_sWindowData.alphaFullscreen.value().m_fAlpha, true}, priority); } else { if (opacityIDX == 0) { - m_sSpecialRenderData.alpha = std::stof(r); - m_sSpecialRenderData.alphaOverride = false; + m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority); } else if (opacityIDX == 1) { - m_sSpecialRenderData.alphaInactive = std::stof(r); - m_sSpecialRenderData.alphaInactiveOverride = false; + m_sWindowData.alphaInactive = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority); } else if (opacityIDX == 2) { - m_sSpecialRenderData.alphaFullscreen = std::stof(r); - m_sSpecialRenderData.alphaFullscreenOverride = false; + m_sWindowData.alphaFullscreen = CWindowOverridableVar(SAlphaValue{std::stof(r), false}, priority); } else { throw std::runtime_error("more than 3 alpha values"); } @@ -675,17 +649,13 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } if (opacityIDX == 1) { - m_sSpecialRenderData.alphaInactiveOverride = m_sSpecialRenderData.alphaOverride; - m_sSpecialRenderData.alphaInactive = m_sSpecialRenderData.alpha; - m_sSpecialRenderData.alphaFullscreenOverride = m_sSpecialRenderData.alphaOverride; - m_sSpecialRenderData.alphaFullscreen = m_sSpecialRenderData.alpha; + m_sWindowData.alphaInactive = m_sWindowData.alpha; + m_sWindowData.alphaFullscreen = m_sWindowData.alpha; } } catch (std::exception& e) { Debug::log(ERR, "Opacity rule \"{}\" failed with: {}", r.szRule, e.what()); } - } else if (r.szRule == "noanim") { - m_sAdditionalConfigData.forceNoAnims = true; } else if (r.szRule.starts_with("animation")) { - auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); - m_sAdditionalConfigData.animationStyle = STYLE; + auto STYLE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); + m_sWindowData.animationStyle = CWindowOverridableVar(STYLE, priority); } else if (r.szRule.starts_with("bordercolor")) { try { // Each vector will only get used if it has at least one color @@ -696,8 +666,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { // Basic form has only two colors, everything else can be parsed as a gradient if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { - m_sSpecialRenderData.activeBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))); - m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))); + m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority); + m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority); return; } @@ -720,24 +690,24 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { else if (activeBorderGradient.m_vColors.empty()) Debug::log(WARN, "Bordercolor rule \"{}\" has no colors, ignoring", r.szRule); else if (inactiveBorderGradient.m_vColors.empty()) - m_sSpecialRenderData.activeBorderColor = activeBorderGradient; + m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority); else { - m_sSpecialRenderData.activeBorderColor = activeBorderGradient; - m_sSpecialRenderData.inactiveBorderColor = inactiveBorderGradient; + m_sWindowData.activeBorderColor = CWindowOverridableVar(activeBorderGradient, priority); + m_sWindowData.inactiveBorderColor = CWindowOverridableVar(inactiveBorderGradient, priority); } } catch (std::exception& e) { Debug::log(ERR, "BorderColor rule \"{}\" failed with: {}", r.szRule, e.what()); } - } else if (r.szRule == "dimaround") { - m_sAdditionalConfigData.dimAround = true; - } else if (r.szRule == "keepaspectratio") { - m_sAdditionalConfigData.keepAspectRatio = true; - } else if (r.szRule.starts_with("focusonactivate")) { - m_sAdditionalConfigData.focusOnActivate = true; - } else if (r.szRule.starts_with("xray")) { - CVarList vars(r.szRule, 0, ' '); - + } else if (auto search = g_pConfigManager->mbWindowProperties.find(VARS[0]); search != g_pConfigManager->mbWindowProperties.end()) { + if (VARS[1].empty()) { + *(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority); + } else { + try { + *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority); + } catch (...) {} + } + } else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) { try { - m_sAdditionalConfigData.xray = configStringToInt(vars[1]); - } catch (...) {} + *(search->second(m_pSelf.lock())) = CWindowOverridableVar(std::stoi(VARS[1]), priority); + } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("idleinhibit")) { auto IDLERULE = r.szRule.substr(r.szRule.find_first_of(' ') + 1); @@ -761,9 +731,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { return; } - m_sAdditionalConfigData.maxSize = VEC; - m_vRealSize = Vector2D(std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().x, m_vRealSize.goal().x), - std::min((double)m_sAdditionalConfigData.maxSize.toUnderlying().y, m_vRealSize.goal().y)); + m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority); + m_vRealSize = + Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("minsize")) { @@ -776,9 +746,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { return; } - m_sAdditionalConfigData.minSize = VEC; - m_vRealSize = Vector2D(std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().x, m_vRealSize.goal().x), - std::max((double)m_sAdditionalConfigData.minSize.toUnderlying().y, m_vRealSize.goal().y)); + m_sWindowData.minSize = CWindowOverridableVar(VEC, priority); + m_vRealSize = + Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y)); g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); if (m_sGroupData.pNextWindow.expired()) setHidden(false); @@ -787,30 +757,20 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } void CWindow::updateDynamicRules() { - m_sSpecialRenderData.activeBorderColor = CGradientValueData(); - m_sSpecialRenderData.inactiveBorderColor = CGradientValueData(); - m_sSpecialRenderData.alpha = 1.f; - m_sSpecialRenderData.alphaInactive = -1.f; - m_sAdditionalConfigData.forceNoBlur = false; - m_sAdditionalConfigData.forceNoBorder = false; - m_sAdditionalConfigData.forceNoShadow = false; - m_sAdditionalConfigData.forceNoDim = false; - if (!m_sAdditionalConfigData.forceOpaqueOverridden) - m_sAdditionalConfigData.forceOpaque = false; - m_sAdditionalConfigData.maxSize = Vector2D(std::numeric_limits::max(), std::numeric_limits::max()); - m_sAdditionalConfigData.minSize = Vector2D(20, 20); - m_sAdditionalConfigData.forceNoAnims = false; - m_sAdditionalConfigData.animationStyle = std::string(""); - m_sAdditionalConfigData.rounding = -1; - m_sAdditionalConfigData.dimAround = false; - m_sAdditionalConfigData.forceRGBX = false; - m_sAdditionalConfigData.borderSize = -1; - m_sAdditionalConfigData.keepAspectRatio = false; - m_sAdditionalConfigData.focusOnActivate = false; - m_sAdditionalConfigData.xray = -1; - m_sAdditionalConfigData.forceTearing = false; - m_sAdditionalConfigData.nearestNeighbor = false; - m_eIdleInhibitMode = IDLEINHIBIT_NONE; + m_sWindowData.alpha.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.alphaInactive.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.alphaFullscreen.unset(PRIORITY_WINDOW_RULE); + + unsetWindowData(PRIORITY_WINDOW_RULE); + + m_sWindowData.animationStyle.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.maxSize.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.minSize.unset(PRIORITY_WINDOW_RULE); + + m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE); + + m_eIdleInhibitMode = IDLEINHIBIT_NONE; m_tags.removeDynamicTags(); @@ -887,7 +847,7 @@ void CWindow::createGroup() { addWindowDeco(std::make_unique(m_pSelf.lock())); g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); + g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -905,7 +865,7 @@ void CWindow::destroyGroup() { m_sGroupData.head = false; updateWindowDecos(); g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); + g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -941,7 +901,7 @@ void CWindow::destroyGroup() { g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(workspaceID()); + g_pCompositor->updateWorkspaceWindowData(workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -1159,48 +1119,43 @@ bool CWindow::opaque() { float CWindow::rounding() { static auto PROUNDING = CConfigValue("decoration:rounding"); - float rounding = m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_sAdditionalConfigData.rounding.toUnderlying(); + float rounding = m_sWindowData.rounding.valueOr(*PROUNDING); - return m_sSpecialRenderData.rounding ? rounding : 0; + return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding; } -void CWindow::updateSpecialRenderData() { +void CWindow::updateWindowData() { const auto PWORKSPACE = m_pWorkspace; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; - updateSpecialRenderData(WORKSPACERULE); + updateWindowData(WORKSPACERULE); } -void CWindow::updateSpecialRenderData(const SWorkspaceRule& workspaceRule) { +void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) { static auto PNOBORDERONFLOATING = CConfigValue("general:no_border_on_floating"); - bool border = true; - if (m_bIsFloating && *PNOBORDERONFLOATING == 1) - border = false; + if (*PNOBORDERONFLOATING) + m_sWindowData.noBorder = CWindowOverridableVar(m_bIsFloating, PRIORITY_LAYOUT); + else + m_sWindowData.noBorder.unset(PRIORITY_LAYOUT); - m_sSpecialRenderData.border = workspaceRule.border.value_or(border); - m_sSpecialRenderData.borderSize = workspaceRule.borderSize.value_or(-1); - m_sSpecialRenderData.decorate = workspaceRule.decorate.value_or(true); - m_sSpecialRenderData.rounding = workspaceRule.rounding.value_or(true); - m_sSpecialRenderData.shadow = workspaceRule.shadow.value_or(true); + m_sWindowData.borderSize.matchOptional(workspaceRule.borderSize, PRIORITY_WORKSPACE_RULE); + m_sWindowData.decorate.matchOptional(workspaceRule.decorate, PRIORITY_WORKSPACE_RULE); + m_sWindowData.noBorder.matchOptional(workspaceRule.noBorder, PRIORITY_WORKSPACE_RULE); + m_sWindowData.noRounding.matchOptional(workspaceRule.noRounding, PRIORITY_WORKSPACE_RULE); + m_sWindowData.noShadow.matchOptional(workspaceRule.noShadow, PRIORITY_WORKSPACE_RULE); } int CWindow::getRealBorderSize() { - if (!m_sSpecialRenderData.border || m_sAdditionalConfigData.forceNoBorder || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) + if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) return 0; - if (m_sAdditionalConfigData.borderSize.toUnderlying() != -1) - return m_sAdditionalConfigData.borderSize.toUnderlying(); - - if (m_sSpecialRenderData.borderSize.toUnderlying() != -1) - return m_sSpecialRenderData.borderSize.toUnderlying(); - static auto PBORDERSIZE = CConfigValue("general:border_size"); - return *PBORDERSIZE; + return m_sWindowData.borderSize.valueOr(*PBORDERSIZE); } bool CWindow::canBeTorn() { - return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint); + return m_sWindowData.tearing.valueOr(m_bTearingHint); } bool CWindow::shouldSendFullscreenState() { @@ -1349,8 +1304,7 @@ void CWindow::activate(bool force) { m_bIsUrgent = true; - if (!force && - (!(*PFOCUSONACTIVATE || m_sAdditionalConfigData.focusOnActivate) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) + if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) return; if (m_bIsFloating) @@ -1526,9 +1480,6 @@ void CWindow::onX11Configure(CBox box) { m_bCreatedOverFullscreen = true; - if (!m_sAdditionalConfigData.windowDanceCompat) - g_pInputManager->refocus(); - g_pHyprRenderer->damageWindow(m_pSelf.lock()); } @@ -1597,3 +1548,12 @@ PHLWINDOW CWindow::getSwallower() { // if none are found (??) then just return the first one return candidates.at(0); } + +void CWindow::unsetWindowData(eOverridePriority priority) { + for (auto const& element : g_pConfigManager->mbWindowProperties) { + element.second(m_pSelf.lock())->unset(priority); + } + for (auto const& element : g_pConfigManager->miWindowProperties) { + element.second(m_pSelf.lock())->unset(priority); + } +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 6bfdbc50..60189fac 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -59,13 +59,36 @@ enum eSuppressEvents { class IWindowTransformer; +struct SAlphaValue { + float m_fAlpha; + bool m_bOverride; + + float applyAlpha(float alpha) { + if (m_bOverride) + return m_fAlpha; + else + return m_fAlpha * alpha; + }; +}; + +enum eOverridePriority { + PRIORITY_LAYOUT, + PRIORITY_WORKSPACE_RULE, + PRIORITY_WINDOW_RULE, + PRIORITY_SET_PROP, +}; + template class CWindowOverridableVar { public: - CWindowOverridableVar(T const& val) { - value = val; + CWindowOverridableVar(T const& value, eOverridePriority priority) { + values[priority] = value; + } + CWindowOverridableVar(T const& value) { + defaultValue = value; } + CWindowOverridableVar() = default; ~CWindowOverridableVar() = default; CWindowOverridableVar& operator=(CWindowOverridableVar const& other) { @@ -73,112 +96,91 @@ class CWindowOverridableVar { if (this == &other) return *this; - // Check if the current object is locked - if (!locked) { - locked = other.locked; - value = other.value; + for (auto const& value : other.values) { + values[value.first] = value.second; } return *this; } - T operator=(T& other) { - if (locked) - return value; - value = other; - return other; + void unset(eOverridePriority priority) { + values.erase(priority); } - void forceSetIgnoreLocked(T const& val, bool lock = false) { - value = val; - locked = lock; + bool hasValue() { + return !values.empty(); } - T operator*(T const& other) { - return value * other; + T value() { + if (!values.empty()) + return std::prev(values.end())->second; + else + throw std::bad_optional_access(); } - T operator+(T const& other) { - return value + other; + T valueOr(T const& other) { + if (hasValue()) + return value(); + else + return other; } - bool operator==(T const& other) { - return other == value; + T valueOrDefault() { + return valueOr(defaultValue); } - bool operator>=(T const& other) { - return value >= other; + eOverridePriority getPriority() { + if (!values.empty()) + return std::prev(values.end())->first; + else + throw std::bad_optional_access(); } - bool operator<=(T const& other) { - return value <= other; + void matchOptional(std::optional const& optValue, eOverridePriority priority) { + if (optValue.has_value()) + values[priority] = optValue.value(); + else + unset(priority); } - bool operator>(T const& other) { - return value > other; - } - - bool operator<(T const& other) { - return value < other; - } - - explicit operator bool() { - return static_cast(value); - } - - T toUnderlying() { - return value; - } - - bool locked = false; - private: - T value; + std::map values; + T defaultValue; // used for toggling, so required for bool }; -struct SWindowSpecialRenderData { - CWindowOverridableVar alphaOverride = false; - CWindowOverridableVar alpha = 1.f; - CWindowOverridableVar alphaInactiveOverride = false; - CWindowOverridableVar alphaInactive = -1.f; // -1 means unset - CWindowOverridableVar alphaFullscreenOverride = false; - CWindowOverridableVar alphaFullscreen = -1.f; // -1 means unset +struct SWindowData { + CWindowOverridableVar alpha = SAlphaValue{1.f, false}; + CWindowOverridableVar alphaInactive = SAlphaValue{1.f, false}; + CWindowOverridableVar alphaFullscreen = SAlphaValue{1.f, false}; - CWindowOverridableVar activeBorderColor = CGradientValueData(); // empty color vector means unset - CWindowOverridableVar inactiveBorderColor = CGradientValueData(); // empty color vector means unset + CWindowOverridableVar allowsInput = false; + CWindowOverridableVar dimAround = false; + CWindowOverridableVar decorate = true; + CWindowOverridableVar focusOnActivate = false; + CWindowOverridableVar keepAspectRatio = false; + CWindowOverridableVar nearestNeighbor = false; + CWindowOverridableVar noAnim = false; + CWindowOverridableVar noBorder = false; + CWindowOverridableVar noBlur = false; + CWindowOverridableVar noDim = false; + CWindowOverridableVar noFocus = false; + CWindowOverridableVar noMaxSize = false; + CWindowOverridableVar noRounding = false; + CWindowOverridableVar noShadow = false; + CWindowOverridableVar opaque = false; + CWindowOverridableVar RGBX = false; + CWindowOverridableVar tearing = false; + CWindowOverridableVar xray = false; - // set by the layout - CWindowOverridableVar borderSize = -1; // -1 means unset - bool rounding = true; - bool border = true; - bool decorate = true; - bool shadow = true; -}; + CWindowOverridableVar rounding; + CWindowOverridableVar borderSize; -struct SWindowAdditionalConfigData { - std::string animationStyle = std::string(""); - CWindowOverridableVar rounding = -1; // -1 means no - CWindowOverridableVar forceNoBlur = false; - CWindowOverridableVar forceOpaque = false; - CWindowOverridableVar forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. - CWindowOverridableVar forceAllowsInput = false; - CWindowOverridableVar forceNoAnims = false; - CWindowOverridableVar forceNoBorder = false; - CWindowOverridableVar forceNoShadow = false; - CWindowOverridableVar forceNoDim = false; - CWindowOverridableVar noFocus = false; - CWindowOverridableVar windowDanceCompat = false; - CWindowOverridableVar noMaxSize = false; - CWindowOverridableVar maxSize = Vector2D(std::numeric_limits::max(), std::numeric_limits::max()); - CWindowOverridableVar minSize = Vector2D(20, 20); - CWindowOverridableVar dimAround = false; - CWindowOverridableVar forceRGBX = false; - CWindowOverridableVar keepAspectRatio = false; - CWindowOverridableVar focusOnActivate = false; - CWindowOverridableVar xray = -1; // -1 means unset, takes precedence over the renderdata one - CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one - CWindowOverridableVar forceTearing = false; - CWindowOverridableVar nearestNeighbor = false; + CWindowOverridableVar animationStyle; + CWindowOverridableVar maxSize; + CWindowOverridableVar minSize; + + CWindowOverridableVar activeBorderColor; + CWindowOverridableVar inactiveBorderColor; }; struct SWindowRule { @@ -331,8 +333,7 @@ class CWindow { std::vector m_vDecosToRemove; // Special render data, rules, etc - SWindowSpecialRenderData m_sSpecialRenderData; - SWindowAdditionalConfigData m_sAdditionalConfigData; + SWindowData m_sWindowData; // Transformers std::vector> m_vTransformers; @@ -423,8 +424,8 @@ class CWindow { int surfacesCount(); int getRealBorderSize(); - void updateSpecialRenderData(); - void updateSpecialRenderData(const struct SWorkspaceRule&); + void updateWindowData(); + void updateWindowData(const struct SWorkspaceRule&); void onBorderAngleAnimEnd(void* ptr); bool isInCurvedCorner(double x, double y); @@ -455,6 +456,7 @@ class CWindow { std::string fetchClass(); void warpCursor(); PHLWINDOW getSwallower(); + void unsetWindowData(eOverridePriority priority); // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index bb1197e5..1612deeb 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -196,8 +196,6 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bIsFloating = false; } else if (r.szRule.starts_with("pseudo")) { PWINDOW->m_bIsPseudotiled = true; - } else if (r.szRule.starts_with("nofocus")) { - PWINDOW->m_sAdditionalConfigData.noFocus = true; } else if (r.szRule.starts_with("noinitialfocus")) { PWINDOW->m_bNoInitialFocus = true; } else if (r.szRule.starts_with("suppressevent")) { @@ -219,12 +217,6 @@ void Events::listener_mapWindow(void* owner, void* data) { overridingNoFullscreen = true; } else if (r.szRule == "fakefullscreen") { requestsFakeFullscreen = true; - } else if (r.szRule == "windowdance") { - PWINDOW->m_sAdditionalConfigData.windowDanceCompat = true; - } else if (r.szRule == "nomaxsize") { - PWINDOW->m_sAdditionalConfigData.noMaxSize = true; - } else if (r.szRule == "forceinput") { - PWINDOW->m_sAdditionalConfigData.forceAllowsInput = true; } else if (r.szRule == "pin") { PWINDOW->m_bPinned = true; } else if (r.szRule == "maximize") { @@ -321,7 +313,7 @@ void Events::listener_mapWindow(void* owner, void* data) { workspaceSilent = false; } - PWINDOW->updateSpecialRenderData(); + PWINDOW->updateWindowData(); if (PWINDOW->m_bIsFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); @@ -457,10 +449,10 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); - if (PWINDOW->m_sAdditionalConfigData.forceAllowsInput) { - PWINDOW->m_sAdditionalConfigData.noFocus = false; - PWINDOW->m_bNoInitialFocus = false; - PWINDOW->m_bX11ShouldntFocus = false; + if (PWINDOW->m_sWindowData.allowsInput.valueOrDefault()) { // if default value wasn't set to false getPriority() would throw an exception + PWINDOW->m_sWindowData.noFocus = CWindowOverridableVar(false, PWINDOW->m_sWindowData.allowsInput.getPriority()); + PWINDOW->m_bNoInitialFocus = false; + PWINDOW->m_bX11ShouldntFocus = false; } // check LS focus grab @@ -479,12 +471,12 @@ void Events::listener_mapWindow(void* owner, void* data) { requestsFullscreen = true; } - if (!PWINDOW->m_sAdditionalConfigData.noFocus && !PWINDOW->m_bNoInitialFocus && + if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); - PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sAdditionalConfigData.forceNoDim ? 0.f : *PDIMSTRENGTH); + PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); } else { PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); PWINDOW->m_fDimPercent.setValueAndWarp(0); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index cbeaa420..d1b4b7ca 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -139,7 +139,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) return; - PWINDOW->updateSpecialRenderData(); + PWINDOW->unsetWindowData(PRIORITY_LAYOUT); static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); static auto PGAPSINDATA = CConfigValue("general:gaps_in"); @@ -160,10 +160,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { - PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); - PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); - PWINDOW->m_sSpecialRenderData.rounding = false; - PWINDOW->m_sSpecialRenderData.shadow = false; + PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->updateWindowDecos(); @@ -496,7 +496,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { return; } - pWindow->updateSpecialRenderData(); + pWindow->unsetWindowData(PRIORITY_LAYOUT); if (pWindow->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); @@ -830,7 +830,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; - pWindow->updateSpecialRenderData(); + pWindow->unsetWindowData(PRIORITY_LAYOUT); } } else { // if it now got fullscreen, make it fullscreen diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index c6a7a66c..56d22d4b 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -386,8 +386,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { - Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sAdditionalConfigData.minSize.toUnderlying()); - Vector2D MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sAdditionalConfigData.maxSize.toUnderlying()); + Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20))); + Vector2D MAXSIZE; + if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue()) + MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value()); + else + MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, Vector2D(std::numeric_limits::max(), std::numeric_limits::max())); Vector2D newSize = m_vBeginDragSizeXY; Vector2D newPos = m_vBeginDragPositionXY; @@ -403,7 +407,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || - (!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sAdditionalConfigData.keepAspectRatio))) { + (!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault()))) { const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x; @@ -538,7 +542,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); - pWindow->updateSpecialRenderData(); + pWindow->unsetWindowData(PRIORITY_LAYOUT); if (pWindow == m_pLastTiledWindow) m_pLastTiledWindow.reset(); @@ -587,7 +591,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // find whether there is a floating window below this one for (auto& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && - !w->m_sAdditionalConfigData.noFocus && w != pWindow) { + !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) { if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) { return w; @@ -607,7 +611,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // if not, floating window for (auto& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && - !w->m_sAdditionalConfigData.noFocus && w != pWindow) + !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) return w; } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 965c0ed7..b5f2fa9f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -264,7 +264,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { const auto MASTERSLEFT = getMastersOnWorkspace(WORKSPACEID); static auto SMALLSPLIT = CConfigValue("master:allow_small_split"); - pWindow->updateSpecialRenderData(); + pWindow->unsetWindowData(PRIORITY_LAYOUT); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); @@ -646,7 +646,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) return; - PWINDOW->updateSpecialRenderData(); + PWINDOW->unsetWindowData(PRIORITY_LAYOUT); static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); @@ -669,10 +669,10 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { - PWINDOW->m_sSpecialRenderData.border = WORKSPACERULE.border.value_or(*PNOGAPSWHENONLY == 2); - PWINDOW->m_sSpecialRenderData.decorate = WORKSPACERULE.decorate.value_or(true); - PWINDOW->m_sSpecialRenderData.rounding = false; - PWINDOW->m_sSpecialRenderData.shadow = false; + PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); + PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->updateWindowDecos(); @@ -922,7 +922,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; - pWindow->updateSpecialRenderData(); + pWindow->unsetWindowData(PRIORITY_LAYOUT); } } else { // if it now got fullscreen, make it fullscreen diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 1fec375e..677b2109 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -102,7 +102,7 @@ void CAnimationManager::tick() { PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (!PMONITOR) continue; - animationsDisabled = animationsDisabled || PWINDOW->m_sAdditionalConfigData.forceNoAnims; + animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); } else if (PWORKSPACE) { PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); if (!PMONITOR) @@ -407,18 +407,19 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled) return; - if (pWindow->m_sAdditionalConfigData.animationStyle != "") { + if (pWindow->m_sWindowData.animationStyle.hasValue()) { + const auto STYLE = pWindow->m_sWindowData.animationStyle.value(); // the window has config'd special anim - if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) { - CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's'); + if (STYLE.starts_with("slide")) { + CVarList animList2(STYLE, 0, 's'); animationSlide(pWindow, animList2[1], close); } else { // anim popin, fallback float minPerc = 0.f; - if (pWindow->m_sAdditionalConfigData.animationStyle.find("%") != std::string::npos) { + if (STYLE.find("%") != std::string::npos) { try { - auto percstr = pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find_last_of(' ')); + auto percstr = STYLE.substr(STYLE.find_last_of(' ')); minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); } catch (std::exception& e) { ; // oops diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index cfc77c10..eb8a3232 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -252,7 +252,7 @@ bool CKeybindManager::ensureMouseBindState() { g_pInputManager->dragMode = MBIND_INVALID; g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(lastDraggedWindow->workspaceID()); + g_pCompositor->updateWorkspaceWindowData(lastDraggedWindow->workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -974,7 +974,7 @@ static void toggleActiveFloatingCore(std::string args, std::optional float g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); } g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); - g_pCompositor->updateWorkspaceSpecialRenderData(PWINDOW->workspaceID()); + g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); } @@ -2239,8 +2239,7 @@ void CKeybindManager::toggleOpaque(std::string unused) { if (!PWINDOW) return; - PWINDOW->m_sAdditionalConfigData.forceOpaque = !PWINDOW->m_sAdditionalConfigData.forceOpaque; - PWINDOW->m_sAdditionalConfigData.forceOpaqueOverridden = true; + PWINDOW->m_sWindowData.opaque = CWindowOverridableVar(!PWINDOW->m_sWindowData.opaque.valueOrDefault(), PRIORITY_SET_PROP); g_pHyprRenderer->damageWindow(PWINDOW); } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 12387900..e702a172 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -206,7 +206,8 @@ Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return Vector2D(99999, 99999); - if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || pWindow->m_sAdditionalConfigData.noMaxSize) + if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || + pWindow->m_sWindowData.noMaxSize.valueOrDefault()) return Vector2D(99999, 99999); auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 3178ab8c..2b603868 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -434,7 +434,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (!w->m_bIsFloating && *POPTIM && !w->onSpecialWorkspace()) continue; - if (w->m_sAdditionalConfigData.forceNoBlur.toUnderlying() == true || w->m_sAdditionalConfigData.xray.toUnderlying() == true) + if (w->m_sWindowData.noBlur.valueOrDefault() || w->m_sWindowData.xray.valueOrDefault() == true) continue; if (w->opaque()) @@ -1130,7 +1130,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB } } - if (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX) + if (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sWindowData.RGBX.valueOrDefault()) shader = &m_RenderData.pCurrentMonData->m_shRGBX; glActiveTexture(GL_TEXTURE0); @@ -1601,7 +1601,7 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { if (!pWindow) return false; - if (pWindow->m_sAdditionalConfigData.forceNoBlur) + if (pWindow->m_sWindowData.noBlur.valueOrDefault()) return false; if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) @@ -1717,7 +1717,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) return false; - if (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 0) + if (pWindow && !pWindow->m_sWindowData.xray.valueOrDefault()) return false; if (pLayer && pLayer->xray == 0) @@ -1726,7 +1726,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin if ((*PBLURNEWOPTIMIZE && pWindow && !pWindow->m_bIsFloating && !pWindow->onSpecialWorkspace()) || *PBLURXRAY) return true; - if ((pLayer && pLayer->xray == 1) || (pWindow && pWindow->m_sAdditionalConfigData.xray.toUnderlying() == 1)) + if ((pLayer && pLayer->xray == 1) || (pWindow && pWindow->m_sWindowData.xray.valueOrDefault())) return true; return false; @@ -1750,7 +1750,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.renderModif.applyToRegion(texDamage); if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || - (m_pCurrentWindow.lock() && (m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur || m_pCurrentWindow->m_sAdditionalConfigData.forceRGBX))) { + (m_pCurrentWindow.lock() && (m_pCurrentWindow->m_sWindowData.noBlur.valueOrDefault() || m_pCurrentWindow->m_sWindowData.RGBX.valueOrDefault()))) { renderTexture(tex, pBox, a, round, false, true); return; } @@ -1847,7 +1847,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in TRACY_GPU_ZONE("RenderBorder"); - if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBorder)) + if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sWindowData.noBorder.valueOrDefault())) return; CBox newBox = *box; @@ -2108,7 +2108,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; - if (*PDIMAROUND && pWindow->m_sAdditionalConfigData.dimAround) { + if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault()) { CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y}; g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value())); g_pHyprRenderer->damageMonitor(PMONITOR); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8d98a182..955a16b9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -531,7 +531,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec decorate = false; renderdata.surface = pWindow->m_pWLSurface->resource(); - renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || (!pWindow->m_sSpecialRenderData.rounding); + renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || pWindow->m_sWindowData.noRounding.valueOrDefault(); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); @@ -545,14 +545,14 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } // apply opaque - if (pWindow->m_sAdditionalConfigData.forceOpaque) + if (pWindow->m_sWindowData.opaque.valueOrDefault()) renderdata.alpha = 1.f; g_pHyprOpenGL->m_pCurrentWindow = pWindow; EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOW); - if (*PDIMAROUND && pWindow->m_sAdditionalConfigData.dimAround && !m_bRenderingSnapshot && mode != RENDER_PASS_POPUP) { + if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault() && !m_bRenderingSnapshot && mode != RENDER_PASS_POPUP) { CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y}; g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha)); } @@ -597,10 +597,10 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } static auto PXWLUSENN = CConfigValue("xwayland:use_nearest_neighbor"); - if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) + if ((pWindow->m_bIsX11 && *PXWLUSENN) || pWindow->m_sWindowData.nearestNeighbor.valueOrDefault()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - if (!pWindow->m_sAdditionalConfigData.forceNoBlur && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { + if (!pWindow->m_sWindowData.noBlur.valueOrDefault() && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, @@ -662,7 +662,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec g_pHyprOpenGL->m_RenderData.discardOpacity = *PBLURIGNOREA; } - if (pWindow->m_sAdditionalConfigData.nearestNeighbor.toUnderlying()) + if (pWindow->m_sWindowData.nearestNeighbor.valueOrDefault()) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; renderdata.surfaceCounter = 0; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 7d9a0401..708215b6 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -133,5 +133,5 @@ std::string CHyprBorderDecoration::getDisplayName() { } bool CHyprBorderDecoration::doesntWantBorders() { - return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders || m_pWindow->getRealBorderSize() == 0; + return m_pWindow->m_sWindowData.noBorder.valueOrDefault() || m_pWindow->m_bX11DoesntWantBorders || m_pWindow->getRealBorderSize() == 0; } diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 6893d78c..423256d7 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -96,13 +96,10 @@ void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { if (PWINDOW->m_cRealShadowColor.value() == CColor(0, 0, 0, 0)) return; // don't draw invisible shadows - if (!PWINDOW->m_sSpecialRenderData.decorate) + if (!PWINDOW->m_sWindowData.decorate.valueOrDefault()) return; - if (!PWINDOW->m_sSpecialRenderData.shadow) - return; - - if (PWINDOW->m_sAdditionalConfigData.forceNoShadow) + if (PWINDOW->m_sWindowData.noShadow.valueOrDefault()) return; static auto PSHADOWS = CConfigValue("decoration:drop_shadow"); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index e461ba08..a13750d0 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -42,7 +42,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { info.priority = *PPRIORITY; info.reserved = true; - if (*PENABLED && m_pWindow->m_sSpecialRenderData.decorate) { + if (*PENABLED && m_pWindow->m_sWindowData.decorate.valueOrDefault()) { if (*PSTACKED) { const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT}, {0, 0}}; @@ -105,7 +105,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - if (!*PENABLED || !m_pWindow->m_sSpecialRenderData.decorate) + if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) return; const auto ASSIGNEDBOX = assignedBoxGlobal(); From 3247d18a7c257ac8c59bf9bfdebaaf51bfc5c1df Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 11 Jul 2024 14:12:19 +0000 Subject: [PATCH 0309/2393] [gha] Nix: update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index d3f40397..1066e37b 100644 --- a/flake.lock +++ b/flake.lock @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1720203444, - "narHash": "sha256-lq2dPPPcwMHTLsFrQ2pRp4c2LwDZWoqzSyjuPdeJCP4=", + "lastModified": 1720545076, + "narHash": "sha256-Pxacc2uoxI00koXp5+CyNqHOTQlqNlK0rlRHDBHX4+g=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "a8c3a135701a7b64db0a88ec353a392f402d2a87", + "rev": "6174a2a25f4e216c0f1d0c4278adc23c476b1d09", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720031269, - "narHash": "sha256-rwz8NJZV+387rnWpTYcXaRNvzUSnnF9aHONoJIYmiUQ=", + "lastModified": 1720542800, + "narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9f4128e00b0ae8ec65918efeba59db998750ead6", + "rev": "feb2849fdeb70028c70d73b848214b00d324a497", "type": "github" }, "original": { From 9ff83f4aa97269bf26381a84501d0b19f1926961 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 11 Jul 2024 16:40:43 +0200 Subject: [PATCH 0310/2393] sessionLock: fix the check for locking a locked session (#6843) --- src/protocols/SessionLock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index e7abc7cb..42df5fd6 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -177,7 +177,7 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { return; } - if (m_vLocks.size() > 1) { + if (locked) { LOGM(ERR, "Tried to lock a locked session"); RESOURCE->inert = true; RESOURCE->resource->sendFinished(); From e728e56cbc6af0a9be1276b2cf8e019a894016e7 Mon Sep 17 00:00:00 2001 From: Virt <41426325+VirtCode@users.noreply.github.com> Date: Mon, 8 Jul 2024 22:50:39 +0200 Subject: [PATCH 0311/2393] meson: install wayland.hpp header --- protocols/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/protocols/meson.build b/protocols/meson.build index f4978c23..7c508659 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -113,7 +113,8 @@ foreach p : wl_server_protos wl_server_protos_gen += custom_target( p.underscorify(), input: p, - install: false, + install: true, + install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], ) From f85c6416c6f5e56c75178ecb24c11e346069197d Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:05:19 +0000 Subject: [PATCH 0312/2393] renderer: fix a few xray regressions (#6855) * fix xray unset modified: src/render/OpenGL.cpp * fix xwray unset modified: src/render/OpenGL.cpp --- src/render/OpenGL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 2b603868..2556fafc 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -434,7 +434,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (!w->m_bIsFloating && *POPTIM && !w->onSpecialWorkspace()) continue; - if (w->m_sWindowData.noBlur.valueOrDefault() || w->m_sWindowData.xray.valueOrDefault() == true) + if (w->m_sWindowData.noBlur.valueOrDefault() || !w->m_sWindowData.xray.hasValue() || w->m_sWindowData.xray.valueOrDefault()) continue; if (w->opaque()) @@ -1717,7 +1717,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) return false; - if (pWindow && !pWindow->m_sWindowData.xray.valueOrDefault()) + if (pWindow && pWindow->m_sWindowData.xray.hasValue() && !pWindow->m_sWindowData.xray.valueOrDefault()) return false; if (pLayer && pLayer->xray == 0) From 7486576fa7a3d394254cb07734679df4b2469071 Mon Sep 17 00:00:00 2001 From: Junxuan Liao <70618504+MikeWalrus@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:32:08 +0800 Subject: [PATCH 0313/2393] session-lock: send `locked` after the lock screen is properly rendered (#6850) The protocol says: > The locked event "must not be sent until a new "locked" frame (either from a > session lock surface or the compositor blanking the output) has been presented > on all outputs and no security sensitive normal/unlocked content is possibly > visible". This helps users ensure the screen is properly locked before suspending the machine. (e.g. with swaylock --ready-fd) --- src/managers/SessionLockManager.cpp | 15 +++++++++++++-- src/managers/SessionLockManager.hpp | 8 +++++++- src/render/Renderer.cpp | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index b4695e0e..83ff3ee7 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/SessionLock.hpp" +#include SSessionLockSurface::SSessionLockSurface(SP surface_) : surface(surface_) { pWlrSurface = surface->surface(); @@ -77,7 +78,6 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pHyprRenderer->damageMonitor(m.get()); }); - pLock->sendLocked(); g_pCompositor->focusSurface(nullptr); } @@ -102,7 +102,6 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64 } // We don't want the red screen to flash. -// This violates the protocol a bit, but tries to handle the missing sync between a lock surface beeing created and the red screen beeing drawn. float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { if (!m_pSessionLock) return 0.F; @@ -118,6 +117,18 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f); } +void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) { + if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked) + return; + m_pSessionLock->m_lockedMonitors.emplace(id); + const auto MONITORS = g_pCompositor->m_vMonitors; + const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); + if (LOCKED) { + m_pSessionLock->lock->sendLocked(); + m_pSessionLock->m_hasSentLocked = true; + } +} + bool CSessionLockManager::isSurfaceSessionLock(SP pSurface) { // TODO: this has some edge cases when it's wrong (e.g. destroyed lock but not yet surfaces) // but can be easily fixed when I rewrite wlr_surface diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index fe4a4434..b01ee288 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -5,6 +5,7 @@ #include "../helpers/signal/Signal.hpp" #include #include +#include class CSessionLockSurface; class CSessionLock; @@ -37,6 +38,9 @@ struct SSessionLock { CHyprSignalListener unlock; CHyprSignalListener destroy; } listeners; + + bool m_hasSentLocked = false; + std::unordered_set m_lockedMonitors; }; class CSessionLockManager { @@ -54,6 +58,8 @@ class CSessionLockManager { void removeSessionLockSurface(SSessionLockSurface*); + void onLockscreenRenderedOnMonitor(uint64_t id); + private: UP m_pSessionLock; @@ -64,4 +70,4 @@ class CSessionLockManager { void onNewSessionLock(SP pWlrLock); }; -inline std::unique_ptr g_pSessionLockManager; \ No newline at end of file +inline std::unique_ptr g_pSessionLockManager; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 955a16b9..a7f3c941 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -990,8 +990,11 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB if (ALPHA < 1.f) /* animate */ damageMonitor(pMonitor); + else + g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } else { renderSessionLockSurface(PSLS, pMonitor, now); + g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } } } From 13bc7e1e1415a0b17db609774f59b594c7633941 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 13 Jul 2024 12:36:29 +0200 Subject: [PATCH 0314/2393] style: fix clang-format --- src/Compositor.cpp | 3 ++- src/config/ConfigDataValues.hpp | 14 +++++++------- src/helpers/MiscFunctions.cpp | 8 ++------ src/macros.hpp | 3 +-- src/managers/PointerManager.cpp | 3 +-- src/managers/input/InputManager.cpp | 3 +-- src/managers/input/TextInput.cpp | 9 +++------ src/protocols/Tablet.cpp | 3 +-- src/render/Renderbuffer.cpp | 3 +-- 9 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2abc1144..d1c51075 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -702,7 +702,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); - if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { + if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && + w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) return w; diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 322bd14a..37c9fc92 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -20,11 +20,11 @@ class ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData { public: - CGradientValueData(){}; + CGradientValueData() {}; CGradientValueData(CColor col) { m_vColors.push_back(col); }; - virtual ~CGradientValueData(){}; + virtual ~CGradientValueData() {}; virtual eConfigValueDataTypes getDataType() { return CVD_TYPE_GRADIENT; @@ -67,11 +67,11 @@ class CGradientValueData : public ICustomConfigValueData { class CCssGapData : public ICustomConfigValueData { public: - CCssGapData() : top(0), right(0), bottom(0), left(0){}; - CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global){}; - CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal){}; - CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal){}; - CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left){}; + CCssGapData() : top(0), right(0), bottom(0), left(0) {}; + CCssGapData(int64_t global) : top(global), right(global), bottom(global), left(global) {}; + CCssGapData(int64_t vertical, int64_t horizontal) : top(vertical), right(horizontal), bottom(vertical), left(horizontal) {}; + CCssGapData(int64_t top, int64_t horizontal, int64_t bottom) : top(top), right(horizontal), bottom(bottom), left(horizontal) {}; + CCssGapData(int64_t top, int64_t right, int64_t bottom, int64_t left) : top(top), right(right), bottom(bottom), left(left) {}; /* Css like directions */ int64_t top; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index aa034254..712e4e50 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -649,13 +649,9 @@ void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) { int64_t getPPIDof(int64_t pid) { #if defined(KERN_PROC_PID) int mib[] = { - CTL_KERN, - KERN_PROC, - KERN_PROC_PID, - (int)pid, + CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid, #if defined(__NetBSD__) || defined(__OpenBSD__) - sizeof(KINFO_PROC), - 1, + sizeof(KINFO_PROC), 1, #endif }; u_int miblen = sizeof(mib) / sizeof(mib[0]); diff --git a/src/macros.hpp b/src/macros.hpp index 67f6301b..f1393cbd 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -40,8 +40,7 @@ #define STICKS(a, b) abs((a) - (b)) < 2 -#define HYPRATOM(name) \ - { name, 0 } +#define HYPRATOM(name) {name, 0} #define RASSERT(expr, reason, ...) \ if (!(expr)) { \ diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index e34aa54b..7090645f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -235,8 +235,7 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, currentCursorImage.size = {buf->width, buf->height}; currentCursorImage.pBuffer = wlr_buffer_lock(buf); - currentCursorImage.hyprListener_destroyBuffer.initCallback( - &buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager"); + currentCursorImage.hyprListener_destroyBuffer.initCallback(&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager"); } currentCursorImage.hotspot = hotspot; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 9180e9cd..b2bbd577 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1624,8 +1624,7 @@ void CInputManager::newSwitch(wlr_input_device* pDevice) { Debug::log(LOG, "New switch with name \"{}\" added", pDevice->name); - PNEWDEV->hyprListener_destroy.initCallback( - &pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice"); + PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice"); const auto PSWITCH = wlr_switch_from_input_device(pDevice); diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 4c7ffe6e..635a8b01 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -41,14 +41,11 @@ void CTextInput::initCallbacks() { g_pInputManager->m_sIMERelay.removeTextInput(this); }); } else { - hyprListener_textInputEnable.initCallback( - &pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput"); + hyprListener_textInputEnable.initCallback(&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput"); - hyprListener_textInputCommit.initCallback( - &pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput"); + hyprListener_textInputCommit.initCallback(&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput"); - hyprListener_textInputDisable.initCallback( - &pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput"); + hyprListener_textInputDisable.initCallback(&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput"); hyprListener_textInputDestroy.initCallback( &pV1Input->sDestroy, diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 518ea5bd..7b62f245 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -215,8 +215,7 @@ void CTabletToolV2Resource::queueFrame() { if (frameSource) return; - frameSource = wl_event_loop_add_idle( - g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this); + frameSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this); } void CTabletToolV2Resource::sendFrame(bool removeSource) { diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index b55a921b..3f591d13 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -58,8 +58,7 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); - hyprListener_destroyBuffer.initCallback( - &buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); + hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); } CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { From 1f6466895326defef370a378f9d7b61a7e246df7 Mon Sep 17 00:00:00 2001 From: Tim Waterhouse Date: Sat, 13 Jul 2024 03:53:23 -0700 Subject: [PATCH 0315/2393] ext-foreign-toplevel: Send done after title and class (#6857) According to the spec (https://wayland.app/protocols/ext-foreign-toplevel-list-v1#ext_foreign_toplevel_handle_v1:event:title), clients should wait for the done signal before applying updates --- src/protocols/ForeignToplevel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 40420da7..f7b3886f 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -81,6 +81,7 @@ void CForeignToplevelList::onTitle(PHLWINDOW pWindow) { return; H->resource->sendTitle(pWindow->m_szTitle.c_str()); + H->resource->sendDone(); } void CForeignToplevelList::onClass(PHLWINDOW pWindow) { @@ -92,6 +93,7 @@ void CForeignToplevelList::onClass(PHLWINDOW pWindow) { return; H->resource->sendAppId(pWindow->m_szClass.c_str()); + H->resource->sendDone(); } void CForeignToplevelList::onUnmap(PHLWINDOW pWindow) { From a770a88e0962f37c0b6f36f1876cbf27db4cf3c9 Mon Sep 17 00:00:00 2001 From: David De Sousa Date: Sat, 13 Jul 2024 12:53:53 +0200 Subject: [PATCH 0316/2393] toplevelexport: fix flipped r/b channels when sharing windows (#6861) fixes #6823 --- src/protocols/ToplevelExport.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 287538b5..d4c66c3b 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -409,7 +409,8 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, frame->box.width, frame->box.height, PFORMAT->glFormat, PFORMAT->glType, pixelData); + auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; + glReadPixels(0, 0, frame->box.width, frame->box.height, glFormat, PFORMAT->glType, pixelData); if (frame->overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); From 45c48984236d7a682a1941b147f8ae489ac9a1e6 Mon Sep 17 00:00:00 2001 From: Tim Waterhouse Date: Sat, 13 Jul 2024 07:21:32 -0700 Subject: [PATCH 0317/2393] socket2: Add windowtitlev2 event which includes the window address (#6856) Fixes #5393 --- src/desktop/Window.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 2dc5846b..4ea34156 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1343,6 +1343,7 @@ void CWindow::onUpdateMeta() { if (m_szTitle != NEWTITLE) { m_szTitle = NEWTITLE; g_pEventManager->postEvent(SHyprIPCEvent{"windowtitle", std::format("{:x}", (uintptr_t)this)}); + g_pEventManager->postEvent(SHyprIPCEvent{"windowtitlev2", std::format("{:x},{}", (uintptr_t)this, m_szTitle)}); EMIT_HOOK_EVENT("windowTitle", m_pSelf.lock()); if (m_pSelf == g_pCompositor->m_pLastWindow) { // if it's the active, let's post an event to update others From ed6c701144b827869e0c0fca7a7849ec251bf9ef Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:29:07 +0000 Subject: [PATCH 0318/2393] renderer: partially revert previous xray fix (#6868) modified: src/render/OpenGL.cpp --- src/render/OpenGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 2556fafc..cb3d2e71 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -434,7 +434,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (!w->m_bIsFloating && *POPTIM && !w->onSpecialWorkspace()) continue; - if (w->m_sWindowData.noBlur.valueOrDefault() || !w->m_sWindowData.xray.hasValue() || w->m_sWindowData.xray.valueOrDefault()) + if (w->m_sWindowData.noBlur.valueOrDefault() || w->m_sWindowData.xray.valueOrDefault()) continue; if (w->opaque()) From bc6b0880dda2607a80f000c134f573c970452a0f Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen <86177399+nktnet1@users.noreply.github.com> Date: Sun, 14 Jul 2024 04:44:32 +1000 Subject: [PATCH 0319/2393] window: override noMaximize if new window takes over fullscreen (#6812) (#6870) --- src/events/Windows.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 1612deeb..44e8fa02 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -465,9 +465,11 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bNoInitialFocus = true; else if (*PNEWTAKESOVERFS == 2) g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); - else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) + else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { requestsMaximize = true; - else + if (*PNEWTAKESOVERFS == 1) + overridingNoMaximize = true; + } else requestsFullscreen = true; } From f442f435d34e983768fcc83b54374ac94a7f7658 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Mon, 15 Jul 2024 09:57:52 +0000 Subject: [PATCH 0320/2393] layout: update workspace rules on layout change (#6878) modified: src/layout/DwindleLayout.cpp modified: src/layout/IHyprLayout.cpp modified: src/layout/MasterLayout.cpp --- src/layout/DwindleLayout.cpp | 3 +++ src/layout/IHyprLayout.cpp | 1 + src/layout/MasterLayout.cpp | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index d1b4b7ca..7fa6fdbc 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -140,6 +140,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for return; PWINDOW->unsetWindowData(PRIORITY_LAYOUT); + PWINDOW->updateWindowData(); static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); static auto PGAPSINDATA = CConfigValue("general:gaps_in"); @@ -497,6 +498,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { } pWindow->unsetWindowData(PRIORITY_LAYOUT); + pWindow->updateWindowData(); if (pWindow->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); @@ -831,6 +833,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); + pWindow->updateWindowData(); } } else { // if it now got fullscreen, make it fullscreen diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 56d22d4b..528cea72 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -543,6 +543,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); pWindow->unsetWindowData(PRIORITY_LAYOUT); + pWindow->updateWindowData(); if (pWindow == m_pLastTiledWindow) m_pLastTiledWindow.reset(); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index b5f2fa9f..d7f264e7 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -265,6 +265,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { static auto SMALLSPLIT = CConfigValue("master:allow_small_split"); pWindow->unsetWindowData(PRIORITY_LAYOUT); + pWindow->updateWindowData(); g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); @@ -647,6 +648,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { return; PWINDOW->unsetWindowData(PRIORITY_LAYOUT); + PWINDOW->updateWindowData(); static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); @@ -923,6 +925,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); + pWindow->updateWindowData(); } } else { // if it now got fullscreen, make it fullscreen From bd526822deb9ed47c0b51b534817aa8541fff07b Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen <86177399+nktnet1@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:48:04 +1000 Subject: [PATCH 0321/2393] config: add option to exit window while retaining fullscreen (#516) (#6880) * feat: saving fullscreen mode and state for restoring later * style: no p-prefix, capitalised constants --- src/config/ConfigManager.cpp | 1 + src/events/Windows.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 01fac7cf..04d29f3a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -352,6 +352,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:close_special_on_empty", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:background_color", Hyprlang::INT{0xff111111}); m_pConfig->addConfigValue("misc:new_window_takes_over_fullscreen", Hyprlang::INT{0}); + m_pConfig->addConfigValue("misc:exit_window_retains_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 44e8fa02..516ac2ae 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -580,6 +580,11 @@ void Events::listener_unmapWindow(void* owner, void* data) { Debug::log(LOG, "{:c} unmapped", PWINDOW); + static auto PEXITRETAINSFS = CConfigValue("misc:exit_window_retains_fullscreen"); + + const auto CURRENTWINDOWFSSTATE = PWINDOW->m_bIsFullscreen; + const auto CURRENTWINDOWFSMODE = PWINDOW->m_pWorkspace->m_efFullscreenMode; + if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); PWINDOW->m_bFadingOut = false; @@ -638,8 +643,11 @@ void Events::listener_unmapWindow(void* owner, void* data) { Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); - if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) + if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) { g_pCompositor->focusWindow(PWINDOWCANDIDATE); + if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE) + g_pCompositor->setWindowFullscreen(PWINDOWCANDIDATE, true, CURRENTWINDOWFSMODE); + } if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) g_pInputManager->refocus(); From da956c8a979471282db6790f5fa5dcec320ec226 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 16 Jul 2024 22:23:37 +0300 Subject: [PATCH 0322/2393] config: use hyprutils helper (#6891) * flake.lock: update nix/overlays: remove xwayland overlay (merged upstream) * config: use hyprutils helper * flake.lock: update * CMake & Meson: update required versions --- CMakeLists.txt | 2 +- flake.lock | 12 +++---- nix/overlays.nix | 11 ------ src/config/ConfigManager.cpp | 69 ++++++++++++++++++------------------ src/config/ConfigManager.hpp | 18 +++++----- src/meson.build | 4 +-- src/render/OpenGL.cpp | 2 +- 7 files changed, 53 insertions(+), 65 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d41dd6e5..07fa8cf6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.5 + hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.0 ) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index 1066e37b..b5f5738a 100644 --- a/flake.lock +++ b/flake.lock @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1720545076, - "narHash": "sha256-Pxacc2uoxI00koXp5+CyNqHOTQlqNlK0rlRHDBHX4+g=", + "lastModified": 1721071737, + "narHash": "sha256-qmC9jGfbE4+EIBbbSAkrfR/p49wShjpv4/KztgE/P54=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "6174a2a25f4e216c0f1d0c4278adc23c476b1d09", + "rev": "eb1ceff2b87f6820789249f63faa8e9dcb54d05f", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720542800, - "narHash": "sha256-ZgnNHuKV6h2+fQ5LuqnUaqZey1Lqqt5dTUAiAnqH0QQ=", + "lastModified": 1720957393, + "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "feb2849fdeb70028c70d73b848214b00d324a497", + "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", "type": "github" }, "original": { diff --git a/nix/overlays.nix b/nix/overlays.nix index cc66e1b5..a4e1df37 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -25,7 +25,6 @@ in { inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default - self.overlays.xwayland # Hyprland packages themselves (final: prev: let @@ -63,14 +62,4 @@ in { hyprland-extras = lib.composeManyExtensions [ inputs.xdph.overlays.xdg-desktop-portal-hyprland ]; - - # Patches XWayland's pkgconfig file to not include Cflags or includedir - # The above two variables trip up CMake and the build fails - xwayland = final: prev: { - xwayland = prev.xwayland.overrideAttrs (old: { - postInstall = '' - sed -i '/includedir/d' $out/lib/pkgconfig/xwayland.pc - ''; - }); - }; } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 04d29f3a..944aa0b2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -628,25 +629,49 @@ CConfigManager::CConfigManager() { g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0}); } -std::string CConfigManager::getConfigDir() { - static const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); +std::optional CConfigManager::generateConfig(std::string configPath) { + std::string parentPath = std::filesystem::path(configPath).parent_path(); - if (xdgConfigHome && std::filesystem::path(xdgConfigHome).is_absolute()) - return xdgConfigHome; + if (!std::filesystem::is_directory(parentPath)) { + Debug::log(WARN, "Creating config home directory"); + try { + std::filesystem::create_directories(parentPath); + } catch (std::exception e) { throw e; } + } - static const char* home = getenv("HOME"); + Debug::log(WARN, "No config file found; attempting to generate."); + std::ofstream ofs; + ofs.open(configPath, std::ios::trunc); + ofs << AUTOCONFIG; + ofs.close(); - if (!home) - throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME is set in the environment. Cannot determine config directory."); + if (!std::filesystem::exists(configPath)) + return "Config could not be generated."; - return home + std::string("/.config"); + return configPath; } std::string CConfigManager::getMainConfigPath() { if (!g_pCompositor->explicitConfigPath.empty()) return g_pCompositor->explicitConfigPath; - return getConfigDir() + "/hypr/" + (ISDEBUG ? "hyprlandd.conf" : "hyprland.conf"); + static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); + if (paths.first.has_value()) { + return paths.first.value(); + } else if (paths.second.has_value()) { + auto configPath = Hyprutils::Path::fullConfigPath(paths.second.value(), ISDEBUG ? "hyprlandd" : "hyprland"); + return generateConfig(configPath).value(); + } else + throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg."); +} + +std::optional CConfigManager::verifyConfigExists() { + std::string mainConfigPath = getMainConfigPath(); + + if (!std::filesystem::exists(mainConfigPath)) + return "broken config dir?"; + + return {}; } const std::string CConfigManager::getConfigString() { @@ -742,32 +767,6 @@ void CConfigManager::setDefaultAnimationVars() { CREATEANIMCFG("specialWorkspace", "workspaces"); } -std::optional CConfigManager::verifyConfigExists() { - std::string mainConfigPath = getMainConfigPath(); - - if (g_pCompositor->explicitConfigPath.empty() && !std::filesystem::exists(mainConfigPath)) { - std::string configPath = std::filesystem::path(mainConfigPath).parent_path(); - - if (!std::filesystem::is_directory(configPath)) { - Debug::log(WARN, "Creating config home directory"); - try { - std::filesystem::create_directories(configPath); - } catch (...) { return "Broken config file! (Could not create config directory)"; } - } - - Debug::log(WARN, "No config file found; attempting to generate."); - std::ofstream ofs; - ofs.open(mainConfigPath, std::ios::trunc); - ofs << AUTOCONFIG; - ofs.close(); - } - - if (!std::filesystem::exists(mainConfigPath)) - return "broken config dir?"; - - return {}; -} - std::optional CConfigManager::resetHLConfig() { m_dMonitorRules.clear(); m_dWindowRules.clear(); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 10021187..df7c202b 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -101,7 +101,6 @@ class CConfigManager { void* const* getConfigValuePtr(const std::string&); Hyprlang::CConfigValue* getHyprlangConfigValuePtr(const std::string& name, const std::string& specialCat = ""); void onPluginLoadUnload(const std::string& name, bool load); - static std::string getConfigDir(); static std::string getMainConfigPath(); const std::string getConfigString(); @@ -224,14 +223,15 @@ class CConfigManager { std::string m_szConfigErrors = ""; // internal methods - void setAnimForChildren(SAnimationPropertyConfig* const); - void updateBlurredLS(const std::string&, const bool); - void setDefaultAnimationVars(); - std::optional resetHLConfig(); - std::optional verifyConfigExists(); - void postConfigReload(const Hyprlang::CParseResult& result); - void reload(); - SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); + void setAnimForChildren(SAnimationPropertyConfig* const); + void updateBlurredLS(const std::string&, const bool); + void setDefaultAnimationVars(); + std::optional resetHLConfig(); + static std::optional generateConfig(std::string configPath); + static std::optional verifyConfigExists(); + void postConfigReload(const Hyprlang::CParseResult& result); + void reload(); + SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); }; inline std::unique_ptr g_pConfigManager; diff --git a/src/meson.build b/src/meson.build index ccb1922a..f6ae043d 100644 --- a/src/meson.build +++ b/src/meson.build @@ -11,9 +11,9 @@ executable('Hyprland', src, dependency('wayland-client'), wlroots.get_variable('wlroots'), dependency('cairo'), - dependency('hyprcursor'), + dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), - dependency('hyprutils', version: '>= 0.1.1'), + dependency('hyprutils', version: '>= 0.2.0'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index cb3d2e71..8229e210 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -842,7 +842,7 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { if (path == "" || path == STRVAL_EMPTY) return; - std::ifstream infile(absolutePath(path, g_pConfigManager->getConfigDir())); + std::ifstream infile(absolutePath(path, g_pConfigManager->getMainConfigPath())); if (!infile.good()) { g_pConfigManager->addParseError("Screen shader parser: Screen shader path not found"); From 293e687389a19b369f312c5c335c9afe7c886be1 Mon Sep 17 00:00:00 2001 From: Party Wumpus <48649272+PartyWumpus@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:03:10 +0100 Subject: [PATCH 0323/2393] renderer: Make shader time always count from zero (#6903) * testing out an initialtime variable * Make time universally start at zero instead of exposing an initial time * Appease the CI --- src/render/OpenGL.cpp | 10 ++++++---- src/render/Shader.hpp | 9 +++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 8229e210..e127ec2d 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -858,9 +858,11 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { return; } - m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj"); - m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex"); - m_sFinalScreenShader.time = glGetUniformLocation(m_sFinalScreenShader.program, "time"); + m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj"); + m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex"); + m_sFinalScreenShader.time = glGetUniformLocation(m_sFinalScreenShader.program, "time"); + if (m_sFinalScreenShader.time != -1) + m_sFinalScreenShader.initialTime = m_tGlobalTimer.getSeconds(); m_sFinalScreenShader.wl_output = glGetUniformLocation(m_sFinalScreenShader.program, "wl_output"); m_sFinalScreenShader.fullSize = glGetUniformLocation(m_sFinalScreenShader.program, "screen_size"); if (m_sFinalScreenShader.fullSize == -1) @@ -1155,7 +1157,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUniform1i(shader->tex, 0); if ((usingFinalShader && *PDT == 0) || CRASHING) { - glUniform1f(shader->time, m_tGlobalTimer.getSeconds()); + glUniform1f(shader->time, m_tGlobalTimer.getSeconds() - shader->initialTime); } else if (usingFinalShader && shader->time != -1) { // Don't let time be unitialised glUniform1f(shader->time, 0.f); diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index 185c3dff..d5a312c3 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -42,9 +42,10 @@ class CShader { GLint gradientLength = -1; GLint angle = -1; - GLint time = -1; - GLint distort = -1; - GLint wl_output = -1; + float initialTime = 0; + GLint time = -1; + GLint distort = -1; + GLint wl_output = -1; // Blur prepare GLint contrast = -1; @@ -64,4 +65,4 @@ class CShader { private: std::unordered_map m_muUniforms; -}; \ No newline at end of file +}; From 300228b503b36e5977b0d58713c5b4cf1f07b8a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?VESSE=20L=C3=A9o?= Date: Wed, 17 Jul 2024 22:30:02 +0200 Subject: [PATCH 0324/2393] flake: add clang-tools to devShell (#6916) --- flake.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index c1be8720..88cb593b 100644 --- a/flake.nix +++ b/flake.nix @@ -90,9 +90,13 @@ stdenv = pkgsFor.${system}.gcc13Stdenv; } { name = "hyprland-shell"; - nativeBuildInputs = with pkgsFor.${system}; [expat libxml2]; + nativeBuildInputs = with pkgsFor.${system}; [ + expat + libxml2 + ]; hardeningDisable = ["fortify"]; inputsFrom = [pkgsFor.${system}.hyprland]; + packages = [pkgsFor.${system}.clang-tools]; }; }); From 8e15f91c2417c8f05d69a93f1294185ccc5f8f3e Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:57:08 -0400 Subject: [PATCH 0325/2393] input: Emulate discrete scrolling from v120 events (#6881) * seat: avoid sending axis_stop() when source is wheel * fix rounding for absolute discrete values greater than 1 Co-authored-by: Agent_00Ming --- src/config/ConfigManager.cpp | 1 + src/managers/SeatManager.cpp | 4 +-- src/managers/input/InputManager.cpp | 42 ++++++++++++++++++++++++++--- src/managers/input/InputManager.hpp | 8 ++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 944aa0b2..71349068 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -472,6 +472,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("input:scroll_button_lock", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:scroll_factor", {1.f}); m_pConfig->addConfigValue("input:scroll_points", {STRVAL_EMPTY}); + m_pConfig->addConfigValue("input:emulate_discrete_scroll", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:natural_scroll", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:touchpad:disable_while_typing", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:touchpad:clickfinger_behavior", Hyprlang::INT{0}); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index fc14f0fc..6589c4bf 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -333,9 +333,7 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double if (source == 0) { p->sendAxisValue120(axis, value120); p->sendAxisDiscrete(axis, discrete); - } - - if (value == 0) + } else if (value == 0) p->sendAxisStop(timeMs, axis); } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index b2bbd577..23e183d0 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -760,6 +760,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { static auto POFFWINDOWAXIS = CConfigValue("input:off_window_axis_events"); static auto PINPUTSCROLLFACTOR = CConfigValue("input:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue("input:touchpad:scroll_factor"); + static auto PEMULATEDISCRETE = CConfigValue("input:emulate_discrete_scroll"); auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); @@ -798,9 +799,44 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { } } } - double deltaDiscrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0; - g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, factor * e.delta, deltaDiscrete > 0 ? std::ceil(deltaDiscrete) : std::floor(deltaDiscrete), - std::round(factor * e.deltaDiscrete), e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + + double discrete = (e.deltaDiscrete != 0) ? (factor * e.deltaDiscrete / std::abs(e.deltaDiscrete)) : 0; + double delta = e.delta * factor; + + if (e.source == 0) { + // if an application supports v120, it should ignore discrete anyways + if ((*PEMULATEDISCRETE >= 1 && std::abs(e.deltaDiscrete) != 120) || *PEMULATEDISCRETE >= 2) { + + const int interval = factor != 0 ? std::round(120 * (1 / factor)) : 120; + + // reset the accumulator when timeout is reached or direction/axis has changed + if (std::signbit(e.deltaDiscrete) != m_ScrollWheelState.lastEventSign || e.axis != m_ScrollWheelState.lastEventAxis || + e.timeMs - m_ScrollWheelState.lastEventTime > 500 /* 500ms taken from libinput default timeout */) { + + m_ScrollWheelState.accumulatedScroll = 0; + // send 1 discrete on first event for responsiveness + discrete = std::copysign(1, e.deltaDiscrete); + } else + discrete = 0; + + for (int ac = m_ScrollWheelState.accumulatedScroll; ac >= interval; ac -= interval) { + discrete += std::copysign(1, e.deltaDiscrete); + m_ScrollWheelState.accumulatedScroll -= interval; + } + + m_ScrollWheelState.lastEventSign = std::signbit(e.deltaDiscrete); + m_ScrollWheelState.lastEventAxis = e.axis; + m_ScrollWheelState.lastEventTime = e.timeMs; + m_ScrollWheelState.accumulatedScroll += std::abs(e.deltaDiscrete); + + delta = 15.0 * discrete * factor; + } + } + + int32_t value120 = std::round(factor * e.deltaDiscrete); + int32_t deltaDiscrete = std::abs(discrete) != 0 && std::abs(discrete) < 1 ? std::copysign(1, discrete) : std::round(discrete); + + g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, delta, deltaDiscrete, value120, e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); } Vector2D CInputManager::getMouseCoordsInternal() { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 8050defe..85ae6197 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -278,6 +278,14 @@ class CInputManager { void restoreCursorIconToApp(); // no-op if restored + // discrete scrolling emulation using v120 data + struct { + bool lastEventSign = 0; + bool lastEventAxis = 0; + uint32_t lastEventTime = 0; + uint32_t accumulatedScroll = 0; + } m_ScrollWheelState; + friend class CKeybindManager; friend class CWLSurface; }; From efccf25fcc72b416c63ff540703d9f061f39a7f2 Mon Sep 17 00:00:00 2001 From: Ferdinand Bachmann Date: Sat, 20 Jul 2024 00:37:20 +0200 Subject: [PATCH 0326/2393] compositor: implement wayland socket handover (#6930) * compositor: implement wayland socket handover This commit implements the compositor side of the Wayland socket handover protocol as described in the [KDE Wiki]. The CLI options are chosen so that they are compatible with Kwin. [KDE Wiki]: https://invent.kde.org/plasma/kwin/-/wikis/Restarting * main: verify that --wayland-fd is a valid file descriptor * main: fail if only one of --socket and --wayland-fd is passed --- docs/Hyprland.1 | 4 ++++ docs/Hyprland.1.rst | 6 ++++++ src/Compositor.cpp | 30 ++++++++++++++++++++---------- src/Compositor.hpp | 2 +- src/main.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index f43d2c5d..5ef24fd5 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -32,6 +32,10 @@ Show command usage. .TP \f[B]-c\f[R], \f[B]--config\f[R] Specify config file to use. +\f[B]--socket\f[R] +Sets the Wayland socket name (for Wayland socket handover) +\f[B]--wayland-fd\f[R] +Sets the Wayland socket file descriptor (for Wayland socket handover) .SH BUGS .TP Submit bug reports and request features online at: diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst index 54126501..c73b4343 100644 --- a/docs/Hyprland.1.rst +++ b/docs/Hyprland.1.rst @@ -41,6 +41,12 @@ OPTIONS **-c**, **--config** Specify config file to use. +**--socket** + Sets the Wayland socket name (for Wayland socket handover) + +**--wayland-fd** + Sets the Wayland socket file descriptor (for Wayland socket handover) + BUGS ==== diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d1c51075..7ffccf36 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -27,6 +27,7 @@ #include using namespace Hyprutils::String; +#include #include #include #include @@ -533,19 +534,28 @@ void CCompositor::prepareFallbackOutput() { wlr_headless_add_output(headless, 1920, 1080); } -void CCompositor::startCompositor() { +void CCompositor::startCompositor(std::string socketName, int socketFd) { initAllSignals(); - // get socket, avoid using 0 - for (int candidate = 1; candidate <= 32; candidate++) { - const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); - const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (!socketName.empty() && socketFd != -1) { + fcntl(socketFd, F_SETFD, FD_CLOEXEC); + const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); if (RETVAL >= 0) { - m_szWLDisplaySocket = CANDIDATESTR; - Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); - break; - } else { - Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); + m_szWLDisplaySocket = socketName; + Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL); + } else + Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL); + } else { + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 17db2c8b..4aec323f 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -78,7 +78,7 @@ class CCompositor { std::unordered_map m_mMonitorIDMap; void initServer(); - void startCompositor(); + void startCompositor(std::string socketName, int socketFd); void cleanup(); void createLockFile(); void removeLockFile(); diff --git a/src/main.cpp b/src/main.cpp index 7e6fee02..1ac3ab8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include #include #include #include @@ -16,6 +17,8 @@ void help() { std::cout << "\nArguments:\n"; std::cout << " --help -h - Show this message again\n"; std::cout << " --config FILE -c FILE - Specify config file to use\n"; + std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; + std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; } @@ -37,6 +40,8 @@ int main(int argc, char** argv) { // parse some args std::string configPath; + std::string socketName; + int socketFd = -1; bool ignoreSudo = false; std::vector args{argv + 1, argv + argc}; @@ -46,6 +51,36 @@ int main(int argc, char** argv) { std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; ignoreSudo = true; + } else if (it->compare("--socket") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + socketName = *std::next(it); + it++; + } else if (it->compare("--wayland-fd") == 0) { + if (std::next(it) == args.end()) { + help(); + + return 1; + } + + try { + socketFd = std::stoi(std::next(it)->c_str()); + + // check if socketFd is a valid file descriptor + if (fcntl(socketFd, F_GETFD) == -1) + throw std::exception(); + } catch (...) { + std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; + help(); + + return 1; + } + + it++; } else if (it->compare("-c") == 0 || it->compare("--config") == 0) { if (std::next(it) == args.end()) { help(); @@ -93,6 +128,13 @@ int main(int argc, char** argv) { std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; } + if (socketName.empty() ^ (socketFd == -1)) { + std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; + std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; + + return 1; + } + std::cout << "Welcome to Hyprland!\n"; // let's init the compositor. @@ -113,7 +155,7 @@ int main(int argc, char** argv) { Debug::log(LOG, "Hyprland init finished."); // If all's good to go, start. - g_pCompositor->startCompositor(); + g_pCompositor->startCompositor(socketName, socketFd); g_pCompositor->m_bIsShuttingDown = true; From 9b0993cc49b7285a2724a87fdb72bfc90cc75cc5 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 19 Jul 2024 22:37:42 +0000 Subject: [PATCH 0327/2393] [gha] build man pages --- docs/Hyprland.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 5ef24fd5..92061da2 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -32,8 +32,10 @@ Show command usage. .TP \f[B]-c\f[R], \f[B]--config\f[R] Specify config file to use. +.TP \f[B]--socket\f[R] Sets the Wayland socket name (for Wayland socket handover) +.TP \f[B]--wayland-fd\f[R] Sets the Wayland socket file descriptor (for Wayland socket handover) .SH BUGS From f642fb97df5c69267a03452533de383ff8023570 Mon Sep 17 00:00:00 2001 From: phonetic112 <73647246+phonetic112@users.noreply.github.com> Date: Sat, 20 Jul 2024 04:11:32 -0400 Subject: [PATCH 0328/2393] core: Fix crash on opening chromium (#6932) --- src/protocols/PresentationTime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 0275b53f..3907bf1e 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -60,7 +60,7 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - if (data->wasPresented) + if (data->wasPresented && when) resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else From 016da234d0e852de3ef20eb2e89ac58d2a85f6e7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:09:54 +0200 Subject: [PATCH 0329/2393] Core: Move to aquamarine (#6608) Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry Co-authored-by: Mihai Fufezan Co-authored-by: Jan Beich Co-authored-by: vaxerski Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo --- .github/actions/setup_base/action.yml | 6 + .gitmodules | 4 - CMakeLists.txt | 42 +- Makefile | 6 +- README.md | 9 +- flake.lock | 30 + flake.nix | 8 + hyprland.pc.in | 2 +- hyprpm/src/core/PluginManager.cpp | 7 +- meson.build | 11 +- nix/default.nix | 3 + nix/overlays.nix | 1 + nix/update-wlroots.sh | 17 - protocols/meson.build | 2 + src/Compositor.cpp | 399 +++++++++---- src/Compositor.hpp | 36 +- src/config/ConfigManager.cpp | 23 +- src/debug/CrashReporter.cpp | 1 + src/debug/HyprCtl.cpp | 183 +++--- src/debug/Log.cpp | 24 - src/debug/Log.hpp | 2 - src/desktop/Popup.cpp | 5 +- src/desktop/Popup.hpp | 4 +- src/desktop/Window.cpp | 3 +- src/devices/IKeyboard.cpp | 256 ++++++++- src/devices/IKeyboard.hpp | 73 ++- src/devices/IPointer.hpp | 10 +- src/devices/ITouch.hpp | 10 +- src/devices/Keyboard.cpp | 66 +-- src/devices/Keyboard.hpp | 22 +- src/devices/Mouse.cpp | 182 +++--- src/devices/Mouse.hpp | 41 +- src/devices/Tablet.cpp | 256 ++++----- src/devices/Tablet.hpp | 154 +++-- src/devices/TouchDevice.cpp | 78 ++- src/devices/TouchDevice.hpp | 26 +- src/devices/VirtualKeyboard.cpp | 63 +- src/devices/VirtualKeyboard.hpp | 21 +- src/devices/VirtualPointer.cpp | 172 +----- src/devices/VirtualPointer.hpp | 37 +- src/events/Devices.cpp | 50 -- src/events/Events.hpp | 31 - src/events/Misc.cpp | 54 -- src/events/Monitors.cpp | 135 +---- src/helpers/CursorShapes.hpp | 43 ++ src/helpers/Format.cpp | 16 + src/helpers/Format.hpp | 9 +- src/helpers/MiscFunctions.cpp | 3 + src/helpers/MiscFunctions.hpp | 1 - src/helpers/Monitor.cpp | 293 ++++++---- src/helpers/Monitor.hpp | 136 +++-- src/helpers/WLClasses.hpp | 14 +- src/helpers/X11Stubs.hpp | 7 - src/helpers/math/Math.cpp | 140 +---- src/helpers/math/Math.hpp | 13 +- src/helpers/sync/SyncTimeline.cpp | 190 +++++++ src/helpers/sync/SyncTimeline.hpp | 47 ++ src/includes.hpp | 76 --- src/macros.hpp | 5 + src/managers/AnimationManager.cpp | 2 +- src/managers/CursorManager.cpp | 327 +++++++---- src/managers/CursorManager.hpp | 70 ++- src/managers/KeybindManager.cpp | 61 +- src/managers/KeybindManager.hpp | 1 + src/managers/PointerManager.cpp | 283 +++------ src/managers/PointerManager.hpp | 50 +- src/managers/ProtocolManager.cpp | 20 + src/managers/SeatManager.cpp | 10 +- src/managers/eventLoop/EventLoopManager.cpp | 15 + src/managers/eventLoop/EventLoopManager.hpp | 16 +- src/managers/input/InputManager.cpp | 232 +++----- src/managers/input/InputManager.hpp | 23 +- src/managers/input/Tablets.cpp | 51 +- src/meson.build | 5 +- src/plugins/PluginAPI.cpp | 1 + src/protocols/CursorShape.cpp | 45 +- src/protocols/DRMLease.cpp | 302 ++++++++++ src/protocols/DRMLease.hpp | 137 +++++ src/protocols/DRMSyncobj.cpp | 183 ++++++ src/protocols/DRMSyncobj.hpp | 82 +++ src/protocols/GammaControl.cpp | 32 +- src/protocols/GammaControl.hpp | 2 +- src/protocols/InputMethodV2.cpp | 22 +- src/protocols/InputMethodV2.hpp | 7 +- src/protocols/LinuxDMABUF.cpp | 323 ++++++++--- src/protocols/LinuxDMABUF.hpp | 52 +- src/protocols/MesaDRM.cpp | 42 +- src/protocols/MesaDRM.hpp | 2 +- src/protocols/OutputManagement.cpp | 56 +- src/protocols/OutputManagement.hpp | 15 +- src/protocols/OutputPower.cpp | 2 +- src/protocols/PresentationTime.cpp | 18 +- src/protocols/Screencopy.cpp | 52 +- src/protocols/Screencopy.hpp | 9 +- src/protocols/Tablet.cpp | 61 +- src/protocols/Tablet.hpp | 5 +- src/protocols/ToplevelExport.cpp | 19 +- src/protocols/ToplevelExport.hpp | 2 +- src/protocols/Viewporter.cpp | 29 +- src/protocols/Viewporter.hpp | 5 +- src/protocols/VirtualKeyboard.cpp | 58 +- src/protocols/VirtualKeyboard.hpp | 13 +- src/protocols/VirtualPointer.cpp | 80 +-- src/protocols/VirtualPointer.hpp | 31 +- src/protocols/XDGOutput.cpp | 6 +- src/protocols/XDGShell.cpp | 1 + src/protocols/core/Compositor.cpp | 149 +++-- src/protocols/core/Compositor.hpp | 14 +- src/protocols/core/Output.cpp | 10 +- src/protocols/core/Output.hpp | 3 + src/protocols/core/Seat.cpp | 4 +- src/protocols/core/Shm.cpp | 27 +- src/protocols/core/Shm.hpp | 8 +- src/protocols/types/Buffer.cpp | 41 +- src/protocols/types/Buffer.hpp | 80 +-- src/protocols/types/DMABuffer.cpp | 12 +- src/protocols/types/DMABuffer.hpp | 12 +- src/protocols/types/WLBuffer.cpp | 15 + src/protocols/types/WLBuffer.hpp | 8 +- src/render/OpenGL.cpp | 487 ++++++++++++---- src/render/OpenGL.hpp | 52 +- src/render/Renderbuffer.cpp | 69 +-- src/render/Renderbuffer.hpp | 31 +- src/render/Renderer.cpp | 599 ++++++++++---------- src/render/Renderer.hpp | 76 +-- src/render/Texture.cpp | 62 +- src/render/Texture.hpp | 15 +- src/signal-safe.hpp | 1 + src/xwayland/Server.cpp | 11 +- src/xwayland/XWM.cpp | 10 +- subprojects/wlroots-hyprland | 1 - 131 files changed, 4755 insertions(+), 3460 deletions(-) delete mode 100755 nix/update-wlroots.sh delete mode 100644 src/events/Devices.cpp delete mode 100644 src/events/Misc.cpp create mode 100644 src/helpers/CursorShapes.hpp delete mode 100644 src/helpers/X11Stubs.hpp create mode 100644 src/helpers/sync/SyncTimeline.cpp create mode 100644 src/helpers/sync/SyncTimeline.hpp create mode 100644 src/protocols/DRMLease.cpp create mode 100644 src/protocols/DRMLease.hpp create mode 100644 src/protocols/DRMSyncobj.cpp create mode 100644 src/protocols/DRMSyncobj.hpp delete mode 160000 subprojects/wlroots-hyprland diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index a7b9994c..26660ce6 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -34,6 +34,7 @@ runs: libglvnd \ libinput \ libliftoff \ + libxcursor \ libxcvt \ libxfont2 \ libxkbcommon \ @@ -73,6 +74,11 @@ runs: run: | git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build + - name: Get aquamarine-git + shell: bash + run: | + git clone https://github.com/hyprwm/aquamarine && cd aquamarine && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target aquamarine && cmake --install build + - name: Get Xorg pacman pkgs shell: bash if: inputs.INSTALL_XORG_PKGS == 'true' diff --git a/.gitmodules b/.gitmodules index 37b48a5a..638f8ba9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,7 +7,3 @@ [submodule "subprojects/tracy"] path = subprojects/tracy url = https://github.com/wolfpld/tracy -[submodule "subprojects/wlroots-hyprland"] - path = subprojects/wlroots-hyprland - url = https://github.com/hyprwm/wlroots-hyprland - ignore = dirty diff --git a/CMakeLists.txt b/CMakeLists.txt index 07fa8cf6..e951b874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,6 @@ cmake_minimum_required(VERSION 3.27) include(CheckIncludeFile) -include(ExternalProject) include(GNUInstallDirs) # Get version @@ -31,9 +30,6 @@ execute_process( # udis add_subdirectory("subprojects/udis86") -# wlroots -message(STATUS "Setting up wlroots") - if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) if(BUILDTYPE_LOWER STREQUAL "release") @@ -53,18 +49,6 @@ else() set(BUILDTYPE_LOWER "release") endif() -ExternalProject_Add( - wlroots-hyprland - PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland - SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland - CONFIGURE_COMMAND meson setup --reconfigure --clearcache build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $,-Db_sanitize=address,-Db_sanitize=none> - BUILD_COMMAND ninja -C build - BUILD_ALWAYS true - BUILD_IN_SOURCE true - BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a - INSTALL_COMMAND echo "wlroots-hyprland: install not needed" -) - find_package(PkgConfig REQUIRED) pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) @@ -84,12 +68,9 @@ endif() include_directories( . "src/" - "subprojects/wlroots-hyprland/include/" - "subprojects/wlroots-hyprland/build/include/" "subprojects/udis86/" "protocols/") set(CMAKE_CXX_STANDARD 23) -add_compile_definitions(WLR_USE_UNSTABLE) add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) @@ -109,9 +90,10 @@ endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(deps REQUIRED IMPORTED_TARGET + aquamarine xkbcommon uuid wayland-server wayland-client wayland-cursor wayland-protocols - cairo pango pangocairo pixman-1 + cairo pango pangocairo pixman-1 xcursor libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.0 ) @@ -127,7 +109,6 @@ if(USE_TRACY) endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) -add_dependencies(Hyprland wlroots-hyprland) set(USE_GPROF ON) @@ -266,7 +247,6 @@ function(protocolWayland) endfunction() target_link_libraries(Hyprland - ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a OpenGL::EGL OpenGL::GL Threads::Threads @@ -314,6 +294,8 @@ protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) protocolNew("stable/viewporter" "viewporter" false) protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolNew("staging/drm-lease" "drm-lease-v1" false) +protocolNew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolWayland() @@ -326,8 +308,8 @@ install(TARGETS Hyprland) install(CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ - ${CMAKE_INSTALL_BINDIR}/Hyprland \ - ${CMAKE_INSTALL_BINDIR}/hyprland + ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ + ${CMAKE_INSTALL_FULL_BINDIR}/hyprland )" ) @@ -358,18 +340,6 @@ install(FILES ${MANPAGES} install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) -# wlroots headers -set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr") -install(DIRECTORY ${HEADERS_WLR} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h") - -# config.h and version.h -set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr") -install(DIRECTORY ${HEADERS_WLR_ROOT}/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr - FILES_MATCHING PATTERN "*.h") - # protocol headers set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") install(DIRECTORY ${HEADERS_PROTO} diff --git a/Makefile b/Makefile index 493a6784..adf6fbe8 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,6 @@ nopch: clear: rm -rf build rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp - rm -rf ./subprojects/wlroots-hyprland/build all: $(MAKE) clear @@ -50,14 +49,11 @@ installheaders: rm -fr ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland mkdir -p ${PREFIX}/include/hyprland/protocols - mkdir -p ${PREFIX}/include/hyprland/wlr mkdir -p ${PREFIX}/share/pkgconfig cmake --build ./build --config Release --target generate-protocol-headers find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland - cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. - cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../.. cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi @@ -88,7 +84,7 @@ asan: @pidof Hyprland > /dev/null && exit 1 || echo "" rm -rf ./wayland - git reset --hard + #git reset --hard @echo -en "If you want to apply a patch, input its path (leave empty for none):\n" @read patchvar diff --git a/README.md b/README.md index ca44621d..fc2bd206 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@
-Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks. +Hyprland is a 100% independent, dynamic tiling Wayland compositor that doesn't sacrifice on its looks. It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins, -easy IPC, much more QoL stuff than other wlr-based compositors and more... +easy IPC, much more QoL stuff than other compositors and more...

@@ -37,7 +37,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more... - All of the eyecandy: gradient borders, blur, animations, shadows and much more - A lot of customization -- Much more QoL stuff than other wlr-based compositors +- 100% independent, no wlroots, no libweston, no kwin, no mutter. - Custom bezier curves for the best animations - Powerful plugin support - Built-in plugin manager @@ -48,7 +48,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more... - Config reloaded instantly upon saving - Fully dynamic workspaces - Two built-in layouts and more available as plugins -- Uses forked wlroots with QoL patches - Global keybinds passed to your apps of choice - Tiling/pseudotiling/floating/fullscreen windows - Special workspaces (scratchpads) @@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
-**[wlroots]** - *For their amazing library* +**[wlroots]** - *For powering Hyprland in the past* **[tinywl]** - *For showing how 2 do stuff* diff --git a/flake.lock b/flake.lock index b5f5738a..b2cc9703 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,34 @@ { "nodes": { + "aquamarine": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprwayland-scanner" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1721487522, + "narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=", + "owner": "hyprwm", + "repo": "aquamarine", + "rev": "acfea3bd1d9e756c7152e639240d52c6628844b0", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "aquamarine", + "type": "github" + } + }, "hyprcursor": { "inputs": { "hyprlang": [ @@ -141,6 +170,7 @@ }, "root": { "inputs": { + "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", "hyprlang": "hyprlang", "hyprutils": "hyprutils", diff --git a/flake.nix b/flake.nix index 88cb593b..9c20b3f5 100644 --- a/flake.nix +++ b/flake.nix @@ -7,6 +7,14 @@ # systems.url = "github:nix-systems/default-linux"; + aquamarine = { + url = "github:hyprwm/aquamarine"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; + }; + hyprcursor = { url = "github:hyprwm/hyprcursor"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/hyprland.pc.in b/hyprland.pc.in index 382fb1e6..81a0ef11 100644 --- a/hyprland.pc.in +++ b/hyprland.pc.in @@ -4,4 +4,4 @@ Name: Hyprland URL: https://github.com/hyprwm/Hyprland Description: Hyprland header files Version: @HYPRLAND_VERSION@ -Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland -I${prefix}/hyprland/wlr +Cflags: -I${prefix} -I${prefix}/hyprland/protocols -I${prefix}/hyprland diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 848b9cab..7d7cc079 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -356,7 +356,7 @@ eHeadersErrors CPluginManager::headersValid() { else headers = ""; - if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) + if (PATH.ends_with("protocols")) continue; verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h"; @@ -493,11 +493,6 @@ bool CPluginManager::updateHeaders(bool force) { return false; } - // le hack. Wlroots has to generate its build/include - ret = execAndGet("cd " + WORKINGDIR + "/subprojects/wlroots-hyprland && meson setup -Drenderers=gles2 -Dexamples=false build"); - if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "meson returned: " + ret); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland"); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing sources"; diff --git a/meson.build b/meson.build index 49c48c6c..b8101f6c 100644 --- a/meson.build +++ b/meson.build @@ -24,8 +24,6 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -wlroots = subproject('wlroots-hyprland', default_options: ['examples=false', 'renderers=gles2']) -have_xwlr = wlroots.get_variable('features').get('xwayland') xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) @@ -38,12 +36,7 @@ cmake = import('cmake') udis = cmake.subproject('udis86') udis86 = udis.dependency('libudis86') -if get_option('xwayland').enabled() and not have_xwlr - error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support') -endif -have_xwayland = xcb_dep.found() and have_xwlr - -if not have_xwayland +if not xcb_dep.found() add_project_arguments('-DNO_XWAYLAND', language: 'cpp') endif @@ -86,5 +79,5 @@ import('pkgconfig').generate( url: 'https://github.com/hyprwm/Hyprland', description: 'Hyprland header files', install_dir: pkg_install_dir, - subdirs: ['', 'hyprland/protocols', 'hyprland', 'hyprland/wlr'], + subdirs: ['', 'hyprland/protocols', 'hyprland'], ) diff --git a/nix/default.nix b/nix/default.nix index a2302688..7775b729 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -6,6 +6,7 @@ makeWrapper, cmake, ninja, + aquamarine, binutils, cairo, expat, @@ -104,6 +105,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov buildInputs = lib.concatLists [ [ + aquamarine cairo expat fribidi @@ -136,6 +138,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ xorg.libxcb + xorg.libXcursor xorg.libXdmcp xorg.xcbutil xorg.xcbutilerrors diff --git a/nix/overlays.nix b/nix/overlays.nix index a4e1df37..9d100d51 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -21,6 +21,7 @@ in { # Packages for variations of Hyprland, dependencies included. hyprland-packages = lib.composeManyExtensions [ # Dependencies + inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default diff --git a/nix/update-wlroots.sh b/nix/update-wlroots.sh deleted file mode 100755 index 01f5cd83..00000000 --- a/nix/update-wlroots.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash - -# get wlroots revision from submodule -SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }') -# and from lockfile -CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }') - -if [ "$SUB_REV" != "$CRT_REV" ]; then - echo "Updating wlroots..." - # update wlroots to submodule revision - sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix - nix flake lock - - echo "wlroots: $CRT_REV -> $SUB_REV" -else - echo "wlroots is up to date!" -fi diff --git a/protocols/meson.build b/protocols/meson.build index 7c508659..5cdeb160 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -66,6 +66,8 @@ new_protocols = [ [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], + [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], + [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7ffccf36..c7a0cfb1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -6,7 +6,10 @@ #include "managers/PointerManager.hpp" #include "managers/SeatManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" +#include #include +#include +#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" @@ -22,16 +25,20 @@ #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" +#include "render/Renderer.hpp" #include "xwayland/XWayland.hpp" #include -using namespace Hyprutils::String; +#include #include #include #include #include +using namespace Hyprutils::String; +using namespace Aquamarine; + int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -72,6 +79,23 @@ void handleUserSignal(int sig) { } } +static LogLevel aqLevelToHl(Aquamarine::eBackendLogLevel level) { + switch (level) { + case Aquamarine::eBackendLogLevel::AQ_LOG_TRACE: return TRACE; + case Aquamarine::eBackendLogLevel::AQ_LOG_DEBUG: return LOG; + case Aquamarine::eBackendLogLevel::AQ_LOG_ERROR: return ERR; + case Aquamarine::eBackendLogLevel::AQ_LOG_WARNING: return WARN; + case Aquamarine::eBackendLogLevel::AQ_LOG_CRITICAL: return CRIT; + default: break; + } + + return NONE; +} + +void aqLog(Aquamarine::eBackendLogLevel level, std::string msg) { + Debug::log(aqLevelToHl(level), "[AQ] {}", msg); +} + void CCompositor::bumpNofile() { if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile)) Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max); @@ -180,6 +204,9 @@ void CCompositor::setRandomSplash() { m_szCurrentSplash = SPLASHES[distribution(engine)]; } +static std::vector> pendingOutputs; + +// void CCompositor::initServer() { m_sWLDisplay = wl_display_create(); @@ -200,102 +227,179 @@ void CCompositor::initServer() { if (envEnabled("HYPRLAND_TRACE")) Debug::trace = true; - wlr_log_init(WLR_INFO, NULL); + Aquamarine::SBackendOptions options; + options.logFunction = aqLog; - if (envEnabled("HYPRLAND_LOG_WLR")) - wlr_log_init(WLR_DEBUG, Debug::wlrLog); - else - wlr_log_init(WLR_ERROR, Debug::wlrLog); + std::vector implementations; + Aquamarine::SBackendImplementationOptions option; + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_HEADLESS; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_MANDATORY; + implementations.emplace_back(option); + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_DRM; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_IF_AVAILABLE; + implementations.emplace_back(option); + option.backendType = Aquamarine::eBackendType::AQ_BACKEND_WAYLAND; + option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_FALLBACK; + implementations.emplace_back(option); - m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession); + m_pAqBackend = CBackend::create(implementations, options); - if (!m_sWLRBackend) { - Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues."); - throwError("wlr_backend_autocreate() failed!"); + if (!m_pAqBackend) { + Debug::log(CRIT, + "m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland " + "session, NOT an X11 one."); + throwError("CBackend::create() failed!"); } - bool isHeadlessOnly = true; - wlr_multi_for_each_backend( - m_sWLRBackend, - [](wlr_backend* backend, void* isHeadlessOnly) { - if (!wlr_backend_is_headless(backend) && !wlr_backend_is_libinput(backend)) - *(bool*)isHeadlessOnly = false; - }, - &isHeadlessOnly); + // TODO: headless only - if (isHeadlessOnly) { - m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now. - } else { - m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend); - if (m_iDRMFD < 0) { - Debug::log(CRIT, "Couldn't query the DRM FD!"); - throwError("wlr_backend_get_drm_fd() failed!"); + initAllSignals(); + + if (!m_pAqBackend->start()) { + Debug::log(CRIT, + "m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a " + "Wayland session, NOT an X11 one."); + throwError("CBackend::create() failed!"); + } + + m_bInitialized = true; + + m_iDRMFD = m_pAqBackend->drmFD(); + Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD); + + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else { + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } - - m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD); } - if (!m_sWLRRenderer) { - Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues."); - throwError("wlr_gles2_renderer_create_with_drm_fd() failed!"); + if (m_szWLDisplaySocket.empty()) { + Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto"); + const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay); + if (SOCKETSTR) + m_szWLDisplaySocket = SOCKETSTR; } - m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer); - - if (!m_sWLRAllocator) { - Debug::log(CRIT, "m_sWLRAllocator was NULL!"); - throwError("wlr_allocator_autocreate() failed!"); + if (m_szWLDisplaySocket.empty()) { + Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); + throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); } - m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer); - - if (!m_sWLREGL) { - Debug::log(CRIT, "m_sWLREGL was NULL!"); - throwError("wlr_gles2_renderer_get_egl() failed!"); - } + Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket); + setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); initManagers(STAGE_BASICINIT); - 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"); - Debug::log(INFO, "VR will not be available"); - } - - m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop); - - if (!m_sWLRHeadlessBackend) { - Debug::log(CRIT, "Couldn't create the headless backend"); - throwError("wlr_headless_backend_create() failed!"); - } - - wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend); - initManagers(STAGE_LATE); + + for (auto& o : pendingOutputs) { + onNewMonitor(o); + } + pendingOutputs.clear(); } void CCompositor::initAllSignals() { - addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend"); - addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); + m_pAqBackend->events.newOutput.registerStaticListener( + [this](void* p, std::any data) { + auto output = std::any_cast>(data); + Debug::log(LOG, "New aquamarine output with name {}", output->name); + if (m_bInitialized) + onNewMonitor(output); + else + pendingOutputs.emplace_back(output); + }, + nullptr); - if (m_sWRLDRMLeaseMgr) - addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); + m_pAqBackend->events.newPointer.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine pointer with name {}", dev->getName()); + g_pInputManager->newMouse(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); - if (m_sWLRSession) - addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session"); + m_pAqBackend->events.newKeyboard.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine keyboard with name {}", dev->getName()); + g_pInputManager->newKeyboard(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); + + m_pAqBackend->events.newTouch.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine touch with name {}", dev->getName()); + g_pInputManager->newTouchDevice(dev); + g_pInputManager->updateCapabilities(); + }, + nullptr); + + m_pAqBackend->events.newSwitch.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine switch with name {}", dev->getName()); + g_pInputManager->newSwitch(dev); + }, + nullptr); + + m_pAqBackend->events.newTablet.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine tablet with name {}", dev->getName()); + g_pInputManager->newTablet(dev); + }, + nullptr); + + m_pAqBackend->events.newTabletPad.registerStaticListener( + [](void* data, std::any d) { + auto dev = std::any_cast>(d); + Debug::log(LOG, "New aquamarine tablet pad with name {}", dev->getName()); + g_pInputManager->newTabletPad(dev); + }, + nullptr); + + if (m_pAqBackend->hasSession()) { + m_pAqBackend->session->events.changeActive.registerStaticListener( + [this](void*, std::any) { + if (m_pAqBackend->session->active) { + Debug::log(LOG, "Session got activated!"); + + m_bSessionActive = true; + + for (auto& m : m_vMonitors) { + scheduleFrameForMonitor(m.get()); + g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); + } + + g_pConfigManager->m_bWantsMonitorReload = true; + } else { + Debug::log(LOG, "Session got deactivated!"); + + m_bSessionActive = false; + + for (auto& m : m_vMonitors) { + m->noFrameSchedule = true; + m->framesToSkip = 1; + } + } + }, + nullptr); + } } void CCompositor::removeAllSignals() { - removeWLSignal(&Events::listen_newOutput); - removeWLSignal(&Events::listen_newInput); - removeWLSignal(&Events::listen_RendererDestroy); - - if (m_sWRLDRMLeaseMgr) - removeWLSignal(&Events::listen_leaseRequest); - - if (m_sWLRSession) - removeWLSignal(&Events::listen_sessionActive); + ; } void CCompositor::cleanEnvironment() { @@ -309,7 +413,7 @@ void CCompositor::cleanEnvironment() { unsetenv("XDG_BACKEND"); unsetenv("XDG_CURRENT_DESKTOP"); - if (m_sWLRSession) { + if (m_pAqBackend->hasSession()) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -352,7 +456,7 @@ void CCompositor::cleanup() { for (auto& m : m_vMonitors) { g_pHyprOpenGL->destroyMonitorResources(m.get()); - wlr_output_state_set_enabled(m->state.wlr(), false); + m->output->state->setEnabled(false); m->state.commit(); } @@ -389,14 +493,8 @@ void CCompositor::cleanup() { g_pHyprCtl.reset(); g_pEventLoopManager.reset(); - if (m_sWLRRenderer) - wlr_renderer_destroy(m_sWLRRenderer); - - if (m_sWLRAllocator) - wlr_allocator_destroy(m_sWLRAllocator); - - if (m_sWLRBackend) - wlr_backend_destroy(m_sWLRBackend); + if (m_pAqBackend) + m_pAqBackend.reset(); if (m_critSigSource) wl_event_source_remove(m_critSigSource); @@ -442,6 +540,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique(); + + Debug::log(LOG, "Creating the EventManager!"); + g_pEventManager = std::make_unique(); } break; case STAGE_BASICINIT: { Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); @@ -472,9 +573,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the SessionLockManager!"); g_pSessionLockManager = std::make_unique(); - Debug::log(LOG, "Creating the EventManager!"); - g_pEventManager = std::make_unique(); - Debug::log(LOG, "Creating the HyprDebugOverlay!"); g_pDebugOverlay = std::make_unique(); @@ -517,26 +615,23 @@ void CCompositor::removeLockFile() { void CCompositor::prepareFallbackOutput() { // create a backup monitor - wlr_backend* headless = nullptr; - wlr_multi_for_each_backend( - m_sWLRBackend, - [](wlr_backend* b, void* data) { - if (wlr_backend_is_headless(b)) - *((wlr_backend**)data) = b; - }, - &headless); + SP headless; + for (auto& impl : m_pAqBackend->getImplementations()) { + if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) { + headless = impl; + break; + } + } if (!headless) { - Debug::log(WARN, "Unsafe state will be ineffective, no fallback output"); + Debug::log(WARN, "No headless in prepareFallbackOutput?!"); return; } - wlr_headless_add_output(headless, 1920, 1080); + headless->createOutput(); } void CCompositor::startCompositor(std::string socketName, int socketFd) { - initAllSignals(); - if (!socketName.empty() && socketFd != -1) { fcntl(socketFd, F_SETFD, FD_CLOEXEC); const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); @@ -568,15 +663,15 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) { if (m_szWLDisplaySocket.empty()) { Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); - wlr_backend_destroy(m_sWLRBackend); throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); } setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); signal(SIGPIPE, SIG_IGN); - if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) { + if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -588,13 +683,6 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) { Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); - if (!wlr_backend_start(m_sWLRBackend)) { - Debug::log(CRIT, "Backend did not start!"); - wlr_backend_destroy(m_sWLRBackend); - wl_display_destroy(m_sWLDisplay); - throwError("The backend could not start!"); - } - prepareFallbackOutput(); g_pHyprRenderer->setCursorFromName("left_ptr"); @@ -882,7 +970,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } -CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { +CMonitor* CCompositor::getMonitorFromOutput(SP out) { for (auto& m : m_vMonitors) { if (m->output == out) { return m.get(); @@ -892,7 +980,7 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) { return nullptr; } -CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) { +CMonitor* CCompositor::getRealMonitorFromOutput(SP out) { for (auto& m : m_vRealMonitors) { if (m->output == out) { return m.get(); @@ -2240,8 +2328,12 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod g_pInputManager->recheckIdleInhibitorStatus(); - // DMAbuf stuff for direct scanout - g_pHyprRenderer->setWindowScanoutMode(pWindow); + // further updates require a monitor + if (!PMONITOR) + return; + + // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. + g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); } @@ -2282,8 +2374,8 @@ void CCompositor::updateWorkspaceWindowData(const int& id) { } } -void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { - if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive) +void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) { + if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive) return; if (!pMonitor->m_bEnabled) @@ -2292,7 +2384,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) { if (pMonitor->renderingActive) pMonitor->pendingFrame = true; - wlr_output_schedule_frame(pMonitor->output); + pMonitor->output->scheduleFrame(reason); } PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { @@ -2808,3 +2900,84 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } + +static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static auto firstMonitorAdded = std::chrono::system_clock::now(); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = PNEWMONITOR->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } + + if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) + return; + + // after 10s, don't set cursor to default monitor + auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded); + if (timePassedSec.count() > 10) { + cursorDefaultDone = true; + return; + } + + if (*PCURSORMONITOR == monitorName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + +void CCompositor::onNewMonitor(SP output) { + // add it to real + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + if (std::string("HEADLESS-1") == output->name) { + g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); + output->name = "FALLBACK"; // we are allowed to do this :) + } + + Debug::log(LOG, "New output with name {}", output->name); + + PNEWMONITOR->szName = output->name; + PNEWMONITOR->output = output; + PNEWMONITOR->self = PNEWMONITOR; + const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; + PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name); + PNEWMONITOR->isUnsafeFallback = FALLBACK; + + EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); + + if (!FALLBACK) + PNEWMONITOR->onConnect(false); + + if (!PNEWMONITOR->m_bEnabled || FALLBACK) + return; + + // ready to process if we have a real monitor + + if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) + g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); + + g_pCompositor->m_bReadyToProcess = true; + + g_pConfigManager->m_bWantsMonitorReload = true; + g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); + + checkDefaultCursorWarp(PNEWMONITOR, output->name); + + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iMonitorID == PNEWMONITOR->ID) { + w->m_iLastSurfaceMonitorID = -1; + w->updateSurfaceScaleTransformDetails(); + } + } + + g_pHyprRenderer->damageMonitor(PNEWMONITOR.get()); + Events::listener_monitorFrame(PNEWMONITOR.get(), nullptr); +} diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 4aec323f..58c5b33d 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -30,6 +30,9 @@ #include "plugins/PluginSystem.hpp" #include "helpers/Watchdog.hpp" +#include +#include + class CWLSurfaceResource; enum eManagersInitStage { @@ -43,22 +46,11 @@ class CCompositor { CCompositor(); ~CCompositor(); - // ------------------ WLR BASICS ------------------ // - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - wlr_backend* m_sWLRBackend; - wlr_session* m_sWLRSession; - wlr_renderer* m_sWLRRenderer; - wlr_allocator* m_sWLRAllocator; - wlr_compositor* m_sWLRCompositor; - wlr_subcompositor* m_sWLRSubCompositor; - wlr_drm* m_sWRLDRM; - wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr; - wlr_egl* m_sWLREGL; - int m_iDRMFD; - wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; - wlr_backend* m_sWLRHeadlessBackend; - // ------------------------------------------------- // + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + int m_iDRMFD = -1; + bool m_bInitialized = false; + SP m_pAqBackend; std::string m_szHyprTempDataRoot = ""; @@ -94,10 +86,9 @@ class CCompositor { bool m_bReadyToProcess = false; bool m_bSessionActive = true; bool m_bDPMSStateON = true; - bool m_bUnsafeState = false; // unsafe state is when there is no monitors. - bool m_bNextIsUnsafe = false; // because wlroots + bool m_bUnsafeState = false; // unsafe state is when there is no monitors. + bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state - bool m_bExitTriggered = false; // For exit dispatcher bool m_bIsShuttingDown = false; // ------------------------------------------------- // @@ -116,8 +107,8 @@ class CCompositor { SP vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); SP vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP); - CMonitor* getMonitorFromOutput(wlr_output*); - CMonitor* getRealMonitorFromOutput(wlr_output*); + CMonitor* getMonitorFromOutput(SP); + CMonitor* getRealMonitorFromOutput(SP); PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); @@ -157,7 +148,7 @@ class CCompositor { void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); PHLWINDOW getX11Parent(PHLWINDOW); - void scheduleFrameForMonitor(CMonitor*); + void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void addToFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLWINDOW); @@ -182,6 +173,7 @@ class CCompositor { void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); void updateSuspendedStates(); PHLWINDOW windowForCPointer(CWindow*); + void onNewMonitor(SP output); std::string explicitConfigPath; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 71349068..a5f18693 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace Hyprutils::String; extern "C" char** environ; @@ -539,6 +540,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); @@ -557,6 +559,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); + m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0}); + // devices m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); @@ -1285,7 +1289,7 @@ void CConfigManager::dispatchExecOnce() { return; // update dbus env - if (g_pCompositor->m_sWLRSession) + if (g_pCompositor->m_pAqBackend->hasSession()) handleRawExec("", #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -1410,7 +1414,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { if (USEVRR == 0) { if (m->vrrActive) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + + m->output->state->setAdaptiveSync(false); if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); @@ -1419,11 +1424,11 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } else if (USEVRR == 1) { if (!m->vrrActive) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); + m->output->state->setAdaptiveSync(true); if (!m->state.test()) { Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + m->output->state->setAdaptiveSync(false); } if (!m->state.commit()) @@ -1442,19 +1447,19 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; - if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1); + if (WORKSPACEFULL) { + m->output->state->setAdaptiveSync(true); if (!m->state.test()) { Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name); - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + m->output->state->setAdaptiveSync(false); } if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); - } else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) { - wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0); + } else if (!WORKSPACEFULL) { + m->output->state->setAdaptiveSync(false); if (!m->state.commit()) Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name); diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index ce1a92ba..c25212fe 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../plugins/PluginSystem.hpp" #include "../signal-safe.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 08d2bb57..b81cfeff 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -20,6 +22,7 @@ #include using namespace Hyprutils::String; +#include #include "../config/ConfigDataValues.hpp" #include "../config/ConfigValue.hpp" @@ -53,20 +56,15 @@ static std::string formatToString(uint32_t drmFormat) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { std::string result; - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - - if (format == FORMAT_NORMAL) - result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0); - else - result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0); - } - - result.pop_back(); + for (auto& m : pMonitor->output->modes) { + if (format == FORMAT_NORMAL) + result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); + else + result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); } + trimTrailingComma(result); + return result; } @@ -75,8 +73,10 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer if (!m->output || m->ID == -1ull) return ""; - result += std::format( - R"#({{ + if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + + result += std::format( + R"#({{ "id": {}, "name": "{}", "description": "{}", @@ -107,14 +107,27 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer "currentFormat": "{}", "availableModes": [{}] }},)#", - m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""), - escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, - m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), - m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, - (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), - (m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), - (m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + + m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model), + escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, + m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), + escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, + (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), + (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), + (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + + } else { + result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, + (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, + !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + } + return result; } @@ -144,16 +157,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1ull) continue; - result += std::format( - "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - (m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(), - (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), - (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + result += + std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, + (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); } } @@ -552,8 +565,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "defaultSpeed": {:.5f} }},)#", (uintptr_t)m.get(), escapeJSONStrings(m->hlName), - wlr_input_device_is_libinput(&m->wlr()->base) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : - 0.f); + m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f); } trimTrailingComma(result); @@ -611,9 +623,8 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { R"#( {{ "address": "0x{:x}", "type": "tabletTool", - "belongsTo": "0x{:x}" }},)#", - (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); + (uintptr_t)d.get()); } trimTrailingComma(result); @@ -641,7 +652,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "address": "0x{:x}", "name": "{}" }},)#", - (uintptr_t)&d, escapeJSONStrings(d.pWlrDevice ? d.pWlrDevice->name : "")); + (uintptr_t)&d, escapeJSONStrings(d.pDevice ? d.pDevice->getName() : "")); } trimTrailingComma(result); @@ -654,9 +665,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { for (auto& m : g_pInputManager->m_vPointers) { result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, - (wlr_input_device_is_libinput(&m->wlr()->base) ? - libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) : - 0.f)); + (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); } result += "\n\nKeyboards:\n"; @@ -675,11 +684,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { } for (auto& d : g_pInputManager->m_vTablets) { - result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->wlr()->width_mm, d->wlr()->height_mm); + result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y); } for (auto& d : g_pInputManager->m_vTabletTools) { - result += std::format("\tTablet Tool at {:x} (belongs to {:x})\n", (uintptr_t)d.get(), d->wlr() ? (uintptr_t)d->wlr()->data : 0); + result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get()); } result += "\n\nTouch:\n"; @@ -691,7 +700,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n\nSwitches:\n"; for (auto& d : g_pInputManager->m_lSwitches) { - result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pWlrDevice ? d.pWlrDevice->name : ""); + result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : ""); } } @@ -1125,24 +1134,22 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) return "device not found"; - const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr(); - const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap); + const auto KEEB = *PKEYBOARD; + + const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); xkb_layout_index_t activeLayout = 0; while (activeLayout < LAYOUTS) { - if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) + if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) break; activeLayout++; } - if (CMD == "next") { - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, - activeLayout > LAYOUTS ? 0 : activeLayout + 1); - } else if (CMD == "prev") { - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, - activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); - } else { - + if (CMD == "next") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); + else if (CMD == "prev") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); + else { int requestedLayout = 0; try { requestedLayout = std::stoi(CMD); @@ -1152,7 +1159,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ return "layout idx out of range of " + std::to_string(LAYOUTS); } - wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout); + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); } return "ok"; @@ -1368,43 +1375,6 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) return result; } -static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) { - wlr_output* output = nullptr; - - if (type.empty() || type == "auto") { - if (wlr_backend_is_wl(backend)) - output = wlr_wl_output_create(backend); - else if (wlr_backend_is_headless(backend)) - output = wlr_headless_add_output(backend, 1920, 1080); - } else { - if (wlr_backend_is_wl(backend) && type == "wayland") - output = wlr_wl_output_create(backend); - else if (wlr_backend_is_headless(backend) && type == "headless") - output = wlr_headless_add_output(backend, 1920, 1080); - } - - if (output && !name.empty()) - g_pCompositor->getMonitorFromOutput(output)->szName = name; - - return output != nullptr; -} - -struct outputData { - std::string type; - std::string name; - bool added; -}; - -void createOutputIter(wlr_backend* backend, void* data) { - const auto DATA = static_cast(data); - - if (DATA->added) - return; - - if (addOutput(backend, DATA->type, DATA->name)) - DATA->added = true; -} - std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { CVarList vars(request, 0, ' '); @@ -1413,15 +1383,36 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { const auto MODE = vars[1]; + bool added = false; + + if (!vars[3].empty()) { + for (auto& m : g_pCompositor->m_vRealMonitors) { + if (m->szName == vars[3]) + return "Name already taken"; + } + } + if (MODE == "create" || MODE == "add") { if (g_pCompositor->getMonitorFromName(vars[3])) return "A real monitor already uses that name."; - outputData result{vars[2], vars[3], false}; + for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { + auto type = impl->type(); - wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result); + if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) { + added = true; + impl->createOutput(vars[3]); + break; + } - if (!result.added) + if (type == Aquamarine::AQ_BACKEND_WAYLAND && (vars[2] == "wayland" || vars[2] == "auto")) { + added = true; + impl->createOutput(vars[3]); + break; + } + } + + if (!added) return "no backend replied to the request"; } else if (MODE == "destroy" || MODE == "remove") { @@ -1433,7 +1424,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { if (!PMONITOR->createdByUser) return "cannot remove a real display. Use the monitor keyword."; - wlr_output_destroy(PMONITOR->output); + PMONITOR->output->destroy(); } return "ok"; diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 7547204a..c2939831 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -10,30 +10,6 @@ void Debug::init(const std::string& IS) { logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); } -void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) { - if (level > wlr_log_get_verbosity()) - return; - - char* outputStr = nullptr; - - vasprintf(&outputStr, fmt, args); - - std::string output = std::string(outputStr); - free(outputStr); - - rollingLog += output + "\n"; - - if (!disableLogs || !**disableLogs) { - std::ofstream ofs; - ofs.open(logFile, std::ios::out | std::ios::app); - ofs << "[wlr] " << output << "\n"; - ofs.close(); - } - - if (!disableStdout) - std::cout << output << "\n"; -} - void Debug::log(LogLevel level, std::string str) { if (level == TRACE && !trace) return; diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index e8cd80cf..33f3c9c1 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -67,6 +67,4 @@ namespace Debug { log(level, logMsg); } - - void wlrLog(wlr_log_importance level, const char* fmt, va_list args); }; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index f0fd556c..131a26b5 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -55,7 +55,7 @@ void CPopup::initAllSignals() { } void CPopup::onNewPopup(SP popup) { - const auto POPUP = m_vChildren.emplace_back(std::make_unique(popup, this)).get(); + const auto POPUP = m_vChildren.emplace_back(makeShared(popup, this)).get(); Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } @@ -250,7 +250,8 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { - for (auto& c : m_vChildren) { + auto cpy = m_vChildren; + for (auto& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 47e180a8..d045cd41 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -60,8 +60,8 @@ class CPopup { bool m_bMapped = false; // - std::vector> m_vChildren; - std::unique_ptr m_pSubsurfaceHead; + std::vector> m_vChildren; + std::unique_ptr m_pSubsurfaceHead; struct { CHyprSignalListener newPopup; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 4ea34156..7497957a 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1155,7 +1155,8 @@ int CWindow::getRealBorderSize() { } bool CWindow::canBeTorn() { - return m_sWindowData.tearing.valueOr(m_bTearingHint); + static auto PTEARING = CConfigValue("general:allow_tearing"); + return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; } bool CWindow::shouldSendFullscreenState() { diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index cb294d1a..284a8295 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -2,7 +2,21 @@ #include "../defines.hpp" #include "../helpers/varlist/VarList.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/SeatManager.hpp" +#include "../config/ConfigManager.hpp" +#include +#include +#include +#define LED_COUNT 3 + +constexpr static std::array MODNAMES = { + XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_NUM, "Mod3", XKB_MOD_NAME_LOGO, "Mod5", +}; + +constexpr static std::array LEDNAMES = {XKB_LED_NAME_NUM, XKB_LED_NAME_CAPS, XKB_LED_NAME_SCROLL}; + +// uint32_t IKeyboard::getCapabilities() { return HID_INPUT_CAPABILITY_KEYBOARD; } @@ -14,27 +28,149 @@ eHIDType IKeyboard::getType() { IKeyboard::~IKeyboard() { events.destroy.emit(); - if (!xkbTranslationState) - return; + clearManuallyAllocd(); +} - xkb_state_unref(xkbTranslationState); - xkbTranslationState = nullptr; +void IKeyboard::clearManuallyAllocd() { + if (xkbStaticState) + xkb_state_unref(xkbStaticState); + + if (xkbState) + xkb_state_unref(xkbState); + + if (xkbKeymap) + xkb_keymap_unref(xkbKeymap); + + if (xkbKeymapFD >= 0) + close(xkbKeymapFD); + + xkbKeymap = nullptr; + xkbState = nullptr; + xkbStaticState = nullptr; + xkbKeymapFD = -1; +} + +void IKeyboard::setKeymap(const SStringRuleNames& rules) { + currentRules = rules; + xkb_rule_names XKBRULES = { + .rules = rules.rules.c_str(), + .model = rules.model.c_str(), + .layout = rules.layout.c_str(), + .variant = rules.variant.c_str(), + .options = rules.options.c_str(), + }; + + const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + if (!CONTEXT) { + Debug::log(ERR, "setKeymap: CONTEXT null??"); + return; + } + + clearManuallyAllocd(); + + Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, + rules.options); + + if (!xkbFilePath.empty()) { + auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath); + + if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) + Debug::log(ERR, "Cannot open input:kb_file= file for reading"); + else { + xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + fclose(KEYMAPFILE); + } + } + + if (!xkbKeymap) + xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!xkbKeymap) { + g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant + + ", options: " + rules.options + ", layout: " + rules.layout + " )"); + + Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, + rules.options); + memset(&XKBRULES, 0, sizeof(XKBRULES)); + + currentRules.rules = ""; + currentRules.model = ""; + currentRules.variant = ""; + currentRules.options = ""; + currentRules.layout = "us"; + + xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); + } + + // set internal translation state + // demo sunao ni ienai + xkbStaticState = xkb_state_new(xkbKeymap); + + updateXKBTranslationState(xkbKeymap); + + const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default"); + + if (NUMLOCKON == 1) { + // lock numlock + const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM); + + if (IDX != XKB_MOD_INVALID) + modifiersState.locked |= (uint32_t)1 << IDX; + + updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group); + } + + for (size_t i = 0; i < LEDNAMES.size(); ++i) { + ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i)); + Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i)); + } + + for (size_t i = 0; i < MODNAMES.size(); ++i) { + modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i)); + Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i)); + } + + auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); + xkbKeymapString = cKeymapStr; + free(cKeymapStr); + + int rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); + else { + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); + close(rw); + if (keymapFDDest == MAP_FAILED) { + Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); + close(ro); + } else { + memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); + munmap(keymapFDDest, xkbKeymapString.length() + 1); + xkbKeymapFD = ro; + } + } + + xkb_context_unref(CONTEXT); + + g_pSeatManager->updateActiveKeyboardData(); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { - if (xkbTranslationState) - xkb_state_unref(xkbTranslationState); + if (xkbState) + xkb_state_unref(xkbState); + + xkbState = nullptr; if (keymap) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); - xkbTranslationState = xkb_state_new(keymap); + xkbState = xkb_state_new(keymap); return; } - const auto WLRKB = wlr(); - const auto KEYMAP = WLRKB->keymap; - const auto STATE = WLRKB->xkb_state; + const auto KEYMAP = xkbKeymap; + const auto STATE = xkbState; const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); @@ -73,7 +209,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); } - xkbTranslationState = xkb_state_new(KEYMAP); + xkbState = xkb_state_new(KEYMAP); xkb_keymap_unref(KEYMAP); xkb_context_unref(PCONTEXT); @@ -94,16 +230,15 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - xkbTranslationState = xkb_state_new(NEWKEYMAP); + xkbState = xkb_state_new(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP); xkb_context_unref(PCONTEXT); } std::string IKeyboard::getActiveLayout() { - const auto WLRKB = wlr(); - const auto KEYMAP = WLRKB->keymap; - const auto STATE = WLRKB->xkb_state; + const auto KEYMAP = xkbKeymap; + const auto STATE = xkbState; const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP); for (uint32_t i = 0; i < LAYOUTSNUM; ++i) { @@ -120,14 +255,12 @@ std::string IKeyboard::getActiveLayout() { } void IKeyboard::updateLEDs() { - auto keyboard = wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) + if (xkbState == nullptr) return; uint32_t leds = 0; - for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) + for (uint32_t i = 0; i < LED_COUNT; ++i) { + if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i))) leds |= (1 << i); } @@ -135,13 +268,88 @@ void IKeyboard::updateLEDs() { } void IKeyboard::updateLEDs(uint32_t leds) { - auto keyboard = wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) + if (!xkbState) return; if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock())) return; - wlr_keyboard_led_update(keyboard, leds); + if (!aq()) + return; + + aq()->updateLEDs(leds); +} + +uint32_t IKeyboard::getModifiers() { + uint32_t modMask = modifiersState.depressed | modifiersState.latched; + uint32_t mods = 0; + for (size_t i = 0; i < modIndexes.size(); ++i) { + if (modIndexes.at(i) == XKB_MOD_INVALID) + continue; + + if (!(modMask & (1 << modIndexes.at(i)))) + continue; + + mods |= (1 << i); + } + + return mods; +} + +void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { + if (!xkbState) + return; + + xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); + + if (!updateModifiersState()) + return; + + updateLEDs(); +} + +bool IKeyboard::updateModifiersState() { + if (!xkbState) + return false; + + auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED); + auto latched = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED); + auto locked = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED); + auto group = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE); + + if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group) + return false; + + modifiersState.depressed = depressed; + modifiersState.latched = latched; + modifiersState.locked = locked; + modifiersState.group = group; + + return true; +} + +void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { + + const auto contains = std::find(pressedXKB.begin(), pressedXKB.end(), xkbKey) != pressedXKB.end(); + + if (contains && pressed) + return; + if (!contains && !pressed) + return; + + if (contains) + std::erase(pressedXKB, xkbKey); + else + pressedXKB.emplace_back(xkbKey); + + xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); + + if (updateModifiersState()) { + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, + }); + } } diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index b1757a18..1ae6c7bc 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -7,15 +7,26 @@ #include -struct wlr_keyboard; +AQUAMARINE_FORWARD(IKeyboard); + +enum eKeyboardModifiers { + HL_MODIFIER_SHIFT = (1 << 0), + HL_MODIFIER_CAPS = (1 << 1), + HL_MODIFIER_CTRL = (1 << 2), + HL_MODIFIER_ALT = (1 << 3), + HL_MODIFIER_MOD2 = (1 << 4), + HL_MODIFIER_MOD3 = (1 << 5), + HL_MODIFIER_META = (1 << 6), + HL_MODIFIER_MOD5 = (1 << 7), +}; class IKeyboard : public IHID { public: virtual ~IKeyboard(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_keyboard* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SKeyEvent { uint32_t timeMs = 0; @@ -24,6 +35,17 @@ class IKeyboard : public IHID { wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED; }; + struct SKeymapEvent { + xkb_keymap* keymap = nullptr; + }; + + struct SModifiersEvent { + uint32_t depressed = 0; + uint32_t latched = 0; + uint32_t locked = 0; + uint32_t group = 0; + }; + struct { CSignal key; CSignal modifiers; @@ -39,25 +61,46 @@ class IKeyboard : public IHID { std::string rules = ""; }; + void setKeymap(const SStringRuleNames& rules); void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); std::string getActiveLayout(); void updateLEDs(); void updateLEDs(uint32_t leds); + uint32_t getModifiers(); + void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + bool updateModifiersState(); // rets whether changed + void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); bool active = false; bool enabled = true; - xkb_layout_index_t activeLayout = 0; - xkb_state* xkbTranslationState = nullptr; + xkb_layout_index_t activeLayout = 0; + xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; + xkb_keymap* xkbKeymap = nullptr; - std::string hlName = ""; - std::string xkbFilePath = ""; + struct { + uint32_t depressed = 0, latched = 0, locked = 0, group = 0; + } modifiersState; - SStringRuleNames currentRules; - int repeatRate = 0; - int repeatDelay = 0; - int numlockOn = -1; - bool resolveBindsBySym = false; + std::array ledIndexes = {XKB_MOD_INVALID}; + std::array modIndexes = {XKB_MOD_INVALID}; + uint32_t leds = 0; - WP self; + std::string hlName = ""; + std::string xkbFilePath = ""; + std::string xkbKeymapString = ""; + int xkbKeymapFD = -1; + + SStringRuleNames currentRules; + int repeatRate = 0; + int repeatDelay = 0; + int numlockOn = -1; + bool resolveBindsBySym = false; + + WP self; + + private: + void clearManuallyAllocd(); + + std::vector pressedXKB; }; diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index b2995b2f..5df47c04 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -5,17 +5,17 @@ #include "../macros.hpp" #include "../helpers/math/Math.hpp" -struct wlr_pointer; +AQUAMARINE_FORWARD(IPointer); /* Base class for a pointer. */ class IPointer : public IHID { public: - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_pointer* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SMotionEvent { uint32_t timeMs = 0; diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index b9cbf2ae..cb8a6e90 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -5,14 +5,14 @@ #include "../macros.hpp" #include "../helpers/math/Math.hpp" -struct wlr_touch; +AQUAMARINE_FORWARD(ITouch); class ITouch : public IHID { public: - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - virtual bool isVirtual() = 0; - virtual wlr_touch* wlr() = 0; + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + virtual bool isVirtual() = 0; + virtual SP aq() = 0; struct SDownEvent { uint32_t timeMs = 0; diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp index 17357edb..ae28c07d 100644 --- a/src/devices/Keyboard.cpp +++ b/src/devices/Keyboard.cpp @@ -1,7 +1,10 @@ #include "Keyboard.hpp" #include "../defines.hpp" +#include "../Compositor.hpp" -SP CKeyboard::create(wlr_keyboard* keeb) { +#include + +SP CKeyboard::create(SP keeb) { SP pKeeb = SP(new CKeyboard(keeb)); pKeeb->self = pKeeb; @@ -13,52 +16,41 @@ bool CKeyboard::isVirtual() { return false; } -wlr_keyboard* CKeyboard::wlr() { - return keyboard; +SP CKeyboard::aq() { + return keyboard.lock(); } -CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) { +CKeyboard::CKeyboard(SP keeb) : keyboard(keeb) { if (!keeb) return; - // clang-format off - hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); - keyboard = nullptr; - events.destroy.emit(); - }, this, "CKeyboard"); + listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) { + keyboard.reset(); + events.destroy.emit(); + }); - hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { - auto E = (wlr_keyboard_key_event*)data; + listeners.key = keeb->events.key.registerListener([this](std::any d) { + auto E = std::any_cast(d); + + updateXkbStateWithKey(E.key + 8, E.pressed); keyboardEvents.key.emit(SKeyEvent{ - .timeMs = E->time_msec, - .keycode = E->keycode, - .updateMods = E->update_state, - .state = E->state, + .timeMs = E.timeMs, + .keycode = E.key, + .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, }); - }, this, "CKeyboard"); + }); - hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { - keyboardEvents.keymap.emit(); - }, this, "CKeyboard"); + listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) { + updateModifiersState(); - hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { - keyboardEvents.modifiers.emit(); - }, this, "CKeyboard"); + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, + }); + }); - hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { - keyboardEvents.repeatInfo.emit(); - }, this, "CKeyboard"); - // clang-format on - - deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; -} - -void CKeyboard::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_key.removeCallback(); - hyprListener_keymap.removeCallback(); - hyprListener_repeatInfo.removeCallback(); - hyprListener_modifiers.removeCallback(); + deviceName = keeb->getName(); } diff --git a/src/devices/Keyboard.hpp b/src/devices/Keyboard.hpp index cf01a9a7..f6de43cb 100644 --- a/src/devices/Keyboard.hpp +++ b/src/devices/Keyboard.hpp @@ -4,21 +4,19 @@ class CKeyboard : public IKeyboard { public: - static SP create(wlr_keyboard* keeb); + static SP create(SP keeb); - virtual bool isVirtual(); - virtual wlr_keyboard* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CKeyboard(wlr_keyboard* keeb); + CKeyboard(SP keeb); - wlr_keyboard* keyboard = nullptr; + WP keyboard; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(key); - DYNLISTENER(modifiers); - DYNLISTENER(keymap); - DYNLISTENER(repeatInfo); + struct { + CHyprSignalListener destroy; + CHyprSignalListener key; + CHyprSignalListener modifiers; + } listeners; }; \ No newline at end of file diff --git a/src/devices/Mouse.cpp b/src/devices/Mouse.cpp index b860298c..ae89ed92 100644 --- a/src/devices/Mouse.cpp +++ b/src/devices/Mouse.cpp @@ -1,7 +1,8 @@ #include "Mouse.hpp" #include "../defines.hpp" +#include -SP CMouse::create(wlr_pointer* mouse) { +SP CMouse::create(SP mouse) { SP pMouse = SP(new CMouse(mouse)); pMouse->self = pMouse; @@ -9,166 +10,143 @@ SP CMouse::create(wlr_pointer* mouse) { return pMouse; } -CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) { +CMouse::CMouse(SP mouse_) : mouse(mouse_) { if (!mouse) return; - // clang-format off - hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); - mouse = nullptr; + listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) { + mouse.reset(); events.destroy.emit(); - }, this, "CMouse"); + }); - hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_event*)data; + listeners.motion = mouse->events.move.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .delta = {E->delta_x, E->delta_y}, - .unaccel = {E->unaccel_dx, E->unaccel_dy}, + .timeMs = E.timeMs, + .delta = E.delta, + .unaccel = E.unaccel, }); - }, this, "CMouse"); + }); - hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_absolute_event*)data; + listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ - .timeMs = E->time_msec, - .absolute = {E->x, E->y}, + .timeMs = E.timeMs, + .absolute = E.absolute, .device = self.lock(), }); - }, this, "CMouse"); + }); - hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { - auto E = (wlr_pointer_button_event*)data; + listeners.button = mouse->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .state = (wl_pointer_button_state)E->state, + .timeMs = E.timeMs, + .button = E.button, + .state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED, }); - }, this, "CMouse"); + }); - hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_pointer_axis_event*)data; + listeners.axis = mouse->events.axis.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.axis.emit(SAxisEvent{ - .timeMs = E->time_msec, - .source = E->source, - .axis = E->orientation, - .relativeDirection = E->relative_direction, - .delta = E->delta, - .deltaDiscrete = E->delta_discrete, + .timeMs = E.timeMs, + .source = (wl_pointer_axis_source)E.source, + .axis = (wl_pointer_axis)E.axis, + .relativeDirection = (wl_pointer_axis_relative_direction)E.direction, + .delta = E.delta, + .deltaDiscrete = E.discrete, }); - }, this, "CMouse"); + }); - hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { - pointerEvents.frame.emit(); - }, this, "CMouse"); + listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); - hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_begin_event*)data; + listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_end_event*)data; + listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeEnd.emit(SSwipeEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_update_event*)data; + listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, + .timeMs = E.timeMs, + .fingers = E.fingers, + .delta = E.delta, }); - }, this, "CMouse"); + }); - hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_begin_event*)data; + listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchBegin.emit(SPinchBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_end_event*)data; + listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchEnd.emit(SPinchEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_update_event*)data; + listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - .scale = E->scale, - .rotation = E->rotation, + .timeMs = E.timeMs, + .fingers = E.fingers, + .delta = E.delta, + .scale = E.scale, + .rotation = E.rotation, }); - }, this, "CMouse"); + }); - hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_begin_event*)data; + listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.holdBegin.emit(SHoldBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, + .timeMs = E.timeMs, + .fingers = E.fingers, }); - }, this, "CMouse"); + }); - hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_end_event*)data; + listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) { + auto E = std::any_cast(d); pointerEvents.holdEnd.emit(SHoldEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, + .timeMs = E.timeMs, + .cancelled = E.cancelled, }); - }, this, "CMouse"); + }); - // clang-format on - - deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN"; -} - -void CMouse::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_motionAbsolute.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_axis.removeCallback(); - hyprListener_frame.removeCallback(); - hyprListener_swipeBegin.removeCallback(); - hyprListener_swipeEnd.removeCallback(); - hyprListener_swipeUpdate.removeCallback(); - hyprListener_pinchBegin.removeCallback(); - hyprListener_pinchEnd.removeCallback(); - hyprListener_pinchUpdate.removeCallback(); - hyprListener_holdBegin.removeCallback(); - hyprListener_holdEnd.removeCallback(); + deviceName = mouse->getName(); } bool CMouse::isVirtual() { return false; } -wlr_pointer* CMouse::wlr() { - return mouse; +SP CMouse::aq() { + return mouse.lock(); } diff --git a/src/devices/Mouse.hpp b/src/devices/Mouse.hpp index 40a65ca8..2b51fbe9 100644 --- a/src/devices/Mouse.hpp +++ b/src/devices/Mouse.hpp @@ -4,33 +4,34 @@ class CMouse : public IPointer { public: - static SP create(wlr_pointer* mouse); + static SP create(SP mouse); - virtual bool isVirtual(); - virtual wlr_pointer* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CMouse(wlr_pointer* mouse); + CMouse(SP mouse); - wlr_pointer* mouse = nullptr; + WP mouse; - void disconnectCallbacks(); + struct { + CHyprSignalListener destroy; - DYNLISTENER(destroy); - DYNLISTENER(motion); - DYNLISTENER(motionAbsolute); - DYNLISTENER(button); - DYNLISTENER(axis); - DYNLISTENER(frame); + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; - DYNLISTENER(swipeBegin); - DYNLISTENER(swipeEnd); - DYNLISTENER(swipeUpdate); + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; - DYNLISTENER(pinchBegin); - DYNLISTENER(pinchEnd); - DYNLISTENER(pinchUpdate); + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; - DYNLISTENER(holdBegin); - DYNLISTENER(holdEnd); + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + } listeners; }; diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp index b5ab16c1..71ca8991 100644 --- a/src/devices/Tablet.cpp +++ b/src/devices/Tablet.cpp @@ -2,8 +2,9 @@ #include "../defines.hpp" #include "../protocols/Tablet.hpp" #include "../protocols/core/Compositor.hpp" +#include -SP CTablet::create(wlr_tablet* tablet) { +SP CTablet::create(SP tablet) { SP pTab = SP(new CTablet(tablet)); pTab->self = pTab; @@ -13,7 +14,7 @@ SP CTablet::create(wlr_tablet* tablet) { return pTab; } -SP CTabletTool::create(wlr_tablet_tool* tablet) { +SP CTabletTool::create(SP tablet) { SP pTab = SP(new CTabletTool(tablet)); pTab->self = pTab; @@ -23,7 +24,7 @@ SP CTabletTool::create(wlr_tablet_tool* tablet) { return pTab; } -SP CTabletPad::create(wlr_tablet_pad* tablet) { +SP CTabletPad::create(SP tablet) { SP pTab = SP(new CTabletPad(tablet)); pTab->self = pTab; @@ -33,33 +34,25 @@ SP CTabletPad::create(wlr_tablet_pad* tablet) { return pTab; } -SP CTabletTool::fromWlr(wlr_tablet_tool* tool) { - return ((CTabletTool*)tool->data)->self.lock(); -} - -SP CTablet::fromWlr(wlr_tablet* tablet) { - return ((CTablet*)tablet->data)->self.lock(); -} - -static uint32_t wlrUpdateToHl(uint32_t wlr) { +static uint32_t aqUpdateToHl(uint32_t aq) { uint32_t result = 0; - if (wlr & WLR_TABLET_TOOL_AXIS_X) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_X) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_X; - if (wlr & WLR_TABLET_TOOL_AXIS_Y) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_Y) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_Y; - if (wlr & WLR_TABLET_TOOL_AXIS_DISTANCE) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_DISTANCE) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_DISTANCE; - if (wlr & WLR_TABLET_TOOL_AXIS_PRESSURE) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_PRESSURE) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_PRESSURE; - if (wlr & WLR_TABLET_TOOL_AXIS_TILT_X) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_X) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X; - if (wlr & WLR_TABLET_TOOL_AXIS_TILT_Y) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_TILT_Y) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y; - if (wlr & WLR_TABLET_TOOL_AXIS_ROTATION) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_ROTATION) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_ROTATION; - if (wlr & WLR_TABLET_TOOL_AXIS_SLIDER) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_SLIDER) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_SLIDER; - if (wlr & WLR_TABLET_TOOL_AXIS_WHEEL) + if (aq & Aquamarine::AQ_TABLET_TOOL_AXIS_WHEEL) result |= CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_WHEEL; return result; } @@ -68,97 +61,81 @@ uint32_t CTablet::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet* CTablet::wlr() { - return tablet; +SP CTablet::aq() { + return tablet.lock(); } -CTablet::CTablet(wlr_tablet* tablet_) : tablet(tablet_) { +CTablet::CTablet(SP tablet_) : tablet(tablet_) { if (!tablet) return; - tablet->data = this; - - // clang-format off - hyprListener_destroy.initCallback(&tablet->base.events.destroy, [this] (void* owner, void* data) { - tablet = nullptr; - disconnectCallbacks(); + listeners.destroy = tablet->events.destroy.registerListener([this](std::any d) { + tablet.reset(); events.destroy.emit(); - }, this, "CTablet"); + }); - hyprListener_axis.initCallback(&tablet->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_axis_event*)data; + listeners.axis = tablet->events.axis.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.axis.emit(SAxisEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .updatedAxes = wlrUpdateToHl(E->updated_axes), - .axis = {E->x, E->y}, - .axisDelta = {E->dx, E->dy}, - .tilt = {E->tilt_x, E->tilt_y}, - .pressure = E->pressure, - .distance = E->distance, - .rotation = E->rotation, - .slider = E->slider, - .wheelDelta = E->wheel_delta, + .timeMs = E.timeMs, + .updatedAxes = aqUpdateToHl(E.updatedAxes), + .axis = E.absolute, + .axisDelta = E.delta, + .tilt = E.tilt, + .pressure = E.pressure, + .distance = E.distance, + .rotation = E.rotation, + .slider = E.slider, + .wheelDelta = E.wheelDelta, }); - }, this, "CTablet"); + }); - hyprListener_proximity.initCallback(&tablet->events.proximity, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_proximity_event*)data; + listeners.proximity = tablet->events.proximity.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.proximity.emit(SProximityEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .proximity = {E->x, E->y}, - .in = E->state == WLR_TABLET_TOOL_PROXIMITY_IN, + .timeMs = E.timeMs, + .proximity = E.absolute, + .in = E.in, }); - }, this, "CTablet"); + }); - hyprListener_tip.initCallback(&tablet->events.tip, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_tip_event*)data; + listeners.tip = tablet->events.tip.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.tip.emit(STipEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .tip = {E->x, E->y}, - .in = E->state == WLR_TABLET_TOOL_TIP_DOWN, + .timeMs = E.timeMs, + .tip = E.absolute, + .in = E.down, }); - }, this, "CTablet"); + }); - hyprListener_button.initCallback(&tablet->events.button, [this] (void* owner, void* data) { - auto E = (wlr_tablet_tool_button_event*)data; + listeners.button = tablet->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); tabletEvents.button.emit(SButtonEvent{ - .tool = E->tool, + .tool = E.tool, .tablet = self.lock(), - .timeMs = E->time_msec, - .button = E->button, - .down = E->state == WLR_BUTTON_PRESSED, + .timeMs = E.timeMs, + .button = E.button, + .down = E.down, }); - }, this, "CTablet"); - // clang-format on + }); - deviceName = tablet->base.name ? tablet->base.name : "UNKNOWN"; + deviceName = tablet->getName(); } CTablet::~CTablet() { - if (tablet) - tablet->data = nullptr; - PROTO::tablet->recheckRegisteredDevices(); } -void CTablet::disconnectCallbacks() { - hyprListener_axis.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_destroy.removeCallback(); - hyprListener_proximity.removeCallback(); - hyprListener_tip.removeCallback(); -} - eHIDType CTablet::getType() { return HID_TYPE_TABLET; } @@ -167,138 +144,111 @@ uint32_t CTabletPad::getCapabilities() { return HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet_pad* CTabletPad::wlr() { - return pad; +SP CTabletPad::aq() { + return pad.lock(); } eHIDType CTabletPad::getType() { return HID_TYPE_TABLET_PAD; } -CTabletPad::CTabletPad(wlr_tablet_pad* pad_) : pad(pad_) { +CTabletPad::CTabletPad(SP pad_) : pad(pad_) { if (!pad) return; - // clang-format off - hyprListener_destroy.initCallback(&pad->base.events.destroy, [this] (void* owner, void* data) { - pad = nullptr; - disconnectCallbacks(); + listeners.destroy = pad->events.destroy.registerListener([this](std::any d) { + pad.reset(); events.destroy.emit(); - }, this, "CTabletPad"); + }); - hyprListener_button.initCallback(&pad->events.button, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_button_event*)data; + listeners.button = pad->events.button.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .down = E->state == WLR_BUTTON_PRESSED, - .mode = E->mode, - .group = E->group, + .timeMs = E.timeMs, + .button = E.button, + .down = E.down, + .mode = E.mode, + .group = E.group, }); - }, this, "CTabletPad"); + }); - hyprListener_ring.initCallback(&pad->events.ring, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_ring_event*)data; + listeners.ring = pad->events.ring.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.ring.emit(SRingEvent{ - .timeMs = E->time_msec, - .finger = E->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, - .ring = E->ring, - .position = E->position, - .mode = E->mode, + .timeMs = E.timeMs, + .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_RING_SOURCE_FINGER, + .ring = E.ring, + .position = E.pos, + .mode = E.mode, }); - }, this, "CTabletPad"); + }); - hyprListener_strip.initCallback(&pad->events.strip, [this] (void* owner, void* data) { - auto E = (wlr_tablet_pad_strip_event*)data; + listeners.strip = pad->events.strip.registerListener([this](std::any d) { + auto E = std::any_cast(d); padEvents.strip.emit(SStripEvent{ - .timeMs = E->time_msec, - .finger = E->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, - .strip = E->strip, - .position = E->position, - .mode = E->mode, + .timeMs = E.timeMs, + .finger = E.source == Aquamarine::ITabletPad::AQ_TABLET_PAD_STRIP_SOURCE_FINGER, + .strip = E.strip, + .position = E.pos, + .mode = E.mode, }); - }, this, "CTabletPad"); + }); - hyprListener_attach.initCallback(&pad->events.attach_tablet, [this] (void* owner, void* data) { - if (!data) - return; - - padEvents.attach.emit(CTabletTool::fromWlr((wlr_tablet_tool*)data)); - }, this, "CTabletPad"); - // clang-format on + listeners.attach = pad->events.attach.registerListener([this](std::any d) { + ; // TODO: this doesn't do anything in aq atm + }); - deviceName = pad->base.name ? pad->base.name : "UNKNOWN"; + deviceName = pad->getName(); } CTabletPad::~CTabletPad() { PROTO::tablet->recheckRegisteredDevices(); } -void CTabletPad::disconnectCallbacks() { - hyprListener_ring.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_destroy.removeCallback(); - hyprListener_strip.removeCallback(); - hyprListener_attach.removeCallback(); -} - uint32_t CTabletTool::getCapabilities() { return HID_INPUT_CAPABILITY_POINTER | HID_INPUT_CAPABILITY_TABLET; } -wlr_tablet_tool* CTabletTool::wlr() { - return tool; +SP CTabletTool::aq() { + return tool.lock(); } eHIDType CTabletTool::getType() { return HID_TYPE_TABLET_TOOL; } -CTabletTool::CTabletTool(wlr_tablet_tool* tool_) : tool(tool_) { +CTabletTool::CTabletTool(SP tool_) : tool(tool_) { if (!tool) return; - // clang-format off - hyprListener_destroy.initCallback(&tool->events.destroy, [this] (void* owner, void* data) { - tool = nullptr; - disconnectCallbacks(); + listeners.destroyTool = tool->events.destroy.registerListener([this](std::any d) { + tool.reset(); events.destroy.emit(); - }, this, "CTabletTool"); - // clang-format on + }); - if (tool->tilt) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_TILT) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_TILT; - if (tool->pressure) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_PRESSURE) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_PRESSURE; - if (tool->distance) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_DISTANCE) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_DISTANCE; - if (tool->rotation) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_ROTATION) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_ROTATION; - if (tool->slider) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_SLIDER) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_SLIDER; - if (tool->wheel) + if (tool->capabilities & Aquamarine::ITabletTool::AQ_TABLET_TOOL_CAPABILITY_WHEEL) toolCapabilities |= HID_TABLET_TOOL_CAPABILITY_WHEEL; - tool->data = this; - - deviceName = std::to_string(tool->hardware_serial) + std::to_string(tool->hardware_wacom); + deviceName = std::format("{:x}-{:x}", tool->serial, tool->id); } CTabletTool::~CTabletTool() { - if (tool) - tool->data = nullptr; - PROTO::tablet->recheckRegisteredDevices(); } -void CTabletTool::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - listeners.destroySurface.reset(); -} - SP CTabletTool::getSurface() { return pSurface.lock(); } diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index ada2cf89..0efbe796 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -6,9 +6,9 @@ #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" -struct wlr_tablet; -struct wlr_tablet_tool; -struct wlr_tablet_pad; +AQUAMARINE_FORWARD(ITablet); +AQUAMARINE_FORWARD(ITabletTool); +AQUAMARINE_FORWARD(ITabletPad); class CTabletTool; class CTabletPad; @@ -21,13 +21,12 @@ class CWLSurfaceResource; */ class CTablet : public IHID { public: - static SP create(wlr_tablet* tablet); - static SP fromWlr(wlr_tablet* tablet); + static SP create(SP tablet); ~CTablet(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - wlr_tablet* wlr(); + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + SP aq(); enum eTabletToolAxes { HID_TABLET_TOOL_AXIS_X = (1 << 0), @@ -42,46 +41,46 @@ class CTablet : public IHID { }; struct SAxisEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - uint32_t updatedAxes = 0; // eTabletToolAxes - Vector2D axis; - Vector2D axisDelta; - Vector2D tilt; - double pressure = 0; - double distance = 0; - double rotation = 0; - double slider = 0; - double wheelDelta = 0; + uint32_t timeMs = 0; + uint32_t updatedAxes = 0; // eTabletToolAxes + Vector2D axis; + Vector2D axisDelta; + Vector2D tilt; + double pressure = 0; + double distance = 0; + double rotation = 0; + double slider = 0; + double wheelDelta = 0; }; struct SProximityEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - Vector2D proximity; - bool in = false; + uint32_t timeMs = 0; + Vector2D proximity; + bool in = false; }; struct STipEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - Vector2D tip; - bool in = false; + uint32_t timeMs = 0; + Vector2D tip; + bool in = false; }; struct SButtonEvent { - wlr_tablet_tool* tool; - SP tablet; + SP tool; + SP tablet; - uint32_t timeMs = 0; - uint32_t button; - bool down = false; + uint32_t timeMs = 0; + uint32_t button; + bool down = false; }; struct { @@ -100,27 +99,27 @@ class CTablet : public IHID { CBox boundBox; // output-local private: - CTablet(wlr_tablet* tablet); + CTablet(SP tablet); - void disconnectCallbacks(); + WP tablet; - wlr_tablet* tablet = nullptr; - - DYNLISTENER(destroy); - DYNLISTENER(axis); - DYNLISTENER(proximity); - DYNLISTENER(tip); - DYNLISTENER(button); + struct { + CHyprSignalListener destroy; + CHyprSignalListener axis; + CHyprSignalListener proximity; + CHyprSignalListener tip; + CHyprSignalListener button; + } listeners; }; class CTabletPad : public IHID { public: - static SP create(wlr_tablet_pad* pad); + static SP create(SP pad); ~CTabletPad(); - virtual uint32_t getCapabilities(); - virtual eHIDType getType(); - wlr_tablet_pad* wlr(); + virtual uint32_t getCapabilities(); + virtual eHIDType getType(); + SP aq(); struct SButtonEvent { uint32_t timeMs = 0; @@ -159,23 +158,22 @@ class CTabletPad : public IHID { std::string hlName; private: - CTabletPad(wlr_tablet_pad* pad); + CTabletPad(SP pad); - void disconnectCallbacks(); + WP pad; - wlr_tablet_pad* pad = nullptr; - - DYNLISTENER(destroy); - DYNLISTENER(ring); - DYNLISTENER(strip); - DYNLISTENER(button); - DYNLISTENER(attach); + struct { + CHyprSignalListener destroy; + CHyprSignalListener ring; + CHyprSignalListener strip; + CHyprSignalListener button; + CHyprSignalListener attach; + } listeners; }; class CTabletTool : public IHID { public: - static SP create(wlr_tablet_tool* tool); - static SP fromWlr(wlr_tablet_tool* tool); + static SP create(SP tool); ~CTabletTool(); enum eTabletToolType { @@ -198,35 +196,31 @@ class CTabletTool : public IHID { HID_TABLET_TOOL_CAPABILITY_WHEEL = (1 << 5), }; - virtual uint32_t getCapabilities(); - wlr_tablet_tool* wlr(); - virtual eHIDType getType(); - SP getSurface(); - void setSurface(SP); + virtual uint32_t getCapabilities(); + SP aq(); + virtual eHIDType getType(); + SP getSurface(); + void setSurface(SP); - WP self; - Vector2D tilt; - bool active = false; // true if in proximity - uint32_t toolCapabilities = 0; + WP self; + Vector2D tilt; + bool active = false; // true if in proximity + uint32_t toolCapabilities = 0; - bool isDown = false; - std::vector buttonsDown; - Vector2D absolutePos; // last known absolute position. + bool isDown = false; + std::vector buttonsDown; + Vector2D absolutePos; // last known absolute position. - std::string hlName; + std::string hlName; private: - CTabletTool(wlr_tablet_tool* tool); + CTabletTool(SP tool); - void disconnectCallbacks(); - - WP pSurface; - - wlr_tablet_tool* tool = nullptr; - - DYNLISTENER(destroy); + WP pSurface; + WP tool; struct { CHyprSignalListener destroySurface; + CHyprSignalListener destroyTool; } listeners; }; \ No newline at end of file diff --git a/src/devices/TouchDevice.cpp b/src/devices/TouchDevice.cpp index 64c521a2..25b7b503 100644 --- a/src/devices/TouchDevice.cpp +++ b/src/devices/TouchDevice.cpp @@ -1,7 +1,8 @@ #include "TouchDevice.hpp" #include "../defines.hpp" +#include -SP CTouchDevice::create(wlr_touch* touch) { +SP CTouchDevice::create(SP touch) { SP pTouch = SP(new CTouchDevice(touch)); pTouch->self = pTouch; @@ -9,78 +10,63 @@ SP CTouchDevice::create(wlr_touch* touch) { return pTouch; } -CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) { +CTouchDevice::CTouchDevice(SP touch_) : touch(touch_) { if (!touch) return; - // clang-format off - hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) { + listeners.destroy = touch->events.destroy.registerListener([this](std::any d) { events.destroy.emit(); - disconnectCallbacks(); - touch = nullptr; - }, this, "CTouchDevice"); + touch.reset(); + }); - hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) { - auto E = (wlr_touch_down_event*)data; + listeners.down = touch->events.down.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.down.emit(SDownEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id, - .pos = {E->x, E->y}, + .timeMs = E.timeMs, + .touchID = E.touchID, + .pos = E.pos, .device = self.lock(), }); - }, this, "CTouchDevice"); + }); - hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) { - auto E = (wlr_touch_up_event*)data; + listeners.up = touch->events.up.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.up.emit(SUpEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id + .timeMs = E.timeMs, + .touchID = E.touchID, }); - }, this, "CTouchDevice"); + }); - hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_touch_motion_event*)data; + listeners.motion = touch->events.move.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id, - .pos = {E->x, E->y}, + .timeMs = E.timeMs, + .touchID = E.touchID, + .pos = E.pos, }); - }, this, "CTouchDevice"); + }); - hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) { - auto E = (wlr_touch_cancel_event*)data; + listeners.cancel = touch->events.cancel.registerListener([this](std::any d) { + auto E = std::any_cast(d); touchEvents.cancel.emit(SCancelEvent{ - .timeMs = E->time_msec, - .touchID = E->touch_id + .timeMs = E.timeMs, + .touchID = E.touchID, }); - }, this, "CTouchDevice"); + }); - hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) { - touchEvents.frame.emit(); - }, this, "CTouchDevice"); + listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); }); - // clang-format on - - deviceName = touch->base.name ? touch->base.name : "UNKNOWN"; + deviceName = touch->getName(); } bool CTouchDevice::isVirtual() { return false; } -wlr_touch* CTouchDevice::wlr() { - return touch; -} - -void CTouchDevice::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_down.removeCallback(); - hyprListener_up.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_cancel.removeCallback(); - hyprListener_frame.removeCallback(); +SP CTouchDevice::aq() { + return touch.lock(); } diff --git a/src/devices/TouchDevice.hpp b/src/devices/TouchDevice.hpp index 51eb76d4..b18df2d0 100644 --- a/src/devices/TouchDevice.hpp +++ b/src/devices/TouchDevice.hpp @@ -4,22 +4,22 @@ class CTouchDevice : public ITouch { public: - static SP create(wlr_touch* touch); + static SP create(SP touch); - virtual bool isVirtual(); - virtual wlr_touch* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: - CTouchDevice(wlr_touch* touch); + CTouchDevice(SP touch); - wlr_touch* touch = nullptr; + WP touch; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(down); - DYNLISTENER(up); - DYNLISTENER(motion); - DYNLISTENER(cancel); - DYNLISTENER(frame); + struct { + CHyprSignalListener destroy; + CHyprSignalListener down; + CHyprSignalListener up; + CHyprSignalListener motion; + CHyprSignalListener cancel; + CHyprSignalListener frame; + } listeners; }; \ No newline at end of file diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp index e2be0078..654ca9f5 100644 --- a/src/devices/VirtualKeyboard.cpp +++ b/src/devices/VirtualKeyboard.cpp @@ -14,58 +14,37 @@ CVirtualKeyboard::CVirtualKeyboard(SP keeb_) : keybo if (!keeb_) return; - auto keeb = keeb_->wlr(); - - // clang-format off - hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); + listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) { keyboard.reset(); - events.destroy.emit(); - }, this, "CVirtualKeyboard"); + events.destroy.emit(); + }); - hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) { - auto E = (wlr_keyboard_key_event*)data; - - keyboardEvents.key.emit(SKeyEvent{ - .timeMs = E->time_msec, - .keycode = E->keycode, - .updateMods = E->update_state, - .state = E->state, + listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); }); + listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) { + auto E = std::any_cast(d); + updateModifiers(E.depressed, E.latched, E.locked, E.group); + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, }); - }, this, "CVirtualKeyboard"); + }); + listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) { + auto E = std::any_cast(d); + xkbKeymap = xkb_keymap_ref(E.keymap); + keyboardEvents.keymap.emit(d); + }); - hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) { - keyboardEvents.keymap.emit(); - }, this, "CVirtualKeyboard"); - - hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) { - keyboardEvents.modifiers.emit(); - }, this, "CVirtualKeyboard"); - - hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) { - keyboardEvents.repeatInfo.emit(); - }, this, "CVirtualKeyboard"); - // clang-format on - - deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN"; + deviceName = keeb_->name; } bool CVirtualKeyboard::isVirtual() { return true; } -wlr_keyboard* CVirtualKeyboard::wlr() { - if (keyboard.expired()) - return nullptr; - return keyboard->wlr(); -} - -void CVirtualKeyboard::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_key.removeCallback(); - hyprListener_keymap.removeCallback(); - hyprListener_repeatInfo.removeCallback(); - hyprListener_modifiers.removeCallback(); +SP CVirtualKeyboard::aq() { + return nullptr; } wl_client* CVirtualKeyboard::getClient() { diff --git a/src/devices/VirtualKeyboard.hpp b/src/devices/VirtualKeyboard.hpp index 5ef88dd3..12a3907c 100644 --- a/src/devices/VirtualKeyboard.hpp +++ b/src/devices/VirtualKeyboard.hpp @@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource; class CVirtualKeyboard : public IKeyboard { public: - static SP create(SP keeb); + static SP create(SP keeb); - virtual bool isVirtual(); - virtual wlr_keyboard* wlr(); + virtual bool isVirtual(); + virtual SP aq(); - wl_client* getClient(); + wl_client* getClient(); private: CVirtualKeyboard(SP keeb); WP keyboard; - void disconnectCallbacks(); - - DYNLISTENER(destroy); - DYNLISTENER(key); - DYNLISTENER(modifiers); - DYNLISTENER(keymap); - DYNLISTENER(repeatInfo); + struct { + CHyprSignalListener destroy; + CHyprSignalListener key; + CHyprSignalListener modifiers; + CHyprSignalListener keymap; + } listeners; }; diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index c8ee3332..faca27dc 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -1,5 +1,6 @@ #include "VirtualPointer.hpp" #include "../protocols/VirtualPointer.hpp" +#include SP CVirtualPointer::create(SP resource) { SP pPointer = SP(new CVirtualPointer(resource)); @@ -13,165 +14,32 @@ CVirtualPointer::CVirtualPointer(SP resource) : point if (!resource->good()) return; - auto mouse = resource->wlr(); - - // clang-format off - hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) { - disconnectCallbacks(); + listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) { + pointer.reset(); events.destroy.emit(); - }, this, "CVirtualPointer"); + }); - hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_event*)data; + listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); }); + listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { pointerEvents.motionAbsolute.emit(d); }); + listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); }); + listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); }); + listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); + listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); }); + listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); }); + listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); }); + listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); }); + listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); }); + listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); }); + listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); + listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); - pointerEvents.motion.emit(SMotionEvent{ - .timeMs = E->time_msec, - .delta = {E->delta_x, E->delta_y}, - .unaccel = {E->unaccel_dx, E->unaccel_dy}, - }); - }, this, "CVirtualPointer"); - - hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) { - auto E = (wlr_pointer_motion_absolute_event*)data; - - pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{ - .timeMs = E->time_msec, - .absolute = {E->x, E->y}, - .device = self.lock(), - }); - }, this, "CVirtualPointer"); - - hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) { - auto E = (wlr_pointer_button_event*)data; - - pointerEvents.button.emit(SButtonEvent{ - .timeMs = E->time_msec, - .button = E->button, - .state = (wl_pointer_button_state)E->state, - }); - }, this, "CVirtualPointer"); - - hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) { - auto E = (wlr_pointer_axis_event*)data; - - pointerEvents.axis.emit(SAxisEvent{ - .timeMs = E->time_msec, - .source = E->source, - .axis = E->orientation, - .relativeDirection = E->relative_direction, - .delta = E->delta, - .deltaDiscrete = E->delta_discrete, - }); - }, this, "CVirtualPointer"); - - hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) { - pointerEvents.frame.emit(); - }, this, "CVirtualPointer"); - - hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_begin_event*)data; - - pointerEvents.swipeBegin.emit(SSwipeBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_end_event*)data; - - pointerEvents.swipeEnd.emit(SSwipeEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_swipe_update_event*)data; - - pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_begin_event*)data; - - pointerEvents.pinchBegin.emit(SPinchBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_end_event*)data; - - pointerEvents.pinchEnd.emit(SPinchEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) { - auto E = (wlr_pointer_pinch_update_event*)data; - - pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - .delta = {E->dx, E->dy}, - .scale = E->scale, - .rotation = E->rotation, - }); - }, this, "CVirtualPointer"); - - hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_begin_event*)data; - - pointerEvents.holdBegin.emit(SHoldBeginEvent{ - .timeMs = E->time_msec, - .fingers = E->fingers, - }); - }, this, "CVirtualPointer"); - - hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) { - auto E = (wlr_pointer_hold_end_event*)data; - - pointerEvents.holdEnd.emit(SHoldEndEvent{ - .timeMs = E->time_msec, - .cancelled = E->cancelled, - }); - }, this, "CVirtualPointer"); - - // clang-format on - - deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN"; + deviceName = pointer->name; } bool CVirtualPointer::isVirtual() { return true; } -void CVirtualPointer::disconnectCallbacks() { - hyprListener_destroy.removeCallback(); - hyprListener_motion.removeCallback(); - hyprListener_motionAbsolute.removeCallback(); - hyprListener_button.removeCallback(); - hyprListener_axis.removeCallback(); - hyprListener_frame.removeCallback(); - hyprListener_swipeBegin.removeCallback(); - hyprListener_swipeEnd.removeCallback(); - hyprListener_swipeUpdate.removeCallback(); - hyprListener_pinchBegin.removeCallback(); - hyprListener_pinchEnd.removeCallback(); - hyprListener_pinchUpdate.removeCallback(); - hyprListener_holdBegin.removeCallback(); - hyprListener_holdEnd.removeCallback(); -} - -wlr_pointer* CVirtualPointer::wlr() { - if (pointer.expired()) - return nullptr; - return pointer->wlr(); +SP CVirtualPointer::aq() { + return nullptr; } diff --git a/src/devices/VirtualPointer.hpp b/src/devices/VirtualPointer.hpp index b22c8bf2..1ecfd842 100644 --- a/src/devices/VirtualPointer.hpp +++ b/src/devices/VirtualPointer.hpp @@ -6,33 +6,34 @@ class CVirtualPointerV1Resource; class CVirtualPointer : public IPointer { public: - static SP create(SP resource); + static SP create(SP resource); - virtual bool isVirtual(); - virtual wlr_pointer* wlr(); + virtual bool isVirtual(); + virtual SP aq(); private: CVirtualPointer(SP); WP pointer; - void disconnectCallbacks(); + struct { + CHyprSignalListener destroy; - DYNLISTENER(destroy); - DYNLISTENER(motion); - DYNLISTENER(motionAbsolute); - DYNLISTENER(button); - DYNLISTENER(axis); - DYNLISTENER(frame); + CHyprSignalListener motion; + CHyprSignalListener motionAbsolute; + CHyprSignalListener button; + CHyprSignalListener axis; + CHyprSignalListener frame; - DYNLISTENER(swipeBegin); - DYNLISTENER(swipeEnd); - DYNLISTENER(swipeUpdate); + CHyprSignalListener swipeBegin; + CHyprSignalListener swipeEnd; + CHyprSignalListener swipeUpdate; - DYNLISTENER(pinchBegin); - DYNLISTENER(pinchEnd); - DYNLISTENER(pinchUpdate); + CHyprSignalListener pinchBegin; + CHyprSignalListener pinchEnd; + CHyprSignalListener pinchUpdate; - DYNLISTENER(holdBegin); - DYNLISTENER(holdEnd); + CHyprSignalListener holdBegin; + CHyprSignalListener holdEnd; + } listeners; }; \ No newline at end of file diff --git a/src/events/Devices.cpp b/src/events/Devices.cpp deleted file mode 100644 index fedc844e..00000000 --- a/src/events/Devices.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Events.hpp" - -#include "../Compositor.hpp" -#include "../helpers/WLClasses.hpp" -#include "../managers/input/InputManager.hpp" -#include "../render/Renderer.hpp" - -// ---------------------------------------------------- // -// _____ ________ _______ _____ ______ _____ // -// | __ \| ____\ \ / /_ _/ ____| ____|/ ____| // -// | | | | |__ \ \ / / | || | | |__ | (___ // -// | | | | __| \ \/ / | || | | __| \___ \ // -// | |__| | |____ \ / _| || |____| |____ ____) | // -// |_____/|______| \/ |_____\_____|______|_____/ // -// // -// ---------------------------------------------------- // - -void Events::listener_newInput(wl_listener* listener, void* data) { - const auto DEVICE = (wlr_input_device*)data; - - switch (DEVICE->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name); - g_pInputManager->newKeyboard(DEVICE); - break; - case WLR_INPUT_DEVICE_POINTER: - Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name); - g_pInputManager->newMouse(DEVICE); - break; - case WLR_INPUT_DEVICE_TOUCH: - Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name); - g_pInputManager->newTouchDevice(DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET: - Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name); - g_pInputManager->newTablet(DEVICE); - break; - case WLR_INPUT_DEVICE_TABLET_PAD: - Debug::log(LOG, "Attached a tablet pad with name {}", DEVICE->name); - g_pInputManager->newTabletPad(DEVICE); - break; - case WLR_INPUT_DEVICE_SWITCH: - Debug::log(LOG, "Attached a switch device with name {}", DEVICE->name); - g_pInputManager->newSwitch(DEVICE); - break; - default: Debug::log(WARN, "Unrecognized input device plugged in: {}", DEVICE->name); break; - } - - g_pInputManager->updateCapabilities(); -} diff --git a/src/events/Events.hpp b/src/events/Events.hpp index f8eb9d2f..8e73f54a 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -8,16 +8,6 @@ // namespace Events { - // Monitor events - LISTENER(change); - LISTENER(newOutput); - - // DRM events - LISTENER(leaseRequest); - - // Layer events - LISTENER(newLayerSurface); - // Window events DYNLISTENFUNC(commitWindow); DYNLISTENFUNC(mapWindow); @@ -35,15 +25,6 @@ namespace Events { DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(ackConfigure); - LISTENER(newInput); - - // Virt Ptr - LISTENER(newVirtPtr); - - // Various - LISTENER(requestSetSel); - LISTENER(requestSetPrimarySel); - // Monitor part 2 the sequel DYNLISTENFUNC(monitorFrame); DYNLISTENFUNC(monitorDestroy); @@ -52,16 +33,4 @@ namespace Events { DYNLISTENFUNC(monitorNeedsFrame); DYNLISTENFUNC(monitorCommit); DYNLISTENFUNC(monitorBind); - - // XWayland - LISTENER(surfaceXWayland); - - // Renderer destroy - LISTENER(RendererDestroy); - - // session - LISTENER(sessionActive); - - // Session Lock - LISTENER(newSessionLock); }; diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp deleted file mode 100644 index 32f894ec..00000000 --- a/src/events/Misc.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "Events.hpp" - -#include "../Compositor.hpp" -#include "../helpers/WLClasses.hpp" -#include "../managers/input/InputManager.hpp" -#include "../render/Renderer.hpp" -#include "../managers/CursorManager.hpp" - -// ------------------------------ // -// __ __ _____ _____ _____ // -// | \/ |_ _|/ ____|/ ____| // -// | \ / | | | | (___ | | // -// | |\/| | | | \___ \| | // -// | | | |_| |_ ____) | |____ // -// |_| |_|_____|_____/ \_____| // -// // -// ------------------------------ // - -void Events::listener_leaseRequest(wl_listener* listener, void* data) { - const auto REQUEST = (wlr_drm_lease_request_v1*)data; - struct wlr_drm_lease_v1* lease = wlr_drm_lease_request_v1_grant(REQUEST); - if (!lease) { - Debug::log(ERR, "Failed to grant lease request!"); - wlr_drm_lease_request_v1_reject(REQUEST); - } -} - -void Events::listener_RendererDestroy(wl_listener* listener, void* data) { - Debug::log(LOG, "!!Renderer destroyed!!"); -} - -void Events::listener_sessionActive(wl_listener* listener, void* data) { - if (g_pCompositor->m_sWLRSession->active) { - Debug::log(LOG, "Session got activated!"); - - g_pCompositor->m_bSessionActive = true; - - for (auto& m : g_pCompositor->m_vMonitors) { - g_pCompositor->scheduleFrameForMonitor(m.get()); - g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); - } - - g_pConfigManager->m_bWantsMonitorReload = true; - } else { - Debug::log(LOG, "Session got inactivated!"); - - g_pCompositor->m_bSessionActive = false; - - for (auto& m : g_pCompositor->m_vMonitors) { - m->noFrameSchedule = true; - m->framesToSkip = 1; - } - } -} diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 2536e1f7..40b6f17e 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -5,6 +5,7 @@ #include "Events.hpp" #include "../debug/HyprCtl.hpp" #include "../config/ConfigValue.hpp" +#include // --------------------------------------------------------- // // __ __ ____ _ _ _____ _______ ____ _____ _____ // @@ -16,99 +17,10 @@ // // // --------------------------------------------------------- // -static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { - - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static auto firstMonitorAdded = std::chrono::steady_clock::now(); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = PNEWMONITOR->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } - - if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) - return; - - // after 10s, don't set cursor to default monitor - auto timePassedSec = std::chrono::duration_cast(std::chrono::steady_clock::now() - firstMonitorAdded); - if (timePassedSec.count() > 10) { - cursorDefaultDone = true; - return; - } - - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - -void Events::listener_newOutput(wl_listener* listener, void* data) { - // new monitor added, let's accommodate for that. - const auto OUTPUT = (wlr_output*)data; - - if (!OUTPUT->name) { - Debug::log(ERR, "New monitor has no name?? Ignoring"); - return; - } - - // add it to real - auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); - if (std::string("HEADLESS-1") == OUTPUT->name) - g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); - - PNEWMONITOR->output = OUTPUT; - PNEWMONITOR->self = PNEWMONITOR; - const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false; - PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name); - PNEWMONITOR->isUnsafeFallback = FALLBACK; - - EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); - - if (!FALLBACK) - PNEWMONITOR->onConnect(false); - - if (!PNEWMONITOR->m_bEnabled || FALLBACK) - return; - - // ready to process if we have a real monitor - - if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) - g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); - - g_pCompositor->m_bReadyToProcess = true; - - g_pConfigManager->m_bWantsMonitorReload = true; - g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get()); - - checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name); - - for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_iMonitorID == PNEWMONITOR->ID) { - w->m_iLastSurfaceMonitorID = -1; - w->updateSurfaceScaleTransformDetails(); - } - } -} - void Events::listener_monitorFrame(void* owner, void* data) { - if (g_pCompositor->m_bExitTriggered) { - // Only signal cleanup once - g_pCompositor->m_bExitTriggered = false; - g_pCompositor->cleanup(); - return; - } - CMonitor* const PMONITOR = (CMonitor*)owner; - if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { + if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Attempted to render frame on inactive session!"); if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { @@ -172,12 +84,10 @@ void Events::listener_monitorFrame(void* owner, void* data) { } void Events::listener_monitorDestroy(void* owner, void* data) { - const auto OUTPUT = (wlr_output*)data; - - CMonitor* pMonitor = nullptr; + CMonitor* pMonitor = (CMonitor*)owner; for (auto& m : g_pCompositor->m_vRealMonitors) { - if (m->output == OUTPUT) { + if (m->output == pMonitor->output) { pMonitor = m.get(); break; } @@ -188,9 +98,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) { Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); - if (pMonitor->output->idle_frame) - wl_event_source_remove(pMonitor->output->idle_frame); - pMonitor->onDisconnect(true); pMonitor->output = nullptr; @@ -201,44 +108,18 @@ void Events::listener_monitorDestroy(void* owner, void* data) { std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == pMonitor; }); } -void Events::listener_monitorStateRequest(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_request_state*)data; - - if (!PMONITOR->createdByUser) - return; - - const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height}; - - PMONITOR->forceSize = SIZE; - - SMonitorRule rule = PMONITOR->activeMonitorRule; - rule.resolution = SIZE; - - g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule); -} - -void Events::listener_monitorDamage(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_damage*)data; - - PMONITOR->addDamage(E->damage); -} - void Events::listener_monitorNeedsFrame(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); } void Events::listener_monitorCommit(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; - const auto E = (wlr_output_event_commit*)data; - - if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) { - g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E); - g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E); + if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER + g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR); + g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR); } } diff --git a/src/helpers/CursorShapes.hpp b/src/helpers/CursorShapes.hpp new file mode 100644 index 00000000..6f3c8a0e --- /dev/null +++ b/src/helpers/CursorShapes.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +// clang-format off +constexpr std::array CURSOR_SHAPE_NAMES = { + "invalid", + "default", + "context-menu", + "help", + "pointer", + "progress", + "wait", + "cell", + "crosshair", + "text", + "vertical-text", + "alias", + "copy", + "move", + "no-drop", + "not-allowed", + "grab", + "grabbing", + "e-resize", + "n-resize", + "ne-resize", + "nw-resize", + "s-resize", + "se-resize", + "sw-resize", + "w-resize", + "ew-resize", + "ns-resize", + "nesw-resize", + "nwse-resize", + "col-resize", + "row-resize", + "all-scroll", + "zoom-in", + "zoom-out", +}; +// clang-format on \ No newline at end of file diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 5251002c..afc8b1c5 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -3,6 +3,8 @@ #include "../includes.hpp" #include "debug/Log.hpp" #include "../macros.hpp" +#include +#include /* DRM formats are LE, while OGL is BE. The two primary formats @@ -309,3 +311,17 @@ uint32_t FormatUtils::glFormatToType(uint32_t gl) { #endif GL_UNSIGNED_BYTE; } + +std::string FormatUtils::drmFormatName(DRMFormat drm) { + auto n = drmGetFormatName(drm); + std::string name = n; + free(n); + return name; +} + +std::string FormatUtils::drmModifierName(uint64_t mod) { + auto n = drmGetFormatModifierName(mod); + std::string name = n; + free(n); + return name; +} diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp index a1ef53f5..8269c5c3 100644 --- a/src/helpers/Format.hpp +++ b/src/helpers/Format.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include "math/Math.hpp" +#include typedef uint32_t DRMFormat; typedef uint32_t SHMFormat; @@ -18,10 +20,7 @@ struct SPixelFormat { Vector2D blockSize; }; -struct SDRMFormat { - uint32_t format = 0; - std::vector mods; -}; +typedef Aquamarine::SDRMFormat SDRMFormat; namespace FormatUtils { SHMFormat drmToShm(DRMFormat drm); @@ -34,4 +33,6 @@ namespace FormatUtils { int minStride(const SPixelFormat* const fmt, int32_t width); uint32_t drmFormatToGL(DRMFormat drm); uint32_t glFormatToType(uint32_t gl); + std::string drmFormatName(DRMFormat drm); + std::string drmModifierName(uint64_t mod); }; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 712e4e50..53c0dc13 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -4,9 +4,12 @@ #include "../Compositor.hpp" #include "../managers/TokenManager.hpp" #include +#include +#include #include #include #include +#include #include #include #include diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 33be7965..49e3bced 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "math/Math.hpp" #include #include diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 20c2e81e..a23b9861 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,12 +1,18 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" +#include "math/Math.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include "../protocols/DRMLease.hpp" +#include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" +#include "../protocols/core/Compositor.hpp" +#include "sync/SyncTimeline.hpp" +#include #include using namespace Hyprutils::String; @@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) { } CMonitor::~CMonitor() { - hyprListener_monitorDestroy.removeCallback(); - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorStateRequest.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); - events.destroy.emit(); } -static void onPresented(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - auto E = (wlr_output_event_present*)data; - - PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags); -} - void CMonitor::onConnect(bool noRule) { - hyprListener_monitorDestroy.removeCallback(); - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorStateRequest.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); - hyprListener_monitorPresented.removeCallback(); - hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor"); - hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor"); - hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor"); - hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor"); - hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor"); - hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor"); - hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor"); - hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor"); - tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm + if (output->supportsExplicit) { + inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); + outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); + } + + listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); + listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); }); + listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); + listeners.needsFrame = + output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); + listeners.presented = output->events.present.registerListener([this](std::any d) { + auto E = std::any_cast(d); + PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); + }); + + listeners.state = output->events.state.registerListener([this](std::any d) { + auto E = std::any_cast(d); + + if (E.size == Vector2D{}) { + // an indication to re-set state + // we can't do much for createdByUser displays I think + if (createdByUser) + return; + + Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); + g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true); + return; + } + + if (!createdByUser) + return; + + const auto SIZE = E.size; + + forceSize = SIZE; + + SMonitorRule rule = activeMonitorRule; + rule.resolution = SIZE; + + g_pHyprRenderer->applyMonitorRule(this, &rule); + }); + + tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; if (m_bEnabled) { - wlr_output_state_set_enabled(state.wlr(), true); + output->state->setEnabled(true); state.commit(); return; } szName = output->name; - szDescription = output->description ? output->description : ""; + szDescription = output->description; // remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description std::erase(szDescription, ','); // field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix - szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); + szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial)); std::erase(szShortDescription, ','); - if (!wlr_backend_is_drm(output->backend)) - createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable + if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) + createdByUser = true; // should be true. WL and Headless backends should be addable / removable // get monitor rule that matches SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); @@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) { // if it's disabled, disable and ignore if (monitorRule.disabled) { - wlr_output_state_set_scale(state.wlr(), 1); - wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL); - - auto PREFSTATE = wlr_output_preferred_mode(output); - - if (!PREFSTATE) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &output->modes, link) { - wlr_output_state_set_mode(state.wlr(), mode); - - if (!wlr_output_test_state(output, state.wlr())) - continue; - - PREFSTATE = mode; - break; - } - } - - if (PREFSTATE) - wlr_output_state_set_mode(state.wlr(), PREFSTATE); - else - Debug::log(WARN, "No mode found for disabled output {}", output->name); - - wlr_output_state_set_enabled(state.wlr(), 0); + output->state->setEnabled(false); if (!state.commit()) Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name); m_bEnabled = false; - hyprListener_monitorFrame.removeCallback(); + listeners.frame.reset(); return; } - if (output->non_desktop) { + if (output->nonDesktop) { Debug::log(LOG, "Not configuring non-desktop output"); - if (g_pCompositor->m_sWRLDRMLeaseMgr) { - wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output); - } - return; - } + if (PROTO::lease) + PROTO::lease->offer(self.lock()); - if (!m_bRenderingInitPassed) { - output->allocator = nullptr; - output->renderer = nullptr; - wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer); - m_bRenderingInitPassed = true; + return; } SP* thisWrapper = nullptr; @@ -151,14 +137,14 @@ void CMonitor::onConnect(bool noRule) { m_bEnabled = true; - wlr_output_state_set_enabled(state.wlr(), 1); + output->state->setEnabled(true); // set mode, also applies if (!noRule) g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); if (!state.commit()) - Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); + Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); damage.setSize(vecTransformedSize); @@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) { renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); PROTO::gamma->applyGammaToState(this); @@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) { g_pConfigManager->m_bWantsMonitorReload = true; } - hyprListener_monitorFrame.removeCallback(); - hyprListener_monitorPresented.removeCallback(); - hyprListener_monitorDamage.removeCallback(); - hyprListener_monitorNeedsFrame.removeCallback(); - hyprListener_monitorCommit.removeCallback(); - hyprListener_monitorBind.removeCallback(); + listeners.frame.reset(); + listeners.presented.reset(); + listeners.needsFrame.reset(); + listeners.commit.reset(); for (size_t i = 0; i < 4; ++i) { for (auto& ls : m_aLayerSurfaceLayers[i]) { @@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) { activeWorkspace->m_bVisible = false; activeWorkspace.reset(); - wlr_output_state_set_enabled(state.wlr(), false); + output->state->setEnabled(false); if (!state.commit()) - Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect"); + Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect"); if (g_pCompositor->m_pLastMonitor.get() == this) g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); @@ -344,9 +328,9 @@ void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } else if (damage.damage(rg)) - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } void CMonitor::addDamage(const CRegion* rg) { @@ -357,11 +341,11 @@ void CMonitor::addDamage(const CBox* box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } if (damage.damage(*box)) - g_pCompositor->scheduleFrameForMonitor(this); + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { @@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); // skip scheduling extra frames for fullsreen apps with vrr - bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && - activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; + bool shouldSkip = + *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { @@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() { static constexpr double MMPERINCH = 25.4; const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2)); - const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2)); + const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2)); const auto PPI = DIAGONALPX / DIAGONALIN; @@ -767,11 +751,11 @@ Vector2D CMonitor::middle() { } void CMonitor::updateMatrix() { - wlr_matrix_identity(projMatrix.data()); + matrixIdentity(projMatrix.data()); if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); - wlr_matrix_transform(projMatrix.data(), transform); - wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); + matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); + matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform)); + matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); } } @@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } +static void onDoneSource(void* data) { + auto pMonitor = (CMonitor*)data; + + if (!PROTO::outputs.contains(pMonitor->szName)) + return; + + PROTO::outputs.at(pMonitor->szName)->sendDone(); +} + +void CMonitor::scheduleDone() { + if (doneSource) + return; + + doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); +} + +bool CMonitor::attemptDirectScanout() { + if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) + return false; // do not DS if this monitor is being mirrored. Will break the functionality. + + if (g_pPointerManager->softwareLockedFor(self.lock())) + return false; + + const auto PCANDIDATE = solitaryClient.lock(); + + if (!PCANDIDATE) + return false; + + const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); + + if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform) + return false; + + // we can't scanout shm buffers. + if (!PSURFACE->current.buffer->dmabuf().success) + return false; + + // FIXME: make sure the buffer actually follows the available scanout dmabuf formats + // and comes from the appropriate device. This may implode on multi-gpu!! + + output->state->setBuffer(PSURFACE->current.buffer); + output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); + + if (!state.test()) + return false; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + Debug::log(TRACE, "presentFeedback for DS"); + PSURFACE->presentFeedback(&now, this, true); + + if (state.commit()) { + if (lastScanout.expired()) { + lastScanout = PCANDIDATE; + Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); + } + } else { + lastScanout.reset(); + return false; + } + + return true; +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; - wlr_output_state_init(&m_state); } CMonitorState::~CMonitorState() { - wlr_output_state_finish(&m_state); + ; } -wlr_output_state* CMonitorState::wlr() { - return &m_state; -} +void CMonitorState::ensureBufferPresent() { + if (!m_pOwner->output->state->state().enabled) { + Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled"); + return; + } -void CMonitorState::clear() { - wlr_output_state_finish(&m_state); - m_state = {0}; - wlr_output_state_init(&m_state); + if (m_pOwner->output->state->state().buffer) + return; + + // this is required for modesetting being possible and might be missing in case of first tests in the renderer + // where we test modes and buffers + Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible"); + m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr)); + m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain } bool CMonitorState::commit() { - bool ret = wlr_output_commit_state(m_pOwner->output, &m_state); - clear(); + if (!updateSwapchain()) + return false; + + ensureBufferPresent(); + + bool ret = m_pOwner->output->commit(); return ret; } bool CMonitorState::test() { - return wlr_output_test_state(m_pOwner->output, &m_state); + if (!updateSwapchain()) + return false; + + ensureBufferPresent(); + + return m_pOwner->output->test(); +} + +bool CMonitorState::updateSwapchain() { + auto options = m_pOwner->output->swapchain->currentOptions(); + const auto& STATE = m_pOwner->output->state->state(); + const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode; + if (!MODE) { + Debug::log(WARN, "updateSwapchain: No mode?"); + return true; + } + options.format = STATE.drmFormat; + options.scanout = true; + options.length = 2; + options.size = MODE->pixelSize; + return m_pOwner->output->swapchain->reconfigure(options); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 8a2acdaf..32fc768a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -12,6 +12,8 @@ #include #include "signal/Signal.hpp" #include "DamageRing.hpp" +#include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs { @@ -38,22 +40,21 @@ struct SMonitorRule { }; class CMonitor; +class CSyncTimeline; -// Class for wrapping the wlr state class CMonitorState { public: CMonitorState(CMonitor* owner); ~CMonitorState(); - wlr_output_state* wlr(); - void clear(); - // commit() will also clear() bool commit(); bool test(); + bool updateSwapchain(); private: - wlr_output_state m_state = {0}; - CMonitor* m_pOwner; + void ensureBufferPresent(); + + CMonitor* m_pOwner; }; class CMonitor { @@ -61,61 +62,69 @@ class CMonitor { CMonitor(); ~CMonitor(); - Vector2D vecPosition = Vector2D(-1, -1); // means unset - Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset - Vector2D vecSize = Vector2D(0, 0); - Vector2D vecPixelSize = Vector2D(0, 0); - Vector2D vecTransformedSize = Vector2D(0, 0); + Vector2D vecPosition = Vector2D(-1, -1); // means unset + Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset + Vector2D vecSize = Vector2D(0, 0); + Vector2D vecPixelSize = Vector2D(0, 0); + Vector2D vecTransformedSize = Vector2D(0, 0); - bool primary = false; + bool primary = false; - uint64_t ID = -1; - PHLWORKSPACE activeWorkspace = nullptr; - PHLWORKSPACE activeSpecialWorkspace = nullptr; - float setScale = 1; // scale set by cfg - float scale = 1; // real scale + uint64_t ID = -1; + PHLWORKSPACE activeWorkspace = nullptr; + PHLWORKSPACE activeSpecialWorkspace = nullptr; + float setScale = 1; // scale set by cfg + float scale = 1; // real scale - std::string szName = ""; - std::string szDescription = ""; - std::string szShortDescription = ""; + std::string szName = ""; + std::string szDescription = ""; + std::string szShortDescription = ""; - Vector2D vecReservedTopLeft = Vector2D(0, 0); - Vector2D vecReservedBottomRight = Vector2D(0, 0); + Vector2D vecReservedTopLeft = Vector2D(0, 0); + Vector2D vecReservedBottomRight = Vector2D(0, 0); - drmModeModeInfo customDrmMode = {}; + drmModeModeInfo customDrmMode = {}; - CMonitorState state; - CDamageRing damage; + CMonitorState state; + CDamageRing damage; - wlr_output* output = nullptr; - float refreshRate = 60; - int framesToSkip = 0; - int forceFullFrames = 0; - bool noFrameSchedule = false; - bool scheduledRecalc = false; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - float xwaylandScale = 1.f; - std::array projMatrix = {0}; - std::optional forceSize; - wlr_output_mode* currentMode = nullptr; + SP output; + float refreshRate = 60; + int framesToSkip = 0; + int forceFullFrames = 0; + bool noFrameSchedule = false; + bool scheduledRecalc = false; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float xwaylandScale = 1.f; + std::array projMatrix = {0}; + std::optional forceSize; + SP currentMode; + SP cursorSwapchain; - bool dpmsStatus = true; - bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. - bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. - bool createdByUser = false; - uint32_t drmFormat = DRM_FORMAT_INVALID; - bool isUnsafeFallback = false; + bool dpmsStatus = true; + bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. + bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed. + bool createdByUser = false; + bool isUnsafeFallback = false; - bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after - bool renderingActive = false; + bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after + bool renderingActive = false; - wl_event_source* renderTimer = nullptr; // for RAT - bool RATScheduled = false; - CTimer lastPresentationTimer; + wl_event_source* renderTimer = nullptr; // for RAT + bool RATScheduled = false; + CTimer lastPresentationTimer; - SMonitorRule activeMonitorRule; + bool isBeingLeased = false; - WP self; + SMonitorRule activeMonitorRule; + + // explicit sync + SP inTimeline; + SP outTimeline; + uint64_t lastWaitPoint = 0; + uint64_t commitSeq = 0; + + WP self; // mirroring CMonitor* pMirrorOf = nullptr; @@ -124,6 +133,9 @@ class CMonitor { // for tearing PHLWINDOWREF solitaryClient; + // for direct scanout + PHLWINDOWREF lastScanout; + struct { bool canTear = false; bool nextRenderTorn = false; @@ -143,15 +155,6 @@ class CMonitor { std::array, 4> m_aLayerSurfaceLayers; - DYNLISTENER(monitorFrame); - DYNLISTENER(monitorDestroy); - DYNLISTENER(monitorStateRequest); - DYNLISTENER(monitorDamage); - DYNLISTENER(monitorNeedsFrame); - DYNLISTENER(monitorCommit); - DYNLISTENER(monitorBind); - DYNLISTENER(monitorPresented); - // methods void onConnect(bool noRule); void onDisconnect(bool destroy = false); @@ -173,6 +176,8 @@ class CMonitor { int64_t activeWorkspaceID(); int64_t activeSpecialWorkspaceID(); CBox logicalBox(); + void scheduleDone(); + bool attemptDirectScanout(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; @@ -184,6 +189,17 @@ class CMonitor { } private: - void setupDefaultWS(const SMonitorRule&); - int findAvailableDefaultWS(); + void setupDefaultWS(const SMonitorRule&); + int findAvailableDefaultWS(); + + wl_event_source* doneSource = nullptr; + + struct { + CHyprSignalListener frame; + CHyprSignalListener destroy; + CHyprSignalListener state; + CHyprSignalListener needsFrame; + CHyprSignalListener presented; + CHyprSignalListener commit; + } listeners; }; diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 6b25e76d..51f90166 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -15,6 +15,8 @@ class IPointer; class IKeyboard; class CWLSurfaceResource; +AQUAMARINE_FORWARD(ISwitch); + struct SRenderData { CMonitor* pMonitor; timespec* when; @@ -70,14 +72,14 @@ struct SSwipeGesture { }; struct SSwitchDevice { - wlr_input_device* pWlrDevice = nullptr; + WP pDevice; - int status = -1; // uninitialized - - DYNLISTENER(destroy); - DYNLISTENER(toggle); + struct { + CHyprSignalListener destroy; + CHyprSignalListener fire; + } listeners; bool operator==(const SSwitchDevice& other) const { - return pWlrDevice == other.pWlrDevice; + return pDevice == other.pDevice; } }; diff --git a/src/helpers/X11Stubs.hpp b/src/helpers/X11Stubs.hpp deleted file mode 100644 index 19bea6f8..00000000 --- a/src/helpers/X11Stubs.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -inline bool wlr_backend_is_x11(void*) { - return false; -} - -inline void wlr_x11_output_create(void*) {} diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp index 560f29c9..fccfd636 100644 --- a/src/helpers/math/Math.cpp +++ b/src/helpers/math/Math.cpp @@ -17,14 +17,14 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; } -static void matrixIdentity(float mat[9]) { +void matrixIdentity(float mat[9]) { static const float identity[9] = { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, }; memcpy(mat, identity, sizeof(identity)); } -static void matrixMultiply(float mat[9], const float a[9], const float b[9]) { +void matrixMultiply(float mat[9], const float a[9], const float b[9]) { float product[9]; product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; @@ -42,141 +42,56 @@ static void matrixMultiply(float mat[9], const float a[9], const float b[9]) { memcpy(mat, product, sizeof(product)); } -static void matrixTranspose(float mat[9], const float a[9]) { +void matrixTranspose(float mat[9], const float a[9]) { float transposition[9] = { a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8], }; memcpy(mat, transposition, sizeof(transposition)); } -static void matrixTranslate(float mat[9], float x, float y) { +void matrixTranslate(float mat[9], float x, float y) { float translate[9] = { 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, translate); } -static void matrixScale(float mat[9], float x, float y) { +void matrixScale(float mat[9], float x, float y) { float scale[9] = { x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, scale); } -static void matrixRotate(float mat[9], float rad) { +void matrixRotate(float mat[9], float rad) { float rotate[9] = { cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, }; matrixMultiply(mat, mat, rotate); } -static std::unordered_map> transforms = { - {HYPRUTILS_TRANSFORM_NORMAL, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_90, - { - 0.0f, - 1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_180, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_270, - { - 0.0f, - -1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_90, - { - 0.0f, - 1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_180, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, - {HYPRUTILS_TRANSFORM_FLIPPED_270, - { - 0.0f, - -1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }}, -}; - -static void matrixTransform(float mat[9], eTransform transform) { - matrixMultiply(mat, mat, transforms.at(transform).data()); +const std::unordered_map>& getTransforms() { + static std::unordered_map> transforms = { + {HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + {HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, + }; + return transforms; } -static void matrixProjection(float mat[9], int width, int height, eTransform transform) { +void matrixTransform(float mat[9], eTransform transform) { + matrixMultiply(mat, mat, getTransforms().at(transform).data()); +} + +void matrixProjection(float mat[9], int width, int height, eTransform transform) { memset(mat, 0, sizeof(*mat) * 9); - const float* t = transforms.at(transform).data(); + const float* t = getTransforms().at(transform).data(); float x = 2.0f / width; float y = 2.0f / height; @@ -219,3 +134,10 @@ void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, c matrixMultiply(mat, projection, mat); } + +wl_output_transform invertTransform(wl_output_transform tr) { + if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) + tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); + + return tr; +} diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp index 4aa65c93..f57cef93 100644 --- a/src/helpers/math/Math.hpp +++ b/src/helpers/math/Math.hpp @@ -7,5 +7,14 @@ using namespace Hyprutils::Math; -eTransform wlTransformToHyprutils(wl_output_transform t); -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); +eTransform wlTransformToHyprutils(wl_output_transform t); +void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); +void matrixProjection(float mat[9], int width, int height, eTransform transform); +void matrixTransform(float mat[9], eTransform transform); +void matrixRotate(float mat[9], float rad); +void matrixScale(float mat[9], float x, float y); +void matrixTranslate(float mat[9], float x, float y); +void matrixTranspose(float mat[9], const float a[9]); +void matrixMultiply(float mat[9], const float a[9], const float b[9]); +void matrixIdentity(float mat[9]); +wl_output_transform invertTransform(wl_output_transform tr); diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp new file mode 100644 index 00000000..352120ea --- /dev/null +++ b/src/helpers/sync/SyncTimeline.cpp @@ -0,0 +1,190 @@ +#include "SyncTimeline.hpp" +#include "../../defines.hpp" +#include "../../managers/eventLoop/EventLoopManager.hpp" + +#include +#include + +SP CSyncTimeline::create(int drmFD_) { + auto timeline = SP(new CSyncTimeline); + timeline->drmFD = drmFD_; + timeline->self = timeline; + + if (drmSyncobjCreate(drmFD_, 0, &timeline->handle)) { + Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj??"); + return nullptr; + } + + return timeline; +} + +SP CSyncTimeline::create(int drmFD_, int drmSyncobjFD) { + auto timeline = SP(new CSyncTimeline); + timeline->drmFD = drmFD_; + timeline->self = timeline; + + if (drmSyncobjFDToHandle(drmFD_, drmSyncobjFD, &timeline->handle)) { + Debug::log(ERR, "CSyncTimeline: failed to create a drm syncobj from fd??"); + return nullptr; + } + + return timeline; +} + +CSyncTimeline::~CSyncTimeline() { + if (handle == 0) + return; + + drmSyncobjDestroy(drmFD, handle); +} + +std::optional CSyncTimeline::check(uint64_t point, uint32_t flags) { +#ifdef __FreeBSD__ + constexpr int ETIME_ERR = ETIMEDOUT; +#else + constexpr int ETIME_ERR = ETIME; +#endif + + uint32_t signaled = 0; + int ret = drmSyncobjTimelineWait(drmFD, &handle, &point, 1, 0, flags, &signaled); + if (ret != 0 && ret != -ETIME_ERR) { + Debug::log(ERR, "CSyncTimeline::check: drmSyncobjTimelineWait failed"); + return std::nullopt; + } + + return ret == 0; +} + +static int handleWaiterFD(int fd, uint32_t mask, void* data) { + auto waiter = (CSyncTimeline::SWaiter*)data; + + if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { + Debug::log(ERR, "handleWaiterFD: eventfd error"); + return 0; + } + + if (mask & WL_EVENT_READABLE) { + uint64_t value = 0; + if (read(fd, &value, sizeof(value)) <= 0) + Debug::log(ERR, "handleWaiterFD: failed to read from eventfd"); + } + + wl_event_source_remove(waiter->source); + waiter->source = nullptr; + + if (waiter->fn) + waiter->fn(); + + if (waiter->timeline) + waiter->timeline->removeWaiter(waiter); + + return 0; +} + +bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t point, uint32_t flags) { + auto w = makeShared(); + w->fn = waiter; + w->timeline = self; + + int eventFD = eventfd(0, EFD_CLOEXEC); + + if (eventFD < 0) { + Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); + return false; + } + + drm_syncobj_eventfd syncobjEventFD = { + .handle = handle, + .flags = flags, + .point = point, + .fd = eventFD, + }; + + if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { + Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); + close(eventFD); + return false; + } + + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + if (!w->source) { + Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); + close(eventFD); + return false; + } + + waiters.emplace_back(w); + + return true; +} + +void CSyncTimeline::removeWaiter(SWaiter* w) { + if (w->source) { + wl_event_source_remove(w->source); + w->source = nullptr; + } + std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); +} + +int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { + int sync = -1; + + uint32_t syncHandle = 0; + if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); + return -1; + } + + if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return -1; + } + + if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { + Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return -1; + } + + drmSyncobjDestroy(drmFD, syncHandle); + return sync; +} + +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { + uint32_t syncHandle = 0; + + if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjCreate failed"); + return false; + } + + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return false; + } + + if (drmSyncobjTransfer(drmFD, handle, dst, syncHandle, 0, 0)) { + Debug::log(ERR, "importFromSyncFileFD: drmSyncobjTransfer failed"); + drmSyncobjDestroy(drmFD, syncHandle); + return false; + } + + drmSyncobjDestroy(drmFD, syncHandle); + return true; +} + +bool CSyncTimeline::transfer(SP from, uint64_t fromPoint, uint64_t toPoint) { + if (drmFD != from->drmFD) { + Debug::log(ERR, "CSyncTimeline::transfer: cannot transfer timelines between gpus, {} -> {}", from->drmFD, drmFD); + return false; + } + + if (drmSyncobjTransfer(drmFD, handle, toPoint, from->handle, fromPoint, 0)) { + Debug::log(ERR, "CSyncTimeline::transfer: drmSyncobjTransfer failed"); + return false; + } + + return true; +} diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp new file mode 100644 index 00000000..3d868a95 --- /dev/null +++ b/src/helpers/sync/SyncTimeline.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include +#include "../memory/Memory.hpp" + +/* + Hyprland synchronization timelines are based on the wlroots' ones, which + are based on Vk timeline semaphores: https://www.khronos.org/blog/vulkan-timeline-semaphores +*/ + +struct wl_event_source; + +class CSyncTimeline { + public: + static SP create(int drmFD_); + static SP create(int drmFD_, int drmSyncobjFD); + ~CSyncTimeline(); + + struct SWaiter { + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + }; + + // check if the timeline point has been signaled + // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE + // std::nullopt on fail + std::optional check(uint64_t point, uint32_t flags); + + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + int exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, int fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + + int drmFD = -1; + uint32_t handle = 0; + WP self; + + private: + CSyncTimeline() = default; + + std::vector> waiters; +}; diff --git a/src/includes.hpp b/src/includes.hpp index afec078a..8b3f3fad 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -16,78 +16,6 @@ #include #include #include -#include -#include -#include -#include - -#if true -// wlroots uses dumb-ass shit that makes it not compile on C++, let's fix that. -// https://github.com/swaywm/wlroots/issues/682 -// pthread first because it uses class in a C++ way and XWayland includes that... -#include - -#define class _class -#define namespace _namespace -#define static -#define delete delete_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if WLR_HAS_X11_BACKEND -#include -#endif -} - -#undef delete -#undef class -#undef namespace -#undef static -#endif #ifdef LEGACY_RENDERER #include @@ -99,10 +27,6 @@ extern "C" { #include #endif -#if !WLR_HAS_X11_BACKEND -#include "helpers/X11Stubs.hpp" -#endif - #ifdef NO_XWAYLAND #define XWAYLAND false #else diff --git a/src/macros.hpp b/src/macros.hpp index f1393cbd..b2adb036 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -105,3 +105,8 @@ class name; \ } \ } + +#define AQUAMARINE_FORWARD(name) \ + namespace Aquamarine { \ + class name; \ + } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 677b2109..dcc7a45f 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -259,7 +259,7 @@ void CAnimationManager::tick() { // manually schedule a frame if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } // do it here, because if this alters the animation vars deque we would be in trouble above. diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index daa4f4be..3a13d10b 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -3,10 +3,11 @@ #include "../config/ConfigValue.hpp" #include "PointerManager.hpp" #include "../xwayland/XWayland.hpp" +#include +#include "../helpers/CursorShapes.hpp" extern "C" { -#include -#include +#include } static int cursorAnimTimer(void* data) { @@ -45,8 +46,7 @@ CCursorManager::CCursorManager() { if (m_iSize == 0) m_iSize = 24; - m_pWLRXCursorMgr = wlr_xcursor_manager_create(getenv("XCURSOR_THEME"), m_iSize); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0); + xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale)); m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr); @@ -56,9 +56,6 @@ CCursorManager::CCursorManager() { } CCursorManager::~CCursorManager() { - if (m_pWLRXCursorMgr) - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); - if (m_pAnimationTimer) wl_event_source_remove(m_pAnimationTimer); } @@ -67,54 +64,61 @@ void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; }); } -static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) { - CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); - g_pCursorManager->dropBufferRef(buffer->parent); +CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + surface = surf; + size = size_; + stride = cairo_image_surface_get_stride(surf); } -static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) { - CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base); - - if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE) - return false; - - *data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface); - *stride = buffer->stride; - *format = DRM_FORMAT_ARGB8888; - return true; -} - -static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) { - ; -} - -// -static const wlr_buffer_impl bufferImpl = { - .destroy = cursorBufferDestroy, - .begin_data_ptr_access = cursorBufferBeginDataPtr, - .end_data_ptr_access = cursorBufferEndDataPtr, -}; - -CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) { - wlrBuffer.surface = surf; - wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); - wlrBuffer.parent = this; - wlrBuffer.stride = cairo_image_surface_get_stride(surf); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) { - wlrBuffer.pixelData = pixelData; - wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y); - wlrBuffer.parent = this; - wlrBuffer.stride = 4 * size_.x; +CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + pixelData = pixelData_; + size = size_; + stride = 4 * size_.x; } CCursorManager::CCursorBuffer::~CCursorBuffer() { - ; // will be freed in .destroy + ; } -wlr_buffer* CCursorManager::getCursorBuffer() { - return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr; +Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool CCursorManager::CCursorBuffer::isSynchronous() { + return true; +} + +bool CCursorManager::CCursorBuffer::good() { + return true; +} + +Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() { + Aquamarine::SSHMAttrs attrs; + attrs.success = true; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.size = size; + attrs.stride = stride; + return attrs; +} + +std::tuple CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) { + return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; +} + +void CCursorManager::CCursorBuffer::endDataPtr() { + ; +} + +SP CCursorManager::getCursorBuffer() { + return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr; } void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotspot) { @@ -127,34 +131,24 @@ void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotsp } void CCursorManager::setXCursor(const std::string& name) { - if (!m_pWLRXCursorMgr) { - g_pPointerManager->resetCursorImage(); - return; - } - float scale = std::ceil(m_fCursorScale); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale); - auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale); - if (!xcursor) { - Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name); - xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale); - } - - if (!xcursor || !xcursor->images[0]) { - Debug::log(ERR, "XCursor is broken. F this garbage."); + if (!xcursor.themeLoaded) { + Debug::log(ERR, "XCursor failed to find theme in setXCursor"); g_pPointerManager->resetCursorImage(); return; } - auto image = xcursor->images[0]; + auto& icon = xcursor.defaultCursor; + // try to get an icon we know if we have one + if (xcursor.cursors.contains(name)) + icon = xcursor.cursors.at(name); - m_vCursorBuffers.emplace_back( - std::make_unique(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y})); + m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot)); - g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale); if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + dropBufferRef(m_vCursorBuffers.at(0).get()); m_bOurBufferConnected = true; } @@ -196,14 +190,14 @@ void CCursorManager::setCursorFromName(const std::string& name) { } } - m_vCursorBuffers.emplace_back(std::make_unique(m_sCurrentCursorShapeData.images[0].surface, - Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, - Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); + m_vCursorBuffers.emplace_back(makeShared(m_sCurrentCursorShapeData.images[0].surface, + Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, + Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, m_fCursorScale); if (m_vCursorBuffers.size() > 1) - wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base); + dropBufferRef(m_vCursorBuffers.at(0).get()); m_bOurBufferConnected = true; @@ -225,7 +219,7 @@ void CCursorManager::tickAnimatedCursor() { if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) m_iCurrentAnimationFrame = 0; - m_vCursorBuffers.emplace_back(std::make_unique( + m_vCursorBuffers.emplace_back(makeShared( m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); @@ -256,10 +250,9 @@ void CCursorManager::setXWaylandCursor() { if (CURSOR.surface) { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); - } else if (const auto XCURSOR = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left_ptr", 1); XCURSOR) { - g_pXWayland->setCursor(XCURSOR->images[0]->buffer, XCURSOR->images[0]->width * 4, {(int)XCURSOR->images[0]->width, (int)XCURSOR->images[0]->height}, - {(double)XCURSOR->images[0]->hotspot_x, (double)XCURSOR->images[0]->hotspot_y}); - } else + } else if (xcursor.themeLoaded) + g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot); + else Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); } @@ -284,7 +277,7 @@ void CCursorManager::updateTheme() { for (auto& m : g_pCompositor->m_vMonitors) { m->forceFullFrames = 5; - g_pCompositor->scheduleFrameForMonitor(m.get()); + g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } } @@ -303,37 +296,163 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); - if (m_pWLRXCursorMgr) - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); + xcursor.loadTheme(name, size); - m_pWLRXCursorMgr = wlr_xcursor_manager_create(name.empty() ? "" : name.c_str(), size); - bool xSuccess = wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0) == 1; + m_szTheme = name; + m_iSize = size; + updateTheme(); + return true; +} - // this basically checks if xcursor changed used theme to default but better - bool diffTheme = false; - wlr_xcursor_manager_theme* theme; - wl_list_for_each(theme, &m_pWLRXCursorMgr->scaled_themes, link) { - if (std::string{theme->theme->name} != name) { - diffTheme = true; - break; +// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c +// however modified to fit wayland cursor shape names better. +// _ -> - +// clang-format off +static std::array XCURSOR_STANDARD_NAMES = { + "X_cursor", + "default", // arrow + "ns-resize", // based-arrow-down + "ns-resize", // based-arrow-up + "boat", + "bogosity", + "sw-resize", // bottom-left-corner + "se-resize", // bottom-right-corner + "s-resize", // bottom-side + "bottom-tee", + "box-spiral", + "center-ptr", + "circle", + "clock", + "coffee-mug", + "cross", + "cross-reverse", + "crosshair", + "diamond-cross", + "dot", + "dotbox", + "double-arrow", + "draft-large", + "draft-small", + "draped-box", + "exchange", + "move", // fleur + "gobbler", + "gumby", + "pointer", // hand1 + "grabbing", // hand2 + "heart", + "icon", + "iron-cross", + "default", // left-ptr + "w-resize", // left-side + "left-tee", + "leftbutton", + "ll-angle", + "lr-angle", + "man", + "middlebutton", + "mouse", + "pencil", + "pirate", + "plus", + "help", // question-arrow + "right-ptr", + "e-resize", // right-side + "right-tee", + "rightbutton", + "rtl-logo", + "sailboat", + "ns-resize", // sb-down-arrow + "ew-resize", // sb-h-double-arrow + "ew-resize", // sb-left-arrow + "ew-resize", // sb-right-arrow + "n-resize", // sb-up-arrow + "s-resize", // sb-v-double-arrow + "shuttle", + "sizing", + "spider", + "spraycan", + "star", + "target", + "cell", // tcross + "nw-resize", // top-left-arrow + "nw-resize", // top-left-corner + "ne-resize", // top-right-corner + "n-resize", // top-side + "top-tee", + "trek", + "ul-angle", + "umbrella", + "ur-angle", + "wait", // watch + "text", // xterm +}; +// clang-format on + +void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) { + if (lastLoadSize == size && themeName == name) + return; + + lastLoadSize = size; + themeLoaded = false; + themeName = name.empty() ? "default" : name; + + auto img = XcursorShapeLoadImage(2, themeName.c_str(), size); + + if (!img) { + Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName); + size = 24; + img = XcursorShapeLoadImage(2, themeName.c_str(), size); + if (!img) { + Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName); + return; } } - if (xSuccess && !diffTheme) { - m_szTheme = name; - m_iSize = size; - updateTheme(); - return true; + defaultCursor = makeShared(); + defaultCursor->size = {(int)img->width, (int)img->height}; + defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot}; + + defaultCursor->pixels.resize(img->width * img->height); + std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t)); + + themeLoaded = true; + + XcursorImageDestroy(img); + + // gather as many shapes as we can find. + cursors.clear(); + + for (auto& shape : CURSOR_SHAPE_NAMES) { + int id = -1; + for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { + if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) { + id = i; + break; + } + } + + if (id < 0) { + Debug::log(LOG, "XCursor has no shape {}, skipping", shape); + continue; + } + + auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size); + + if (!xImage) { + Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape); + continue; + } + + auto xcursor = makeShared(); + xcursor->size = {(int)xImage->width, (int)xImage->height}; + xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot}; + + xcursor->pixels.resize(xImage->width * xImage->height); + std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t)); + + cursors.emplace(std::string{shape}, xcursor); + + XcursorImageDestroy(xImage); } - - Debug::log(ERR, "X also failed loading theme \"{}\", falling back to previous theme.", name); - - m_pHyprcursor = std::make_unique(m_szTheme.c_str(), hcLogger); - - wlr_xcursor_manager_destroy(m_pWLRXCursorMgr); - m_pWLRXCursorMgr = wlr_xcursor_manager_create(m_szTheme.c_str(), m_iSize); - wlr_xcursor_manager_load(m_pWLRXCursorMgr, 1.0); - - updateTheme(); - return false; } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 3ee98ca6..4324dfb4 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -6,47 +6,51 @@ #include "../includes.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/memory/Memory.hpp" +#include "../macros.hpp" +#include -struct wlr_buffer; -struct wlr_xcursor_manager; class CWLSurface; +AQUAMARINE_FORWARD(IBuffer); + class CCursorManager { public: CCursorManager(); ~CCursorManager(); - wlr_buffer* getCursorBuffer(); + SP getCursorBuffer(); - void setCursorFromName(const std::string& name); - void setCursorSurface(SP surf, const Vector2D& hotspot); - void setXCursor(const std::string& name); + void setCursorFromName(const std::string& name); + void setCursorSurface(SP surf, const Vector2D& hotspot); + void setXCursor(const std::string& name); - bool changeTheme(const std::string& name, const int size); - void updateTheme(); - SCursorImageData dataFor(const std::string& name); // for xwayland - void setXWaylandCursor(); + bool changeTheme(const std::string& name, const int size); + void updateTheme(); + SCursorImageData dataFor(const std::string& name); // for xwayland + void setXWaylandCursor(); - void tickAnimatedCursor(); + void tickAnimatedCursor(); - class CCursorBuffer { + class CCursorBuffer : public Aquamarine::IBuffer { public: CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); ~CCursorBuffer(); - struct SCursorWlrBuffer { - wlr_buffer base; - cairo_surface_t* surface = nullptr; - bool dropped = false; - CCursorBuffer* parent = nullptr; - uint8_t* pixelData = nullptr; - size_t stride = 0; - } wlrBuffer; + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good(); + virtual Aquamarine::SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); private: - Vector2D size; - Vector2D hotspot; + Vector2D hotspot; + cairo_surface_t* surface = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; friend class CCursorManager; }; @@ -56,7 +60,7 @@ class CCursorManager { bool m_bOurBufferConnected = false; private: - std::vector> m_vCursorBuffers; + std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; @@ -70,8 +74,24 @@ class CCursorManager { int m_iCurrentAnimationFrame = 0; Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; - // xcursor fallback - wlr_xcursor_manager* m_pWLRXCursorMgr = nullptr; + // gangsta bootleg XCursor impl. Whenever Hyprland has to use + // an xcursor, just use the pointer. + struct SXCursor { + Vector2D size; + Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + }; + + struct SXCursorManager { + void loadTheme(const std::string& name, int size); + + int lastLoadSize = 0; + + bool themeLoaded = false; + std::string themeName = ""; + SP defaultCursor; + std::unordered_map> cursors; + } xcursor; }; inline std::unique_ptr g_pCursorManager; \ No newline at end of file diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index eb8a3232..e9dfd1ae 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -4,10 +4,12 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" +#include "../devices/IKeyboard.hpp" #include "KeybindManager.hpp" #include "PointerManager.hpp" #include "Compositor.hpp" #include "TokenManager.hpp" +#include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" @@ -15,6 +17,7 @@ #include #include #include +#include #include using namespace Hyprutils::String; @@ -157,37 +160,37 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) { uint32_t modMask = 0; std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper); if (mods.contains("SHIFT")) - modMask |= WLR_MODIFIER_SHIFT; + modMask |= HL_MODIFIER_SHIFT; if (mods.contains("CAPS")) - modMask |= WLR_MODIFIER_CAPS; + modMask |= HL_MODIFIER_CAPS; if (mods.contains("CTRL") || mods.contains("CONTROL")) - modMask |= WLR_MODIFIER_CTRL; + modMask |= HL_MODIFIER_CTRL; if (mods.contains("ALT") || mods.contains("MOD1")) - modMask |= WLR_MODIFIER_ALT; + modMask |= HL_MODIFIER_ALT; if (mods.contains("MOD2")) - modMask |= WLR_MODIFIER_MOD2; + modMask |= HL_MODIFIER_MOD2; if (mods.contains("MOD3")) - modMask |= WLR_MODIFIER_MOD3; - if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4")) - modMask |= WLR_MODIFIER_LOGO; + modMask |= HL_MODIFIER_MOD3; + if (mods.contains("SUPER") || mods.contains("WIN") || mods.contains("LOGO") || mods.contains("MOD4") || mods.contains("META")) + modMask |= HL_MODIFIER_META; if (mods.contains("MOD5")) - modMask |= WLR_MODIFIER_MOD5; + modMask |= HL_MODIFIER_MOD5; return modMask; } uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { switch (keycode - 8) { - case KEY_LEFTMETA: return WLR_MODIFIER_LOGO; - case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO; - case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT; - case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT; - case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL; - case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL; - case KEY_LEFTALT: return WLR_MODIFIER_ALT; - case KEY_RIGHTALT: return WLR_MODIFIER_ALT; - case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS; - case KEY_NUMLOCK: return WLR_MODIFIER_MOD2; + case KEY_LEFTMETA: return HL_MODIFIER_META; + case KEY_RIGHTMETA: return HL_MODIFIER_META; + case KEY_LEFTSHIFT: return HL_MODIFIER_SHIFT; + case KEY_RIGHTSHIFT: return HL_MODIFIER_SHIFT; + case KEY_LEFTCTRL: return HL_MODIFIER_CTRL; + case KEY_RIGHTCTRL: return HL_MODIFIER_CTRL; + case KEY_LEFTALT: return HL_MODIFIER_ALT; + case KEY_RIGHTALT: return HL_MODIFIER_ALT; + case KEY_CAPSLOCK: return HL_MODIFIER_CAPS; + case KEY_NUMLOCK: return HL_MODIFIER_MOD2; default: return 0; } } @@ -366,8 +369,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE); - const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->wlr()->xkb_state, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) return true; @@ -554,7 +557,7 @@ int repeatKeyHandler(void* data) { Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); DISPATCHER->second((*ppActiveKeybind)->arg); - wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->wlr()->repeat_info.rate); + wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate); return 0; } @@ -786,7 +789,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { // beyond this point, return true to not handle anything else. // we'll avoid printing shit to active windows. - if (g_pCompositor->m_sWLRSession) { + if (g_pCompositor->m_pAqBackend->hasSession()) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. @@ -810,8 +813,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY); - wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY); - return true; + g_pCompositor->m_pAqBackend->session->switchVT(TTY); } return true; @@ -893,6 +895,7 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { for (auto& e : HLENV) { setenv(e.first.c_str(), e.second.c_str(), 1); } + setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); close(socket[0]); close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); @@ -1659,7 +1662,7 @@ void CKeybindManager::renameWorkspace(std::string args) { } void CKeybindManager::exitHyprland(std::string argz) { - g_pCompositor->m_bExitTriggered = true; + g_pEventLoopManager->doLater([]() { g_pCompositor->cleanup(); }); } void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { @@ -2121,8 +2124,8 @@ void CKeybindManager::sendshortcut(std::string args) { const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) { - xkb_keymap* km = KB->wlr()->keymap; - xkb_state* ks = KB->xkbTranslationState; + xkb_keymap* km = KB->xkbKeymap; + xkb_state* ks = KB->xkbState; xkb_keycode_t keycode_min, keycode_max; keycode_min = xkb_keymap_min_keycode(km); @@ -2259,7 +2262,7 @@ void CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; - wlr_output_state_set_enabled(m->state.wlr(), enable); + m->output->state->setEnabled(enable); m->dpmsStatus = enable; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 2a256760..284280cd 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include #include +#include #include "../devices/IPointer.hpp" class CInputManager; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 7090645f..cf10db71 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -6,133 +6,8 @@ #include "../protocols/core/Compositor.hpp" #include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" -#include -#include -#include - -// TODO: make nicer -// this will come with the eventual rewrite of wlr_drm, etc... -static bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) { - ASSERT(a->format == b->format); - - size_t capacity = a->len < b->len ? a->len : b->len; - uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity); - if (!modifiers) - return false; - - struct wlr_drm_format fmt = { - .format = a->format, - .len = 0, - .capacity = capacity, - .modifiers = modifiers, - }; - - for (size_t i = 0; i < a->len; i++) { - for (size_t j = 0; j < b->len; j++) { - if (a->modifiers[i] == b->modifiers[j]) { - ASSERT(fmt.len < fmt.capacity); - fmt.modifiers[fmt.len++] = a->modifiers[i]; - break; - } - } - } - - wlr_drm_format_finish(dst); - *dst = fmt; - return true; -} - -static bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) { - ASSERT(src->len <= src->capacity); - - uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len); - if (!modifiers) - return false; - - memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len); - - wlr_drm_format_finish(dst); - dst->capacity = src->len; - dst->len = src->len; - dst->format = src->format; - dst->modifiers = modifiers; - return true; -} - -static const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) { - if (!r->impl->get_render_formats) - return nullptr; - - return r->impl->get_render_formats(r); -} - -static bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) { - - const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer); - if (render_formats == NULL) { - wlr_log(WLR_ERROR, "Failed to get render formats"); - return false; - } - - const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt); - if (render_format == NULL) { - wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt); - return false; - } - - if (display_formats != NULL) { - const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt); - if (display_format == NULL) { - wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt); - return false; - } - if (!wlr_drm_format_intersect(format, display_format, render_format)) { - wlr_log(WLR_DEBUG, - "Failed to intersect display and render " - "modifiers for format 0x%" PRIX32 " on output %s", - fmt, output->name); - return false; - } - } else { - // The output can display any format - if (!wlr_drm_format_copy(format, render_format)) - return false; - } - - if (format->len == 0) { - wlr_drm_format_finish(format); - wlr_log(WLR_DEBUG, "Failed to pick output format"); - return false; - } - - return true; -} - -static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) { - struct wlr_allocator* allocator = output->allocator; - ASSERT(allocator != NULL); - - const struct wlr_drm_format_set* display_formats = NULL; - if (output->impl->get_cursor_formats) { - display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps); - if (display_formats == NULL) { - wlr_log(WLR_DEBUG, "Failed to get cursor display formats"); - return false; - } - } - - // Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797 - // If this fails to find a shared modifier try to use a linear - // modifier. This avoids a scenario where the hardware cannot render to - // linear textures but only linear textures are supported for cursors, - // as is the case with Nvidia and VmWare GPUs - if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) { - // Clear the format as output_pick_format doesn't zero it - memset(format, 0, sizeof(*format)); - return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888); - } - return true; -} +#include +#include CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { @@ -201,6 +76,11 @@ void CPointerManager::unlockSoftwareForMonitor(SP mon) { updateCursorBackend(); } +bool CPointerManager::softwareLockedFor(SP mon) { + auto state = stateFor(mon); + return state->softwareLocks > 0 || state->hardwareFailed; +} + Vector2D CPointerManager::position() { return pointerPos; } @@ -216,7 +96,7 @@ SP CPointerManager::stateFor(SP return *it; } -void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) { +void CPointerManager::setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale) { damageIfSoftware(); if (buf == currentCursorImage.pBuffer) { if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) { @@ -232,10 +112,8 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, resetCursorImage(false); if (buf) { - currentCursorImage.size = {buf->width, buf->height}; - currentCursorImage.pBuffer = wlr_buffer_lock(buf); - - currentCursorImage.hyprListener_destroyBuffer.initCallback(&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager"); + currentCursorImage.size = buf->size; + currentCursorImage.pBuffer = buf; } currentCursorImage.hotspot = hotspot; @@ -317,8 +195,8 @@ void CPointerManager::recheckEnteredOutputs() { // if we are using hw cursors, prevent // the cursor from being stuck at the last point. // if we are leaving it, move it to narnia. - if (!s->hardwareFailed && s->monitor->output->impl->move_cursor) - s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420); + if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) + s->monitor->output->moveCursor({-1337, -420}); if (!currentCursorImage.surface) continue; @@ -339,16 +217,11 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.destroySurface.reset(); currentCursorImage.commitSurface.reset(); currentCursorImage.surface.reset(); - } else if (currentCursorImage.pBuffer) { - wlr_buffer_unlock(currentCursorImage.pBuffer); - currentCursorImage.hyprListener_destroyBuffer.removeCallback(); + } else if (currentCursorImage.pBuffer) currentCursorImage.pBuffer = nullptr; - } - if (currentCursorImage.pBufferTexture) { - wlr_texture_destroy(currentCursorImage.pBufferTexture); - currentCursorImage.pBufferTexture = nullptr; - } + if (currentCursorImage.bufferTex) + currentCursorImage.bufferTex = nullptr; currentCursorImage.scale = 1.F; currentCursorImage.hotspot = {0, 0}; @@ -370,9 +243,8 @@ void CPointerManager::resetCursorImage(bool apply) { } if (ms->cursorFrontBuffer) { - if (ms->monitor->output->impl->set_cursor) - ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0); - wlr_buffer_unlock(ms->cursorFrontBuffer); + if (ms->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER) + ms->monitor->output->setCursor(nullptr, {}); ms->cursorFrontBuffer = nullptr; } } @@ -418,18 +290,18 @@ void CPointerManager::onCursorMoved() { continue; const auto CURSORPOS = getCursorPosForMonitor(m); - m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y); + m->output->moveCursor(CURSORPOS); } } bool CPointerManager::attemptHardwareCursor(SP state) { auto output = state->monitor->output; - if (!output->impl->set_cursor) + if (!(output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) return false; const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock()); - state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y); + state->monitor->output->moveCursor(CURSORPOS); auto texture = getCurrentCursorTexture(); @@ -459,64 +331,62 @@ bool CPointerManager::attemptHardwareCursor(SP state, wlr_buffer* buf) { - if (!state->monitor->output->impl->set_cursor) +bool CPointerManager::setHWCursorBuffer(SP state, SP buf) { + if (!(state->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) return false; const auto HOTSPOT = transformedHotspot(state->monitor.lock()); Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT); - if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x, HOTSPOT.y)) + if (!state->monitor->output->setCursor(buf, HOTSPOT)) return false; - wlr_buffer_unlock(state->cursorFrontBuffer); state->cursorFrontBuffer = buf; - g_pCompositor->scheduleFrameForMonitor(state->monitor.get()); - - if (buf) - wlr_buffer_lock(buf); + g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); return true; } -wlr_buffer* CPointerManager::renderHWCursorBuffer(SP state, SP texture) { +SP CPointerManager::renderHWCursorBuffer(SP state, SP texture) { auto output = state->monitor->output; - int w = currentCursorImage.size.x, h = currentCursorImage.size.y; - if (output->impl->get_cursor_size) { - output->impl->get_cursor_size(output, &w, &h); + auto maxSize = output->cursorPlaneSize(); + auto cursorSize = currentCursorImage.size; - if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) { - Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h); - return nullptr; - } - } - - if (w <= 0 || h <= 0) { - Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h); + if (maxSize == Vector2D{}) return nullptr; - } - if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) { - wlr_drm_format fmt = {0}; - if (!output_pick_cursor_format(output, &fmt)) { - Debug::log(TRACE, "Failed to pick cursor format"); + if (maxSize != Vector2D{-1, -1}) { + if (cursorSize.x > maxSize.x || cursorSize.y > maxSize.y) { + Debug::log(TRACE, "hardware cursor too big! {} > {}", currentCursorImage.size, maxSize); return nullptr; } + } else + maxSize = cursorSize; - wlr_swapchain_destroy(output->cursor_swapchain); - output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt); - wlr_drm_format_finish(&fmt); + if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) { - if (!output->cursor_swapchain) { - Debug::log(TRACE, "Failed to create cursor swapchain"); + if (!state->monitor->cursorSwapchain) + state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend()); + + auto options = state->monitor->cursorSwapchain->currentOptions(); + options.size = maxSize; + options.length = 2; + options.scanout = true; + options.cursor = true; + options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; + // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, + // but if it's set, we don't wanna change it. + + if (!state->monitor->cursorSwapchain->reconfigure(options)) { + Debug::log(TRACE, "Failed to reconfigure cursor swapchain"); return nullptr; } } - wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr); + auto buf = state->monitor->cursorSwapchain->next(nullptr); if (!buf) { Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); return nullptr; @@ -525,16 +395,45 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SPmakeEGLCurrent(); - g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs + g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); + + auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); + if (!RBO) { + Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); + static auto PDUMB = CConfigValue("cursor:allow_dumb_copy"); + if (!*PDUMB) + return nullptr; + + auto bufData = buf->beginDataPtr(0); + auto bufPtr = std::get<0>(bufData); + + // clear buffer + memset(bufPtr, 0, std::get<2>(bufData)); + + auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; + + if (texBuffer) { + auto textAttrs = texBuffer->shm(); + auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto texPtr = std::get<0>(texData); + Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride); + // copy cursor texture + for (int i = 0; i < texBuffer->shm().size.y; i++) + memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + } + + buf->endDataPtr(); + + return buf; + } - const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888); RBO->bind(); g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; - Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, Vector2D{w, h}, + Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize, currentCursorImage.scale, state->monitor->scale, xbox.size()); g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); @@ -543,9 +442,7 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SPm_RenderData.pMonitor = nullptr; - g_pHyprRenderer->onRenderbufferDestroy(RBO); - - wlr_buffer_unlock(buf); + g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); return buf; } @@ -579,7 +476,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* box.x = std::round(box.x); box.y = std::round(box.y); - g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F); + g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F, 0, false, false, currentCursorImage.waitTimeline, currentCursorImage.waitPoint); if (currentCursorImage.surface) currentCursorImage.surface->resource()->frame(now); @@ -587,17 +484,19 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} - //.transform(pMonitor->transform, pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale) + .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale, + pMonitor->vecTransformedSize.y / pMonitor->scale) .pos() * pMonitor->scale; } Vector2D CPointerManager::transformedHotspot(SP pMonitor) { - if (!pMonitor->output->cursor_swapchain) + if (!pMonitor->cursorSwapchain) return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}} - .transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height) + .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->cursorSwapchain->currentOptions().size.x, + pMonitor->cursorSwapchain->currentOptions().size.y) .pos(); } @@ -799,10 +698,8 @@ SP CPointerManager::getCurrentCursorTexture() { return nullptr; if (currentCursorImage.pBuffer) { - if (!currentCursorImage.pBufferTexture) { - currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer); - currentCursorImage.bufferTex = makeShared(currentCursorImage.pBufferTexture); - } + if (!currentCursorImage.bufferTex) + currentCursorImage.bufferTex = makeShared(currentCursorImage.pBuffer); return currentCursorImage.bufferTex; } diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index da639340..cf4f1a94 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -6,13 +6,15 @@ #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" #include "../desktop/WLSurface.hpp" +#include "../helpers/sync/SyncTimeline.hpp" #include class CMonitor; -struct wlr_input_device; class IHID; class CTexture; +AQUAMARINE_FORWARD(IBuffer); + /* The naming here is a bit confusing. CPointerManager manages the _position_ and _displaying_ of the cursor, @@ -37,7 +39,7 @@ class CPointerManager { void move(const Vector2D& deltaLogical); void warpAbsolute(Vector2D abs, SP dev); - void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale); + void setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale); void setCursorSurface(SP buf, const Vector2D& hotspot); void resetCursorImage(bool apply = true); @@ -47,6 +49,7 @@ class CPointerManager { void unlockSoftwareForMonitor(CMonitor* pMonitor); void lockSoftwareAll(); void unlockSoftwareAll(); + bool softwareLockedFor(SP pMonitor); void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); @@ -135,45 +138,42 @@ class CPointerManager { } currentMonitorLayout; struct { - wlr_buffer* pBuffer = nullptr; - SP bufferTex; - WP surface; - wlr_texture* pBufferTexture = nullptr; + SP pBuffer; + SP bufferTex; + WP surface; - Vector2D hotspot; - Vector2D size; - float scale = 1.F; + Vector2D hotspot; + Vector2D size; + float scale = 1.F; - CHyprSignalListener destroySurface; - CHyprSignalListener commitSurface; - DYNLISTENER(destroyBuffer); + CHyprSignalListener destroySurface; + CHyprSignalListener commitSurface; + SP waitTimeline = nullptr; + uint64_t waitPoint = 0; } currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors Vector2D pointerPos = {0, 0}; struct SMonitorPointerState { SMonitorPointerState(SP m) : monitor(m) {} - ~SMonitorPointerState() { - if (cursorFrontBuffer) - wlr_buffer_unlock(cursorFrontBuffer); - } + ~SMonitorPointerState() {} - WP monitor; + WP monitor; - int softwareLocks = 0; - bool hardwareFailed = false; - CBox box; // logical - bool entered = false; - bool hwApplied = false; + int softwareLocks = 0; + bool hardwareFailed = false; + CBox box; // logical + bool entered = false; + bool hwApplied = false; - wlr_buffer* cursorFrontBuffer = nullptr; + SP cursorFrontBuffer; }; std::vector> monitorStates; SP stateFor(SP mon); bool attemptHardwareCursor(SP state); - wlr_buffer* renderHWCursorBuffer(SP state, SP texture); - bool setHWCursorBuffer(SP state, wlr_buffer* buf); + SP renderHWCursorBuffer(SP state, SP texture); + bool setHWCursorBuffer(SP state, SP buf); struct { SP monitorAdded; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 74cebd0c..387cac8f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -1,5 +1,7 @@ #include "ProtocolManager.hpp" +#include "../config/ConfigValue.hpp" + #include "../protocols/TearingControl.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/XDGOutput.hpp" @@ -35,6 +37,8 @@ #include "../protocols/Viewporter.hpp" #include "../protocols/MesaDRM.hpp" #include "../protocols/LinuxDMABUF.hpp" +#include "../protocols/DRMLease.hpp" +#include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -45,6 +49,10 @@ #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" +#include "../Compositor.hpp" + +#include +#include void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); @@ -65,6 +73,8 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { CProtocolManager::CProtocolManager() { + static const auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { auto M = std::any_cast(param); @@ -131,6 +141,16 @@ CProtocolManager::CProtocolManager() { PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + if (b->type() != Aquamarine::AQ_BACKEND_DRM) + continue; + + PROTO::lease = std::make_unique(&wp_drm_lease_device_v1_interface, 1, "DRMLease"); + if (*PENABLEEXPLICIT) + PROTO::sync = std::make_unique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); + break; + } + if (g_pHyprOpenGL->getDRMFormats().size() > 0) { PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 6589c4bf..801ae55a 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -94,8 +94,8 @@ void CSeatManager::setKeyboard(SP KEEB) { } void CSeatManager::updateActiveKeyboardData() { - if (keyboard && keyboard->wlr()) - PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); + if (keyboard) + PROTO::seat->updateRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay); PROTO::seat->updateKeymap(); } @@ -103,7 +103,7 @@ void CSeatManager::setKeyboardFocus(SP surf) { if (state.keyboardFocus == surf) return; - if (!keyboard || !keyboard->wlr()) { + if (!keyboard) { Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set"); return; } @@ -144,7 +144,7 @@ void CSeatManager::setKeyboardFocus(SP surf) { continue; k->sendEnter(surf); - k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group); + k->sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); } } @@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& return; } - if (!mouse || !mouse->wlr()) { + if (!mouse) { Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); return; } diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 0d1b0223..ed7a4f72 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -1,5 +1,6 @@ #include "EventLoopManager.hpp" #include "../../debug/Log.hpp" +#include "../../Compositor.hpp" #include #include @@ -7,6 +8,8 @@ #include #include +#include + #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { @@ -25,9 +28,21 @@ static int timerWrite(int fd, uint32_t mask, void* data) { return 1; } +static int aquamarineFDWrite(int fd, uint32_t mask, void* data) { + auto POLLFD = (Aquamarine::SPollFD*)data; + POLLFD->onSignal(); + return 1; +} + void CEventLoopManager::enterLoop() { m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); + for (auto& fd : aqPollFDs) { + m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); + fd->onSignal(); // dispatch outstanding + } + wl_display_run(m_sWayland.display); Debug::log(LOG, "Kicked off the event loop! :("); diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 0b2f9578..39d8bbeb 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -7,6 +7,10 @@ #include "EventLoopTimer.hpp" +namespace Aquamarine { + struct SPollFD; +}; + class CEventLoopManager { public: CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop); @@ -33,9 +37,10 @@ class CEventLoopManager { private: struct { - wl_event_loop* loop = nullptr; - wl_display* display = nullptr; - wl_event_source* eventSource = nullptr; + wl_event_loop* loop = nullptr; + wl_display* display = nullptr; + wl_event_source* eventSource = nullptr; + std::vector aqEventSources; } m_sWayland; struct { @@ -43,7 +48,10 @@ class CEventLoopManager { int timerfd = -1; } m_sTimers; - SIdleData m_sIdle; + SIdleData m_sIdle; + std::vector> aqPollFDs; + + friend class CSyncTimeline; }; inline std::unique_ptr g_pEventLoopManager; \ No newline at end of file diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 23e183d0..255023b9 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1,6 +1,6 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" -#include "wlr/types/wlr_switch.h" +#include #include #include #include "../../config/ConfigValue.hpp" @@ -28,6 +28,8 @@ #include "../../managers/PointerManager.hpp" #include "../../managers/SeatManager.hpp" +#include + CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { if (!cursorImageUnlocked()) @@ -189,8 +191,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); - if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(PMONITOR); + if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule) + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); PHLWINDOW forcedFocus = m_pForcedFocus.lock(); @@ -372,8 +374,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); - if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); + if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule) + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); // grabs if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { @@ -843,8 +845,8 @@ Vector2D CInputManager::getMouseCoordsInternal() { return g_pPointerManager->position(); } -void CInputManager::newKeyboard(wlr_input_device* keyboard) { - const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(wlr_keyboard_from_input_device(keyboard))); +void CInputManager::newKeyboard(SP keyboard) { + const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(keyboard)); setupKeyboard(PNEWKEYBOARD); @@ -856,14 +858,14 @@ void CInputManager::newVirtualKeyboard(SP keyboard) setupKeyboard(PNEWKEYBOARD); - Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard->wlr()); + Debug::log(LOG, "New virtual keyboard created at {:x}", (uintptr_t)PNEWKEYBOARD.get()); } void CInputManager::setupKeyboard(SP keeb) { m_vHIDs.push_back(keeb); try { - keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name); + keeb->hlName = getNameForNewDevice(keeb->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Keyboard had no name???"); // logic error } @@ -962,83 +964,12 @@ void CInputManager::applyConfigToKeyboard(SP pKeyboard) { // we can ignore those and just apply } - wlr_keyboard_set_repeat_info(pKeyboard->wlr(), std::max(0, REPEATRATE), std::max(0, REPEATDELAY)); - - pKeyboard->repeatDelay = REPEATDELAY; - pKeyboard->repeatRate = REPEATRATE; + pKeyboard->repeatRate = std::max(0, REPEATRATE); + pKeyboard->repeatDelay = std::max(0, REPEATDELAY); pKeyboard->numlockOn = NUMLOCKON; pKeyboard->xkbFilePath = FILEPATH; - xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; - - pKeyboard->currentRules.rules = RULES; - pKeyboard->currentRules.model = MODEL; - pKeyboard->currentRules.variant = VARIANT; - pKeyboard->currentRules.options = OPTIONS; - pKeyboard->currentRules.layout = LAYOUT; - - const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - if (!CONTEXT) { - Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??"); - return; - } - - Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model, - rules.options); - - xkb_keymap* KEYMAP = NULL; - - if (!FILEPATH.empty()) { - auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath); - - if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE) - Debug::log(ERR, "Cannot open input:kb_file= file for reading"); - else { - KEYMAP = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - fclose(KEYMAPFILE); - } - } - - if (!KEYMAP) - KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (!KEYMAP) { - g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS + - ", layout: " + LAYOUT + " )"); - - Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, - rules.options); - memset(&rules, 0, sizeof(rules)); - - pKeyboard->currentRules.rules = ""; - pKeyboard->currentRules.model = ""; - pKeyboard->currentRules.variant = ""; - pKeyboard->currentRules.options = ""; - pKeyboard->currentRules.layout = "us"; - - KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - } - - wlr_keyboard_set_keymap(pKeyboard->wlr(), KEYMAP); - - pKeyboard->updateXKBTranslationState(); - - wlr_keyboard_modifiers wlrMods = {0}; - - if (NUMLOCKON == 1) { - // lock numlock - const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM); - - if (IDX != XKB_MOD_INVALID) - wlrMods.locked |= (uint32_t)1 << IDX; - } - - if (wlrMods.locked != 0) - wlr_keyboard_notify_modifiers(pKeyboard->wlr(), 0, 0, wlrMods.locked, 0); - - xkb_keymap_unref(KEYMAP); - xkb_context_unref(CONTEXT); + pKeyboard->setKeymap(IKeyboard::SStringRuleNames{LAYOUT, MODEL, VARIANT, OPTIONS, RULES}); const auto LAYOUTSTR = pKeyboard->getActiveLayout(); @@ -1053,11 +984,11 @@ void CInputManager::newVirtualMouse(SP mouse) { setupMouse(PMOUSE); - Debug::log(LOG, "New virtual mouse created, pointer WLR: {:x}", (uintptr_t)mouse->wlr()); + Debug::log(LOG, "New virtual mouse created"); } -void CInputManager::newMouse(wlr_input_device* mouse) { - const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(wlr_pointer_from_input_device(mouse))); +void CInputManager::newMouse(SP mouse) { + const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(mouse)); setupMouse(PMOUSE); @@ -1068,13 +999,13 @@ void CInputManager::setupMouse(SP mauz) { m_vHIDs.push_back(mauz); try { - mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name); + mauz->hlName = getNameForNewDevice(mauz->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Mouse had no name???"); // logic error } - if (wlr_input_device_is_libinput(&mauz->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&mauz->wlr()->base); + if (mauz->aq() && mauz->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = mauz->aq()->getLibinputHandle(); Debug::log(LOG, "New mouse has libinput sens {:.2f} ({:.2f}) with accel profile {} ({})", libinput_device_config_accel_get_speed(LIBINPUTDEV), libinput_device_config_accel_get_default_speed(LIBINPUTDEV), (int)libinput_device_config_accel_get_profile(LIBINPUTDEV), @@ -1120,8 +1051,8 @@ void CInputManager::setPointerConfigs() { } } - if (wlr_input_device_is_libinput(&m->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base); + if (m->aq() && m->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = m->aq()->getLibinputHandle(); double touchw = 0, touchh = 0; const auto ISTOUCHPAD = libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) && @@ -1261,16 +1192,14 @@ static void removeFromHIDs(WP hid) { } void CInputManager::destroyKeyboard(SP pKeyboard) { - if (pKeyboard->xkbTranslationState) - xkb_state_unref(pKeyboard->xkbTranslationState); - pKeyboard->xkbTranslationState = nullptr; + Debug::log(LOG, "Keyboard at {:x} removed", (uintptr_t)pKeyboard.get()); std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { bool found = false; for (auto& k : m_vKeyboards | std::views::reverse) { - if (!k->wlr()) + if (!k) continue; g_pSeatManager->setKeyboard(k); @@ -1287,6 +1216,8 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { } void CInputManager::destroyPointer(SP mouse) { + Debug::log(LOG, "Pointer at {:x} removed", (uintptr_t)mouse.get()); + std::erase_if(m_vPointers, [mouse](const auto& other) { return other == mouse; }); g_pSeatManager->setMouse(m_vPointers.size() > 0 ? m_vPointers.front() : nullptr); @@ -1333,20 +1264,7 @@ void CInputManager::updateKeyboardsLeds(SP pKeyboard) { if (!pKeyboard) return; - auto keyboard = pKeyboard->wlr(); - - if (!keyboard || keyboard->xkb_state == nullptr) - return; - - uint32_t leds = 0; - for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i])) - leds |= (1 << i); - } - - for (auto& k : m_vKeyboards) { - k->updateLEDs(leds); - } + pKeyboard->updateLEDs(); } void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { @@ -1374,7 +1292,7 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { const auto IME = m_sIMERelay.m_pIME.lock(); if (IME && IME->hasGrab() && !DISALLOWACTION) { - IME->setKeyboard(pKeyboard->wlr()); + IME->setKeyboard(pKeyboard); IME->sendKey(e.timeMs, e.keycode, e.state); } else { g_pSeatManager->setKeyboard(pKeyboard); @@ -1392,15 +1310,14 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard); const auto ALLMODS = accumulateModsFromAllKBs(); - const auto PWLRKB = pKeyboard->wlr(); - auto MODS = PWLRKB->modifiers; + auto MODS = pKeyboard->modifiersState; MODS.depressed = ALLMODS; const auto IME = m_sIMERelay.m_pIME.lock(); if (IME && IME->hasGrab() && !DISALLOWACTION) { - IME->setKeyboard(PWLRKB); + IME->setKeyboard(pKeyboard); IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); } else { g_pSeatManager->setKeyboard(pKeyboard); @@ -1409,12 +1326,12 @@ void CInputManager::onKeyboardMod(SP pKeyboard) { updateKeyboardsLeds(pKeyboard); - if (PWLRKB->modifiers.group != pKeyboard->activeLayout) { - pKeyboard->activeLayout = PWLRKB->modifiers.group; + if (pKeyboard->modifiersState.group != pKeyboard->activeLayout) { + pKeyboard->activeLayout = pKeyboard->modifiersState.group; const auto LAYOUT = pKeyboard->getActiveLayout(); - pKeyboard->updateXKBTranslationState(); + Debug::log(LOG, "LAYOUT CHANGED TO {} GROUP {}", LAYOUT, MODS.group); g_pEventManager->postEvent(SHyprIPCEvent{"activelayout", pKeyboard->hlName + "," + LAYOUT}); EMIT_HOOK_EVENT("activeLayout", (std::vector{pKeyboard, LAYOUT})); @@ -1524,10 +1441,10 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; - if (!kb->enabled || !kb->wlr()) + if (!kb->enabled) continue; - finalMask |= wlr_keyboard_get_modifiers(kb->wlr()); + finalMask |= kb->getModifiers(); } return finalMask; @@ -1543,12 +1460,12 @@ void CInputManager::disableAllKeyboards(bool virt) { } } -void CInputManager::newTouchDevice(wlr_input_device* pDevice) { - const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice))); +void CInputManager::newTouchDevice(SP pDevice) { + const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(pDevice)); m_vHIDs.push_back(PNEWDEV); try { - PNEWDEV->hlName = getNameForNewDevice(pDevice->name); + PNEWDEV->hlName = getNameForNewDevice(PNEWDEV->deviceName); } catch (std::exception& e) { Debug::log(ERR, "Touch Device had no name???"); // logic error } @@ -1572,8 +1489,8 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) { void CInputManager::setTouchDeviceConfigs(SP dev) { auto setConfig = [&](SP PTOUCHDEV) -> void { - if (wlr_input_device_is_libinput(&PTOUCHDEV->wlr()->base)) { - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&PTOUCHDEV->wlr()->base); + if (dev->aq() && dev->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = dev->aq()->getLibinputHandle(); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled"); const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; @@ -1589,11 +1506,12 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { bool bound = !output.empty() && output != STRVAL_EMPTY; const bool AUTODETECT = output == "[[Auto]]"; if (!bound && AUTODETECT) { - const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name; - if (DEFAULTOUTPUT) { - output = DEFAULTOUTPUT; - bound = true; - } + // FIXME: + // const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name; + // if (DEFAULTOUTPUT) { + // output = DEFAULTOUTPUT; + // bound = true; + // } } PTOUCHDEV->boundOutput = bound ? output : ""; const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr; @@ -1617,9 +1535,9 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { void CInputManager::setTabletConfigs() { for (auto& t : m_vTablets) { - if (wlr_input_device_is_libinput(&t->wlr()->base)) { + if (t->aq()->getLibinputHandle()) { const auto NAME = t->hlName; - const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&t->wlr()->base); + const auto LIBINPUTDEV = t->aq()->getLibinputHandle(); const auto RELINPUT = g_pConfigManager->getDeviceInt(NAME, "relative_input", "input:tablet:relative_input"); t->relativeInput = RELINPUT; @@ -1647,51 +1565,37 @@ void CInputManager::setTabletConfigs() { const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position"); if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) { - t->activeArea = CBox{ACTIVE_AREA_POS.x / t->wlr()->width_mm, ACTIVE_AREA_POS.y / t->wlr()->height_mm, (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->wlr()->width_mm, - (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->wlr()->height_mm}; + t->activeArea = CBox{ACTIVE_AREA_POS.x / t->aq()->physicalSize.x, ACTIVE_AREA_POS.y / t->aq()->physicalSize.y, + (ACTIVE_AREA_POS.x + ACTIVE_AREA_SIZE.x) / t->aq()->physicalSize.x, (ACTIVE_AREA_POS.y + ACTIVE_AREA_SIZE.y) / t->aq()->physicalSize.y}; } } } } -void CInputManager::newSwitch(wlr_input_device* pDevice) { - const auto PNEWDEV = &m_lSwitches.emplace_back(); - PNEWDEV->pWlrDevice = pDevice; +void CInputManager::newSwitch(SP pDevice) { + const auto PNEWDEV = &m_lSwitches.emplace_back(); + PNEWDEV->pDevice = pDevice; - Debug::log(LOG, "New switch with name \"{}\" added", pDevice->name); + Debug::log(LOG, "New switch with name \"{}\" added", pDevice->getName()); - PNEWDEV->hyprListener_destroy.initCallback(&pDevice->events.destroy, [&](void* owner, void* data) { destroySwitch((SSwitchDevice*)owner); }, PNEWDEV, "SwitchDevice"); + PNEWDEV->listeners.destroy = pDevice->events.destroy.registerListener([this, PNEWDEV](std::any d) { destroySwitch(PNEWDEV); }); - const auto PSWITCH = wlr_switch_from_input_device(pDevice); + PNEWDEV->listeners.fire = pDevice->events.fire.registerListener([PNEWDEV](std::any d) { + const auto NAME = PNEWDEV->pDevice->getName(); + const auto E = std::any_cast(d); - PNEWDEV->hyprListener_toggle.initCallback( - &PSWITCH->events.toggle, - [&](void* owner, void* data) { - const auto PDEVICE = (SSwitchDevice*)owner; - const auto NAME = std::string(PDEVICE->pWlrDevice->name); - const auto E = (wlr_switch_toggle_event*)data; + Debug::log(LOG, "Switch {} fired, triggering binds.", NAME); - if (PDEVICE->status != -1 && PDEVICE->status == E->switch_state) - return; + g_pKeybindManager->onSwitchEvent(NAME); - Debug::log(LOG, "Switch {} fired, triggering binds.", NAME); - - g_pKeybindManager->onSwitchEvent(NAME); - - switch (E->switch_state) { - case WLR_SWITCH_STATE_ON: - Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME); - g_pKeybindManager->onSwitchOnEvent(NAME); - break; - case WLR_SWITCH_STATE_OFF: - Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME); - g_pKeybindManager->onSwitchOffEvent(NAME); - break; - } - - PDEVICE->status = E->switch_state; - }, - PNEWDEV, "SwitchDevice"); + if (E.enable) { + Debug::log(LOG, "Switch {} turn on, triggering binds.", NAME); + g_pKeybindManager->onSwitchOnEvent(NAME); + } else { + Debug::log(LOG, "Switch {} turn off, triggering binds.", NAME); + g_pKeybindManager->onSwitchOffEvent(NAME); + } + }); } void CInputManager::destroySwitch(SSwitchDevice* pDevice) { diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 85ae6197..ebf00b2d 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -18,6 +18,14 @@ class CVirtualKeyboardV1Resource; class CVirtualPointerV1Resource; class IKeyboard; +AQUAMARINE_FORWARD(IPointer); +AQUAMARINE_FORWARD(IKeyboard); +AQUAMARINE_FORWARD(ITouch); +AQUAMARINE_FORWARD(ISwitch); +AQUAMARINE_FORWARD(ITablet); +AQUAMARINE_FORWARD(ITabletTool); +AQUAMARINE_FORWARD(ITabletPad); + enum eClickBehaviorMode { CLICKMODE_DEFAULT = 0, CLICKMODE_KILL @@ -82,15 +90,14 @@ class CInputManager { void onKeyboardKey(std::any, SP); void onKeyboardMod(SP); - void newKeyboard(wlr_input_device*); + void newKeyboard(SP); void newVirtualKeyboard(SP); - void newMouse(wlr_input_device*); + void newMouse(SP); void newVirtualMouse(SP); - void newTouchDevice(wlr_input_device*); - void newSwitch(wlr_input_device*); - void newTabletTool(wlr_tablet_tool*); - void newTabletPad(wlr_input_device*); - void newTablet(wlr_input_device*); + void newTouchDevice(SP); + void newSwitch(SP); + void newTabletPad(SP); + void newTablet(SP); void destroyTouchDevice(SP); void destroyKeyboard(SP); void destroyPointer(SP); @@ -232,7 +239,7 @@ class CInputManager { void mouseMoveUnified(uint32_t, bool refocus = false); - SP ensureTabletToolPresent(wlr_tablet_tool*); + SP ensureTabletToolPresent(SP); void applyConfigToKeyboard(SP); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index f1157e4b..5e50e851 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -62,7 +62,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f if (!motion) return; - if (LASTHLSURFACE->constraint() && tool->wlr()->type != WLR_TABLET_TOOL_TYPE_MOUSE) { + if (LASTHLSURFACE->constraint() && tool->aq()->type != Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE) { // cursor logic will completely break here as the cursor will be locked. // let's just "map" the desired position to the constraint area. @@ -102,7 +102,7 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { Vector2D delta = {std::isnan(dx) ? 0.0 : dx, std::isnan(dy) ? 0.0 : dy}; switch (e.tool->type) { - case WLR_TABLET_TOOL_TYPE_MOUSE: { + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: { g_pPointerManager->move(delta); break; } @@ -205,12 +205,12 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { PROTO::idle->onActivity(); } -void CInputManager::newTablet(wlr_input_device* pDevice) { - const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(wlr_tablet_from_input_device(pDevice))); +void CInputManager::newTablet(SP pDevice) { + const auto PNEWTABLET = m_vTablets.emplace_back(CTablet::create(pDevice)); m_vHIDs.push_back(PNEWTABLET); try { - PNEWTABLET->hlName = deviceNameToInternalString(pDevice->name); + PNEWTABLET->hlName = deviceNameToInternalString(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Tablet had no name???"); // logic error } @@ -227,28 +227,32 @@ void CInputManager::newTablet(wlr_input_device* pDevice) { setTabletConfigs(); } -SP CInputManager::ensureTabletToolPresent(wlr_tablet_tool* pTool) { - if (pTool->data == nullptr) { - const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool)); - m_vHIDs.push_back(PTOOL); +SP CInputManager::ensureTabletToolPresent(SP pTool) { - PTOOL->events.destroy.registerStaticListener( - [this](void* owner, std::any d) { - auto TOOL = ((CTabletTool*)owner)->self; - destroyTabletTool(TOOL.lock()); - }, - PTOOL.get()); + for (auto& t : m_vTabletTools) { + if (t->aq() == pTool) + return t; } - return CTabletTool::fromWlr(pTool); + const auto PTOOL = m_vTabletTools.emplace_back(CTabletTool::create(pTool)); + m_vHIDs.push_back(PTOOL); + + PTOOL->events.destroy.registerStaticListener( + [this](void* owner, std::any d) { + auto TOOL = ((CTabletTool*)owner)->self; + destroyTabletTool(TOOL.lock()); + }, + PTOOL.get()); + + return PTOOL; } -void CInputManager::newTabletPad(wlr_input_device* pDevice) { - const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(wlr_tablet_pad_from_input_device(pDevice))); +void CInputManager::newTabletPad(SP pDevice) { + const auto PNEWPAD = m_vTabletPads.emplace_back(CTabletPad::create(pDevice)); m_vHIDs.push_back(PNEWPAD); try { - PNEWPAD->hlName = deviceNameToInternalString(pDevice->name); + PNEWPAD->hlName = deviceNameToInternalString(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Pad had no name???"); // logic error } @@ -259,7 +263,7 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { destroyTabletPad(PAD.lock()); }, PNEWPAD.get()); - PNEWPAD->padEvents.button.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.button.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); @@ -267,26 +271,25 @@ void CInputManager::newTabletPad(wlr_input_device* pDevice) { PROTO::tablet->buttonPad(PPAD, E.button, E.timeMs, E.down); }, PNEWPAD.get()); - PNEWPAD->padEvents.strip.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.strip.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); PROTO::tablet->strip(PPAD, E.strip, E.position, E.finger, E.timeMs); }, PNEWPAD.get()); - PNEWPAD->padEvents.ring.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.ring.registerStaticListener([](void* owner, std::any e) { const auto E = std::any_cast(e); const auto PPAD = ((CTabletPad*)owner)->self.lock(); PROTO::tablet->ring(PPAD, E.ring, E.position, E.finger, E.timeMs); }, PNEWPAD.get()); - PNEWPAD->padEvents.attach.registerStaticListener([this](void* owner, std::any e) { + PNEWPAD->padEvents.attach.registerStaticListener([](void* owner, std::any e) { const auto PPAD = ((CTabletPad*)owner)->self.lock(); const auto TOOL = std::any_cast>(e); PPAD->parent = TOOL; }, PNEWPAD.get()); - // clang-format on } diff --git a/src/meson.build b/src/meson.build index f6ae043d..71854fa4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,14 +2,15 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') executable('Hyprland', src, - cpp_args: ['-DWLR_USE_UNSTABLE'], link_args: '-rdynamic', cpp_pch: 'pch/pch.hpp', dependencies: [ server_protos, + dependency('aquamarine'), + dependency('gbm'), + dependency('xcursor'), dependency('wayland-server'), dependency('wayland-client'), - wlroots.get_variable('wlroots'), dependency('cairo'), dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 6e09ba2c..098e3f12 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../debug/HyprCtl.hpp" #include +#include #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 2f25b22b..812afe53 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -1,48 +1,9 @@ #include "CursorShape.hpp" #include +#include "../helpers/CursorShapes.hpp" #define LOGM PROTO::cursorShape->protoLog -// clang-format off -constexpr const char* SHAPE_NAMES[] = { - "invalid", - "default", - "context-menu", - "help", - "pointer", - "progress", - "wait", - "cell", - "crosshair", - "text", - "vertical-text", - "alias", - "copy", - "move", - "no-drop", - "not-allowed", - "grab", - "grabbing", - "e-resize", - "n-resize", - "ne-resize", - "nw-resize", - "s-resize", - "se-resize", - "sw-resize", - "w-resize", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "col-resize", - "row-resize", - "all-scroll", - "zoom-in", - "zoom-out", -}; -// clang-format on - CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -82,7 +43,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr } void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { - if ((uint32_t)shape == 0 || (uint32_t)shape > sizeof(SHAPE_NAMES)) { + if ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) { pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); return; } @@ -90,7 +51,7 @@ void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t ser SSetShapeEvent event; event.pMgr = pMgr; event.shape = shape; - event.shapeName = SHAPE_NAMES[shape]; + event.shapeName = CURSOR_SHAPE_NAMES.at(shape); events.setShape.emit(event); } \ No newline at end of file diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp new file mode 100644 index 00000000..9f5b6312 --- /dev/null +++ b/src/protocols/DRMLease.cpp @@ -0,0 +1,302 @@ +#include "DRMLease.hpp" +#include "../Compositor.hpp" +#include +#include + +#define LOGM PROTO::lease->protoLog + +CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + + parent = request->parent; + requested = request->requested; + + for (auto& m : requested) { + if (!m->monitor || m->monitor->isBeingLeased) { + LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null")); + resource->sendFinished(); + return; + } + } + + // grant the lease if it is seemingly valid + + LOGM(LOG, "Leasing outputs: {}", [this]() { + std::string roll; + for (auto& o : requested) { + roll += std::format("{} ", o->monitor->szName); + } + return roll; + }()); + + std::vector> outputs; + for (auto& m : requested) { + outputs.emplace_back(m->monitor->output); + } + + auto aqlease = Aquamarine::CDRMLease::create(outputs); + if (!aqlease) { + LOGM(ERR, "Rejecting lease: backend failed to alloc a lease"); + resource->sendFinished(); + return; + } + + LOGM(LOG, "Granting lease, sending fd {}", aqlease->leaseFD); + + resource->sendLeaseFd(aqlease->leaseFD); + + lease = aqlease; + + for (auto& m : requested) { + m->monitor->isBeingLeased = true; + } + + listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) { + for (auto& m : requested) { + if (m && m->monitor) + m->monitor->isBeingLeased = false; + } + + resource->sendFinished(); + }); + + close(lease->leaseFD); +} + +bool CDRMLeaseResource::good() { + return resource->resource(); +} + +CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setRequestConnector([this](CWpDrmLeaseRequestV1* r, wl_resource* conn) { + if (!conn) { + resource->error(-1, "Null connector"); + return; + } + + auto CONNECTOR = CDRMLeaseConnectorResource::fromResource(conn); + + if (std::find(requested.begin(), requested.end(), CONNECTOR) != requested.end()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Connector already requested"); + return; + } + + // TODO: when (if) we add multi, make sure this is from the correct device. + + requested.emplace_back(CONNECTOR); + }); + + resource->setSubmit([this](CWpDrmLeaseRequestV1* r, uint32_t id) { + if (requested.empty()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "No connectors added"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), self.lock()); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + PROTO::lease->m_vLeases.emplace_back(RESOURCE); + + // per protcol, after submit, this is dead. + PROTO::lease->destroyResource(this); + }); +} + +bool CDRMLeaseRequestResource::good() { + return resource->resource(); +} + +SP CDRMLeaseConnectorResource::fromResource(wl_resource* res) { + auto data = (CDRMLeaseConnectorResource*)(((CWpDrmLeaseConnectorV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setData(this); + + listeners.destroyMonitor = monitor->events.destroy.registerListener([this](std::any d) { + resource->sendWithdrawn(); + dead = true; + }); +} + +bool CDRMLeaseConnectorResource::good() { + return resource->resource(); +} + +void CDRMLeaseConnectorResource::sendData() { + resource->sendName(monitor->szName.c_str()); + resource->sendDescription(monitor->szDescription.c_str()); + + auto AQDRMOutput = (Aquamarine::CDRMOutput*)monitor->output.get(); + resource->sendConnectorId(AQDRMOutput->getConnectorID()); + + resource->sendDone(); +} + +CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + resource->setRelease([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id)); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->self = RESOURCE; + + PROTO::lease->m_vRequests.emplace_back(RESOURCE); + + LOGM(LOG, "New lease request {}", id); + + RESOURCE->parent = self; + }); + + int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); + if (fd < 0) { + LOGM(ERR, "Failed to dup fd in lease"); + return; + } + + LOGM(LOG, "Sending DRMFD {} to new lease device", fd); + resource->sendDrmFd(fd); + close(fd); + + for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) { + sendConnector(m.lock()); + } + + resource->sendDone(); +} + +bool CDRMLeaseDeviceResource::good() { + return resource->resource(); +} + +void CDRMLeaseDeviceResource::sendConnector(SP monitor) { + if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end()) + return; + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), monitor); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->parent = self; + RESOURCE->self = RESOURCE; + + LOGM(LOG, "Sending new connector {}", monitor->szName); + + connectorsSent.emplace_back(RESOURCE); + PROTO::lease->m_vConnectors.emplace_back(RESOURCE); + + resource->sendConnector(RESOURCE->resource.get()); + + RESOURCE->sendData(); +} + +CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + + auto fd = drm->getNonMasterFD(); + + if (fd < 0) { + LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); + return; + } + + close(fd); + success = true; + name = drm->gpuName; +} + +CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + if (b->type() != Aquamarine::AQ_BACKEND_DRM) + continue; + + auto drm = ((Aquamarine::CDRMBackend*)b.get())->self.lock(); + + primaryDevice = makeShared(drm); + + if (primaryDevice->success) + break; + } + + if (!primaryDevice || primaryDevice->success) { + PROTO::lease.reset(); + return; + } +} + +void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) { + std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseRequestResource* resource) { + std::erase_if(m_vRequests, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { + std::erase_if(m_vLeases, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::offer(SP monitor) { + if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) + return; + + if (monitor->output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) + return; + + if (monitor->output->getBackend() != primaryDevice->backend) { + LOGM(ERR, "Monitor {} cannot be leased: primaryDevice lease is for a different device", monitor->szName); + return; + } + + primaryDevice->offeredOutputs.emplace_back(monitor); + + for (auto& m : m_vManagers) { + m->sendConnector(monitor); + m->resource->sendDone(); + } +} diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp new file mode 100644 index 00000000..56eaa3db --- /dev/null +++ b/src/protocols/DRMLease.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "drm-lease-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +/* + TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) +*/ + +AQUAMARINE_FORWARD(CDRMBackend); +AQUAMARINE_FORWARD(CDRMLease); +class CDRMLeaseDeviceResource; +class CMonitor; +class CDRMLeaseProtocol; +class CDRMLeaseConnectorResource; +class CDRMLeaseRequestResource; + +class CDRMLeaseResource { + public: + CDRMLeaseResource(SP resource_, SP request); + + bool good(); + + WP parent; + std::vector> requested; + WP lease; + + int leaseFD = -1; + + struct { + CHyprSignalListener destroyLease; + } listeners; + + private: + SP resource; +}; + +class CDRMLeaseRequestResource { + public: + CDRMLeaseRequestResource(SP resource_); + + bool good(); + + WP parent; + WP self; + std::vector> requested; + + private: + SP resource; +}; + +class CDRMLeaseConnectorResource { + public: + CDRMLeaseConnectorResource(SP resource_, SP monitor_); + static SP fromResource(wl_resource*); + + bool good(); + void sendData(); + + WP self; + WP parent; + WP monitor; + bool dead = false; + + private: + SP resource; + + struct { + CHyprSignalListener destroyMonitor; + } listeners; + + friend class CDRMLeaseDeviceResource; +}; + +class CDRMLeaseDeviceResource { + public: + CDRMLeaseDeviceResource(SP resource_); + + bool good(); + void sendConnector(SP monitor); + + std::vector> connectorsSent; + + WP self; + + private: + SP resource; + + friend class CDRMLeaseProtocol; +}; + +class CDRMLeaseDevice { + public: + CDRMLeaseDevice(SP drmBackend); + + std::string name = ""; + bool success = false; + SP backend; + + std::vector> offeredOutputs; +}; + +class CDRMLeaseProtocol : public IWaylandProtocol { + public: + CDRMLeaseProtocol(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); + + void offer(SP monitor); + + private: + void destroyResource(CDRMLeaseDeviceResource* resource); + void destroyResource(CDRMLeaseConnectorResource* resource); + void destroyResource(CDRMLeaseRequestResource* resource); + void destroyResource(CDRMLeaseResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vConnectors; + std::vector> m_vRequests; + std::vector> m_vLeases; + + SP primaryDevice; + + friend class CDRMLeaseDeviceResource; + friend class CDRMLeaseConnectorResource; + friend class CDRMLeaseRequestResource; + friend class CDRMLeaseResource; +}; + +namespace PROTO { + inline UP lease; +}; diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp new file mode 100644 index 00000000..41178109 --- /dev/null +++ b/src/protocols/DRMSyncobj.cpp @@ -0,0 +1,183 @@ +#include "DRMSyncobj.hpp" +#include + +#include "core/Compositor.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "../Compositor.hpp" + +#include + +#define LOGM PROTO::sync->protoLog + +CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setSetAcquirePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + acquireTimeline = timeline; + acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + releaseTimeline = timeline; + releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!!acquireTimeline != !!releaseTimeline) { + resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline"); + surface->pending.rejected = true; + return; + } + + if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); + surface->pending.rejected = true; + return; + } + + if (!acquireTimeline) + return; + + // wait for the acquire timeline to materialize + auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + if (!materialized.has_value()) { + LOGM(ERR, "Failed to check the acquire timeline"); + resource->noMemory(); + return; + } + + if (materialized) + return; + + surface->lockPendingState(); + acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + }); +} + +bool CDRMSyncobjSurfaceResource::good() { + return resource->resource(); +} + +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + + if (!timeline) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); + return; + } +} + +SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { + auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CDRMSyncobjTimelineResource::good() { + return resource->resource(); +} + +CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setGetSurface([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, wl_resource* surf) { + if (!surf) { + resource->error(-1, "Invalid surface"); + return; + } + + auto SURF = CWLSurfaceResource::fromResource(surf); + if (!SURF) { + resource->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->syncobj) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_SURFACE_EXISTS, "Surface already has a syncobj attached"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), SURF); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vSurfaces.emplace_back(RESOURCE); + SURF->syncobj = RESOURCE; + + LOGM(LOG, "New linux_syncobj at {:x} for surface {:x}", (uintptr_t)RESOURCE.get(), (uintptr_t)SURF.get()); + }); + + resource->setImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vTimelines.emplace_back(RESOURCE); + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New linux_drm_timeline at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CDRMSyncobjManagerResource::good() { + return resource->resource(); +} + +CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + drmFD = g_pCompositor->m_iDRMFD; +} + +void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjManagerResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjTimelineResource* resource) { + std::erase_if(m_vTimelines, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [resource](const auto& e) { return e.get() == resource; }); +} diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp new file mode 100644 index 00000000..c1c884ff --- /dev/null +++ b/src/protocols/DRMSyncobj.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "linux-drm-syncobj-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CWLSurfaceResource; +class CDRMSyncobjTimelineResource; +class CSyncTimeline; + +class CDRMSyncobjSurfaceResource { + public: + CDRMSyncobjSurfaceResource(SP resource_, SP surface_); + + bool good(); + + WP surface; + WP acquireTimeline, releaseTimeline; + uint64_t acquirePoint = 0, releasePoint = 0; + + private: + SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; +}; + +class CDRMSyncobjTimelineResource { + public: + CDRMSyncobjTimelineResource(SP resource_, int fd_); + static SP fromResource(wl_resource*); + + bool good(); + + WP self; + int fd = -1; + SP timeline; + + private: + SP resource; +}; + +class CDRMSyncobjManagerResource { + public: + CDRMSyncobjManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CDRMSyncobjProtocol : public IWaylandProtocol { + public: + CDRMSyncobjProtocol(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); + + private: + void destroyResource(CDRMSyncobjManagerResource* resource); + void destroyResource(CDRMSyncobjTimelineResource* resource); + void destroyResource(CDRMSyncobjSurfaceResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vTimelines; + std::vector> m_vSurfaces; + + // + int drmFD = -1; + + friend class CDRMSyncobjManagerResource; + friend class CDRMSyncobjTimelineResource; + friend class CDRMSyncobjSurfaceResource; +}; + +namespace PROTO { + inline UP sync; +}; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 7c3b39ce..494d9862 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } } - gammaSize = wlr_output_get_gamma_size(pMonitor->output); + gammaSize = pMonitor->output->getGammaSize(); if (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); @@ -81,6 +81,24 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out gammaTableSet = true; close(fd); + + // translate the table to AQ format + std::vector red, green, blue; + red.resize(gammaTable.size() / 3); + green.resize(gammaTable.size() / 3); + blue.resize(gammaTable.size() / 3); + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + red.at(i) = gammaTable.at(i); + green.at(i) = gammaTable.at(gammaTable.size() / 3 + i); + blue.at(i) = gammaTable.at((gammaTable.size() / 3) * 2 + i); + } + + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + gammaTable.at(i * 3) = red.at(i); + gammaTable.at(i * 3 + 1) = green.at(i); + gammaTable.at(i * 3 + 2) = blue.at(i); + } + applyToMonitor(); }); @@ -95,7 +113,7 @@ CGammaControl::~CGammaControl() { return; // reset the LUT if the client dies for whatever reason and doesn't unset the gamma - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } bool CGammaControl::good() { @@ -109,19 +127,15 @@ void CGammaControl::applyToMonitor() { LOGM(LOG, "setting to monitor {}", pMonitor->szName); if (!gammaTableSet) { - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); return; } - uint16_t* red = &gammaTable.at(0); - uint16_t* green = &gammaTable.at(gammaSize); - uint16_t* blue = &gammaTable.at(gammaSize * 2); - - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue); + pMonitor->output->state->setGammaLut(gammaTable); if (!pMonitor->state.test()) { LOGM(LOG, "setting to monitor {} failed", pMonitor->szName); - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } g_pHyprRenderer->damageMonitor(pMonitor); diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 93465b81..963eea5c 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -23,7 +23,7 @@ class CGammaControl { CMonitor* pMonitor = nullptr; size_t gammaSize = 0; bool gammaTableSet = false; - std::vector gammaTable; + std::vector gammaTable; // [r,g,b]+ void onMonitorDestroy(); diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 24f7ad54..def4d837 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -4,6 +4,7 @@ #include "../devices/IKeyboard.hpp" #include #include "core/Compositor.hpp" +#include #define LOGM PROTO::ime->protoLog @@ -19,7 +20,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SPkeyboard->wlr()); + sendKeyboardData(g_pSeatManager->keyboard.lock()); } CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { @@ -27,37 +28,36 @@ CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); }); } -void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { +void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { if (keyboard == pLastKeyboard) return; pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->keymap_size); + int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); if (keymapFD < 0) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); if (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); close(keymapFD); return; } - memcpy(data, keyboard->keymap_string, keyboard->keymap_size); - munmap(data, keyboard->keymap_size); + memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); + munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->keymap_size); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); close(keymapFD); - const auto MODS = keyboard->modifiers; - sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); + sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); - resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay); + resource->sendRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay); } void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { @@ -316,7 +316,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc } } -void CInputMethodV2::setKeyboard(wlr_keyboard* keyboard) { +void CInputMethodV2::setKeyboard(SP keyboard) { for (auto& gw : grabs) { auto g = gw.lock(); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index bc21270c..0b2c7a49 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -11,6 +11,7 @@ class CInputMethodKeyboardGrabV2; class CInputMethodPopupV2; +class IKeyboard; class CInputMethodV2 { public: @@ -58,7 +59,7 @@ class CInputMethodV2 { bool hasGrab(); void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void setKeyboard(wlr_keyboard* keyboard); + void setKeyboard(SP keyboard); wl_client* client(); wl_client* grabClient(); @@ -90,13 +91,13 @@ class CInputMethodKeyboardGrabV2 { void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void sendKeyboardData(wlr_keyboard* keyboard); + void sendKeyboardData(SP keyboard); private: SP resource; WP owner; - wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY + WP pLastKeyboard; }; class CInputMethodPopupV2 { diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index cf8f8730..0fbf832e 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "core/Compositor.hpp" #include "types/DMABuffer.hpp" #include "types/WLBuffer.hpp" @@ -22,21 +23,66 @@ static std::optional devIDFromFD(int fd) { return stat.st_rdev; } -CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector tranches_) { +CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector, SDMABUFTranche>> tranches_) : + rendererTranche(_rendererTranche), monitorTranches(tranches_) { + + std::vector formatsVec; std::set> formats; - for (auto& t : tranches_) { - for (auto& fmt : t.formats) { - for (auto& mod : fmt.mods) { - formats.insert(std::make_pair<>(fmt.format, mod)); + + // insert formats into vec if they got inserted into set, meaning they're unique + size_t i = 0; + + rendererTranche.indicies.clear(); + for (auto& fmt : rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + // if it was inserted into set, then its unique and will have a new index in vec + rendererTranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + // if it wasn't inserted then find its index in vec + auto it = + std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + rendererTranche.indicies.push_back(it - formatsVec.begin()); } } } - tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + for (auto& [monitor, tranche] : monitorTranches) { + tranche.indicies.clear(); + for (auto& fmt : tranche.formats) { + for (auto& mod : fmt.modifiers) { + // apparently these can implode on planes, so dont use them + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + continue; + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + tranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + auto it = std::find_if(formatsVec.begin(), formatsVec.end(), + [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + tranche.indicies.push_back(it - formatsVec.begin()); + } + } + } + } - auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); + + int fds[2] = {0}; + allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); @@ -47,33 +93,18 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector> formatsVec; - for (auto& f : formats) { - formatsVec.push_back(f); - } + std::copy(formatsVec.begin(), formatsVec.end(), arr); - size_t i = 0; - for (auto& [fmt, mod] : formatsVec) { - arr[i++] = SDMABUFFeedbackTableEntry{ - .fmt = fmt, - .modifier = mod, - }; - } + munmap(arr, tableSize); - munmap(arr, tableLen); - - mainDevice = device; - tableFD = fds[1]; - tranches = formatsVec; - - // TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho. + tableFD = fds[1]; } -CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { +CDMABUFFormatTable::~CDMABUFFormatTable() { close(tableFD); } -CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) { +CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { buffer = makeShared(id, client, attrs); buffer->resource->buffer = buffer; @@ -103,7 +134,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SPsetOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); - attrs = makeShared(); + attrs = makeShared(); attrs->success = true; @@ -190,7 +221,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { return; } - LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes); + LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, FormatUtils::drmFormatName(attrs->format), attrs->planes); for (int i = 0; i < attrs->planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]); } @@ -277,32 +308,9 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); - if (surface) - LOGM(ERR, "FIXME: surface feedback stub"); - - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); - - resource->sendFormatTable(feedback->tableFD, feedback->tableLen); - - // send default feedback - struct wl_array deviceArr = { - .size = sizeof(feedback->mainDevice), - .data = (void*)&feedback->mainDevice, - }; - resource->sendMainDevice(&deviceArr); - resource->sendTrancheTargetDevice(&deviceArr); - resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0); - - wl_array indices; - wl_array_init(&indices); - for (size_t i = 0; i < feedback->tranches.size(); ++i) { - *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; - } - resource->sendTrancheFormats(&indices); - wl_array_release(&indices); - resource->sendTrancheDone(); - - resource->sendDone(); + auto& formatTable = PROTO::linuxDma->formatTable; + resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + sendDefaultFeedback(); } CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { @@ -313,6 +321,41 @@ bool CLinuxDMABUFFeedbackResource::good() { return resource->resource(); } +void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) { + struct wl_array deviceArr = { + .size = sizeof(tranche.device), + .data = (void*)&tranche.device, + }; + resource->sendTrancheTargetDevice(&deviceArr); + + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags); + + wl_array indices = { + .size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)), + .data = tranche.indicies.data(), + }; + resource->sendTrancheFormats(&indices); + resource->sendTrancheDone(); +} + +// default tranche is based on renderer (egl) +void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() { + auto mainDevice = PROTO::linuxDma->mainDevice; + auto& formatTable = PROTO::linuxDma->formatTable; + + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + resource->sendMainDevice(&deviceArr); + + sendTranche(formatTable->rendererTranche); + + resource->sendDone(); + + lastFeedbackWasScanout = false; +} + CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { if (!good()) return; @@ -361,48 +404,81 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) { - if (resource->version() < 3) { - if (mod == DRM_FORMAT_MOD_INVALID) - resource->sendFormat(fmt); - continue; + for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + resource->sendFormat(fmt.drmFormat); + continue; + } + + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + + resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); } - - // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 - - resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); } } CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { - int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int rendererFD = g_pCompositor->m_iDRMFD; auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } mainDevice = *dev; - auto fmts = g_pHyprOpenGL->getDRMFormats(); - - SDMABufTranche tranche = { - .device = *dev, - .formats = fmts, + SDMABUFTranche eglTranche = { + .device = mainDevice, + .flags = 0, // renderer isnt for ds so dont set flag. + .formats = g_pHyprOpenGL->getDRMFormats(), }; - std::vector tches; - tches.push_back(tranche); + std::vector, SDMABUFTranche>> tches; - defaultFeedback = std::make_unique(*dev, tches); + if (g_pCompositor->m_pAqBackend->hasSession()) { + // this assumes there's only 1 device used for both scanout and rendering + // also that each monitor never changes its primary plane + + for (auto& mon : g_pCompositor->m_vMonitors) { + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + tches.push_back(std::make_pair<>(mon, tranche)); + } + + static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche)); + resetFormatTable(); + }); + + static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); + resetFormatTable(); + }); + } + + formatTable = std::make_unique(eglTranche, tches); drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } @@ -411,17 +487,51 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); drmFreeDevice(&device); if (mainDeviceFD < 0) { - LOGM(ERR, "failed to open drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to open drm dev, disabling linux dmabuf"); + removeGlobal(); return; } } else { - LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]); + protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); + removeGlobal(); } }); } +void CLinuxDMABufV1Protocol::resetFormatTable() { + if (!formatTable) + return; + + LOGM(LOG, "Resetting format table"); + + // this might be a big copy + auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); + + for (auto& feedback : m_vFeedbacks) { + feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + if (feedback->lastFeedbackWasScanout) { + SP mon; + auto HLSurface = CWLSurface::fromResource(feedback->surface); + if (auto w = HLSurface->getWindow(); w) + if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) + mon = m->self.lock(); + + if (!mon) { + feedback->sendDefaultFeedback(); + return; + } + + updateScanoutTranche(feedback->surface, mon); + } else { + feedback->sendDefaultFeedback(); + } + } + + // delete old table after we sent new one + formatTable = std::move(newFormatTable); +} + CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { if (mainDeviceFD >= 0) close(mainDeviceFD); @@ -452,3 +562,52 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resour void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); } + +void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { + SP feedbackResource; + for (auto& f : m_vFeedbacks) { + if (f->surface != surface) + continue; + + feedbackResource = f; + break; + } + + if (!feedbackResource) { + LOGM(LOG, "updateScanoutTranche: surface has no dmabuf_feedback"); + return; + } + + if (!pMonitor) { + LOGM(LOG, "updateScanoutTranche: resetting feedback"); + feedbackResource->sendDefaultFeedback(); + return; + } + + const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(), + [pMonitor](std::pair, SDMABUFTranche> pair) { return pair.first == pMonitor; }); + + if (monitorTranchePair == formatTable->monitorTranches.end()) { + LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); + return; + } + + auto& monitorTranche = (*monitorTranchePair).second; + + LOGM(LOG, "updateScanoutTranche: sending a scanout tranche"); + + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + feedbackResource->resource->sendMainDevice(&deviceArr); + + // prioritize scnaout tranche but have renderer fallback tranche + // also yes formats can be duped here because different tranche flags (ds and no ds) + feedbackResource->sendTranche(monitorTranche); + feedbackResource->sendTranche(formatTable->rendererTranche); + + feedbackResource->resource->sendDone(); + + feedbackResource->lastFeedbackWasScanout = true; +} diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 2b8ce736..0e25cdc6 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -7,15 +7,16 @@ #include "wayland.hpp" #include "linux-dmabuf-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../helpers/Format.hpp" +#include "../helpers/Monitor.hpp" +#include class CDMABuffer; -struct SDRMFormat; -struct SDMABUFAttrs; class CWLSurfaceResource; class CLinuxDMABuffer { public: - CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CLinuxDMABuffer(); bool good(); @@ -31,34 +32,29 @@ class CLinuxDMABuffer { }; #pragma pack(push, 1) -struct SDMABUFFeedbackTableEntry { +struct SDMABUFFormatTableEntry { uint32_t fmt = 0; char pad[4]; uint64_t modifier = 0; }; #pragma pack(pop) -class SCompiledDMABUFTranche { - dev_t device = 0; - uint32_t flags = 0; - std::vector indices; -}; - -struct SDMABufTranche { +struct SDMABUFTranche { dev_t device = 0; uint32_t flags = 0; std::vector formats; + std::vector indicies; }; -class CCompiledDMABUFFeedback { +class CDMABUFFormatTable { public: - CCompiledDMABUFFeedback(dev_t device, std::vector tranches); - ~CCompiledDMABUFFeedback(); + CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector, SDMABUFTranche>> tranches); + ~CDMABUFFormatTable(); - dev_t mainDevice = 0; - int tableFD = -1; - size_t tableLen = 0; - std::vector> tranches; + int tableFD = -1; + size_t tableSize = 0; + SDMABUFTranche rendererTranche; + std::vector, SDMABUFTranche>> monitorTranches; }; class CLinuxDMABBUFParamsResource { @@ -66,12 +62,12 @@ class CLinuxDMABBUFParamsResource { CLinuxDMABBUFParamsResource(SP resource_); ~CLinuxDMABBUFParamsResource(); - bool good(); - void create(uint32_t id); // 0 means not immed + bool good(); + void create(uint32_t id); // 0 means not immed - SP attrs; - WP createdBuffer; - bool used = false; + SP attrs; + WP createdBuffer; + bool used = false; private: SP resource; @@ -86,11 +82,16 @@ class CLinuxDMABUFFeedbackResource { ~CLinuxDMABUFFeedbackResource(); bool good(); + void sendDefaultFeedback(); + void sendTranche(SDMABUFTranche& tranche); SP surface; // optional, for surface feedbacks private: SP resource; + bool lastFeedbackWasScanout = false; + + friend class CLinuxDMABufV1Protocol; }; class CLinuxDMABUFResource { @@ -110,6 +111,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { ~CLinuxDMABufV1Protocol(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void updateScanoutTranche(SP surface, SP pMonitor); private: void destroyResource(CLinuxDMABUFResource* resource); @@ -117,13 +119,15 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { void destroyResource(CLinuxDMABBUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); + void resetFormatTable(); + // std::vector> m_vManagers; std::vector> m_vFeedbacks; std::vector> m_vParams; std::vector> m_vBuffers; - UP defaultFeedback; + UP formatTable; dev_t mainDevice; int mainDeviceFD = -1; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 0bcf4a9c..ed412555 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -2,12 +2,11 @@ #include #include #include "../Compositor.hpp" -#include #include "types/WLBuffer.hpp" #define LOGM PROTO::mesaDRM->protoLog -CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) { +CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); for (int i = 0; i < attrs_.planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); @@ -60,10 +59,27 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { return; } - SDMABUFAttrs attrs; + uint64_t mod = DRM_FORMAT_MOD_INVALID; + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + for (auto& f : fmts) { + if (f.drmFormat != fmt) + continue; + + for (auto& m : f.modifiers) { + if (m == DRM_FORMAT_MOD_LINEAR) + continue; + + mod = m; + break; + } + break; + } + + Aquamarine::SDMABUFAttrs attrs; attrs.success = true; attrs.size = {w, h}; - attrs.modifier = DRM_FORMAT_MOD_INVALID; + attrs.modifier = mod; attrs.planes = 1; attrs.offsets[0] = off0; attrs.strides[0] = str0; @@ -87,7 +103,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { auto fmts = g_pHyprOpenGL->getDRMFormats(); for (auto& fmt : fmts) { - resource->sendFormat(fmt.format); + resource->sendFormat(fmt.drmFormat); } } @@ -97,10 +113,10 @@ bool CMesaDRMResource::good() { CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { drmDevice* dev = nullptr; - int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int drmFD = g_pCompositor->m_iDRMFD; if (drmGetDevice2(drmFD, 0, &dev) != 0) { - LOGM(ERR, "Failed to get device"); - PROTO::mesaDRM.reset(); + protoLog(ERR, "Failed to get device, disabling MesaDRM"); + removeGlobal(); return; } @@ -108,7 +124,15 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co nodeName = dev->nodes[DRM_NODE_RENDER]; } else { ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); - LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + + if (!dev->nodes[DRM_NODE_PRIMARY]) { + protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); + drmFreeDevice(&dev); + removeGlobal(); + return; + } + + protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); nodeName = dev->nodes[DRM_NODE_PRIMARY]; } drmFreeDevice(&dev); diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp index ad31a182..46811d68 100644 --- a/src/protocols/MesaDRM.hpp +++ b/src/protocols/MesaDRM.hpp @@ -10,7 +10,7 @@ class CMesaDRMBufferResource { public: - CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CMesaDRMBufferResource(); bool good(); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 68c50193..66f4c5f0 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -2,6 +2,8 @@ #include #include "../Compositor.hpp" +using namespace Aquamarine; + #define LOGM PROTO::outputManagement->protoLog COutputManager::COutputManager(SP resource_) : resource(resource_) { @@ -123,8 +125,8 @@ void COutputHead::sendAllData() { resource->sendName(pMonitor->szName.c_str()); resource->sendDescription(pMonitor->szDescription.c_str()); - if (pMonitor->output->phys_width > 0 && pMonitor->output->phys_height > 0) - resource->sendPhysicalSize(pMonitor->output->phys_width, pMonitor->output->phys_height); + if (pMonitor->output->physicalSize.x > 0 && pMonitor->output->physicalSize.y > 0) + resource->sendPhysicalSize(pMonitor->output->physicalSize.x, pMonitor->output->physicalSize.y); resource->sendEnabled(pMonitor->m_bEnabled); if (pMonitor->m_bEnabled) { @@ -133,12 +135,12 @@ void COutputHead::sendAllData() { resource->sendScale(wl_fixed_from_double(pMonitor->scale)); } - if (pMonitor->output->make && VERSION >= 2) - resource->sendMake(pMonitor->output->make); - if (pMonitor->output->model && VERSION >= 2) - resource->sendModel(pMonitor->output->model); - if (pMonitor->output->serial && VERSION >= 2) - resource->sendSerialNumber(pMonitor->output->serial); + if (!pMonitor->output->make.empty() && VERSION >= 2) + resource->sendMake(pMonitor->output->make.c_str()); + if (!pMonitor->output->model.empty() && VERSION >= 2) + resource->sendModel(pMonitor->output->model.c_str()); + if (!pMonitor->output->serial.empty() && VERSION >= 2) + resource->sendSerialNumber(pMonitor->output->serial.c_str()); if (VERSION >= 4) resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED); @@ -146,12 +148,12 @@ void COutputHead::sendAllData() { // send all available modes if (modes.empty()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - makeAndSendNewMode(mode); + if (!pMonitor->output->modes.empty()) { + for (auto& m : pMonitor->output->modes) { + makeAndSendNewMode(m); } + } else if (pMonitor->output->state->state().customMode) { + makeAndSendNewMode(pMonitor->output->state->state().customMode); } else makeAndSendNewMode(nullptr); } @@ -164,9 +166,9 @@ void COutputHead::sendAllData() { if (!m) continue; - if (m->mode == pMonitor->currentMode) { + if (m->mode == pMonitor->output->state->state().mode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -197,7 +199,7 @@ void COutputHead::updateMode() { if (m->mode == pMonitor->currentMode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -207,7 +209,7 @@ void COutputHead::updateMode() { } } -void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) { +void COutputHead::makeAndSendNewMode(SP mode) { const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), mode)); if (!RESOURCE->good()) { @@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() { return pMonitor; } -COutputMode::COutputMode(SP resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) { +COutputMode::COutputMode(SP resource_, SP mode_) : resource(resource_), mode(mode_) { if (!good()) return; @@ -237,11 +239,11 @@ void COutputMode::sendAllData() { if (!mode) return; - LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->width, mode->height, mode->refresh, mode->preferred); + LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate, mode->preferred); - resource->sendSize(mode->width, mode->height); - if (mode->refresh > 0) - resource->sendRefresh(mode->refresh); + resource->sendSize(mode->pixelSize.x, mode->pixelSize.y); + if (mode->refreshRate > 0) + resource->sendRefresh(mode->refreshRate); if (mode->preferred) resource->sendPreferred(); } @@ -250,8 +252,8 @@ bool COutputMode::good() { return resource->resource(); } -wlr_output_mode* COutputMode::getMode() { - return mode; +SP COutputMode::getMode() { + return mode.lock(); } COutputConfiguration::COutputConfiguration(SP resource_, SP owner_) : resource(resource_), owner(owner_) { @@ -364,8 +366,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { newRule.disabled = false; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; - newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F; + newRule.resolution = head->state.mode->getMode()->pixelSize; + newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { newRule.resolution = head->state.customMode.size; newRule.refreshRate = head->state.customMode.refresh / 1000.F; @@ -425,7 +427,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, MODE->getMode()->width, MODE->getMode()->height, MODE->getMode()->refresh); + LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); }); resource->setSetCustomMode([this](CZwlrOutputConfigurationHeadV1* r, int32_t w, int32_t h, int32_t refresh) { diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 81ae9a71..36478d0b 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CMonitor; @@ -34,15 +35,15 @@ class COutputManager { class COutputMode { public: - COutputMode(SP resource_, wlr_output_mode* mode_); + COutputMode(SP resource_, SP mode_); - bool good(); - wlr_output_mode* getMode(); - void sendAllData(); + bool good(); + SP getMode(); + void sendAllData(); private: - SP resource; - wlr_output_mode* mode = nullptr; + SP resource; + WP mode; friend class COutputHead; friend class COutputManagementProtocol; @@ -61,7 +62,7 @@ class COutputHead { SP resource; CMonitor* pMonitor = nullptr; - void makeAndSendNewMode(wlr_output_mode* mode); + void makeAndSendNewMode(SP mode); void sendCurrentMode(); std::vector> modes; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index ef287cfa..597b9871 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -17,7 +17,7 @@ COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_ pMonitor->dpmsStatus = mode == ZWLR_OUTPUT_POWER_V1_MODE_ON; - wlr_output_state_set_enabled(pMonitor->state.wlr(), pMonitor->dpmsStatus); + pMonitor->output->state->setEnabled(mode == ZWLR_OUTPUT_POWER_V1_MODE_ON); if (!pMonitor->state.commit()) LOGM(ERR, "Couldn't set dpms to {} for {}", pMonitor->dpmsStatus, pMonitor->szName); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 3907bf1e..e9472fc3 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -3,6 +3,8 @@ #include "../helpers/Monitor.hpp" #include "../managers/HookSystemManager.hpp" #include "core/Compositor.hpp" +#include "core/Output.hpp" +#include #define LOGM PROTO::presentation->protoLog @@ -41,13 +43,11 @@ bool CPresentationFeedback::good() { } void CPresentationFeedback::sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { - auto client = resource->client(); - wl_resource* res; - wl_resource_for_each(res, &data->pMonitor->output->resources) { - if (client == wl_resource_get_client(res)) { - resource->sendSyncOutput(res); - break; - } + auto client = resource->client(); + + if (PROTO::outputs.contains(data->pMonitor->szName)) { + if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource) + resource->sendSyncOutput(outputResource->getResource()->resource()); } uint32_t flags = 0; @@ -55,9 +55,9 @@ void CPresentationFeedback::sendQueued(SP data, timespe flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC; if (data->zeroCopy) flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; if (data->wasPresented && when) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8a6285a1..5d1c9332 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -266,20 +266,17 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r return; } - if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat; if (box.width == 0 && box.height == 0) PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)}; else { PFRAME->box = box; } - int ow, oh; - wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y) + .scale(PFRAME->pMonitor->scale) + .round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -383,10 +380,10 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); } -void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { - m_pLastMonitorBackBuffer = e->state->buffer; +void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) { + m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer; shareAllFrames(pMonitor); - m_pLastMonitorBackBuffer = nullptr; + m_pLastMonitorBackBuffer.reset(); } void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { @@ -473,11 +470,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { } bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); auto shm = frame->buffer->shm(); auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm @@ -487,10 +480,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat); + fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat); if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { - wlr_texture_destroy(sourceTex); + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering"); return false; } @@ -509,8 +502,8 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { + Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format"); g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); return false; } @@ -539,27 +532,24 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via shm"); return true; } bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) { + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame"); return false; + } - CBox monbox = - CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} - .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. - .transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); + CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} + .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. + .transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); @@ -569,7 +559,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via dma"); return true; } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index be434285..4999773b 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -8,9 +8,10 @@ #include "../managers/HookSystemManager.hpp" #include "../helpers/Timer.hpp" #include "../managers/eventLoop/EventLoopTimer.hpp" +#include class CMonitor; -class IWLBuffer; +class IHLBuffer; enum eClientOwners { CLIENT_SCREENCOPY = 0, @@ -56,7 +57,7 @@ struct SScreencopyFrame { bool bufferDMA = false; - WP buffer; + WP buffer; CMonitor* pMonitor = nullptr; PHLWINDOWREF pWindow; @@ -79,7 +80,7 @@ class CScreencopyProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); - void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; @@ -93,7 +94,7 @@ class CScreencopyProtocolManager { std::vector m_vFramesAwaitingWrite; - wlr_buffer* m_pLastMonitorBackBuffer = nullptr; + SP m_pLastMonitorBackBuffer; void shareAllFrames(CMonitor* pMonitor); void shareFrame(SScreencopyFrame* frame); diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 7b62f245..72c7cfde 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -5,6 +5,7 @@ #include "core/Seat.hpp" #include "core/Compositor.hpp" #include +#include #define LOGM PROTO::tablet->protoLog @@ -44,17 +45,17 @@ bool CTabletPadGroupV2Resource::good() { return resource->resource(); } -void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_group* group) { - resource->sendModes(group->mode_count); +void CTabletPadGroupV2Resource::sendData(SP pad, SP group) { + resource->sendModes(group->modes); wl_array buttonArr; wl_array_init(&buttonArr); - wl_array_add(&buttonArr, group->button_count * sizeof(int)); - memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int)); + wl_array_add(&buttonArr, group->buttons.size() * sizeof(int)); + memcpy(buttonArr.data, group->buttons.data(), group->buttons.size() * sizeof(int)); resource->sendButtons(&buttonArr); wl_array_release(&buttonArr); - for (size_t i = 0; i < group->strip_count; ++i) { + for (size_t i = 0; i < group->strips.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vStrips.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -67,7 +68,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_grou resource->sendStrip(RESOURCE->resource.get()); } - for (size_t i = 0; i < group->ring_count; ++i) { + for (size_t i = 0; i < group->rings.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vRings.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -97,23 +98,20 @@ bool CTabletPadV2Resource::good() { void CTabletPadV2Resource::sendData() { // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : pad->aq()->paths) { + resource->sendPath(p.c_str()); } - resource->sendButtons(pad->wlr()->button_count); + resource->sendButtons(pad->aq()->buttons); - wlr_tablet_pad_group* group; - size_t i = 0; - wl_list_for_each(group, &pad->wlr()->groups, link) { - createGroup(group, i++); + for (size_t i = 0; i < pad->aq()->groups.size(); ++i) { + createGroup(pad->aq()->groups.at(i), i); } resource->sendDone(); } -void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) { +void CTabletPadV2Resource::createGroup(SP group, size_t idx) { const auto RESOURCE = PROTO::tablet->m_vGroups.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), idx)); @@ -142,13 +140,10 @@ bool CTabletV2Resource::good() { void CTabletV2Resource::sendData() { resource->sendName(tablet->deviceName.c_str()); - resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id); + resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID); - // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size); - (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : tablet->aq()->paths) { + resource->sendPath(p.c_str()); } resource->sendDone(); @@ -179,23 +174,23 @@ bool CTabletToolV2Resource::good() { } void CTabletToolV2Resource::sendData() { - static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type { - switch (wlr) { - case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; - case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; - case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; - case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; - case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; - case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; - case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; + static auto AQ_TYPE_TO_PROTO = [](uint32_t aq) -> zwpTabletToolV2Type { + switch (aq) { + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; default: ASSERT(false); } UNREACHABLE(); }; - resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type)); - resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF); - resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF); + resource->sendType(AQ_TYPE_TO_PROTO(tool->aq()->type)); + resource->sendHardwareSerial(tool->aq()->serial >> 32, tool->aq()->serial & 0xFFFFFFFF); + resource->sendHardwareIdWacom(tool->aq()->id >> 32, tool->aq()->id & 0xFFFFFFFF); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE) resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE) diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 58f13c1a..1ebcb1e5 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "tablet-v2.hpp" #include "../helpers/math/Math.hpp" +#include class CTablet; class CTabletTool; @@ -51,7 +52,7 @@ class CTabletPadGroupV2Resource { CTabletPadGroupV2Resource(SP resource_, size_t idx); bool good(); - void sendData(SP pad, wlr_tablet_pad_group* group); + void sendData(SP pad, SP group); std::vector> rings; std::vector> strips; @@ -83,7 +84,7 @@ class CTabletPadV2Resource { private: SP resource; - void createGroup(wlr_tablet_pad_group* group, size_t idx); + void createGroup(SP group, size_t idx); friend class CTabletSeat; friend class CTabletV2Protocol; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index d4c66c3b..0e78e5f7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -193,16 +193,11 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou return; } - if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PMONITOR->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat; PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; - int ow, oh; - wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -289,12 +284,10 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r m_vFramesAwaitingWrite.emplace_back(PFRAME); } -void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { +void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output); - std::vector framesToRemove; // share frame if correct output @@ -306,7 +299,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp continue; } - if (PMONITOR != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) + if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) continue; CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; @@ -370,7 +363,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->makeEGLCurrent(); CFramebuffer outFB; - outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat); + outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); if (frame->overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index f044a781..c3620d41 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -21,7 +21,7 @@ class CToplevelExportProtocolManager { 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, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 8cb69dbe..03c5775e 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -52,6 +52,21 @@ CViewportResource::CViewportResource(SP resource_, SPpending.viewport.hasSource = true; surface->pending.viewport.source = {x, y, w, h}; }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!surface || !surface->pending.buffer) + return; + + if (surface->pending.viewport.hasSource) { + auto& src = surface->pending.viewport.source; + + if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) { + resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); + surface->pending.rejected = true; + return; + } + } + }); } CViewportResource::~CViewportResource() { @@ -66,20 +81,6 @@ bool CViewportResource::good() { return resource->resource(); } -void CViewportResource::verify() { - if (!surface) - return; - - if (surface->pending.viewport.hasSource) { - auto& src = surface->pending.viewport.source; - - if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) { - resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); - return; - } - } -} - CViewporterResource::CViewporterResource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp index 01278203..3c2a4eef 100644 --- a/src/protocols/Viewporter.hpp +++ b/src/protocols/Viewporter.hpp @@ -15,11 +15,14 @@ class CViewportResource { ~CViewportResource(); bool good(); - void verify(); WP surface; private: SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; }; class CViewporterResource { diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 009c277c..2642ec11 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,12 +1,9 @@ #include "VirtualKeyboard.hpp" #include +#include "../devices/IKeyboard.hpp" #define LOGM PROTO::virtualKeyboard->protoLog -static const struct wlr_keyboard_impl virtualKeyboardImpl = { - .name = "virtual-keyboard", -}; - CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_key_event event = { - .time_msec = timeMs, - .keycode = key, - .update_state = false, - .state = (wl_keyboard_key_state)state, - }; - wlr_keyboard_notify_key(&keyboard, &event); + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = timeMs, + .keycode = key, + .state = (wl_keyboard_key_state)state, + }); + + const bool CONTAINS = std::find(pressed.begin(), pressed.end(), key) != pressed.end(); + if (state && !CONTAINS) + pressed.emplace_back(key); + else if (!state && CONTAINS) + std::erase(pressed, key); }); resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { @@ -43,7 +44,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group); + events.modifiers.emit(IKeyboard::SModifiersEvent{ + .depressed = depressed, + .latched = latched, + .locked = locked, + .group = group, + }); }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { @@ -75,7 +81,9 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_set_keymap(&keyboard, xkbKeymap); + events.keymap.emit(IKeyboard::SKeymapEvent{ + .keymap = xkbKeymap, + }); hasKeymap = true; xkb_keymap_unref(xkbKeymap); @@ -83,22 +91,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP close(fd); }); - wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard"); + name = "hl-virtual-keyboard"; } CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() { events.destroy.emit(); - wlr_keyboard_finish(&keyboard); } bool CVirtualKeyboardV1Resource::good() { return resource->resource(); } -wlr_keyboard* CVirtualKeyboardV1Resource::wlr() { - return &keyboard; -} - wl_client* CVirtualKeyboardV1Resource::client() { return resource->resource() ? resource->client() : nullptr; } @@ -106,17 +109,16 @@ wl_client* CVirtualKeyboardV1Resource::client() { void CVirtualKeyboardV1Resource::releasePressed() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - size_t keycodesNum = keyboard.num_keycodes; - for (size_t i = 0; i < keycodesNum; ++i) { - struct wlr_keyboard_key_event event = { - .time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000), - .keycode = keyboard.keycodes[keycodesNum - i - 1], - .update_state = false, - .state = WL_KEYBOARD_KEY_STATE_RELEASED, - }; - wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes + for (auto& p : pressed) { + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000, + .keycode = p, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }); } + + pressed.clear(); } CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 447b5db9..93b63bb5 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -14,19 +14,24 @@ class CVirtualKeyboardV1Resource { struct { CSignal destroy; + CSignal key; + CSignal modifiers; + CSignal keymap; } events; - bool good(); - wlr_keyboard* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name = ""; private: SP resource; - wlr_keyboard keyboard; void releasePressed(); bool hasKeymap = false; + + std::vector pressed; }; class CVirtualKeyboardProtocol : public IWaylandProtocol { diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 1fb83888..bdeec32d 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -2,10 +2,6 @@ #define LOGM PROTO::virtualPointer->protoLog -static const wlr_pointer_impl pointerImpl = { - .name = "virtual-pointer-v1", -}; - CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r PROTO::virtualPointer->destroyResource(this); }); - wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointerV1Resource"); - resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) { - wlr_pointer_motion_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .delta_x = wl_fixed_to_double(dx), - .delta_y = wl_fixed_to_double(dy), - .unaccel_dx = wl_fixed_to_double(dx), - .unaccel_dy = wl_fixed_to_double(dy), - }; - wl_signal_emit_mutable(&pointer.events.motion, &event); + events.move.emit(IPointer::SMotionEvent{ + .timeMs = timeMs, + .delta = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + .unaccel = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + }); }); resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) { if (!xExtent || !yExtent) return; - wlr_pointer_motion_absolute_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .x = (double)x / xExtent, - .y = (double)y / yExtent, - }; - wl_signal_emit_mutable(&pointer.events.motion_absolute, &event); + events.warp.emit(IPointer::SMotionAbsoluteEvent{ + .timeMs = timeMs, + .absolute = {(double)x / xExtent, (double)y / yExtent}, + }); }); resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) { - struct wlr_pointer_button_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .button = button, - .state = (wl_pointer_button_state)state, - }; - wl_signal_emit_mutable(&pointer.events.button, &event); + events.button.emit(IPointer::SButtonEvent{ + .timeMs = timeMs, + .button = button, + .state = (wl_pointer_button_state)state, + }); }); resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) { @@ -63,18 +48,18 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r } axis = axis_; - axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; + axisEvents[axis] = IPointer::SAxisEvent{.timeMs = timeMs, .axis = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; }); resource->setFrame([this](CZwlrVirtualPointerV1* r) { for (auto& e : axisEvents) { - if (!e.pointer) + if (!e.timeMs) continue; - wl_signal_emit_mutable(&pointer.events.axis, &e); - e.pointer = nullptr; + events.axis.emit(e); + e.timeMs = 0; } - wl_signal_emit_mutable(&pointer.events.frame, &pointer); + events.frame.emit(); }); resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; }); @@ -85,12 +70,11 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = 0; - axisEvents[axis].delta_discrete = 0; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = 0; + axisEvents[axis].deltaDiscrete = 0; }); resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) { @@ -99,17 +83,15 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = wl_fixed_to_double(value); - axisEvents[axis].delta_discrete = discrete * 120; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = wl_fixed_to_double(value); + axisEvents[axis].deltaDiscrete = discrete * 120; }); } CVirtualPointerV1Resource::~CVirtualPointerV1Resource() { - wlr_pointer_finish(&pointer); events.destroy.emit(); } @@ -117,10 +99,6 @@ bool CVirtualPointerV1Resource::good() { return resource->resource(); } -wlr_pointer* CVirtualPointerV1Resource::wlr() { - return &pointer; -} - wl_client* CVirtualPointerV1Resource::client() { return resource->client(); } diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 59a7e739..ee5ee7e2 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -7,6 +7,7 @@ #include "WaylandProtocol.hpp" #include "wlr-virtual-pointer-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../devices/IPointer.hpp" class CVirtualPointerV1Resource { public: @@ -15,19 +16,35 @@ class CVirtualPointerV1Resource { struct { CSignal destroy; + CSignal move; + CSignal warp; + CSignal button; + CSignal axis; + CSignal frame; + + CSignal swipeBegin; + CSignal swipeUpdate; + CSignal swipeEnd; + + CSignal pinchBegin; + CSignal pinchUpdate; + CSignal pinchEnd; + + CSignal holdBegin; + CSignal holdEnd; } events; - bool good(); - wlr_pointer* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name; private: - SP resource; - wlr_pointer pointer; + SP resource; - uint32_t axis = 0; + uint32_t axis = 0; - std::array axisEvents; + std::array axisEvents; }; class CVirtualPointerProtocol : public IWaylandProtocol { diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 03e58956..073aa502 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -75,8 +75,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 if (XDGVER >= OUTPUT_NAME_SINCE_VERSION) pXDGOutput->resource->sendName(PMONITOR->szName.c_str()); - if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description) - pXDGOutput->resource->sendDescription(PMONITOR->output->description); + if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && !PMONITOR->output->description.empty()) + pXDGOutput->resource->sendDescription(PMONITOR->output->description.c_str()); pXDGOutput->sendDetails(); @@ -93,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() { o->sendDetails(); - wlr_output_schedule_done(o->monitor->output); + o->monitor->scheduleDone(); } } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9c56df93..8276ed55 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -4,6 +4,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" +#include #define LOGM PROTO::xdgShell->protoLog diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 691267b0..5cd6005a 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -6,6 +6,9 @@ #include "Subcompositor.hpp" #include "../Viewporter.hpp" #include "../../helpers/Monitor.hpp" +#include "../PresentationTime.hpp" +#include "../DRMSyncobj.hpp" +#include "../../render/Renderer.hpp" #define LOGM PROTO::compositor->protoLog @@ -102,58 +105,14 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.size = tfs / pending.scale; } - if (viewportResource) - viewportResource->verify(); - pending.damage.intersect(CBox{{}, pending.size}); - auto previousBuffer = current.buffer; - CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + events.precommit.emit(); + if (pending.rejected) + return; - current = pending; - pending.damage.clear(); - pending.bufferDamage.clear(); - - if (current.buffer && !bufferReleased) { - // without previous dolphin et al are weird vvv - //CRegion surfaceDamage = - // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); - current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. - - // release the buffer if it's synchronous as update() has done everything thats needed - // so we can let the app know we're done. - if (current.buffer->isSynchronous()) { - current.buffer->sendRelease(); - bufferReleased = true; - } - } - - // TODO: we should _accumulate_ and not replace above if sync - if (role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)role.get(); - if (subsurface->sync) - return; - - events.commit.emit(); - } else { - // send commit to all synced surfaces in this tree. - breadthfirst( - [](SP surf, const Vector2D& offset, void* data) { - if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); - if (!subsurface->sync) - return; - } - surf->events.commit.emit(); - }, - nullptr); - } - - // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { - previousBuffer->sendRelease(); - bufferReleased = true; - } + if (stateLocks <= 0) + commitPendingState(); }); resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); @@ -426,7 +385,97 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; - return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(wlr_output_transform_invert(current.transform)), trc.x, trc.y).add(current.bufferDamage); + return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); +} + +void CWLSurfaceResource::lockPendingState() { + stateLocks++; +} + +void CWLSurfaceResource::unlockPendingState() { + stateLocks--; + if (stateLocks <= 0) + commitPendingState(); +} + +void CWLSurfaceResource::commitPendingState() { + auto previousBuffer = current.buffer; + CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + + current = pending; + pending.damage.clear(); + pending.bufferDamage.clear(); + + if (current.buffer && !bufferReleased) { + // without previous dolphin et al are weird vvv + //CRegion surfaceDamage = + // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); + current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + + // release the buffer if it's synchronous as update() has done everything thats needed + // so we can let the app know we're done. + if (current.buffer->isSynchronous()) { + current.buffer->sendReleaseWithSurface(self.lock()); + bufferReleased = true; + } + } + + // TODO: we should _accumulate_ and not replace above if sync + if (role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)role.get(); + if (subsurface->sync) + return; + + events.commit.emit(); + } else { + // send commit to all synced surfaces in this tree. + breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + if (!subsurface->sync) + return; + } + surf->events.commit.emit(); + }, + nullptr); + } + + // for async buffers, we can only release the buffer once we are unrefing it from current. + if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { + if (previousBuffer->lockedByBackend) { + previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { + if (!self.expired()) // could be dead in the dtor + previousBuffer->sendReleaseWithSurface(self.lock()); + else + previousBuffer->sendRelease(); + previousBuffer->hlEvents.backendRelease.reset(); + bufferReleased = true; + }); + } else + previousBuffer->sendReleaseWithSurface(self.lock()); + + bufferReleased = true; + } +} + +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { + frame(when); + auto FEEDBACK = makeShared(self.lock()); + FEEDBACK->attachMonitor(pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + + if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) + return; + + // attach explicit sync + g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); + + if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { + Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); + pMonitor->lastWaitPoint = syncobj->acquirePoint; + } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 2f276719..5e6413c8 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -24,6 +24,7 @@ class CWLSurface; class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; +class CDRMSyncobjSurfaceResource; class CWLCallbackResource { public: @@ -74,6 +75,7 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { + CSignal precommit; CSignal commit; CSignal map; CSignal unmap; @@ -81,11 +83,11 @@ class CWLSurfaceResource { CSignal destroy; } events; - struct { + struct SState { CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; int scale = 1; - SP buffer; + SP buffer; SP texture; Vector2D offset; Vector2D size; @@ -95,6 +97,7 @@ class CWLSurfaceResource { Vector2D destination; CBox source; } viewport; + bool rejected = false; // void reset() { @@ -115,9 +118,13 @@ class CWLSurfaceResource { std::vector> subsurfaces; WP role; WP viewportResource; + WP syncobj; // may not be present void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); + void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); + void lockPendingState(); + void unlockPendingState(); // returns a pair: found surface (null if not found) and surface local coords. // localCoords param is relative to 0,0 of this surface @@ -130,7 +137,10 @@ class CWLSurfaceResource { // tracks whether we should release the buffer bool bufferReleased = false; + int stateLocks = 0; + void destroy(); + void commitPendingState(); void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); }; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 10daa15e..4ba23cbe 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni PROTO::outputs.at(monitor->szName)->destroyResource(this); }); - resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null", - monitor->output->model ? monitor->output->model : "null", monitor->transform); + resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), + monitor->output->model.c_str(), monitor->transform); if (resource->version() >= 4) { resource->sendName(monitor->szName.c_str()); resource->sendDescription(monitor->szDescription.c_str()); @@ -115,3 +115,9 @@ void CWLOutputProtocol::remove() { bool CWLOutputProtocol::isDefunct() { return defunct; } + +void CWLOutputProtocol::sendDone() { + for (auto& r : m_vOutputs) { + r->resource->sendDone(); + } +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 46981635..46e4057b 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -26,6 +26,8 @@ class CWLOutputResource { private: SP resource; wl_client* pClient = nullptr; + + friend class CWLOutputProtocol; }; class CWLOutputProtocol : public IWaylandProtocol { @@ -35,6 +37,7 @@ class CWLOutputProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); SP outputResourceFrom(wl_client* client); + void sendDone(); WP monitor; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 464a901c..21a47575 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { int fd; uint32_t size; if (keyboard) { - fd = keyboard->wlr()->keymap_fd; - size = keyboard->wlr()->keymap_size; + fd = keyboard->xkbKeymapFD; + size = keyboard->xkbKeymapString.length() + 1; } else { fd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (fd < 0) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 4088949f..75c2134a 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -41,20 +41,20 @@ CWLSHMBuffer::~CWLSHMBuffer() { ; } -eBufferCapability CWLSHMBuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CWLSHMBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CWLSHMBuffer::type() { - return BUFFER_TYPE_SHM; +Aquamarine::eBufferType CWLSHMBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; } bool CWLSHMBuffer::isSynchronous() { return true; } -SSHMAttrs CWLSHMBuffer::shm() { - SSHMAttrs attrs; +Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { + Aquamarine::SSHMAttrs attrs; attrs.success = true; attrs.fd = pool->fd; attrs.format = FormatUtils::shmToDRM(fmt); @@ -188,11 +188,18 @@ CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { if (shmFormats.empty()) { - size_t len = 0; - const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len); + shmFormats.push_back(WL_SHM_FORMAT_ARGB8888); + shmFormats.push_back(WL_SHM_FORMAT_XRGB8888); - for (size_t i = 0; i < len; ++i) { - shmFormats.push_back(FormatUtils::drmToShm(formats[i])); + static const std::array supportedShmFourccFormats = { + DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, + }; + + for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) { + if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) + continue; + + shmFormats.push_back(fmt.drmFormat); } } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 70a8b208..fab325fe 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -29,16 +29,16 @@ class CSHMPool { void resize(size_t size); }; -class CWLSHMBuffer : public IWLBuffer { +class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); virtual ~CWLSHMBuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual void update(const CRegion& damage); virtual bool isSynchronous(); - virtual SSHMAttrs shm(); + virtual Aquamarine::SSHMAttrs shm(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 5ed942e1..0217f7e2 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -1,41 +1,10 @@ #include "Buffer.hpp" -#include "WLBuffer.hpp" -SDMABUFAttrs IWLBuffer::dmabuf() { - return SDMABUFAttrs{}; +void IHLBuffer::sendRelease() { + resource->sendRelease(); } -SSHMAttrs IWLBuffer::shm() { - return SSHMAttrs{}; -} - -std::tuple IWLBuffer::beginDataPtr(uint32_t flags) { - return {nullptr, 0, 0}; -} - -void IWLBuffer::endDataPtr() { - ; // empty -} - -void IWLBuffer::sendRelease() { - if (!resource || !resource->resource) - return; - resource->resource->sendRelease(); -} - -void IWLBuffer::lock() { - locks++; -} - -void IWLBuffer::unlock() { - locks--; - - ASSERT(locks >= 0); - - if (locks <= 0) - sendRelease(); -} - -bool IWLBuffer::locked() { - return locks; +void IHLBuffer::sendReleaseWithSurface(SP surf) { + if (resource && resource->good()) + resource->sendReleaseWithSurface(surf); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index 9999a4e9..ba8278f3 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -1,75 +1,29 @@ #pragma once #include "../../defines.hpp" -#include "../../helpers/signal/Signal.hpp" #include "../../render/Texture.hpp" +#include "./WLBuffer.hpp" -#include -#include +#include -enum eBufferCapability { - BUFFER_CAPABILITY_DATAPTR = (1 << 0), -}; - -enum eBufferType { - BUFFER_TYPE_DMABUF = 0, - BUFFER_TYPE_SHM, - BUFFER_TYPE_MISC, -}; - -class CWLBufferResource; - -struct SDMABUFAttrs { - bool success = false; - Vector2D size; - uint32_t format = 0; // fourcc - uint64_t modifier = 0; - - int planes = 1; - std::array offsets = {0}; - std::array strides = {0}; - std::array fds = {-1, -1, -1, -1}; -}; - -struct SSHMAttrs { - bool success = false; - int fd = 0; - uint32_t format = 0; - Vector2D size; - int stride = 0; - int64_t offset = 0; -}; - -class IWLBuffer { +class IHLBuffer : public Aquamarine::IBuffer { public: - virtual ~IWLBuffer() { + virtual ~IHLBuffer() { ; - }; + } + virtual Aquamarine::eBufferCapability caps() = 0; + virtual Aquamarine::eBufferType type() = 0; + virtual void update(const CRegion& damage) = 0; + virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good() = 0; + virtual void sendRelease(); + virtual void sendReleaseWithSurface(SP); - virtual eBufferCapability caps() = 0; - virtual eBufferType type() = 0; - virtual void update(const CRegion& damage) = 0; - virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu - virtual SDMABUFAttrs dmabuf(); - virtual SSHMAttrs shm(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - virtual void sendRelease(); - virtual void lock(); - virtual void unlock(); - virtual bool locked(); - - Vector2D size; - bool opaque = false; - - SP resource; - - SP texture; + SP texture; + bool opaque = false; + SP resource; struct { - CSignal destroy; - } events; - - private: - int locks = 0; + CHyprSignalListener backendRelease; + } hlEvents; }; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 7c3a9886..63a26c76 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -3,7 +3,7 @@ #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" -CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) { +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) { g_pHyprRenderer->makeEGLCurrent(); listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { @@ -31,12 +31,12 @@ CDMABuffer::~CDMABuffer() { closeFDs(); } -eBufferCapability CDMABuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CDMABuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CDMABuffer::type() { - return BUFFER_TYPE_DMABUF; +Aquamarine::eBufferType CDMABuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF; } void CDMABuffer::update(const CRegion& damage) { @@ -47,7 +47,7 @@ bool CDMABuffer::isSynchronous() { return false; } -SDMABUFAttrs CDMABuffer::dmabuf() { +Aquamarine::SDMABUFAttrs CDMABuffer::dmabuf() { return attrs; } diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp index d07840b7..6977df4c 100644 --- a/src/protocols/types/DMABuffer.hpp +++ b/src/protocols/types/DMABuffer.hpp @@ -2,16 +2,16 @@ #include "Buffer.hpp" -class CDMABuffer : public IWLBuffer { +class CDMABuffer : public IHLBuffer { public: - CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_); + CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_); virtual ~CDMABuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual bool isSynchronous(); virtual void update(const CRegion& damage); - virtual SDMABUFAttrs dmabuf(); + virtual Aquamarine::SDMABUFAttrs dmabuf(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); bool good(); @@ -21,7 +21,7 @@ class CDMABuffer : public IWLBuffer { bool success = false; private: - SDMABUFAttrs attrs; + Aquamarine::SDMABUFAttrs attrs; struct { CHyprSignalListener resourceDestroy; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index e53538cb..d34a867d 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -1,5 +1,10 @@ #include "WLBuffer.hpp" #include "Buffer.hpp" +#include "../core/Compositor.hpp" +#include "../DRMSyncobj.hpp" +#include "../../helpers/sync/SyncTimeline.hpp" +#include "../../Compositor.hpp" +#include CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { if (!good()) @@ -27,6 +32,16 @@ void CWLBufferResource::sendRelease() { resource->sendRelease(); } +void CWLBufferResource::sendReleaseWithSurface(SP surf) { + sendRelease(); + + if (!surf || !surf->syncobj) + return; + + if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1)) + Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed"); +} + wl_resource* CWLBufferResource::getResource() { return resource->resource(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index ac177965..59512128 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -7,7 +7,8 @@ #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -class IWLBuffer; +class IHLBuffer; +class CWLSurfaceResource; class CWLBufferResource { public: @@ -16,9 +17,10 @@ class CWLBufferResource { bool good(); void sendRelease(); + void sendReleaseWithSurface(SP); wl_resource* getResource(); - WP buffer; + WP buffer; WP self; @@ -27,5 +29,5 @@ class CWLBufferResource { SP resource; - friend class IWLBuffer; + friend class IHLBuffer; }; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e127ec2d..b2b046ce 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -9,6 +9,9 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" #include +#include +#include +#include inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); @@ -19,17 +22,203 @@ inline void loadGLProc(void* pProc, const char* name) { *(void**)pProc = proc; } +static enum LogLevel eglLogToLevel(EGLint type) { + switch (type) { + case EGL_DEBUG_MSG_CRITICAL_KHR: return CRIT; + case EGL_DEBUG_MSG_ERROR_KHR: return ERR; + case EGL_DEBUG_MSG_WARN_KHR: return WARN; + case EGL_DEBUG_MSG_INFO_KHR: return LOG; + default: return LOG; + } +} + +static const char* eglErrorToString(EGLint error) { + switch (error) { + case EGL_SUCCESS: return "EGL_SUCCESS"; + case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; + case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; + case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; + case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; + case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; + case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; + case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; + case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; + case EGL_BAD_DEVICE_EXT: return "EGL_BAD_DEVICE_EXT"; + case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; + case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; + case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; + case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; + case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; + case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; + } + return "Unknown"; +} + +static void eglLog(EGLenum error, const char* command, EGLint type, EGLLabelKHR thread, EGLLabelKHR obj, const char* msg) { + Debug::log(eglLogToLevel(type), "[EGL] Command {} errored out with {} (0x{}): {}", command, eglErrorToString(error), error, msg); +} + +static int openRenderNode(int drmFd) { + auto renderName = drmGetRenderDeviceNameFromFd(drmFd); + if (!renderName) { + // This can happen on split render/display platforms, fallback to + // primary node + renderName = drmGetPrimaryDeviceNameFromFd(drmFd); + if (!renderName) { + Debug::log(ERR, "drmGetPrimaryDeviceNameFromFd failed"); + return -1; + } + Debug::log(LOG, "DRM dev {} has no render node, falling back to primary", renderName); + + drmVersion* render_version = drmGetVersion(drmFd); + if (render_version && render_version->name) { + Debug::log(LOG, "DRM dev versionName", render_version->name); + if (strcmp(render_version->name, "evdi") == 0) { + free(renderName); + renderName = (char*)malloc(sizeof(char) * 15); + strcpy(renderName, "/dev/dri/card0"); + } + drmFreeVersion(render_version); + } + } + + Debug::log(LOG, "openRenderNode got drm device {}", renderName); + + int renderFD = open(renderName, O_RDWR | O_CLOEXEC); + if (renderFD < 0) + Debug::log(ERR, "openRenderNode failed to open drm device {}", renderName); + + free(renderName); + return renderFD; +} + +void CHyprOpenGLImpl::initEGL(bool gbm) { + std::vector attrs; + if (m_sExts.KHR_display_reference) { + attrs.push_back(EGL_TRACK_REFERENCES_KHR); + attrs.push_back(EGL_TRUE); + } + + attrs.push_back(EGL_NONE); + + m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data()); + if (m_pEglDisplay == EGL_NO_DISPLAY) + RASSERT(false, "EGL: failed to create a platform display"); + + attrs.clear(); + + EGLint major, minor; + if (eglInitialize(m_pEglDisplay, &major, &minor) == EGL_FALSE) + RASSERT(false, "EGL: failed to initialize a platform display"); + + const std::string EGLEXTENSIONS = (const char*)eglQueryString(m_pEglDisplay, EGL_EXTENSIONS); + + m_sExts.IMG_context_priority = EGLEXTENSIONS.contains("IMG_context_priority"); + m_sExts.EXT_create_context_robustness = EGLEXTENSIONS.contains("EXT_create_context_robustness"); + m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); + m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + + if (m_sExts.IMG_context_priority) { + Debug::log(LOG, "EGL: IMG_context_priority supported, requesting high"); + attrs.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + attrs.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } + + if (m_sExts.EXT_create_context_robustness) { + Debug::log(LOG, "EGL: EXT_create_context_robustness supported, requesting lose on reset"); + attrs.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT); + attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); + } + + attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); + attrs.push_back(3); + attrs.push_back(EGL_CONTEXT_MINOR_VERSION); + attrs.push_back(2); + attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG); + attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE); + + attrs.push_back(EGL_NONE); + + m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data()); + if (m_pEglContext == EGL_NO_CONTEXT) + RASSERT(false, "EGL: failed to create a context"); + + if (m_sExts.IMG_context_priority) { + EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; + eglQueryContext(m_pEglDisplay, m_pEglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority); + if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG) + Debug::log(ERR, "EGL: Failed to obtain a high priority context"); + else + Debug::log(LOG, "EGL: Got a high priority context"); + } + + eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext); +} + CHyprOpenGLImpl::CHyprOpenGLImpl() { - RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)), - "Couldn't unset current EGL!"); + const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); - const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS); - - RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); + Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS); m_iDRMFD = g_pCompositor->m_iDRMFD; + m_sExts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference"); + + loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); + loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); + loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); + loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); + loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); + loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); + loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR"); + loadGLProc(&m_sProc.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT"); + loadGLProc(&m_sProc.eglCreateSyncKHR, "eglCreateSyncKHR"); + loadGLProc(&m_sProc.eglDestroySyncKHR, "eglDestroySyncKHR"); + loadGLProc(&m_sProc.eglDupNativeFenceFDANDROID, "eglDupNativeFenceFDANDROID"); + loadGLProc(&m_sProc.eglWaitSyncKHR, "eglWaitSyncKHR"); + + RASSERT(m_sProc.eglCreateSyncKHR, "Display driver doesn't support eglCreateSyncKHR"); + RASSERT(m_sProc.eglDupNativeFenceFDANDROID, "Display driver doesn't support eglDupNativeFenceFDANDROID"); + RASSERT(m_sProc.eglWaitSyncKHR, "Display driver doesn't support eglWaitSyncKHR"); + + if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration")) + loadGLProc(&m_sProc.eglQueryDevicesEXT, "eglQueryDevicesEXT"); + + if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_query")) { + loadGLProc(&m_sProc.eglQueryDeviceStringEXT, "eglQueryDeviceStringEXT"); + loadGLProc(&m_sProc.eglQueryDisplayAttribEXT, "eglQueryDisplayAttribEXT"); + } + + if (EGLEXTENSIONS.contains("EGL_KHR_debug")) { + loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR"); + static const EGLAttrib debugAttrs[] = { + EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, EGL_NONE, + }; + m_sProc.eglDebugMessageControlKHR(::eglLog, debugAttrs); + } + + RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue."); + + // if (m_sProc.eglQueryDevicesEXT) { + // // TODO: + // } + + if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { + m_iGBMFD = openRenderNode(m_iDRMFD); + if (m_iGBMFD < 0) + RASSERT(false, "Couldn't open a gbm fd"); + + m_pGbmDevice = gbm_create_device(m_iGBMFD); + if (!m_pGbmDevice) + RASSERT(false, "Couldn't open a gbm device"); + + initEGL(true); + } else + RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver."); + + auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); + RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); + m_szExtensions = EXTENSIONS; Debug::log(LOG, "Creating the Hypr OpenGL Renderer!"); @@ -38,16 +227,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions); - loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES"); - loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR"); - loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR"); - loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT"); - loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT"); - loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES"); - - m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); - m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import"); - m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers"); + m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra"); RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required"); @@ -74,7 +254,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); - RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); + RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); m_tGlobalTimer.reset(); } @@ -86,7 +266,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo return std::nullopt; EGLint len = 0; - if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { + if (!m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, 0, nullptr, nullptr, &len)) { Debug::log(ERR, "EGL: Failed to query mods"); return std::nullopt; } @@ -100,7 +280,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo mods.resize(len); external.resize(len); - m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); + m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len); std::vector result; bool linearIsExternal = false; @@ -139,9 +319,9 @@ void CHyprOpenGLImpl::initDRMFormats() { Debug::log(WARN, "EGL: No mod support"); } else { EGLint len = 0; - m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len); + m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, 0, nullptr, &len); formats.resize(len); - m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len); + m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, len, formats.data(), &len); } if (formats.size() == 0) { @@ -149,7 +329,7 @@ void CHyprOpenGLImpl::initDRMFormats() { return; } - wlr_log(WLR_DEBUG, "Supported DMA-BUF formats:"); + Debug::log(LOG, "Supported DMA-BUF formats:"); std::vector dmaFormats; @@ -170,8 +350,8 @@ void CHyprOpenGLImpl::initDRMFormats() { mods.push_back(DRM_FORMAT_MOD_INVALID); dmaFormats.push_back(SDRMFormat{ - .format = fmt, - .mods = mods, + .drmFormat = fmt, + .modifiers = mods, }); std::vector> modifierData; @@ -209,7 +389,7 @@ void CHyprOpenGLImpl::initDRMFormats() { drmFormats = dmaFormats; } -EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { +EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attrs) { std::vector attribs; attribs.push_back(EGL_WIDTH); @@ -251,7 +431,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) { attribs.push_back(EGL_NONE); - EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); + EGLImageKHR image = m_sProc.eglCreateImageKHR(m_pEglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data()); if (image == EGL_NO_IMAGE_KHR) { Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError()); return EGL_NO_IMAGE_KHR; @@ -342,7 +522,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool } bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { - // passes requiring introspection are the ones that need to render blur. + // passes requiring introspection are the ones that need to render blur, + // or when we are rendering to a multigpu target static auto PBLUR = CConfigValue("decoration:blur:enabled"); static auto PXRAY = CConfigValue("decoration:blur:xray"); @@ -446,7 +627,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return false; } -void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) { +void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; #ifndef GLES2 @@ -472,12 +653,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRe matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); - wlr_matrix_identity(m_RenderData.monitorProjection.data()); + matrixIdentity(m_RenderData.monitorProjection.data()); if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; - wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); - wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform); - wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); + matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform)); + matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); } m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; @@ -545,10 +726,10 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); - m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); + m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); } if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) @@ -597,7 +778,7 @@ void CHyprOpenGLImpl::end() { TRACY_GPU_ZONE("RenderEnd"); - // end the render, copy the data to the WLR framebuffer + // end the render, copy the data to the main framebuffer if (m_bOffloadedFramebuffer) { m_RenderData.damage = m_RenderData.finalDamage; m_bEndFrame = true; @@ -915,11 +1096,8 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) { CBox newBox = *pBox; if (transform) { - int w, h; - wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h); - - const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); - newBox.transform(TR, w, h); + const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); + newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); } glScissor(newBox.x, newBox.y, newBox.width, newBox.height); @@ -1008,18 +1186,18 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion box = &newBox; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); #endif @@ -1027,7 +1205,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); CBox transformedBox = *box; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1072,16 +1250,17 @@ void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, i scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV, + SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); scissor((CBox*)nullptr); } void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV, - bool allowDim) { + bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -1099,12 +1278,19 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB static auto PDT = CConfigValue("debug:damage_tracking"); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); + + if (waitTimeline != nullptr) { + if (!waitForTimelinePoint(waitTimeline, waitPoint)) { + Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); + return; + } + } CShader* shader = nullptr; @@ -1151,7 +1337,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1187,7 +1373,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB } CBox transformedBox = newBox; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1262,12 +1448,12 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; @@ -1279,7 +1465,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1316,12 +1502,12 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf m_RenderData.renderModif.applyToBox(newBox); // get transform - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; @@ -1330,7 +1516,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf #ifndef GLES2 glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1i(shader->tex, 0); @@ -1374,13 +1560,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glDisable(GL_STENCIL_TEST); // get transforms for the full monitor - const auto TRANSFORM = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)); + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); float matrix[9]; CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); // get the config settings static auto PBLURSIZE = CConfigValue("decoration:blur:size"); @@ -1390,9 +1576,9 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // prep damage CRegion damage{*originalDamage}; - wlr_region_transform(damage.pixman(), damage.pixman(), wlr_output_transform_invert(m_RenderData.pMonitor->transform), m_RenderData.pMonitor->vecTransformedSize.x, - m_RenderData.pMonitor->vecTransformedSize.y); - wlr_region_expand(damage.pixman(), damage.pixman(), *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)); + damage.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + m_RenderData.pMonitor->vecTransformedSize.y); + damage.expand(*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)); // helper const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB; @@ -1419,7 +1605,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); @@ -1464,7 +1650,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a @@ -1511,13 +1697,13 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // and draw for (int i = 1; i <= *PBLURPASSES; ++i) { - wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); + tempDamage = damage.copy().scale(1.f / (1 << i)); drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down } for (int i = *PBLURPASSES - 1; i >= 0; --i) { - wlr_region_scale(tempDamage.pixman(), damage.pixman(), 1.f / (1 << i)); // when upsampling we make the region twice as big - drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up + tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big + drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up } // finalize the image @@ -1541,7 +1727,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); @@ -1679,7 +1865,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage); // render onto blurFB - m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat); + m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->blurFB.bind(); clear(CColor(0, 0, 0, 0)); @@ -1773,7 +1960,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float inverseOpaque = {0, 0, pBox->width, pBox->height}; } - wlr_region_scale(inverseOpaque.pixman(), inverseOpaque.pixman(), m_RenderData.pMonitor->scale); + inverseOpaque.scale(m_RenderData.pMonitor->scale); // vvv TODO: layered blur fbs? const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations(m_pCurrentLayer, m_pCurrentWindow.lock()) && !blockBlurOptimization; @@ -1872,11 +2059,11 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in round += round == 0 ? 0 : scaledBorderSize; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); const auto BLEND = m_bBlend; blend(true); @@ -1886,7 +2073,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); #endif @@ -1898,7 +2085,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); CBox transformedBox = *box; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); @@ -1949,14 +2136,14 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; g_pHyprRenderer->makeEGLCurrent(); pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer); @@ -2000,7 +2187,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; PHLWINDOWREF ref{pWindow}; @@ -2009,7 +2196,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { const auto PFRAMEBUFFER = &m_mWindowFramebuffers[ref]; - PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER); @@ -2049,14 +2236,14 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) { // we need to "damage" the entire monitor // so that we render the entire window - // this is temporary, doesnt mess with the actual wlr damage + // this is temporary, doesnt mess with the actual damage CRegion fakeDamage{0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y}; g_pHyprRenderer->makeEGLCurrent(); const auto PFRAMEBUFFER = &m_mLayerFramebuffers[pLayer]; - PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->drmFormat); + PFRAMEBUFFER->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, PFRAMEBUFFER); @@ -2178,11 +2365,11 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const const auto col = color; float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here + projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, + m_RenderData.monitorProjection.data()); float glMatrix[9]; - wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + matrixMultiply(glMatrix, m_RenderData.projection, matrix); glEnable(GL_BLEND); @@ -2191,7 +2378,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const #ifndef GLES2 glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix); #else - wlr_matrix_transpose(glMatrix, glMatrix); + matrixTranspose(glMatrix, glMatrix); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); #endif glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); @@ -2238,7 +2425,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated()) - m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->drmFormat); + m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->monitorMirrorFB.bind(); @@ -2270,11 +2458,11 @@ void CHyprOpenGLImpl::renderMirrored() { return; // replace monitor projection to undo the mirrored monitor's projection - wlr_matrix_identity(monitor->projMatrix.data()); - wlr_matrix_translate(monitor->projMatrix.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); - wlr_matrix_transform(monitor->projMatrix.data(), monitor->transform); - wlr_matrix_transform(monitor->projMatrix.data(), wlr_output_transform_invert(mirrored->transform)); - wlr_matrix_translate(monitor->projMatrix.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); + matrixIdentity(m_RenderData.monitorProjection.data()); + matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform)); + matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform))); + matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); // clear stuff outside of mirrored area (e.g. when changing to mirrored) clear(CColor(0, 0, 0, 0)); @@ -2282,7 +2470,7 @@ void CHyprOpenGLImpl::renderMirrored() { renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false); // reset matrix for further drawing - monitor->updateMatrix(); + m_RenderData.monitorProjection = monitor->projMatrix; } void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const CAIROSURFACE, double offsetY, const Vector2D& size) { @@ -2338,7 +2526,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { const auto PFB = &m_mMonitorBGFBs[pMonitor]; PFB->release(); - PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->drmFormat); + PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); Debug::log(LOG, "Allocated texture for BGTex"); // TODO: use relative paths to the installation @@ -2474,6 +2662,9 @@ void CHyprOpenGLImpl::clearWithTex() { void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { g_pHyprRenderer->makeEGLCurrent(); + if (!g_pHyprOpenGL) + return; + auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor); if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) { RESIT->second.mirrorFB.release(); @@ -2500,8 +2691,8 @@ void CHyprOpenGLImpl::saveMatrix() { } void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { - wlr_matrix_scale(m_RenderData.projection, scale, scale); - wlr_matrix_translate(m_RenderData.projection, translate.x, translate.y); + matrixScale(m_RenderData.projection, scale, scale); + matrixTranslate(m_RenderData.projection, translate.x, translate.y); } void CHyprOpenGLImpl::restoreMatrix() { @@ -2533,29 +2724,63 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { } uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { - GLint glf = -1, glt = -1, as = 0; - /*glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &glf); - glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &glt); - glGetIntegerv(GL_ALPHA_BITS, &as);*/ - - if (glf == 0 || glt == 0) { - glf = FormatUtils::drmFormatToGL(pMonitor->drmFormat); - glt = FormatUtils::glFormatToType(glf); - } - - if (const auto FMT = FormatUtils::getPixelFormatFromGL(glf, glt, as > 0); FMT) - return FMT->drmFormat; - - if (m_sExts.EXT_read_format_bgra) - return DRM_FORMAT_XRGB8888; - - return DRM_FORMAT_XBGR8888; + return pMonitor->output->state->state().drmFormat; } std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } +SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { + std::vector attribs; + int dupFd = -1; + if (fenceFD > 0) { + int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); + if (dupFd < 0) { + Debug::log(ERR, "createEGLSync: dup failed"); + return nullptr; + } + + attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); + attribs.push_back(dupFd); + attribs.push_back(EGL_NONE); + } + + EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); + if (sync == EGL_NO_SYNC_KHR) { + Debug::log(ERR, "eglCreateSyncKHR failed"); + if (dupFd >= 0) + close(dupFd); + return nullptr; + } + + auto eglsync = SP(new CEGLSync); + eglsync->sync = sync; + return eglsync; +} + +bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { + int fd = timeline->exportAsSyncFileFD(point); + if (fd < 0) { + Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); + return false; + } + + auto sync = g_pHyprOpenGL->createEGLSync(fd); + close(fd); + if (!sync) { + Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); + return false; + } + + if (!sync->wait()) { + Debug::log(ERR, "waitForTimelinePoint: failed to wait on an eglsync from explicit timeline"); + return false; + } + + return true; +} + void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; @@ -2616,3 +2841,35 @@ float SRenderModifData::combinedScale() { } return scale; } + +CEGLSync::~CEGLSync() { + if (sync == EGL_NO_SYNC_KHR) + return; + + if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) + Debug::log(ERR, "eglDestroySyncKHR failed"); +} + +int CEGLSync::dupFenceFD() { + if (sync == EGL_NO_SYNC_KHR) + return -1; + + int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); + return -1; + } + + return fd; +} + +bool CEGLSync::wait() { + if (sync == EGL_NO_SYNC_KHR) + return false; + + if (g_pHyprOpenGL->m_sProc.eglWaitSyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync, 0) != EGL_TRUE) { + Debug::log(ERR, "eglWaitSyncKHR failed"); + return false; + } + return true; +} diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 814b80fe..712b87f3 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -6,6 +6,8 @@ #include "../helpers/Timer.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/Format.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include #include #include #include @@ -18,10 +20,14 @@ #include "Transformer.hpp" #include "Renderbuffer.hpp" +#include +#include #include +#include #include "../debug/TracyDefines.hpp" +struct gbm_device; class CHyprRenderer; inline const float fullVerts[] = { @@ -119,6 +125,21 @@ struct SCurrentRenderData { float discardOpacity = 0.f; }; +class CEGLSync { + public: + ~CEGLSync(); + + EGLSyncKHR sync = nullptr; + + int dupFenceFD(); + bool wait(); + + private: + CEGLSync() = default; + + friend class CHyprOpenGLImpl; +}; + class CGradientValueData; class CHyprOpenGLImpl { @@ -126,14 +147,15 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr); + void beginSimple(CMonitor*, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); void end(); void renderRect(CBox*, const CColor&, int round = 0); void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, + SP waitTimeline = nullptr, uint64_t waitPoint = 0); void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); @@ -182,12 +204,19 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(CMonitor* pMonitor); std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + bool m_bReloadScreenShader = true; // at launch it can be set PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window @@ -205,12 +234,24 @@ class CHyprOpenGLImpl { PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr; PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr; PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr; + PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr; + PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr; + PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr; + PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr; + PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr; + PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr; + PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr; + PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr; + PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr; } m_sProc; struct { bool EXT_read_format_bgra = false; bool EXT_image_dma_buf_import = false; bool EXT_image_dma_buf_import_modifiers = false; + bool KHR_display_reference = false; + bool IMG_context_priority = false; + bool EXT_create_context_robustness = false; } m_sExts; private: @@ -220,7 +261,7 @@ class CHyprOpenGLImpl { std::vector drmFormats; bool m_bHasModifiers = false; - int m_iDRMFD; + int m_iDRMFD = -1; std::string m_szExtensions; bool m_bFakeFrame = false; @@ -238,6 +279,7 @@ class CHyprOpenGLImpl { void createBGTextureForMonitor(CMonitor*); void initShaders(); void initDRMFormats(); + void initEGL(bool gbm); // std::optional> getModsForFormat(EGLint format); @@ -246,7 +288,7 @@ class CHyprOpenGLImpl { CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); void renderTextureInternalWithDamage(SP, CBox* pBox, float a, CRegion* damage, int round = 0, bool discardOpaque = false, bool noAA = false, - bool allowCustomUV = false, bool allowDim = false); + bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 3f591d13..58ed88d6 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -2,6 +2,8 @@ #include "OpenGL.hpp" #include "../Compositor.hpp" #include "../protocols/types/Buffer.hpp" +#include +#include #include @@ -15,58 +17,17 @@ CRenderbuffer::~CRenderbuffer() { m_sFramebuffer.release(); glDeleteRenderbuffers(1, &m_iRBO); - g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage); + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_iImage); } -CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) { - - // EVIL, but we can't include a hidden header because nixos is fucking special - static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*); - static bool symbolFound = false; - if (!symbolFound) { - PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf")); - - symbolFound = true; - - RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!"); - - Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF); - } - // end evil hack - - struct wlr_dmabuf_attributes dmabuf = {0}; - if (!wlr_buffer_get_dmabuf(buffer, &dmabuf)) - throw std::runtime_error("wlr_buffer_get_dmabuf failed"); - - bool externalOnly; - m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly); - if (m_iImage == EGL_NO_IMAGE_KHR) - throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed"); - - glGenRenderbuffers(1, &m_iRBO); - glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); - g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage); - glBindRenderbuffer(GL_RENDERBUFFER, 0); - - glGenFramebuffers(1, &m_sFramebuffer.m_iFb); - m_sFramebuffer.m_vSize = {buffer->width, buffer->height}; - m_sFramebuffer.bind(); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer"); -} - -CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { +CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) { auto dma = buffer->dmabuf(); m_iImage = g_pHyprOpenGL->createEGLImage(dma); - if (m_iImage == EGL_NO_IMAGE_KHR) - throw std::runtime_error("createEGLImage failed"); + if (m_iImage == EGL_NO_IMAGE_KHR) { + Debug::log(ERR, "rb: createEGLImage failed"); + return; + } glGenRenderbuffers(1, &m_iRBO); glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO); @@ -78,10 +39,20 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : m_pHLBuffe m_sFramebuffer.bind(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw std::runtime_error("rbo: glCheckFramebufferStatus failed"); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Debug::log(ERR, "rbo: glCheckFramebufferStatus failed"); + return; + } glBindFramebuffer(GL_FRAMEBUFFER, 0); + + listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); }); + + m_bGood = true; +} + +bool CRenderbuffer::good() { + return m_bGood; } void CRenderbuffer::bind() { diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index ed7050c5..e6bfa909 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -1,30 +1,35 @@ #pragma once +#include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/WLListener.hpp" #include "Framebuffer.hpp" +#include class CMonitor; -class IWLBuffer; class CRenderbuffer { public: - CRenderbuffer(wlr_buffer* buffer, uint32_t format); - CRenderbuffer(SP buffer, uint32_t format); + CRenderbuffer(SP buffer, uint32_t format); ~CRenderbuffer(); - void bind(); - void bindFB(); - void unbind(); - CFramebuffer* getFB(); - uint32_t getFormat(); + bool good(); + void bind(); + void bindFB(); + void unbind(); + CFramebuffer* getFB(); + uint32_t getFormat(); - wlr_buffer* m_pWlrBuffer = nullptr; - WP m_pHLBuffer = {}; - - DYNLISTENER(destroyBuffer); + WP m_pHLBuffer; private: - EGLImageKHR m_iImage = 0; + void* m_iImage = nullptr; GLuint m_iRBO = 0; CFramebuffer m_sFramebuffer; uint32_t m_uDrmFormat = 0; + bool m_bGood = false; + + struct { + CHyprSignalListener destroyBuffer; + } listeners; }; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a7f3c941..82dfc887 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2,6 +2,8 @@ #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" #include +#include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -13,6 +15,10 @@ #include "../protocols/PresentationTime.hpp" #include "../protocols/core/DataDevice.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/DRMSyncobj.hpp" +#include "../protocols/LinuxDMABUF.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "debug/Log.hpp" extern "C" { #include @@ -25,11 +31,11 @@ static int cursorTicker(void* data) { } CHyprRenderer::CHyprRenderer() { - if (g_pCompositor->m_sWLRSession) { - wlr_device* dev; - wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) { - const auto DRMV = drmGetVersion(dev->fd); - + if (g_pCompositor->m_pAqBackend->hasSession()) { + for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { + const auto DRMV = drmGetVersion(dev->fd); + if (!DRMV) + continue; std::string name = std::string{DRMV->name, DRMV->name_len}; std::transform(name.begin(), name.end(), name.begin(), tolower); @@ -42,7 +48,7 @@ CHyprRenderer::CHyprRenderer() { drmFreeVersion(DRMV); } } else { - Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks"); + Debug::log(LOG, "Aq backend has no session, omitting full DRM node checks"); const auto DRMV = drmGetVersion(g_pCompositor->m_iDRMFD); @@ -108,6 +114,14 @@ static void renderSurface(SP surface, int x, int y, void* da if (!TEXTURE->m_iTexID) return; + // explicit sync: wait for the timeline, if any + if (surface->syncobj && surface->syncobj->acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); + return; + } + } + TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; @@ -167,12 +181,10 @@ static void renderSurface(SP surface, int x, int y, void* da if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->discarded(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for invisible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } + return; // invisible } @@ -225,11 +237,8 @@ static void renderSurface(SP surface, int x, int y, void* da } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - surface->frame(RDATA->when); - auto FEEDBACK = makeShared(surface); - FEEDBACK->attachMonitor(RDATA->pMonitor); - FEEDBACK->presented(); - PROTO::presentation->queueData(FEEDBACK); + Debug::log(TRACE, "presentFeedback for visible surface"); + surface->presentFeedback(RDATA->when, RDATA->pMonitor); } g_pHyprOpenGL->blend(true); @@ -1079,53 +1088,6 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPmirrors.empty() || pMonitor->isMirror() || m_bDirectScanoutBlocked) - // return false; // do not DS if this monitor is being mirrored. Will break the functionality. - - // if (!wlr_output_is_direct_scanout_allowed(pMonitor->output)) - // return false; - - // const auto PCANDIDATE = pMonitor->solitaryClient.lock(); - - // if (!PCANDIDATE) - // return false; - - // const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - - // if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform) - // return false; - - // // finally, we should be GTG. - // wlr_output_state_set_buffer(pMonitor->state.wlr(), &PSURFACE->buffer->base); - - // if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) - // return false; - - // timespec now; - // clock_gettime(CLOCK_MONOTONIC, &now); - // PSURFACE->frame(&now); - // auto FEEDBACK = makeShared(PSURFACE); - // FEEDBACK->attachMonitor(pMonitor); - // FEEDBACK->presented(); - // FEEDBACK->setPresentationType(true); - // PROTO::presentation->queueData(FEEDBACK); - - // if (pMonitor->state.commit()) { - // if (m_pLastScanout.expired()) { - // m_pLastScanout = PCANDIDATE; - // Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); - // } - // } else { - // m_pLastScanout.reset(); - // return false; - // } - - // return true; -} - void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now(); static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now(); @@ -1177,7 +1139,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->framesToSkip -= 1; if (!pMonitor->noFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); else Debug::log(LOG, "NoFrameSchedule hit for {}.", pMonitor->szName); @@ -1205,6 +1167,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID); } + if (!pMonitor->output->needsFrame && pMonitor->forceFullFrames == 0) + return; + // tearing and DS first bool shouldTear = false; if (pMonitor->tearingState.nextRenderTorn) { @@ -1230,11 +1195,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (!*PNODIRECTSCANOUT && !shouldTear) { - if (attemptDirectScanout(pMonitor)) { + if (pMonitor->attemptDirectScanout()) { return; - } else if (!m_pLastScanout.expired()) { + } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); - m_pLastScanout.reset(); + pMonitor->lastScanout.reset(); } } @@ -1249,7 +1214,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { clock_gettime(CLOCK_MONOTONIC, &now); // check the damage - bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged(); + bool hasChanged = pMonitor->output->needsFrame || pMonitor->damage.hasChanged(); if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) return; @@ -1295,7 +1260,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); - pMonitor->state.clear(); return; } @@ -1316,11 +1280,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. // now, prep the damage, get the extended damage region - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring + damage.expand(BLURRADIUS); // expand for proper blurring finalDamage = damage; - wlr_region_expand(damage.pixman(), damage.pixman(), BLURRADIUS); // expand for proper blurring 2 + damage.expand(BLURRADIUS); // expand for proper blurring } else finalDamage = damage; } @@ -1396,10 +1360,10 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { - CRegion frameDamage{}; + CRegion frameDamage{finalDamage}; - const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform); - wlr_region_transform(frameDamage.pixman(), finalDamage.pixman(), TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); + const auto TRANSFORM = invertTransform(pMonitor->transform); + frameDamage.transform(wlTransformToHyprutils(TRANSFORM), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR) frameDamage.add(0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y); @@ -1414,18 +1378,16 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { EMIT_HOOK_EVENT("render", RENDER_POST); - pMonitor->state.wlr()->tearing_page_flip = shouldTear; + pMonitor->output->state->setPresentationMode(shouldTear ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : + Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!pMonitor->state.commit()) { - pMonitor->damage.damageEntire(); - return; - } + commitPendingAndDoExplicitSync(pMonitor); if (shouldTear) pMonitor->tearingState.busy = true; if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame) - g_pCompositor->scheduleFrameForMonitor(pMonitor); + g_pCompositor->scheduleFrameForMonitor(pMonitor, Aquamarine::IOutput::AQ_SCHEDULE_RENDER_MONITOR); pMonitor->pendingFrame = false; @@ -1442,6 +1404,63 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } +bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + // apply timelines for explicit sync + pMonitor->output->state->resetExplicitFences(); + + bool anyExplicit = !explicitPresented.empty(); + if (anyExplicit) { + Debug::log(TRACE, "Explicit sync presented begin"); + auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); + if (inFence < 0) + Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); + + pMonitor->output->state->setExplicitInFence(inFence); + + for (auto& e : explicitPresented) { + Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); + if (!e->syncobj || !e->syncobj->releaseTimeline) + continue; + e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); + } + + explicitPresented.clear(); + auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); + if (outFence < 0) + Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); + + pMonitor->output->state->setExplicitOutFence(outFence); + Debug::log(TRACE, "Explicit sync presented end"); + } + + pMonitor->lastWaitPoint = 0; + + bool ok = pMonitor->state.commit(); + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } + + if (!*PENABLEEXPLICIT) + return ok; + + if (pMonitor->output->state->state().explicitInFence >= 0) + close(pMonitor->output->state->state().explicitInFence); + + if (pMonitor->output->state->state().explicitOutFence >= 0) { + if (ok) + pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + close(pMonitor->output->state->state().explicitOutFence); + } + + return ok; +} + void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { Vector2D translate = {geometry.x, geometry.y}; float scale = (float)geometry.width / pMonitor->vecPixelSize.x; @@ -1480,33 +1499,11 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE } } -void CHyprRenderer::setWindowScanoutMode(PHLWINDOW pWindow) { - // FIXME: fix when moved to new impl - // if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked()) - // return; +void CHyprRenderer::setSurfaceScanoutMode(SP surface, SP monitor) { + if (!PROTO::linuxDma) + return; - // if (!pWindow->m_bIsFullscreen) { - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), nullptr); - // Debug::log(LOG, "Scanout mode OFF set for {}", pWindow); - // return; - // } - - // const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - - // const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = { - // .main_renderer = g_pCompositor->m_sWLRRenderer, - // .scanout_primary_output = PMONITOR->output, - // }; - - // wlr_linux_dmabuf_feedback_v1 feedback = {0}; - - // if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, &INIT_OPTIONS)) - // return; - - // wlr_linux_dmabuf_v1_set_surface_feedback(g_pCompositor->m_sWLRLinuxDMABuf, pWindow->m_pWLSurface->resource(), &feedback); - // wlr_linux_dmabuf_feedback_v1_finish(&feedback); - - // Debug::log(LOG, "Scanout mode ON set for {}", pWindow); + PROTO::linuxDma->updateScanoutTranche(surface, monitor); } // taken from Sway. @@ -1572,7 +1569,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorvecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto& ls : layerSurfaces) { - if (ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) + if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) continue; const auto PLAYER = ls->layerSurface; @@ -1708,7 +1705,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou damageBox.scale(scale); // schedule frame events - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y))); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->getMonitorFromVector(Vector2D(x, y)), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); if (damageBox.empty()) return; @@ -1820,13 +1817,13 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion monbox.x = (monitor->vecTransformedSize.x - monbox.w) / 2; monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; - wlr_region_scale(transformed.pixman(), transformed.pixman(), scale); + transformed.scale(scale); transformed.transform(wlTransformToHyprutils(mirrored->transform), mirrored->vecPixelSize.x * scale, mirrored->vecPixelSize.y * scale); transformed.translate(Vector2D(monbox.x, monbox.y)); mirror->addDamage(&transformed); - g_pCompositor->scheduleFrameForMonitor(mirror); + g_pCompositor->scheduleFrameForMonitor(mirror, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } } @@ -1869,7 +1866,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // don't touch VR headsets - if (pMonitor->output->non_desktop) + if (pMonitor->output->nonDesktop) return true; if (!pMonitor->m_bEnabled) { @@ -1900,7 +1897,10 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // Needed in case we are switching from a custom modeline to a standard mode pMonitor->customDrmMode = {}; pMonitor->currentMode = nullptr; - bool autoScale = false; + + pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + + bool autoScale = false; if (RULE->scale > 0.1) { pMonitor->scale = RULE->scale; @@ -1910,38 +1910,35 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->scale = DEFAULTSCALE; } - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - pMonitor->setScale = pMonitor->scale; - - wlr_output_state_set_transform(pMonitor->state.wlr(), RULE->transform); + pMonitor->setScale = pMonitor->scale; pMonitor->transform = RULE->transform; - const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : RULE->refreshRate * 1000; + const auto WLRREFRESHRATE = pMonitor->output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0; // loop over modes and choose an appropriate one. if (RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) { - if (!wl_list_empty(&pMonitor->output->modes) && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { - wlr_output_mode* mode; - bool found = false; + if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { + bool found = false; - wl_list_for_each(mode, &pMonitor->output->modes, link) { + for (auto& mode : pMonitor->output->modes) { // if delta of refresh rate, w and h chosen and mode is < 1 we accept it - if (DELTALESSTHAN(mode->width, RULE->resolution.x, 1) && DELTALESSTHAN(mode->height, RULE->resolution.y, 1) && - DELTALESSTHAN(mode->refresh / 1000.f, RULE->refreshRate, 1)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) && + DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) { + pMonitor->output->state->setMode(mode); - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); found = true; - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -1949,14 +1946,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!found) { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (!pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, @@ -1965,13 +1962,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); @@ -1982,30 +1979,30 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR bool fail = false; if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) { - if (!wlr_output_is_drm(pMonitor->output)) { + if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) { Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); fail = true; } else { - auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); - if (mode) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - pMonitor->customDrmMode = RULE->drmMode; - } else { - Debug::log(ERR, "wlr_drm_connector_add_mode failed"); - fail = true; - } + // FIXME: + // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); + // if (mode) { + // wlr_output_state_set_mode(pMonitor->state.wlr(), mode); + // pMonitor->customDrmMode = RULE->drmMode; + // } else { + // Debug::log(ERR, "wlr_drm_connector_add_mode failed"); + // fail = true; + // } } - } else { - wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE); - } + } else + pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); pMonitor->vecSize = RULE->resolution; pMonitor->refreshRate = RULE->refreshRate; - if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { + if (fail || !pMonitor->state.test()) { Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->output->name, RULE->resolution, @@ -2014,48 +2011,47 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->customDrmMode = {}; - } else { + } else Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate); - } } } else if (RULE->resolution != Vector2D()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - float currentWidth = 0; - float currentHeight = 0; - float currentRefresh = 0; - bool success = false; + if (!pMonitor->output->modes.empty()) { + float currentWidth = 0; + float currentHeight = 0; + float currentRefresh = 0; + bool success = false; //(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution if (RULE->resolution == Vector2D(-1, -1)) { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + mode->refreshRate > (currentRefresh + 3000.f)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } } } else { - wl_list_for_each(mode, &pMonitor->output->modes, link) { - if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || - (mode->width > currentWidth && mode->height > currentHeight)) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - currentWidth = mode->width; - currentHeight = mode->height; - currentRefresh = mode->refresh; + for (auto& mode : pMonitor->output->modes) { + if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || + (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) { + pMonitor->output->state->setMode(mode); + if (pMonitor->state.test()) { + currentWidth = mode->pixelSize.x; + currentHeight = mode->pixelSize.y; + currentRefresh = mode->refreshRate; success = true; } } @@ -2063,10 +2059,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } if (!success) { - Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh / 1000.f); + if (pMonitor->output->state->state().mode) + Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, + (float)RULE->refreshRate, pMonitor->output->state->state().mode->pixelSize.x, pMonitor->output->state->state().mode->pixelSize.y, + pMonitor->output->state->state().mode->refreshRate / 1000.f); - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, (float)RULE->refreshRate); @@ -2074,13 +2072,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + (float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; pMonitor->currentMode = PREFERREDMODE; } else { @@ -2091,27 +2089,26 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } } else { - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + const auto PREFERREDMODE = pMonitor->output->preferredMode(); if (!PREFERREDMODE) { Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; + if (!pMonitor->output->modes.empty()) { + for (auto& mode : pMonitor->output->modes) { + pMonitor->output->state->setMode(mode); - wl_list_for_each(mode, &pMonitor->output->modes, link) { - wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f); + if (!pMonitor->state.test()) { + Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y, + mode->refreshRate / 1000.f); continue; } Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution, - (float)RULE->refreshRate, mode->width, mode->height, mode->refresh); + (float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate); - pMonitor->refreshRate = mode->refresh / 1000.f; - pMonitor->vecSize = Vector2D(mode->width, mode->height); + pMonitor->refreshRate = mode->refreshRate / 1000.f; + pMonitor->vecSize = mode->pixelSize; pMonitor->currentMode = mode; break; @@ -2119,21 +2116,49 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } else { // Preferred is valid - wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE); + pMonitor->output->state->setMode(PREFERREDMODE); - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = PREFERREDMODE->pixelSize; + pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f; pMonitor->currentMode = PREFERREDMODE; Debug::log(LOG, "Setting preferred mode for {}", pMonitor->output->name); } } - pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR() - || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync + pMonitor->vrrActive = pMonitor->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR() + || pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync pMonitor->vecPixelSize = pMonitor->vecSize; + // clang-format off + static const std::array>, 2> formats{ + std::vector>{ /* 10-bit */ + {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + }, + std::vector>{ /* 8-bit */ + {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} + } + }; + // clang-format on + + bool set10bit = false; + + for (auto& fmt : formats[(int)!RULE->enable10bit]) { + pMonitor->output->state->setFormat(fmt.second); + + if (!pMonitor->state.test()) { + Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); + } else { + Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); + if (RULE->enable10bit && fmt.first.contains("101010")) + set10bit = true; + break; + } + } + + pMonitor->enabled10bit = set10bit; + Vector2D logicalSize = pMonitor->vecPixelSize / pMonitor->scale; if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { // invalid scale, will produce fractional pixels. @@ -2145,10 +2170,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR double scaleZero = searchScale / 120.0; Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero; - if (logicalZero == logicalZero.round()) { + if (logicalZero == logicalZero.round()) pMonitor->scale = scaleZero; - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale); - } else { + else { for (size_t i = 1; i < 90; ++i) { double scaleUp = (searchScale + i) / 120.0; double scaleDown = (searchScale - i) / 120.0; @@ -2185,57 +2209,21 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } else pMonitor->scale = searchScale; } - - // for wlroots, that likes flooring, we have to do this. - double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale); - logicalX += 0.1; - - wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX); } } - // clang-format off - static const std::array>, 2> formats{ - std::vector>{ /* 10-bit */ - {"DRM_FORMAT_XRGB2101010", DRM_FORMAT_XRGB2101010}, {"DRM_FORMAT_XBGR2101010", DRM_FORMAT_XBGR2101010}, {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - }, - std::vector>{ /* 8-bit */ - {"DRM_FORMAT_XRGB8888", DRM_FORMAT_XRGB8888}, {"DRM_FORMAT_XBGR8888", DRM_FORMAT_XBGR8888}, {"DRM_FORMAT_INVALID", DRM_FORMAT_INVALID} - } - }; - // clang-format on - - bool set10bit = false; - pMonitor->drmFormat = DRM_FORMAT_INVALID; - - for (auto& fmt : formats[(int)!RULE->enable10bit]) { - wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second); - - if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) { - Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); - } else { - Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first); - if (RULE->enable10bit && fmt.first.contains("101010")) - set10bit = true; - - pMonitor->drmFormat = fmt.second; - break; - } - } - - pMonitor->enabled10bit = set10bit; + pMonitor->output->scheduleFrame(); if (!pMonitor->state.commit()) Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name); - int x, y; - wlr_output_transformed_resolution(pMonitor->output, &x, &y); - pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).round(); - pMonitor->vecTransformedSize = Vector2D(x, y); + Vector2D xfmd = pMonitor->transform % 2 == 1 ? Vector2D{pMonitor->vecPixelSize.y, pMonitor->vecPixelSize.x} : pMonitor->vecPixelSize; + pMonitor->vecSize = (xfmd / pMonitor->scale).round(); + pMonitor->vecTransformedSize = xfmd; if (pMonitor->createdByUser) { CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; - transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + transformedBox.transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height); } @@ -2245,7 +2233,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (WAS10B != pMonitor->enabled10bit || OLDRES != pMonitor->vecPixelSize) g_pHyprOpenGL->destroyMonitorResources(pMonitor); - // updato wlroots g_pCompositor->arrangeMonitors(); pMonitor->damage.setSize(pMonitor->vecTransformedSize); @@ -2260,9 +2247,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // updato us arrangeLayersForMonitor(pMonitor->ID); - // frame skip - pMonitor->framesToSkip = 1; - // reload to fix mirrors g_pConfigManager->m_bWantsMonitorReload = true; @@ -2329,7 +2313,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Hiding the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2341,7 +2325,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Showing the cursor (hl-mandated)"); for (auto& m : g_pCompositor->m_vMonitors) { - if (m->output->software_cursor_locks == 0) + if (!g_pPointerManager->softwareLockedFor(m)) continue; g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? @@ -2570,37 +2554,37 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { pMonitor->solitaryClient = PCANDIDATE; } -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) { - auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; }); - - if (it != m_vRenderbuffers.end()) - return it->get(); - - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); -} - -CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { +SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; }); if (it != m_vRenderbuffers.end()) - return it->get(); + return *it; - return m_vRenderbuffers.emplace_back(std::make_unique(buffer, fmt)).get(); + auto buf = makeShared(buffer, fmt); + + if (!buf->good()) + return nullptr; + + m_vRenderbuffers.emplace_back(buf); + return buf; } void CHyprRenderer::makeEGLCurrent() { - if (!g_pCompositor) + if (!g_pCompositor || !g_pHyprOpenGL) return; - if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL)) - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)); + if (eglGetCurrentContext() != g_pHyprOpenGL->m_pEglContext) + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_pHyprOpenGL->m_pEglContext); } void CHyprRenderer::unsetEGL() { - eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!g_pHyprOpenGL) + return; + + eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2618,35 +2602,33 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return true; } - int bufferAge = 0; + /* This is a constant expression, as we always use double-buffering in our swapchain + TODO: Rewrite the CDamageRing to take advantage of that maybe? It's made to support longer swapchains atm because we used to do wlroots */ + static constexpr const int HL_BUFFER_AGE = 2; if (!buffer) { - if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) { - Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName); - return false; - } - - m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge); - if (!m_pCurrentWlrBuffer) { + m_pCurrentBuffer = pMonitor->output->swapchain->next(nullptr); + if (!m_pCurrentBuffer) { Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName); return false; } } else - m_pCurrentHLBuffer = buffer; + m_pCurrentBuffer = buffer; try { - if (m_pCurrentWlrBuffer) - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat); - else - m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat); + m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentBuffer, pMonitor->output->state->state().drmFormat); } catch (std::exception& e) { Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName); - wlr_buffer_unlock(m_pCurrentWlrBuffer); + return false; + } + + if (!m_pCurrentRenderbuffer) { + Debug::log(ERR, "failed to start a render pass for output {}, no RBO could be obtained", pMonitor->szName); return false; } if (mode == RENDER_MODE_NORMAL) { - damage = pMonitor->damage.getBufferDamage(bufferAge); + damage = pMonitor->damage.getBufferDamage(HL_BUFFER_AGE); pMonitor->damage.rotate(); } @@ -2662,6 +2644,9 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); + static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + + PMONITOR->commitSeq++; if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); @@ -2674,29 +2659,57 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_FULL_FAKE) return; - if (isNvidia() && *PNVIDIAANTIFLICKER) - glFinish(); - else - glFlush(); - if (m_eRenderMode == RENDER_MODE_NORMAL) { - wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer); - unsetEGL(); // flush the context - } + PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - wlr_buffer_unlock(m_pCurrentWlrBuffer); + if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto sync = g_pHyprOpenGL->createEGLSync(-1); + if (!sync) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); + return; + } + + auto dupedfd = sync->dupFenceFD(); + sync.reset(); + if (dupedfd < 0) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); + return; + } + + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); + close(dupedfd); + if (!ok) { + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); + return; + } + } else { + if (isNvidia() && *PNVIDIAANTIFLICKER) + glFinish(); + else + glFlush(); + } + } m_pCurrentRenderbuffer->unbind(); m_pCurrentRenderbuffer = nullptr; - m_pCurrentWlrBuffer = nullptr; + m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { std::erase_if(m_vRenderbuffers, [&](const auto& rbo) { return rbo.get() == rb; }); } -CRenderbuffer* CHyprRenderer::getCurrentRBO() { +SP CHyprRenderer::getCurrentRBO() { return m_pCurrentRenderbuffer; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 8f404c88..72efe8c4 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -12,7 +12,7 @@ struct SMonitorRule; class CWorkspace; class CWindow; class CInputPopup; -class IWLBuffer; +class IHLBuffer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -69,35 +69,35 @@ class CHyprRenderer { void setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); - CRenderbuffer* getCurrentRBO(); + SP getCurrentRBO(); bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); - void endRender(); + bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; - PHLWINDOWREF m_pLastScanout; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; + CMonitor* m_pMostHzMonitor = nullptr; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); - bool attemptDirectScanout(CMonitor*); - void setWindowScanoutMode(PHLWINDOW); - void initiateManualCrash(); + void setSurfaceScanoutMode(SP surface, SP monitor); // nullptr monitor resets + void initiateManualCrash(); - bool m_bCrashingInProgress = false; - float m_fCrashingDistort = 0.5f; - wl_event_source* m_pCrashingLoop = nullptr; - wl_event_source* m_pCursorTicker = nullptr; + bool m_bCrashingInProgress = false; + float m_fCrashingDistort = 0.5f; + wl_event_source* m_pCrashingLoop = nullptr; + wl_event_source* m_pCursorTicker = nullptr; - CTimer m_tRenderTimer; + CTimer m_tRenderTimer; + + std::vector> explicitPresented; struct { int hotspotX; @@ -107,26 +107,27 @@ class CHyprRenderer { } m_sLastCursorData; private: - void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); - void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) - void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) - void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); - void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false); - void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); - void renderDragIcon(CMonitor*, timespec*); - void renderIMEPopup(CInputPopup*, CMonitor*, timespec*); - void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); - void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything - void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); + void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); + void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) + void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) + void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); + void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false); + void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); + void renderDragIcon(CMonitor*, timespec*); + void renderIMEPopup(CInputPopup*, CMonitor*, timespec*); + void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); + void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything + void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); - bool m_bCursorHidden = false; - bool m_bCursorHasSurface = false; - CRenderbuffer* m_pCurrentRenderbuffer = nullptr; - wlr_buffer* m_pCurrentWlrBuffer = nullptr; - WP m_pCurrentHLBuffer = {}; - eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; + bool commitPendingAndDoExplicitSync(CMonitor* pMonitor); - bool m_bNvidia = false; + bool m_bCursorHidden = false; + bool m_bCursorHasSurface = false; + SP m_pCurrentRenderbuffer = nullptr; + SP m_pCurrentBuffer; + eRenderMode m_eRenderMode = RENDER_MODE_NORMAL; + + bool m_bNvidia = false; struct { bool hiddenOnTouch = false; @@ -134,9 +135,8 @@ class CHyprRenderer { bool hiddenOnKeyboard = false; } m_sCursorHiddenConditions; - CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt); - CRenderbuffer* getOrCreateRenderbuffer(SP buffer, uint32_t fmt); - std::vector> m_vRenderbuffers; + SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); + std::vector> m_vRenderbuffers; friend class CHyprOpenGLImpl; friend class CToplevelExportProtocolManager; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 46c501a0..0f5b4c4c 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -9,7 +9,7 @@ CTexture::CTexture() { } CTexture::~CTexture() { - if (m_bNonOwning || !g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) + if (!g_pCompositor || g_pCompositor->m_bIsShuttingDown || !g_pHyprRenderer) return; g_pHyprRenderer->makeEGLCurrent(); @@ -17,6 +17,45 @@ CTexture::~CTexture() { } CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { + createFromShm(drmFormat, pixels, stride, size_); +} + +CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) { + createFromDma(attrs, image); +} + +CTexture::CTexture(const SP buffer) { + if (!buffer) + return; + + auto attrs = buffer->dmabuf(); + + if (!attrs.success) { + // attempt shm + auto shm = buffer->shm(); + + if (!shm.success) { + Debug::log(ERR, "Cannot create a texture: buffer has no dmabuf or shm"); + return; + } + + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); + + createFromShm(fmt, pixelData, bufLen, shm.size); + return; + } + + auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf()); + + if (!image) { + Debug::log(ERR, "Cannot create a texture: failed to create an EGLImage"); + return; + } + + createFromDma(attrs, image); +} + +void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { g_pHyprRenderer->makeEGLCurrent(); const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat); @@ -41,24 +80,7 @@ CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const V GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); } -CTexture::CTexture(wlr_texture* tex) { - RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!"); - wlr_gles2_texture_attribs attrs; - wlr_gles2_texture_get_attribs(tex, &attrs); - - m_iTarget = attrs.target; - m_iTexID = attrs.tex; - m_bNonOwning = true; - - if (m_iTarget == GL_TEXTURE_2D) - m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX; - else - m_iType = TEXTURE_EXTERNAL; - - m_vSize = Vector2D((int)tex->width, (int)tex->height); -} - -CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) { +void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) { if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) { Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES"); return; @@ -119,7 +141,7 @@ void CTexture::destroyTexture() { } if (m_pEglImage) - g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage); + g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_pEglImage); m_pEglImage = nullptr; } diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index c80e943d..0da95300 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -1,9 +1,9 @@ #pragma once #include "../defines.hpp" +#include -class IWLBuffer; -struct SDMABUFAttrs; +class IHLBuffer; HYPRUTILS_FORWARD(Math, CRegion); enum TEXTURETYPE { @@ -23,10 +23,10 @@ class CTexture { CTexture(const CTexture&) = delete; CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); - CTexture(wlr_texture*); + CTexture(const SP buffer); // this ctor takes ownership of the eglImage. - CTexture(const SDMABUFAttrs&, void* image); + CTexture(const Aquamarine::SDMABUFAttrs&, void* image); ~CTexture(); void destroyTexture(); @@ -37,6 +37,9 @@ class CTexture { GLenum m_iTarget = GL_TEXTURE_2D; GLuint m_iTexID = 0; Vector2D m_vSize; - void* m_pEglImage = nullptr; - bool m_bNonOwning = false; // wlr + void* m_pEglImage = nullptr; + + private: + void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); + void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); }; \ No newline at end of file diff --git a/src/signal-safe.hpp b/src/signal-safe.hpp index 70320ad1..3a38f043 100644 --- a/src/signal-safe.hpp +++ b/src/signal-safe.hpp @@ -1,6 +1,7 @@ #pragma once #include "defines.hpp" +#include template class MaxLengthCString { diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index e2dab412..3f4e7b43 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -18,12 +18,13 @@ #include #include #include +#include // TODO: cleanup static bool set_cloexec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD); if (flags == -1) { - wlr_log_errno(WLR_ERROR, "fcntl failed"); + Debug::log(ERR, "fcntl failed"); return false; } if (cloexec) { @@ -32,7 +33,7 @@ static bool set_cloexec(int fd, bool cloexec) { flags = flags & ~FD_CLOEXEC; } if (fcntl(fd, F_SETFD, flags) == -1) { - wlr_log_errno(WLR_ERROR, "fcntl failed"); + Debug::log(ERR, "fcntl failed"); return false; } return true; @@ -44,7 +45,7 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) { fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - wlr_log_errno(WLR_ERROR, "Failed to create socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); return -1; } if (!set_cloexec(fd, true)) { @@ -57,12 +58,12 @@ static int openSocket(struct sockaddr_un* addr, size_t path_size) { } if (bind(fd, (struct sockaddr*)addr, size) < 0) { rc = errno; - wlr_log_errno(WLR_ERROR, "Failed to bind socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); goto cleanup; } if (listen(fd, 1) < 0) { rc = errno; - wlr_log_errno(WLR_ERROR, "Failed to listen to socket %c%s", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); goto cleanup; } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b34d0cfe..b55df7fc 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -299,8 +299,8 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { auto id = e->data.data32[0]; auto resource = wl_client_get_object(g_pXWayland->pServer->xwaylandClient, id); if (resource) { - auto wlrSurface = CWLSurfaceResource::fromResource(resource); - associate(XSURF, wlrSurface); + auto surf = CWLSurfaceResource::fromResource(resource); + associate(XSURF, surf); } } else if (e->type == HYPRATOMS["WL_SURFACE_SERIAL"]) { if (XSURF->wlSerial) { @@ -755,7 +755,7 @@ void CXWM::getVisual() { } if (visualtype == NULL) { - wlr_log(WLR_DEBUG, "No 32 bit visualtype\n"); + Debug::log(LOG, "xwm: No 32-bit visualtype"); return; } @@ -768,7 +768,7 @@ void CXWM::getRenderFormat() { xcb_render_query_pict_formats_cookie_t cookie = xcb_render_query_pict_formats(connection); xcb_render_query_pict_formats_reply_t* reply = xcb_render_query_pict_formats_reply(connection, cookie, NULL); if (!reply) { - wlr_log(WLR_ERROR, "Did not get any reply from xcb_render_query_pict_formats"); + Debug::log(LOG, "xwm: No xcb_render_query_pict_formats_reply_t reply"); return; } xcb_render_pictforminfo_iterator_t iter = xcb_render_query_pict_formats_formats_iterator(reply); @@ -783,7 +783,7 @@ void CXWM::getRenderFormat() { } if (format == NULL) { - wlr_log(WLR_DEBUG, "No 32 bit render format"); + Debug::log(LOG, "xwm: No 32-bit render format"); free(reply); return; } diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland deleted file mode 160000 index 422207db..00000000 --- a/subprojects/wlroots-hyprland +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 422207dbcf0949e28042403edab539159282885e From cf373d315e9fb060576ed407bd5ee2dfb8a6d2e2 Mon Sep 17 00:00:00 2001 From: khachbe Date: Sun, 21 Jul 2024 13:59:09 +0200 Subject: [PATCH 0330/2393] touch: add touch swipe invert config (#6940) --- src/config/ConfigManager.cpp | 1 + src/managers/input/Touch.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a5f18693..6928a802 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -519,6 +519,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("gestures:workspace_swipe_forever", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_use_r", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); + m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index a1f949c2..736a2ae5 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -103,7 +103,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { return; const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); + static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_touch_invert"); static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); // Handle the workspace swipe if there is one From 043b859ea2ec8173d8a0f1f90012fcca82275d22 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 16:42:43 +0200 Subject: [PATCH 0331/2393] hyprpm: init submodules after resets ref #6948 --- hyprpm/src/core/PluginManager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 7d7cc079..036609f3 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -172,6 +172,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; return false; } + ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); + if (m_bVerbose) + std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; } progress.m_iSteps = 1; @@ -226,6 +229,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); + + ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); + if (m_bVerbose) + std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + + break; } } From efcbcd7297e2c9b06e3cd5d3296d47504f502cee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 16:45:40 +0200 Subject: [PATCH 0332/2393] input: fix invalid usage of dev in setTouchDeviceConfigs ref #6943 --- src/managers/input/InputManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 255023b9..492d2805 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1488,9 +1488,9 @@ void CInputManager::newTouchDevice(SP pDevice) { } void CInputManager::setTouchDeviceConfigs(SP dev) { - auto setConfig = [&](SP PTOUCHDEV) -> void { - if (dev->aq() && dev->aq()->getLibinputHandle()) { - const auto LIBINPUTDEV = dev->aq()->getLibinputHandle(); + auto setConfig = [](SP PTOUCHDEV) -> void { + if (PTOUCHDEV->aq() && PTOUCHDEV->aq()->getLibinputHandle()) { + const auto LIBINPUTDEV = PTOUCHDEV->aq()->getLibinputHandle(); const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled"); const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED; From f7fb7e7e49e3b47f9b72c55fbf2d093e1a7981f5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 17:27:15 +0200 Subject: [PATCH 0333/2393] xwayland: avoid unfocusing on OR child focuses fixes #6698 --- src/xwayland/XWM.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b55df7fc..0eaa16be 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -398,10 +398,10 @@ void CXWM::focusWindow(SP surf) { focusedSurface = surf; - // send state to all surfaces, sometimes we might lose some + // send state to all toplevel surfaces, sometimes we might lose some // that could still stick with the focused atom for (auto& s : mappedSurfaces) { - if (!s) + if (!s || s->overrideRedirect) continue; sendState(s.lock()); @@ -879,7 +879,7 @@ void CXWM::activateSurface(SP surf, bool activate) { if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - if (!activate || !surf) { + if (!surf || (!activate || !surf->overrideRedirect /* if we are focusing on an OR child, don't unfocus parent */)) { setActiveWindow((uint32_t)XCB_WINDOW_NONE); focusWindow(nullptr); } else { From 7f624d2236162db847c70ce1caa12851e77e60eb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 17:41:26 +0200 Subject: [PATCH 0334/2393] xwayland: fixup WM_SIZE_HINTS handling according to ICCCM --- src/managers/XWaylandManager.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index e702a172..f329dbe1 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -76,13 +76,21 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); if (SIZEHINTS && pWindow->m_iX11Type != 2) { - pbox->x = SIZEHINTS->x; - pbox->y = SIZEHINTS->y; - pbox->width = SIZEHINTS->width; - pbox->height = SIZEHINTS->height; - } else { + // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. + // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property + pbox->x = pWindow->m_pXWaylandSurface->geometry.x; + pbox->y = pWindow->m_pXWaylandSurface->geometry.y; + + if ((SIZEHINTS->flags & 0x2 /* ICCCM USSize */) || (SIZEHINTS->flags & 0x8 /* ICCCM PSize */)) { + pbox->w = SIZEHINTS->base_width; + pbox->h = SIZEHINTS->base_height; + } else { + pbox->w = pWindow->m_pXWaylandSurface->geometry.w; + pbox->h = pWindow->m_pXWaylandSurface->geometry.h; + } + } else *pbox = pWindow->m_pXWaylandSurface->geometry; - } + } else if (pWindow->m_pXDGSurface) *pbox = pWindow->m_pXDGSurface->current.geometry; } From faa157e1626fb56b5f01ac0597518cc41bf1c40b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:18:07 +0300 Subject: [PATCH 0335/2393] gitignore: add CMake residual files --- .gitignore | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 3601f422..78f794fc 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake +CPackConfig.cmake +CPackSourceConfig.cmake +hyprland.pc _deps build/ @@ -15,6 +18,9 @@ result* /.idea/ .envrc .cache +.direnv +/.cmake/ +/.worktree/ *.o protocols/*.c* @@ -31,5 +37,3 @@ gmon.out PKGBUILD src/version.h - -.direnv From 928d1dd38a6e4a791d4a4374a4a3bf02311adbb2 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:27:03 +0300 Subject: [PATCH 0336/2393] CMake, Meson, Nix: replace props.json with VERSION --- CMakeLists.txt | 4 ++-- VERSION | 1 + meson.build | 2 +- nix/overlays.nix | 5 ++--- props.json | 3 --- 5 files changed, 6 insertions(+), 9 deletions(-) create mode 100644 VERSION delete mode 100644 props.json diff --git a/CMakeLists.txt b/CMakeLists.txt index e951b874..b65d361e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ include(CheckIncludeFile) include(GNUInstallDirs) # Get version -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS) -string(JSON VER GET ${PROPS} version) +file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) +string(STRIP ${VER_RAW} VER) project(Hyprland DESCRIPTION "A Modern C++ Wayland Compositor" diff --git a/VERSION b/VERSION new file mode 100644 index 00000000..6599454d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.41.2 diff --git a/meson.build b/meson.build index b8101f6c..4446ea0f 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('Hyprland', 'cpp', 'c', - version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(), + version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(), default_options : [ 'warning_level=2', 'default_library=static', diff --git a/nix/overlays.nix b/nix/overlays.nix index 9d100d51..d8979b45 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -3,13 +3,12 @@ lib, inputs, }: let - props = builtins.fromJSON (builtins.readFile ../props.json); - mkDate = longDate: (lib.concatStringsSep "-" [ (builtins.substring 0 4 longDate) (builtins.substring 4 2 longDate) (builtins.substring 6 2 longDate) ]); + version = lib.removeSuffix "\n" (builtins.readFile ../VERSION); in { # Contains what a user is most likely to care about: # Hyprland itself, XDPH and the Share Picker. @@ -33,7 +32,7 @@ in { in { hyprland = final.callPackage ./default.nix { stdenv = final.gcc13Stdenv; - version = "${props.version}+date=${date}_${self.shortRev or "dirty"}"; + version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; inherit date; }; diff --git a/props.json b/props.json deleted file mode 100644 index 2ff7562e..00000000 --- a/props.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "version": "0.41.2" -} \ No newline at end of file From db1f5cd13732bc440b8e5e353d87cdf7faaf1872 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 18 Jul 2024 21:27:41 +0300 Subject: [PATCH 0337/2393] CMake: fmt --- CMakeLists.txt | 427 +++++++++++++++++++++++++++---------------------- 1 file changed, 236 insertions(+), 191 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b65d361e..2bd4e0d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,10 +7,10 @@ include(GNUInstallDirs) file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VER) -project(Hyprland - DESCRIPTION "A Modern C++ Wayland Compositor" - VERSION ${VER} -) +project( + Hyprland + DESCRIPTION "A Modern C++ Wayland Compositor" + VERSION ${VER}) set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) @@ -21,32 +21,30 @@ set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") message(STATUS "Gathering git info") -# Get git info -# hash and branch -execute_process( - COMMAND ./scripts/generateVersion.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) +# Get git info hash and branch +execute_process(COMMAND ./scripts/generateVersion.sh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) # udis add_subdirectory("subprojects/udis86") if(CMAKE_BUILD_TYPE) - string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) - if(BUILDTYPE_LOWER STREQUAL "release") - # Pass. - elseif(BUILDTYPE_LOWER STREQUAL "debug") - # Pass. - elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") - set(BUILDTYPE_LOWER "debugoptimized") - elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") - set(BUILDTYPE_LOWER "minsize") - elseif(BUILDTYPE_LOWER STREQUAL "none") - set(BUILDTYPE_LOWER "plain") - else() - set(BUILDTYPE_LOWER "release") - endif() -else() + string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) + if(BUILDTYPE_LOWER STREQUAL "release") + # Pass. + elseif(BUILDTYPE_LOWER STREQUAL "debug") + # Pass. + elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo") + set(BUILDTYPE_LOWER "debugoptimized") + elseif(BUILDTYPE_LOWER STREQUAL "minsizerel") + set(BUILDTYPE_LOWER "minsize") + elseif(BUILDTYPE_LOWER STREQUAL "none") + set(BUILDTYPE_LOWER "plain") + else() set(BUILDTYPE_LOWER "release") + endif() +else() + set(BUILDTYPE_LOWER "release") endif() find_package(PkgConfig REQUIRED) @@ -58,22 +56,24 @@ message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Configuring Hyprland in Debug with CMake") - add_compile_definitions(HYPRLAND_DEBUG) + message(STATUS "Configuring Hyprland in Debug with CMake") + add_compile_definitions(HYPRLAND_DEBUG) else() - add_compile_options(-O3) - message(STATUS "Configuring Hyprland in Release with CMake") + add_compile_options(-O3) + message(STATUS "Configuring Hyprland in Release with CMake") endif() -include_directories( - . - "src/" - "subprojects/udis86/" - "protocols/") +include_directories(. "src/" "subprojects/udis86/" "protocols/") set(CMAKE_CXX_STANDARD 23) -add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value - -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith - -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) +add_compile_options( + -Wall + -Wextra + -Wno-unused-parameter + -Wno-unused-value + -Wno-missing-field-initializers + -Wno-narrowing + -Wno-pointer-arith + -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=) set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE) set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) @@ -83,20 +83,39 @@ message(STATUS "Checking deps...") find_package(Threads REQUIRED) if(LEGACY_RENDERER) - set(GLES_VERSION "GLES2") + set(GLES_VERSION "GLES2") else() - set(GLES_VERSION "GLES3") + set(GLES_VERSION "GLES3") endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET - aquamarine - xkbcommon uuid - wayland-server wayland-client wayland-cursor wayland-protocols - cairo pango pangocairo pixman-1 xcursor - libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.0 -) +pkg_check_modules( + deps + REQUIRED + IMPORTED_TARGET + aquamarine + xkbcommon + uuid + wayland-server + wayland-client + wayland-cursor + wayland-protocols + cairo + pango + pangocairo + pixman-1 + xcursor + libdrm + libinput + hwdata + libseat + libdisplay-info + libliftoff + libudev + gbm + hyprlang>=0.3.2 + hyprcursor>=0.1.7 + hyprutils>=0.2.0) find_package(hyprwayland-scanner 0.3.10 REQUIRED) @@ -104,8 +123,8 @@ file(GLOB_RECURSE SRCFILES "src/*.cpp") set(TRACY_CPP_FILES "") if(USE_TRACY) - set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") - message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) + set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp") + message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) @@ -113,75 +132,88 @@ add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) set(USE_GPROF ON) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Setting debug flags") + message(STATUS "Setting debug flags") - if (WITH_ASAN) - message(STATUS "Enabling ASan") + if(WITH_ASAN) + message(STATUS "Enabling ASan") - target_link_libraries(Hyprland asan) - target_compile_options(Hyprland PUBLIC -fsanitize=address) + target_link_libraries(Hyprland asan) + target_compile_options(Hyprland PUBLIC -fsanitize=address) + endif() + + if(USE_TRACY) + message(STATUS "Tracy is turned on") + + option(TRACY_ENABLE "" ON) + option(TRACY_ON_DEMAND "" ON) + add_subdirectory(subprojects/tracy) + + target_link_libraries(Hyprland Tracy::TracyClient) + + if(USE_TRACY_GPU) + message(STATUS "Tracy GPU Profiling is turned on") + add_compile_definitions(USE_TRACY_GPU) endif() + endif() - if(USE_TRACY) - message(STATUS "Tracy is turned on") - - option( TRACY_ENABLE "" ON) - option( TRACY_ON_DEMAND "" ON) - add_subdirectory (subprojects/tracy) - - target_link_libraries(Hyprland Tracy::TracyClient) - - if(USE_TRACY_GPU) - message(STATUS "Tracy GPU Profiling is turned on") - add_compile_definitions(USE_TRACY_GPU) - endif() - endif() - - add_compile_options(-fno-pie -fno-builtin) - add_link_options(-no-pie -fno-builtin) - if(USE_GPROF) - add_compile_options(-pg) - add_link_options(-pg) - endif() + add_compile_options(-fno-pie -fno-builtin) + add_link_options(-no-pie -fno-builtin) + if(USE_GPROF) + add_compile_options(-pg) + add_link_options(-pg) + endif() endif() check_include_file("execinfo.h" EXECINFOH) if(EXECINFOH) - message(STATUS "Configuration supports execinfo") - add_compile_definitions(HAS_EXECINFO) + message(STATUS "Configuration supports execinfo") + add_compile_definitions(HAS_EXECINFO) endif() include(CheckLibraryExists) check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO) if(HAVE_LIBEXECINFO) - target_link_libraries(Hyprland execinfo) + target_link_libraries(Hyprland execinfo) endif() check_include_file("sys/timerfd.h" HAS_TIMERFD) pkg_check_modules(epoll IMPORTED_TARGET epoll-shim) if(NOT HAS_TIMERFD AND epoll_FOUND) - target_link_libraries(Hyprland PkgConfig::epoll) + target_link_libraries(Hyprland PkgConfig::epoll) endif() if(LEGACY_RENDERER) - message(STATUS "Using the legacy GLES2 renderer!") - add_compile_definitions(LEGACY_RENDERER) + message(STATUS "Using the legacy GLES2 renderer!") + add_compile_definitions(LEGACY_RENDERER) endif() if(NO_XWAYLAND) - message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") - add_compile_definitions(NO_XWAYLAND) + message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!") + add_compile_definitions(NO_XWAYLAND) else() - message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") - pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors) - target_link_libraries(Hyprland PkgConfig::xdeps) + message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") + pkg_check_modules( + xdeps + REQUIRED + IMPORTED_TARGET + xcb + xwayland + xcb-util + xcb-render + xcb-xfixes + xcb-icccm + xcb-composite + xcb-res + xcb-ewmh + xcb-errors) + target_link_libraries(Hyprland PkgConfig::xdeps) endif() if(NO_SYSTEMD) - message(STATUS "SYSTEMD support is disabled...") + message(STATUS "SYSTEMD support is disabled...") else() - message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") - add_compile_definitions(USES_SYSTEMD) + message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") + add_compile_definitions(USES_SYSTEMD) endif() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) @@ -190,7 +222,8 @@ include(CPack) message(STATUS "Setting precompiled headers") -target_precompile_headers(Hyprland PRIVATE $<$:src/pch/pch.hpp>) +target_precompile_headers(Hyprland PRIVATE + $<$:src/pch/pch.hpp>) message(STATUS "Setting link libraries") @@ -200,104 +233,115 @@ target_link_libraries(Hyprland rt PkgConfig::deps) add_custom_target(generate-protocol-headers) function(protocol protoPath protoName external) - if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() + if(external) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + else() + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + COMMAND ${WaylandScanner} server-header ${path} + protocols/${protoName}-protocol.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c + COMMAND ${WaylandScanner} private-code ${path} + protocols/${protoName}-protocol.c + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources( + Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h + ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) endfunction() -function(protocolNew protoPath protoName external) - if (external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp - ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp - COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) +function(protocolnew protoPath protoName external) + if(external) + set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + else() + set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) + endif() + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp + ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp + COMMAND hyprwayland-scanner ${path}/${protoName}.xml + ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/${protoName}.cpp + protocols/${protoName}.hpp) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp) endfunction() function(protocolWayland) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp - ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp - COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - ) - target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) - target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) + add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp + ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp + COMMAND hyprwayland-scanner --wayland-enums + ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) + target_sources(generate-protocol-headers + PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) endfunction() -target_link_libraries(Hyprland - OpenGL::EGL - OpenGL::GL - Threads::Threads - libudis86 - uuid -) +target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads + libudis86 uuid) -protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true) -protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) -protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) -protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) +protocol("protocols/wlr-screencopy-unstable-v1.xml" + "wlr-screencopy-unstable-v1" true) +protocol( + "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" + "hyprland-global-shortcuts-v1" true) +protocol( + "subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" + "hyprland-toplevel-export-v1" true) +protocol("unstable/text-input/text-input-unstable-v1.xml" + "text-input-unstable-v1" false) -protocolNew("protocols" "wlr-gamma-control-unstable-v1" true) -protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) -protocolNew("protocols" "wlr-output-power-management-unstable-v1" true) -protocolNew("protocols" "virtual-keyboard-unstable-v1" true) -protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true) -protocolNew("protocols" "input-method-unstable-v2" true) -protocolNew("protocols" "wlr-output-management-unstable-v1" true) -protocolNew("protocols" "kde-server-decoration" true) -protocolNew("protocols" "wlr-data-control-unstable-v1" true) -protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true) -protocolNew("protocols" "wlr-layer-shell-unstable-v1" true) -protocolNew("protocols" "wayland-drm" true) -protocolNew("staging/tearing-control" "tearing-control-v1" false) -protocolNew("staging/fractional-scale" "fractional-scale-v1" false) -protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false) -protocolNew("staging/cursor-shape" "cursor-shape-v1" false) -protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) -protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) -protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) -protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false) -protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false) -protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) -protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false) -protocolNew("unstable/text-input" "text-input-unstable-v3" false) -protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false) -protocolNew("staging/xdg-activation" "xdg-activation-v1" false) -protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false) -protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false) -protocolNew("stable/tablet" "tablet-v2" false) -protocolNew("stable/presentation-time" "presentation-time" false) -protocolNew("stable/xdg-shell" "xdg-shell" false) -protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false) -protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false) -protocolNew("stable/viewporter" "viewporter" false) -protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false) -protocolNew("staging/drm-lease" "drm-lease-v1" false) -protocolNew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) +protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) +protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) +protocolnew("protocols" "wlr-output-power-management-unstable-v1" true) +protocolnew("protocols" "virtual-keyboard-unstable-v1" true) +protocolnew("protocols" "wlr-virtual-pointer-unstable-v1" true) +protocolnew("protocols" "input-method-unstable-v2" true) +protocolnew("protocols" "wlr-output-management-unstable-v1" true) +protocolnew("protocols" "kde-server-decoration" true) +protocolnew("protocols" "wlr-data-control-unstable-v1" true) +protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" + true) +protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "wayland-drm" true) +protocolnew("staging/tearing-control" "tearing-control-v1" false) +protocolnew("staging/fractional-scale" "fractional-scale-v1" false) +protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) +protocolnew("staging/cursor-shape" "cursor-shape-v1" false) +protocolnew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false) +protocolnew("unstable/relative-pointer" "relative-pointer-unstable-v1" false) +protocolnew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false) +protocolnew("staging/alpha-modifier" "alpha-modifier-v1" false) +protocolnew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" + false) +protocolnew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false) +protocolnew("unstable/keyboard-shortcuts-inhibit" + "keyboard-shortcuts-inhibit-unstable-v1" false) +protocolnew("unstable/text-input" "text-input-unstable-v3" false) +protocolnew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" + false) +protocolnew("staging/xdg-activation" "xdg-activation-v1" false) +protocolnew("staging/ext-idle-notify" "ext-idle-notify-v1" false) +protocolnew("staging/ext-session-lock" "ext-session-lock-v1" false) +protocolnew("stable/tablet" "tablet-v2" false) +protocolnew("stable/presentation-time" "presentation-time" false) +protocolnew("stable/xdg-shell" "xdg-shell" false) +protocolnew("unstable/primary-selection" "primary-selection-unstable-v1" false) +protocolnew("staging/xwayland-shell" "xwayland-shell-v1" false) +protocolnew("stable/viewporter" "viewporter" false) +protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) +protocolnew("staging/drm-lease" "drm-lease-v1" false) +protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) -protocolWayland() +protocolwayland() # tools add_subdirectory(hyprctl) @@ -306,12 +350,12 @@ add_subdirectory(hyprpm) # binary and symlink install(TARGETS Hyprland) -install(CODE "execute_process( \ +install( + CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ ${CMAKE_INSTALL_FULL_BINDIR}/hyprland - )" -) + )") # session file install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop @@ -319,8 +363,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop # wallpapers file(GLOB_RECURSE WALLPAPERS "assets/wall*") -install(FILES ${WALLPAPERS} - DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) +install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) # default config install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf @@ -332,9 +375,7 @@ install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf # man pages file(GLOB_RECURSE MANPAGES "docs/*.1") -install(FILES ${MANPAGES} - DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) - +install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) # pkgconfig entry install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc @@ -342,12 +383,16 @@ install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc # protocol headers set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols") -install(DIRECTORY ${HEADERS_PROTO} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h*") +install( + DIRECTORY ${HEADERS_PROTO} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING + PATTERN "*.h*") # hyprland headers set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src") -install(DIRECTORY ${HEADERS_SRC} - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland - FILES_MATCHING PATTERN "*.h*") +install( + DIRECTORY ${HEADERS_SRC} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland + FILES_MATCHING + PATTERN "*.h*") From e6fc9873b5e10e7ac00085da7d599776ed72f297 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Jul 2024 19:31:36 +0300 Subject: [PATCH 0338/2393] flake.lock: update --- flake.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/flake.lock b/flake.lock index b2cc9703..f61f18a1 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721487522, - "narHash": "sha256-aF3uwUwUK2CgbItoMe3IJF0yidIEWcDx47AiH5y8VKk=", + "lastModified": 1721571743, + "narHash": "sha256-hat7wggtDISBJD8kTo5MTrT+IsY/Ha2MwgjmqqijoCA=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "acfea3bd1d9e756c7152e639240d52c6628844b0", + "rev": "601f6cf95cbe4fef02dc7faf34bba58566c914e9", "type": "github" }, "original": { @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1720108799, - "narHash": "sha256-AxRkTJlbB8r7aG6gvc7IaLhc2T9TO4/8uqanKRxukBQ=", + "lastModified": 1721330371, + "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "a5c0d57325c5f0814c39110a70ca19c070ae9486", + "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1720381373, - "narHash": "sha256-lyC/EZdHULsaAKVryK11lgHY9u6pXr7qR4irnxNWC7k=", + "lastModified": 1721324361, + "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "5df0174fd09de4ac5475233d65ffc703e89b82eb", + "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1721071737, - "narHash": "sha256-qmC9jGfbE4+EIBbbSAkrfR/p49wShjpv4/KztgE/P54=", + "lastModified": 1721324102, + "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "eb1ceff2b87f6820789249f63faa8e9dcb54d05f", + "rev": "962582a090bc233c4de9d9897f46794280288989", "type": "github" }, "original": { @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1720215857, - "narHash": "sha256-JPdL+Qul+jEueAn8CARfcWP83eJgwkhMejQYfDvrgvU=", + "lastModified": 1721324119, + "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "d5fa094ca27e0039be5e94c0a80ae433145af8bb", + "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1720957393, - "narHash": "sha256-oedh2RwpjEa+TNxhg5Je9Ch6d3W1NKi7DbRO1ziHemA=", + "lastModified": 1721379653, + "narHash": "sha256-8MUgifkJ7lkZs3u99UDZMB4kbOxvMEXQZ31FO3SopZ0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "693bc46d169f5af9c992095736e82c3488bf7dbb", + "rev": "1d9c2c9b3e71b9ee663d11c5d298727dace8d374", "type": "github" }, "original": { From 3b6bcd6ddcfebd1fed0694aa2c0bd9753f4d5d46 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 19:25:01 +0200 Subject: [PATCH 0339/2393] presentation-feedback: fix invalid values sent after aq merge --- src/protocols/PresentationTime.cpp | 10 +++++++++- src/protocols/core/Compositor.cpp | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index e9472fc3..a2fc270c 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -60,7 +60,7 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - if (data->wasPresented && when) + if (data->wasPresented) resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else @@ -104,6 +104,14 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su } void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { + timespec now; + timespec* presentedAt = when; + if (!presentedAt) { + // just put the current time, we don't have anything better + clock_gettime(CLOCK_MONOTONIC, &now); + when = &now; + } + for (auto& feedback : m_vFeedbacks) { if (!feedback->surface) continue; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 5cd6005a..d11ba40c 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -463,7 +463,7 @@ void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, boo frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); - FEEDBACK->discarded(); + FEEDBACK->presented(); PROTO::presentation->queueData(FEEDBACK); if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) From cbaac6deafb857662d630efbca8b0ebac0f11b44 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 20:02:48 +0200 Subject: [PATCH 0340/2393] xwm: drop invalid case for clearing X focus fixes #6955 --- src/xwayland/XWM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 0eaa16be..81c59cc2 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -879,7 +879,7 @@ void CXWM::activateSurface(SP surf, bool activate) { if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - if (!surf || (!activate || !surf->overrideRedirect /* if we are focusing on an OR child, don't unfocus parent */)) { + if (!surf) { setActiveWindow((uint32_t)XCB_WINDOW_NONE); focusWindow(nullptr); } else { From 341fb4497fc6b5e6097361c2820a4cd4d1c6ccab Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 22:05:53 +0200 Subject: [PATCH 0341/2393] wayland/compositor: fixup buffer damage tracking for wl_shm buffers remove qt hack, fixup conditions fixes #6844 --- src/protocols/core/Compositor.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index d11ba40c..12647811 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -84,7 +84,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{}; - if (oldBufSize != newBufSize) + if (oldBufSize != newBufSize || current.buffer != pending.buffer) pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; bufferReleased = false; @@ -407,10 +407,7 @@ void CWLSurfaceResource::commitPendingState() { pending.bufferDamage.clear(); if (current.buffer && !bufferReleased) { - // without previous dolphin et al are weird vvv - //CRegion surfaceDamage = - // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); - current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + current.buffer->update(accumulateCurrentBufferDamage()); // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. From 33e933e2a020c874037df568d6c033ae20f30bf7 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 22:09:29 +0200 Subject: [PATCH 0342/2393] renderer: drop redundant spammy trace log --- src/render/Renderer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 82dfc887..724bd69c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -236,10 +236,8 @@ static void renderSurface(SP surface, int x, int y, void* da g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } - if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { - Debug::log(TRACE, "presentFeedback for visible surface"); + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) surface->presentFeedback(RDATA->when, RDATA->pMonitor); - } g_pHyprOpenGL->blend(true); From 672bf1f8670b200da57e2f6de4e9ed7efd8c98fc Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 21 Jul 2024 23:25:20 +0200 Subject: [PATCH 0343/2393] compositor: ignore setting surface scanout if DS is disabled --- src/Compositor.cpp | 6 +++++- src/render/Renderer.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c7a0cfb1..02ca5363 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2285,6 +2285,8 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { } void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMode mode) { + static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState) return; @@ -2333,7 +2335,9 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod return; // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. - g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); + // ignore if DS is disabled. + if (!*PNODIRECTSCANOUT) + g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 724bd69c..84d607b8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -236,7 +236,7 @@ static void renderSurface(SP surface, int x, int y, void* da g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } - if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) + if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) surface->presentFeedback(RDATA->when, RDATA->pMonitor); g_pHyprOpenGL->blend(true); From 5979ceb56b165ee35809a0eeda5f4be1aedbb7b6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 12:37:54 +0200 Subject: [PATCH 0344/2393] surface: fixup logical damage size calculations fixes #6618 --- src/desktop/WLSurface.cpp | 41 +++++++++++++++++++++++++++------------ src/desktop/WLSurface.hpp | 21 ++++++++++---------- src/render/Renderer.cpp | 2 +- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 97335d27..a7a2e5aa 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -74,6 +74,16 @@ Vector2D CWLSurface::correctSmallVec() const { return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize); } +Vector2D CWLSurface::correctSmallVecBuf() const { + if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.buffer) + return {}; + + const auto SIZE = getViewporterCorrectedSize(); + const auto BS = m_pResource->current.buffer->size; + + return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}); +} + Vector2D CWLSurface::getViewporterCorrectedSize() const { if (!exists() || !m_pResource->current.buffer) return {}; @@ -81,16 +91,15 @@ Vector2D CWLSurface::getViewporterCorrectedSize() const { return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; } -CRegion CWLSurface::logicalDamage() const { +CRegion CWLSurface::computeDamage() const { if (!m_pResource->current.buffer) return {}; CRegion damage = m_pResource->accumulateCurrentBufferDamage(); damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); - damage.scale(1.0 / m_pResource->current.scale); - const auto VPSIZE = getViewporterCorrectedSize(); - const auto CORRECTVEC = correctSmallVec(); + const auto BUFSIZE = m_pResource->current.buffer->size; + const auto CORRECTVEC = correctSmallVecBuf(); if (m_pResource->current.viewport.hasSource) damage.intersect(m_pResource->current.viewport.source); @@ -98,9 +107,17 @@ CRegion CWLSurface::logicalDamage() const { const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size; - damage.scale({VPSIZE.x / SCALEDSRCSIZE.x, VPSIZE.y / SCALEDSRCSIZE.y}); + damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y}); damage.translate(CORRECTVEC); + // go from buffer coords in the damage to hl logical + + const auto BOX = getSurfaceBoxGlobal(); + const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.buffer->size : + Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */}; + + damage.scale(SCALE); + return damage; } @@ -141,27 +158,27 @@ void CWLSurface::init() { Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this); } -PHLWINDOW CWLSurface::getWindow() { +PHLWINDOW CWLSurface::getWindow() const { return m_pWindowOwner.lock(); } -PHLLS CWLSurface::getLayer() { +PHLLS CWLSurface::getLayer() const { return m_pLayerOwner.lock(); } -CPopup* CWLSurface::getPopup() { +CPopup* CWLSurface::getPopup() const { return m_pPopupOwner; } -CSubsurface* CWLSurface::getSubsurface() { +CSubsurface* CWLSurface::getSubsurface() const { return m_pSubsurfaceOwner; } -bool CWLSurface::desktopComponent() { +bool CWLSurface::desktopComponent() const { return !m_pLayerOwner.expired() || !m_pWindowOwner.expired() || m_pSubsurfaceOwner || m_pPopupOwner; } -std::optional CWLSurface::getSurfaceBoxGlobal() { +std::optional CWLSurface::getSurfaceBoxGlobal() const { if (!desktopComponent()) return {}; @@ -181,7 +198,7 @@ void CWLSurface::appendConstraint(WP constraint) { m_pConstraint = constraint; } -SP CWLSurface::constraint() { +SP CWLSurface::constraint() const { return m_pConstraint.lock(); } diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 447f4582..bb476e0f 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -33,22 +33,23 @@ class CWLSurface { SP resource() const; bool exists() const; - bool small() const; // means surface is smaller than the requested size - Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces + bool small() const; // means surface is smaller than the requested size + Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces + Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords Vector2D getViewporterCorrectedSize() const; - CRegion logicalDamage() const; + CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned bool visible(); // getters for owners. - PHLWINDOW getWindow(); - PHLLS getLayer(); - CPopup* getPopup(); - CSubsurface* getSubsurface(); + PHLWINDOW getWindow() const; + PHLLS getLayer() const; + CPopup* getPopup() const; + CSubsurface* getSubsurface() const; // desktop components misc utils - std::optional getSurfaceBoxGlobal(); + std::optional getSurfaceBoxGlobal() const; void appendConstraint(WP constraint); - SP constraint(); + SP constraint() const; // allow stretching. Useful for plugins. bool m_bFillIgnoreSmall = false; @@ -107,7 +108,7 @@ class CWLSurface { void destroy(); void init(); - bool desktopComponent(); + bool desktopComponent() const; struct { CHyprSignalListener destroy; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 84d607b8..835fed91 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1693,7 +1693,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou return; const auto WLSURF = CWLSurface::fromResource(pSurface); - CRegion damageBox = WLSURF ? WLSURF->logicalDamage() : CRegion{}; + CRegion damageBox = WLSURF ? WLSURF->computeDamage() : CRegion{}; if (!WLSURF) { Debug::log(ERR, "BUG THIS: No CWLSurface for surface in damageSurface!!!"); return; From 1797319a0785cf9ae4f406d40bc27b032c6f5fb2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 13:01:55 +0200 Subject: [PATCH 0345/2393] renderer: untransform textures matching display transform fixes #6754 This will break if the client uses a transform that is not equal to the display, reverting to old behavior. Combining transforms is left as a todo for the future. --- src/protocols/core/Compositor.cpp | 3 +++ src/render/OpenGL.cpp | 10 +++++++--- src/render/Texture.hpp | 13 ++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 12647811..f1c83531 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -406,6 +406,9 @@ void CWLSurfaceResource::commitPendingState() { pending.damage.clear(); pending.bufferDamage.clear(); + if (current.buffer && current.buffer->texture) + current.buffer->texture->m_eTransform = wlTransformToHyprutils(current.transform); + if (current.buffer && !bufferReleased) { current.buffer->update(accumulateCurrentBufferDamage()); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index b2b046ce..fef69f7c 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1277,9 +1277,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB static auto PDIMINACTIVE = CConfigValue("decoration:dim_inactive"); static auto PDT = CConfigValue("debug:damage_tracking"); - // get transform - const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); - float matrix[9]; + // get the needed transform for this texture + const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!! + eTransform TRANSFORM = HYPRUTILS_TRANSFORM_NORMAL; + if (m_bEndFrame || TRANSFORMS_MATCH) + TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); + + float matrix[9]; projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); float glMatrix[9]; diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index 0da95300..a54be8c5 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -2,9 +2,11 @@ #include "../defines.hpp" #include +#include class IHLBuffer; HYPRUTILS_FORWARD(Math, CRegion); +using namespace Hyprutils::Math; enum TEXTURETYPE { TEXTURE_INVALID, // Invalid @@ -33,11 +35,12 @@ class CTexture { void allocate(); void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); - TEXTURETYPE m_iType = TEXTURE_RGBA; - GLenum m_iTarget = GL_TEXTURE_2D; - GLuint m_iTexID = 0; - Vector2D m_vSize; - void* m_pEglImage = nullptr; + TEXTURETYPE m_iType = TEXTURE_RGBA; + GLenum m_iTarget = GL_TEXTURE_2D; + GLuint m_iTexID = 0; + Vector2D m_vSize = {}; + void* m_pEglImage = nullptr; + eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL; private: void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); From 3132f0275e78bdf1a78aee4ccd2944e9e5ba95bd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 13:05:06 +0200 Subject: [PATCH 0346/2393] touch: set lastInputTouch on every event --- src/managers/input/Touch.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 736a2ae5..7863140b 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -6,6 +6,8 @@ #include "../SeatManager.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { + m_bLastInputTouch = true; + static auto PSWIPETOUCH = CConfigValue("gestures:workspace_swipe_touch"); static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); @@ -54,8 +56,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } } - m_bLastInputTouch = true; - m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus; m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus; m_sTouchData.touchFocusLS = m_pFoundLSToFocus; @@ -83,6 +83,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } void CInputManager::onTouchUp(ITouch::SUpEvent e) { + m_bLastInputTouch = true; + EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e); if (m_sActiveSwipe.pWorkspaceBegin) { // If there was a swipe from this finger, end it. @@ -96,6 +98,8 @@ void CInputManager::onTouchUp(ITouch::SUpEvent e) { } void CInputManager::onTouchMove(ITouch::SMotionEvent e) { + m_bLastInputTouch = true; + EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e); if (m_sActiveSwipe.pWorkspaceBegin) { // Do nothing if this is using a different finger. From 511e9ccdd199a90a7378fae1f950de6a315cc406 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:15:40 +0300 Subject: [PATCH 0347/2393] xwm: Fix xwayland black window bug after losing focus (#6966) * fix xwayland black window bug * resend normal state --- src/xwayland/XWM.cpp | 22 +++++++++++++++++++++- src/xwayland/XWM.hpp | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 81c59cc2..bb69afda 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -378,6 +378,20 @@ void CXWM::handleFocusIn(xcb_focus_in_event_t* e) { focusWindow(focusedSurface.lock()); } +void CXWM::handleFocusOut(xcb_focus_out_event_t* e) { + Debug::log(TRACE, "[xwm] focusOut mode={}, detail={}, event={}", e->mode, e->detail, e->event); + + const auto XSURF = windowForXID(e->event); + + if (!XSURF) + return; + + Debug::log(TRACE, "[xwm] focusOut for {} {} {} surface {}", XSURF->mapped ? "mapped" : "unmapped", XSURF->fullscreen ? "fullscreen" : "windowed", + XSURF == focusedSurface ? "focused" : "unfocused", XSURF->state.title); + + // do something? +} + void CXWM::sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask) { xcb_client_message_event_t event = { .response_type = XCB_CLIENT_MESSAGE, @@ -674,9 +688,10 @@ int CXWM::onEvent(int fd, uint32_t mask) { case XCB_PROPERTY_NOTIFY: handlePropertyNotify((xcb_property_notify_event_t*)event); break; case XCB_CLIENT_MESSAGE: handleClientMessage((xcb_client_message_event_t*)event); break; case XCB_FOCUS_IN: handleFocusIn((xcb_focus_in_event_t*)event); break; + case XCB_FOCUS_OUT: handleFocusOut((xcb_focus_out_event_t*)event); break; case 0: handleError((xcb_value_error_t*)event); break; default: { - ; + Debug::log(TRACE, "[xwm] unhandled event {}", event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK); } } free(event); @@ -891,6 +906,11 @@ void CXWM::activateSurface(SP surf, bool activate) { } void CXWM::sendState(SP surf) { + Debug::log(TRACE, "[xwm] sendState for {} {} {} surface {}", surf->mapped ? "mapped" : "unmapped", surf->fullscreen ? "fullscreen" : "windowed", + surf == focusedSurface ? "focused" : "unfocused", surf->state.title); + if (surf->fullscreen && surf->mapped && surf == focusedSurface) + surf->setWithdrawn(false); // resend normal state + if (surf->withdrawn) { xcb_delete_property(connection, surf->xID, HYPRATOMS["_NET_WM_STATE"]); return; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 88606416..4f6f3f7c 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -104,6 +104,7 @@ class CXWM { void handlePropertyNotify(xcb_property_notify_event_t* e); void handleClientMessage(xcb_client_message_event_t* e); void handleFocusIn(xcb_focus_in_event_t* e); + void handleFocusOut(xcb_focus_out_event_t* e); void handleError(xcb_value_error_t* e); bool handleSelectionEvent(xcb_generic_event_t* e); From d03fa94c2ca1a642959e31adc4fcc2447a3cc623 Mon Sep 17 00:00:00 2001 From: diniamo <55629891+diniamo@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:16:25 +0000 Subject: [PATCH 0348/2393] core: avoid locking 2 wayland sockets (#6971) * fix: avoid locking 2 wayland sockets * format * fix formatting --- src/Compositor.cpp | 69 ++++++++++++++-------------------------------- src/Compositor.hpp | 4 +-- src/main.cpp | 4 +-- 3 files changed, 24 insertions(+), 53 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 02ca5363..e3ef664d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -207,7 +207,7 @@ void CCompositor::setRandomSplash() { static std::vector> pendingOutputs; // -void CCompositor::initServer() { +void CCompositor::initServer(std::string socketName, int socketFd) { m_sWLDisplay = wl_display_create(); @@ -267,16 +267,25 @@ void CCompositor::initServer() { m_iDRMFD = m_pAqBackend->drmFD(); Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD); - // get socket, avoid using 0 - for (int candidate = 1; candidate <= 32; candidate++) { - const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); - const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (!socketName.empty() && socketFd != -1) { + fcntl(socketFd, F_SETFD, FD_CLOEXEC); + const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); if (RETVAL >= 0) { - m_szWLDisplaySocket = CANDIDATESTR; - Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); - break; - } else { - Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); + m_szWLDisplaySocket = socketName; + Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL); + } else + Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL); + } else { + // get socket, avoid using 0 + for (int candidate = 1; candidate <= 32; candidate++) { + const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); + const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); + if (RETVAL >= 0) { + m_szWLDisplaySocket = CANDIDATESTR; + Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); + break; + } else + Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); } } @@ -292,7 +301,6 @@ void CCompositor::initServer() { throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); } - Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket); setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); setenv("XDG_SESSION_TYPE", "wayland", 1); @@ -631,44 +639,7 @@ void CCompositor::prepareFallbackOutput() { headless->createOutput(); } -void CCompositor::startCompositor(std::string socketName, int socketFd) { - if (!socketName.empty() && socketFd != -1) { - fcntl(socketFd, F_SETFD, FD_CLOEXEC); - const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd); - if (RETVAL >= 0) { - m_szWLDisplaySocket = socketName; - Debug::log(LOG, "wl_display_add_socket_fd for {} succeeded with {}", socketName, RETVAL); - } else - Debug::log(WARN, "wl_display_add_socket_fd for {} returned {}: skipping", socketName, RETVAL); - } else { - // get socket, avoid using 0 - for (int candidate = 1; candidate <= 32; candidate++) { - const auto CANDIDATESTR = ("wayland-" + std::to_string(candidate)); - const auto RETVAL = wl_display_add_socket(m_sWLDisplay, CANDIDATESTR.c_str()); - if (RETVAL >= 0) { - m_szWLDisplaySocket = CANDIDATESTR; - Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL); - break; - } else - Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate); - } - } - - if (m_szWLDisplaySocket.empty()) { - Debug::log(WARN, "All candidates failed, trying wl_display_add_socket_auto"); - const auto SOCKETSTR = wl_display_add_socket_auto(m_sWLDisplay); - if (SOCKETSTR) - m_szWLDisplaySocket = SOCKETSTR; - } - - if (m_szWLDisplaySocket.empty()) { - Debug::log(CRIT, "m_szWLDisplaySocket NULL!"); - throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)"); - } - - setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); - setenv("XDG_SESSION_TYPE", "wayland", 1); - +void CCompositor::startCompositor() { signal(SIGPIPE, SIG_IGN); if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 58c5b33d..a274ca58 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -69,8 +69,8 @@ class CCompositor { std::unordered_map m_mMonitorIDMap; - void initServer(); - void startCompositor(std::string socketName, int socketFd); + void initServer(std::string socketName, int socketFd); + void startCompositor(); void cleanup(); void createLockFile(); void removeLockFile(); diff --git a/src/main.cpp b/src/main.cpp index 1ac3ab8b..3e51c6c8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,7 +147,7 @@ int main(int argc, char** argv) { return 1; } - g_pCompositor->initServer(); + g_pCompositor->initServer(socketName, socketFd); if (!envEnabled("HYPRLAND_NO_RT")) Init::gainRealTime(); @@ -155,7 +155,7 @@ int main(int argc, char** argv) { Debug::log(LOG, "Hyprland init finished."); // If all's good to go, start. - g_pCompositor->startCompositor(socketName, socketFd); + g_pCompositor->startCompositor(); g_pCompositor->m_bIsShuttingDown = true; From 83a5395eaa99fecef777827fff1de486c06b6180 Mon Sep 17 00:00:00 2001 From: diniamo Date: Mon, 22 Jul 2024 13:45:34 +0200 Subject: [PATCH 0349/2393] flake: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index f61f18a1..f9933958 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1720194466, - "narHash": "sha256-Rizg9efi6ue95zOp0MeIV2ZedNo+5U9G2l6yirgBUnA=", + "lastModified": 1721648131, + "narHash": "sha256-cyyxu/oj4QEFp3CVx2WeXa9T4OAUyynuBJHGkBZSxJI=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "b9b97e5ba23fe7bd5fa4df54696102e8aa863cf6", + "rev": "663be9cad424b170b28b9fa8a61042d721007f3b", "type": "github" }, "original": { From 5bae7f150b228d3bf677d09fd0c320328b0d0ff0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 16:56:51 +0200 Subject: [PATCH 0350/2393] wayland/output: avoid sending events to dead outputs ref #6835 --- src/managers/ProtocolManager.cpp | 8 +++++--- src/protocols/core/Output.cpp | 5 +++-- src/protocols/core/Output.hpp | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 387cac8f..5a44680f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -66,8 +66,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { else if (!ISMIRROR && (!PROTO::outputs.contains(pMonitor->szName) || PROTO::outputs.at(pMonitor->szName)->isDefunct())) { if (PROTO::outputs.contains(pMonitor->szName)) PROTO::outputs.erase(pMonitor->szName); - PROTO::outputs.emplace(pMonitor->szName, - std::make_unique(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); + PROTO::outputs.emplace(pMonitor->szName, makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); } } @@ -86,7 +85,10 @@ CProtocolManager::CProtocolManager() { if (PROTO::outputs.contains(M->szName)) PROTO::outputs.erase(M->szName); - PROTO::outputs.emplace(M->szName, std::make_unique(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock())); + + auto ref = makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", M->szName), M->self.lock()); + PROTO::outputs.emplace(M->szName, ref); + ref->self = ref; m_mModeChangeListeners[M->szName] = M->events.modeChanged.registerListener([M, this](std::any d) { onMonitorModeChange(M); }); }); diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 4ba23cbe..878d1484 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -49,7 +49,7 @@ SP CWLOutputResource::getResource() { } void CWLOutputResource::updateState() { - if (!monitor) + if (!monitor || (owner && owner->defunct)) return; if (resource->version() >= 2) @@ -83,7 +83,8 @@ void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, return; } - RESOURCE->self = RESOURCE; + RESOURCE->self = RESOURCE; + RESOURCE->owner = self; } void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) { diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 46e4057b..49c32ec1 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -8,6 +8,7 @@ #include "../../helpers/signal/Signal.hpp" class CMonitor; +class CWLOutputProtocol; class CWLOutputResource { public: @@ -20,7 +21,7 @@ class CWLOutputResource { void updateState(); WP monitor; - + WP owner; WP self; private: @@ -40,6 +41,7 @@ class CWLOutputProtocol : public IWaylandProtocol { void sendDone(); WP monitor; + WP self; // will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global) void remove(); @@ -61,5 +63,5 @@ class CWLOutputProtocol : public IWaylandProtocol { }; namespace PROTO { - inline std::unordered_map> outputs; + inline std::unordered_map> outputs; }; From 87db950189d87eb00d01b9df9959b36ba0f4d5c7 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 16:57:35 +0200 Subject: [PATCH 0351/2393] wl_seat: avoid sending events to objects without caps ref #6835 --- src/protocols/core/Seat.cpp | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 21a47575..7a295372 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -27,6 +27,9 @@ void CWLTouchResource::sendDown(SP surface, uint32_t timeMs, if (!owner) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + ASSERT(surface->client() == owner->client()); currentSurface = surface; @@ -41,6 +44,9 @@ void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { if (!owner) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); fingers--; if (fingers <= 0) { @@ -54,6 +60,9 @@ void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& l if (!owner) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } @@ -61,6 +70,9 @@ void CWLTouchResource::sendFrame() { if (!owner) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendFrame(); } @@ -68,6 +80,9 @@ void CWLTouchResource::sendCancel() { if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendCancel(); } @@ -75,6 +90,9 @@ void CWLTouchResource::sendShape(int32_t id, const Vector2D& shape) { if (!owner || !currentSurface || resource->version() < 6) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendShape(id, wl_fixed_from_double(shape.x), wl_fixed_from_double(shape.y)); } @@ -82,6 +100,9 @@ void CWLTouchResource::sendOrientation(int32_t id, double angle) { if (!owner || !currentSurface || resource->version() < 6) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_TOUCH)) + return; + resource->sendOrientation(id, wl_fixed_from_double(angle)); } @@ -113,6 +134,9 @@ void CWLPointerResource::sendEnter(SP surface, const Vector2 if (!owner || currentSurface == surface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + if (currentSurface) { LOGM(WARN, "requested CWLPointerResource::sendEnter without sendLeave first."); sendLeave(); @@ -130,6 +154,9 @@ void CWLPointerResource::sendLeave() { if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + // release all buttons unless we have a dnd going on in which case // the events shall be lost. if (!PROTO::data->dndActive()) { @@ -151,6 +178,9 @@ void CWLPointerResource::sendMotion(uint32_t timeMs, const Vector2D& local) { if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendMotion(timeMs, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } @@ -158,6 +188,9 @@ void CWLPointerResource::sendButton(uint32_t timeMs, uint32_t button, wl_pointer if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + if (state == WL_POINTER_BUTTON_STATE_RELEASED && std::find(pressedButtons.begin(), pressedButtons.end(), button) == pressedButtons.end()) { LOGM(ERR, "sendButton release on a non-pressed button"); return; @@ -178,6 +211,9 @@ void CWLPointerResource::sendAxis(uint32_t timeMs, wl_pointer_axis axis, double if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxis(timeMs, axis, wl_fixed_from_double(value)); } @@ -185,6 +221,9 @@ void CWLPointerResource::sendFrame() { if (!owner || resource->version() < 5) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendFrame(); } @@ -192,6 +231,9 @@ void CWLPointerResource::sendAxisSource(wl_pointer_axis_source source) { if (!owner || !currentSurface || resource->version() < 5) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxisSource(source); } @@ -199,6 +241,9 @@ void CWLPointerResource::sendAxisStop(uint32_t timeMs, wl_pointer_axis axis) { if (!owner || !currentSurface || resource->version() < 5) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxisStop(timeMs, axis); } @@ -206,6 +251,9 @@ void CWLPointerResource::sendAxisDiscrete(wl_pointer_axis axis, int32_t discrete if (!owner || !currentSurface || resource->version() < 5) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxisDiscrete(axis, discrete); } @@ -213,6 +261,9 @@ void CWLPointerResource::sendAxisValue120(wl_pointer_axis axis, int32_t value120 if (!owner || !currentSurface || resource->version() < 8) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxisValue120(axis, value120); } @@ -220,6 +271,9 @@ void CWLPointerResource::sendAxisRelativeDirection(wl_pointer_axis axis, wl_poin if (!owner || !currentSurface || resource->version() < 9) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) + return; + resource->sendAxisRelativeDirection(axis, direction); } @@ -250,6 +304,9 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!keyboard) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; int fd; uint32_t size; @@ -275,6 +332,9 @@ void CWLKeyboardResource::sendEnter(SP surface) { if (!owner || currentSurface == surface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + if (currentSurface) { LOGM(WARN, "requested CWLKeyboardResource::sendEnter without sendLeave first."); sendLeave(); @@ -297,6 +357,9 @@ void CWLKeyboardResource::sendLeave() { if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + resource->sendLeave(g_pSeatManager->nextSerial(owner.lock()), currentSurface->getResource().get()); currentSurface.reset(); listeners.destroySurface.reset(); @@ -306,6 +369,9 @@ void CWLKeyboardResource::sendKey(uint32_t timeMs, uint32_t key, wl_keyboard_key if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + resource->sendKey(g_pSeatManager->nextSerial(owner.lock()), timeMs, key, state); } @@ -313,6 +379,9 @@ void CWLKeyboardResource::sendMods(uint32_t depressed, uint32_t latched, uint32_ if (!owner || !currentSurface) return; + if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) + return; + resource->sendModifiers(g_pSeatManager->nextSerial(owner.lock()), depressed, latched, locked, group); } From 77b134e23baf769aecdf2ea8ed14d55d00228ce1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 17:24:24 +0200 Subject: [PATCH 0352/2393] virtual-pointer: fixup virtual pointer warp events fixes #6976 --- src/devices/VirtualPointer.cpp | 7 ++++++- src/managers/PointerManager.cpp | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index faca27dc..f9a1c409 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -20,7 +20,12 @@ CVirtualPointer::CVirtualPointer(SP resource) : point }); listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); }); - listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { pointerEvents.motionAbsolute.emit(d); }); + listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { + // we need to unpack the event and add our device here because it's required to calculate the position correctly + auto E = std::any_cast(d); + E.device = self.lock(); + pointerEvents.motionAbsolute.emit(E); + }); listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); }); listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); }); listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); }); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index cf10db71..b1542fed 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -620,7 +620,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) { void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { SP currentMonitor = g_pCompositor->m_pLastMonitor.lock(); - if (!currentMonitor) + if (!currentMonitor || !dev) return; if (!std::isnan(abs.x)) From e8374e07927826f43d30803b6db00c3b88482e7e Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:06:11 -0500 Subject: [PATCH 0353/2393] debug: get rid of useless 1s in logs (#6969) * get rid of 1s in logs lol * replace WLR with AQ in logs --- src/Compositor.cpp | 10 +++++----- src/desktop/LayerSurface.cpp | 6 +++--- src/helpers/Monitor.cpp | 2 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 8 ++++---- src/protocols/AlphaModifier.cpp | 4 ++-- src/protocols/FractionalScale.cpp | 4 ++-- src/protocols/ToplevelExport.cpp | 2 +- src/xwayland/XWM.cpp | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e3ef664d..24098bee 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1100,7 +1100,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo return; if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) { - Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface); + Debug::log(LOG, "surface {:x} won't receive kb focus becuase grab rejected it", (uintptr_t)pSurface.get()); return; } @@ -1123,9 +1123,9 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo g_pSeatManager->setKeyboardFocus(pSurface); if (pWindowOwner) - Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface, pWindowOwner); + Debug::log(LOG, "Set keyboard focus to surface {:x}, with {}", (uintptr_t)pSurface.get(), pWindowOwner); else - Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface); + Debug::log(LOG, "Set keyboard focus to surface {:x}", (uintptr_t)pSurface.get()); g_pXWaylandManager->activateSurface(pSurface, true); m_pLastFocus = pSurface; @@ -2836,7 +2836,7 @@ void CCompositor::setPreferredScaleForSurface(SP pSurface, d const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface", (uintptr_t)pSurface.get()); return; } @@ -2849,7 +2849,7 @@ void CCompositor::setPreferredTransformForSurface(SP pSurfac const auto PSURFACE = CWLSurface::fromResource(pSurface); if (!PSURFACE) { - Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface); + Debug::log(WARN, "Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface", (uintptr_t)pSurface.get()); return; } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 9a891531..83b0992f 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -74,7 +74,7 @@ CLayerSurface::~CLayerSurface() { } void CLayerSurface::onDestroy() { - Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface); + Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -114,7 +114,7 @@ void CLayerSurface::onDestroy() { } void CLayerSurface::onMap() { - Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); + Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface.get()); mapped = true; interactivity = layerSurface->current.interactivity; @@ -177,7 +177,7 @@ void CLayerSurface::onMap() { } void CLayerSurface::onUnmap() { - Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface); + Debug::log(LOG, "LayerSurface {:x} unmapped", (uintptr_t)layerSurface.get()); g_pEventManager->postEvent(SHyprIPCEvent{"closelayer", layerSurface->layerNamespace}); EMIT_HOOK_EVENT("closeLayer", self.lock()); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a23b9861..635427d1 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -148,7 +148,7 @@ void CMonitor::onConnect(bool noRule) { damage.setSize(vecTransformedSize); - Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output); + Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output.get()); setupDefaultWS(monitorRule); diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index a38acdbf..da2429bc 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -7,7 +7,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique()).get(); PINHIBIT->inhibitor = std::any_cast>(inhibitor); - Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface); + Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface.get()); PINHIBIT->inhibitor->listeners.destroy = PINHIBIT->inhibitor->resource->events.destroy.registerListener([this, PINHIBIT](std::any data) { std::erase_if(m_vIdleInhibitors, [PINHIBIT](const auto& other) { return other.get() == PINHIBIT; }); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 492d2805..e2c62367 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -228,7 +228,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; } else - Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF, (uintptr_t)CONSTRAINT.get()); + Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get()); } // if we are holding a pointer button, @@ -570,7 +570,7 @@ void CInputManager::processMouseRequest(std::any E) { auto e = std::any_cast(E); - Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf); + Debug::log(LOG, "cursorImage request: surface {:x}", (uintptr_t)e.surf.get()); if (e.surf != m_sCursorSurfaceInfo.wlSurface->resource()) { m_sCursorSurfaceInfo.wlSurface->unassign(); @@ -850,7 +850,7 @@ void CInputManager::newKeyboard(SP keyboard) { setupKeyboard(PNEWKEYBOARD); - Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard); + Debug::log(LOG, "New keyboard created, pointers Hypr: {:x} and AQ: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard.get()); } void CInputManager::newVirtualKeyboard(SP keyboard) { @@ -992,7 +992,7 @@ void CInputManager::newMouse(SP mouse) { setupMouse(PMOUSE); - Debug::log(LOG, "New mouse created, pointer WLR: {:x}", (uintptr_t)mouse); + Debug::log(LOG, "New mouse created, pointer AQ: {:x}", (uintptr_t)mouse.get()); } void CInputManager::setupMouse(SP mauz) { diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index 04dcd0a8..38b8c800 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -87,7 +87,7 @@ void CAlphaModifierProtocol::destroyModifier(CAlphaModifier* modifier) { void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, SP surface) { if (std::find_if(m_mAlphaModifiers.begin(), m_mAlphaModifiers.end(), [surface](const auto& e) { return e.first == surface; }) != m_mAlphaModifiers.end()) { - LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface); + LOGM(ERR, "AlphaModifier already present for surface {:x}", (uintptr_t)surface.get()); pMgr->error(WP_ALPHA_MODIFIER_V1_ERROR_ALREADY_CONSTRUCTED, "AlphaModifier already present"); return; } @@ -100,4 +100,4 @@ void CAlphaModifierProtocol::onGetSurface(CWpAlphaModifierV1* pMgr, uint32_t id, m_mAlphaModifiers.erase(surface); return; } -} \ No newline at end of file +} diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 6d225e99..5bf56c5a 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -28,7 +28,7 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP surface) { for (auto& [k, v] : m_mAddons) { if (k == surface) { - LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface); + LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface.get()); pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); return; } @@ -80,4 +80,4 @@ bool CFractionalScaleAddon::good() { SP CFractionalScaleAddon::surf() { return surface.lock(); -} \ No newline at end of file +} diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 0e78e5f7..e982ad6f 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -221,7 +221,7 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r const auto PWINDOW = PFRAME->pWindow.lock(); if (!validMapped(PWINDOW)) { - Debug::log(ERR, "Client requested sharing of window handle {:x} which is gone!", (uintptr_t)PWINDOW.get()); + Debug::log(ERR, "Client requested sharing of window handle {:x} which is gone!", PWINDOW); hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); removeFrame(PFRAME); return; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index bb69afda..498710a4 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -937,7 +937,7 @@ void CXWM::onNewSurface(SP surf) { if (surf->client() != g_pXWayland->pServer->xwaylandClient) return; - Debug::log(LOG, "[xwm] New XWayland surface at {:x}", (uintptr_t)surf); + Debug::log(LOG, "[xwm] New XWayland surface at {:x}", (uintptr_t)surf.get()); const auto WLID = surf->id(); From f17f8b219c699ab52f3d784cad90bdef5bb78188 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 19:05:24 +0200 Subject: [PATCH 0354/2393] pointer/hw: extend cursor swapchain to 3 otherwise on some commits we draw twice and we draw over the front buffer --- src/managers/PointerManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index b1542fed..55bd0509 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -373,7 +373,10 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain->currentOptions(); options.size = maxSize; - options.length = 2; + // TODO: this is a band-aid. If the current cursor image has not yet been committed (no rendering has yet been done) + // we should revert the swapchain and avoid rendering to the front buffer. + // as a band-aid, extend the swapchain to 3 as we sometimes double-render on a cursor shape change. + options.length = 3; options.scanout = true; options.cursor = true; options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; From 4c3b03516209a49244a8f044143c1162752b8a7a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 19:19:37 +0200 Subject: [PATCH 0355/2393] pointer/hw: rollback the swapchain on multiple renders without a commit fixes the hack --- src/managers/PointerManager.cpp | 21 +++++++++++++++++---- src/managers/PointerManager.hpp | 6 ++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 55bd0509..3b425688 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -24,6 +24,14 @@ CPointerManager::CPointerManager() { }, nullptr); }); + + hooks.monitorPreRender = g_pHookSystem->hookDynamic("preRender", [this](void* self, SCallbackInfo& info, std::any data) { + auto state = stateFor(std::any_cast(data)->self.lock()); + if (!state) + return; + + state->cursorRendered = false; + }); } void CPointerManager::lockSoftwareAll() { @@ -373,10 +381,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain->currentOptions(); options.size = maxSize; - // TODO: this is a band-aid. If the current cursor image has not yet been committed (no rendering has yet been done) - // we should revert the swapchain and avoid rendering to the front buffer. - // as a band-aid, extend the swapchain to 3 as we sometimes double-render on a cursor shape change. - options.length = 3; + options.length = 2; options.scanout = true; options.cursor = true; options.multigpu = state->monitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; @@ -389,6 +394,14 @@ SP CPointerManager::renderHWCursorBuffer(SPcursorRendered) + state->monitor->cursorSwapchain->rollback(); + + state->cursorRendered = true; + auto buf = state->monitor->cursorSwapchain->next(nullptr); if (!buf) { Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain"); diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index cf4f1a94..4a4c4f61 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -163,8 +163,9 @@ class CPointerManager { int softwareLocks = 0; bool hardwareFailed = false; CBox box; // logical - bool entered = false; - bool hwApplied = false; + bool entered = false; + bool hwApplied = false; + bool cursorRendered = false; SP cursorFrontBuffer; }; @@ -177,6 +178,7 @@ class CPointerManager { struct { SP monitorAdded; + SP monitorPreRender; } hooks; }; From 7c68236a51291e71db04233d04eae65f4ebd594f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 22 Jul 2024 23:05:22 +0200 Subject: [PATCH 0356/2393] egl: avoid setting debug mode and handle legacyrenderer ref #6973 --- src/render/OpenGL.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index fef69f7c..15b3cad8 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -130,12 +130,15 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); } +#ifndef GLES2 attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); attrs.push_back(3); attrs.push_back(EGL_CONTEXT_MINOR_VERSION); attrs.push_back(2); - attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG); - attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE); +#else + attrs.push_back(EGL_CONTEXT_CLIENT_VERSION); + attrs.push_back(2); +#endif attrs.push_back(EGL_NONE); From 3c758db95c129ed6ca7ce0c1b5b82ad6e189488d Mon Sep 17 00:00:00 2001 From: Sam Lakerveld Date: Mon, 22 Jul 2024 23:36:58 +0200 Subject: [PATCH 0357/2393] renderer/layer-shell: use explicitly set exclusiveEdge (#6984) --- src/protocols/LayerShell.cpp | 2 ++ src/render/Renderer.cpp | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index fd66ba5e..029f261d 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -152,6 +152,8 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPsetSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { + // TODO: validate anchor + pending.committed |= STATE_EDGE; pending.exclusiveEdge = anchor; }); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 835fed91..d8de7ba8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1506,7 +1506,8 @@ void CHyprRenderer::setSurfaceScanoutMode(SP surface, SP 0) { + if ((exclusiveEdge == edges[i].singular_anchor || anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) { if (edges[i].positive_axis) { *edges[i].positive_axis += exclusive + edges[i].margin; } @@ -1638,7 +1639,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgeometry = box; - applyExclusive(*usableArea, PSTATE->anchor, PSTATE->exclusive, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); + applyExclusive(*usableArea, PSTATE->anchor, PSTATE->exclusive, PSTATE->exclusiveEdge, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); if (Vector2D{box.width, box.height} != OLDSIZE) ls->layerSurface->configure(box.size()); From 752604cfe954bd96bd6b5aca3e80dafb6a426cfb Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 23 Jul 2024 20:40:33 +0300 Subject: [PATCH 0358/2393] Nix: remove meson (used by wlroots) --- nix/default.nix | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 7775b729..e4e12f43 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -31,7 +31,6 @@ libuuid, libxkbcommon, mesa, - meson, pango, pciutils, pcre2, @@ -90,7 +89,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov jq makeWrapper cmake - meson # for wlroots ninja pkg-config python3 # for udis86 @@ -114,10 +112,12 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov hyprcursor hyprlang hyprutils - libGL - libdrm libdatrie + libdisplay-info + libdrm + libGL libinput + libliftoff libselinux libsepol libthai @@ -127,13 +127,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov pango pciutils pcre2 + seatd tomlplusplus wayland wayland-protocols - # for wlroots - seatd - libdisplay-info - libliftoff ] (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ From 077494ee85c8fa4c6ae74ad8d749feea826294d2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 23 Jul 2024 19:56:42 +0200 Subject: [PATCH 0359/2393] surface: fix zero_scaling xwayland damage --- src/desktop/WLSurface.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index a7a2e5aa..90924145 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -118,6 +118,9 @@ CRegion CWLSurface::computeDamage() const { damage.scale(SCALE); + if (m_pWindowOwner) + damage.scale(m_pWindowOwner->m_fX11SurfaceScaledBy); // fix xwayland:force_zero_scaling stuff that will be fucked by the above a bit + return damage; } From a5f58a31268da95e36c0918ac75589c05e81b892 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:03:15 -0500 Subject: [PATCH 0360/2393] layer-shell: validate exclusiveEdge and don't set it as top by default (#7006) * validate exclusiveEdge and don't set it as top by default * make sure exclusive edge anchor is within bounds --- src/protocols/LayerShell.cpp | 12 ++++++++++-- src/protocols/LayerShell.hpp | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 029f261d..4e733b35 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -11,7 +11,7 @@ void CLayerShellResource::SState::reset() { exclusive = 0; interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; - exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + exclusiveEdge = (zwlrLayerSurfaceV1Anchor)0; desiredSize = {}; margin = {0, 0, 0, 0}; } @@ -152,7 +152,15 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPsetSetExclusiveEdge([this](CZwlrLayerSurfaceV1* r, zwlrLayerSurfaceV1Anchor anchor) { - // TODO: validate anchor + if (anchor > (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_EXCLUSIVE_EDGE, "Invalid exclusive edge"); + return; + } + + if (!pending.anchor || !(pending.anchor & anchor)) { + r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_EXCLUSIVE_EDGE, "Exclusive edge doesn't align with anchor"); + return; + } pending.committed |= STATE_EDGE; pending.exclusiveEdge = anchor; diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 6d29248a..221d95c0 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -47,7 +47,7 @@ class CLayerShellResource : public ISurfaceRole { Vector2D desiredSize; zwlrLayerSurfaceV1KeyboardInteractivity interactivity = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; zwlrLayerShellV1Layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; - zwlrLayerSurfaceV1Anchor exclusiveEdge = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + zwlrLayerSurfaceV1Anchor exclusiveEdge = (zwlrLayerSurfaceV1Anchor)0; uint32_t committed = 0; struct { From 8a4548e4302b1cc00fca368a7cc2e3171516420c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 23 Jul 2024 23:38:50 +0200 Subject: [PATCH 0361/2393] window: drop ack requirement for applying pending reported size fixes #6533 --- src/events/Windows.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 516ac2ae..a5511e17 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -702,12 +702,7 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) return; - if (PWINDOW->m_bIsX11) - PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. - else if (PWINDOW->m_pPendingSizeAck.has_value()) { - PWINDOW->m_vReportedSize = PWINDOW->m_pPendingSizeAck->second; - PWINDOW->m_pPendingSizeAck.reset(); - } + PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; From e2efecc24e6534f46352cab13975778e3f0b5735 Mon Sep 17 00:00:00 2001 From: Leon Date: Wed, 24 Jul 2024 00:38:15 +0200 Subject: [PATCH 0362/2393] flake: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index f9933958..4545c61d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721571743, - "narHash": "sha256-hat7wggtDISBJD8kTo5MTrT+IsY/Ha2MwgjmqqijoCA=", + "lastModified": 1721755137, + "narHash": "sha256-DcJkFNaHGRMIkexx/ol2oNiUFT/zqnZH6dwODdHubIU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "601f6cf95cbe4fef02dc7faf34bba58566c914e9", + "rev": "4c72cd4d0b0368ce78bf94ea7f23d47670f0d429", "type": "github" }, "original": { From 2da3cfb4220af818b8b44fcc52c9b9b54cbe155e Mon Sep 17 00:00:00 2001 From: Leon <99900077+leon-erd@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:59:50 +0200 Subject: [PATCH 0363/2393] touch: fix touch swipe invert config (#7014) --- src/managers/input/Touch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7863140b..40af4b1e 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -14,7 +14,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { // TODO: WORKSPACERULE.gapsOut.value_or() auto gapsOut = *PGAPSOUT; static auto PBORDERSIZE = CConfigValue("general:border_size"); - static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); + static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_touch_invert"); EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e); auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : ""); From 99088eaed806d9268967baf09bc09cdb987c5357 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 24 Jul 2024 11:07:22 +0200 Subject: [PATCH 0364/2393] compositor: simplify getWindowFromSurface --- src/Compositor.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 24098bee..7caaa98a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1184,15 +1184,10 @@ SP CCompositor::vectorToLayerSurface(const Vector2D& pos, st } PHLWINDOW CCompositor::getWindowFromSurface(SP pSurface) { - for (auto& w : m_vWindows) { - if (!w->m_bIsMapped || w->m_bFadingOut) - continue; + if (!pSurface || !pSurface->hlSurface) + return nullptr; - if (w->m_pWLSurface->resource() == pSurface) - return w; - } - - return nullptr; + return pSurface->hlSurface->getWindow(); } PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { From 72bce7efd5b302412f13485af27985965ddf830f Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:10:36 +0000 Subject: [PATCH 0365/2393] keybinds: add bindp and noshortcutsinhibit (#7017) --- src/config/ConfigManager.cpp | 8 +++++-- src/config/ConfigManager.hpp | 1 + src/desktop/Window.hpp | 37 +++++++++++++++--------------- src/managers/KeybindManager.cpp | 7 +++--- src/managers/KeybindManager.hpp | 1 + src/protocols/ShortcutsInhibit.cpp | 3 +++ 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6928a802..5a8f2bd2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1983,6 +1983,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool ignoreMods = false; bool multiKey = false; bool hasDescription = false; + bool dontInhibit = false; const auto BINDARGS = command.substr(4); for (auto& arg : BINDARGS) { @@ -2004,6 +2005,8 @@ std::optional CConfigManager::handleBind(const std::string& command multiKey = true; } else if (arg == 'd') { hasDescription = true; + } else if (arg == 'p') { + dontInhibit = true; } else { return "bind: invalid flag"; } @@ -2072,8 +2075,9 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, - release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription}); + g_pKeybindManager->addKeybind(SKeybind{ + parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release, + repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit}); } return {}; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index df7c202b..b4a49b7a 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -182,6 +182,7 @@ class CConfigManager { {"nomaxsize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noMaxSize; }}, {"norounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noRounding; }}, {"noshadow", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShadow; }}, + {"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }}, {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }}, diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 60189fac..108b804c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -153,24 +153,25 @@ struct SWindowData { CWindowOverridableVar alphaInactive = SAlphaValue{1.f, false}; CWindowOverridableVar alphaFullscreen = SAlphaValue{1.f, false}; - CWindowOverridableVar allowsInput = false; - CWindowOverridableVar dimAround = false; - CWindowOverridableVar decorate = true; - CWindowOverridableVar focusOnActivate = false; - CWindowOverridableVar keepAspectRatio = false; - CWindowOverridableVar nearestNeighbor = false; - CWindowOverridableVar noAnim = false; - CWindowOverridableVar noBorder = false; - CWindowOverridableVar noBlur = false; - CWindowOverridableVar noDim = false; - CWindowOverridableVar noFocus = false; - CWindowOverridableVar noMaxSize = false; - CWindowOverridableVar noRounding = false; - CWindowOverridableVar noShadow = false; - CWindowOverridableVar opaque = false; - CWindowOverridableVar RGBX = false; - CWindowOverridableVar tearing = false; - CWindowOverridableVar xray = false; + CWindowOverridableVar allowsInput = false; + CWindowOverridableVar dimAround = false; + CWindowOverridableVar decorate = true; + CWindowOverridableVar focusOnActivate = false; + CWindowOverridableVar keepAspectRatio = false; + CWindowOverridableVar nearestNeighbor = false; + CWindowOverridableVar noAnim = false; + CWindowOverridableVar noBorder = false; + CWindowOverridableVar noBlur = false; + CWindowOverridableVar noDim = false; + CWindowOverridableVar noFocus = false; + CWindowOverridableVar noMaxSize = false; + CWindowOverridableVar noRounding = false; + CWindowOverridableVar noShadow = false; + CWindowOverridableVar noShortcutsInhibit = false; + CWindowOverridableVar opaque = false; + CWindowOverridableVar RGBX = false; + CWindowOverridableVar tearing = false; + CWindowOverridableVar xray = false; CWindowOverridableVar rounding; CWindowOverridableVar borderSize; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e9dfd1ae..185426dd 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -607,10 +607,8 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); - if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) { + if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); - return false; - } for (auto& k : m_lKeybinds) { const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; @@ -619,6 +617,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi const bool IGNORECONDITIONS = SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. + if (!k.dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) + continue; + if (!k.locked && g_pSessionLockManager->isSessionLocked()) continue; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 284280cd..e3ba2f2d 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -34,6 +34,7 @@ struct SKeybind { bool ignoreMods = false; bool multiKey = false; bool hasDescription = false; + bool dontInhibit = false; // DO NOT INITIALIZE bool shadowed = false; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index 211a7a01..226fccb6 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -73,6 +73,9 @@ bool CKeyboardShortcutsInhibitProtocol::isInhibited() { if (!g_pCompositor->m_pLastFocus) return false; + if (g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock())->m_sWindowData.noShortcutsInhibit.valueOrDefault()) + return false; + for (auto& in : m_vInhibitors) { if (in->surface() != g_pCompositor->m_pLastFocus) continue; From fe1975488725c006f4dc4575c1eb1df84ed1a893 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 24 Jul 2024 16:26:44 +0200 Subject: [PATCH 0366/2393] shortcutsInhibit: fix crash --- src/protocols/ShortcutsInhibit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index 226fccb6..1a0433e6 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -73,7 +73,7 @@ bool CKeyboardShortcutsInhibitProtocol::isInhibited() { if (!g_pCompositor->m_pLastFocus) return false; - if (g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock())->m_sWindowData.noShortcutsInhibit.valueOrDefault()) + if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); PWINDOW && PWINDOW->m_sWindowData.noShortcutsInhibit.valueOrDefault()) return false; for (auto& in : m_vInhibitors) { From f2b6ebbf5427c319c7b3c9621a98751598b360f9 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:42:45 +0000 Subject: [PATCH 0367/2393] keybinds: remove toggleopaque (#7024) modified: src/managers/KeybindManager.cpp modified: src/managers/KeybindManager.hpp --- src/managers/KeybindManager.cpp | 12 ------------ src/managers/KeybindManager.hpp | 1 - 2 files changed, 13 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 185426dd..fda27598 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -101,7 +101,6 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["pass"] = pass; m_mDispatchers["sendshortcut"] = sendshortcut; m_mDispatchers["layoutmsg"] = layoutmsg; - m_mDispatchers["toggleopaque"] = toggleOpaque; m_mDispatchers["dpms"] = dpms; m_mDispatchers["movewindowpixel"] = moveWindow; m_mDispatchers["resizewindowpixel"] = resizeWindow; @@ -2237,17 +2236,6 @@ void CKeybindManager::layoutmsg(std::string msg) { g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); } -void CKeybindManager::toggleOpaque(std::string unused) { - const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - - if (!PWINDOW) - return; - - PWINDOW->m_sWindowData.opaque = CWindowOverridableVar(!PWINDOW->m_sWindowData.opaque.valueOrDefault(), PRIORITY_SET_PROP); - - g_pHyprRenderer->damageWindow(PWINDOW); -} - void CKeybindManager::dpms(std::string arg) { bool enable = arg.starts_with("on"); std::string port = ""; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index e3ba2f2d..7201df04 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -190,7 +190,6 @@ class CKeybindManager { static void pass(std::string); static void sendshortcut(std::string); static void layoutmsg(std::string); - static void toggleOpaque(std::string); static void dpms(std::string); static void swapnext(std::string); static void swapActiveWorkspaces(std::string); From b16fb9770ca984fb4e0f44e188b0786180afb8ba Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 24 Jul 2024 17:48:38 +0200 Subject: [PATCH 0368/2393] egl: support getting the device via platform_device a neat EXT --- src/render/OpenGL.cpp | 93 ++++++++++++++++++++++++++++++++++++------- src/render/OpenGL.hpp | 2 + 2 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 15b3cad8..ab7f566a 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -101,7 +101,7 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { attrs.push_back(EGL_NONE); - m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data()); + m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : m_pEglDevice, attrs.data()); if (m_pEglDisplay == EGL_NO_DISPLAY) RASSERT(false, "EGL: failed to create a platform display"); @@ -158,6 +158,60 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext); } +static bool drmDeviceHasName(const drmDevice* device, const std::string& name) { + for (size_t i = 0; i < DRM_NODE_MAX; i++) { + if (!(device->available_nodes & (1 << i))) + continue; + + if (device->nodes[i] == name) + return true; + } + return false; +} + +EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { + EGLint nDevices = 0; + if (!m_sProc.eglQueryDevicesEXT(0, nullptr, &nDevices)) { + Debug::log(ERR, "eglDeviceFromDRMFD: eglQueryDevicesEXT failed"); + return EGL_NO_DEVICE_EXT; + } + + if (nDevices <= 0) { + Debug::log(ERR, "eglDeviceFromDRMFD: no devices"); + return EGL_NO_DEVICE_EXT; + } + + std::vector devices; + devices.resize(nDevices); + + if (!m_sProc.eglQueryDevicesEXT(nDevices, devices.data(), &nDevices)) { + Debug::log(ERR, "eglDeviceFromDRMFD: eglQueryDevicesEXT failed (2)"); + return EGL_NO_DEVICE_EXT; + } + + drmDevice* drmDev = nullptr; + if (int ret = drmGetDevice(drmFD, &drmDev); ret < 0) { + Debug::log(ERR, "eglDeviceFromDRMFD: drmGetDevice failed"); + return EGL_NO_DEVICE_EXT; + } + + for (auto& d : devices) { + auto devName = m_sProc.eglQueryDeviceStringEXT(d, EGL_DRM_DEVICE_FILE_EXT); + if (!devName) + continue; + + if (drmDeviceHasName(drmDev, devName)) { + Debug::log(LOG, "eglDeviceFromDRMFD: Using device {}", devName); + drmFreeDevice(&drmDev); + return d; + } + } + + drmFreeDevice(&drmDev); + Debug::log(LOG, "eglDeviceFromDRMFD: No drm devices found"); + return EGL_NO_DEVICE_EXT; +} + CHyprOpenGLImpl::CHyprOpenGLImpl() { const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); @@ -202,22 +256,33 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue."); - // if (m_sProc.eglQueryDevicesEXT) { - // // TODO: - // } + bool success = false; + if (EGLEXTENSIONS.contains("EXT_platform_device") || !m_sProc.eglQueryDevicesEXT || !m_sProc.eglQueryDeviceStringEXT) { + m_pEglDevice = eglDeviceFromDRMFD(m_iDRMFD); - if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { - m_iGBMFD = openRenderNode(m_iDRMFD); - if (m_iGBMFD < 0) - RASSERT(false, "Couldn't open a gbm fd"); + if (m_pEglDevice != EGL_NO_DEVICE_EXT) { + success = true; + initEGL(false); + } + } - m_pGbmDevice = gbm_create_device(m_iGBMFD); - if (!m_pGbmDevice) - RASSERT(false, "Couldn't open a gbm device"); + if (!success) { + Debug::log(WARN, "EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm"); + if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { + success = true; + m_iGBMFD = openRenderNode(m_iDRMFD); + if (m_iGBMFD < 0) + RASSERT(false, "Couldn't open a gbm fd"); - initEGL(true); - } else - RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver."); + m_pGbmDevice = gbm_create_device(m_iGBMFD); + if (!m_pGbmDevice) + RASSERT(false, "Couldn't open a gbm device"); + + initEGL(true); + } + } + + RASSERT(success, "EGL does not support KHR_platform_gbm or EXT_platform_device, this is an issue with your gpu driver."); auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS); RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!"); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 712b87f3..5c4ee811 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -216,6 +216,7 @@ class CHyprOpenGLImpl { gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; bool m_bReloadScreenShader = true; // at launch it can be set @@ -280,6 +281,7 @@ class CHyprOpenGLImpl { void initShaders(); void initDRMFormats(); void initEGL(bool gbm); + EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); // std::optional> getModsForFormat(EGLint format); From 735e3c6c56d22059ee6340c0327e4b5a9154f013 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:05:54 +0000 Subject: [PATCH 0369/2393] crashreporter: add date and flags to crash report (#7028) modified: src/debug/CrashReporter.cpp --- src/debug/CrashReporter.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index c25212fe..c31975b8 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -105,7 +105,19 @@ void CrashReporter::createAndSaveCrash(int sig) { finalCrashReport += GIT_COMMIT_HASH; finalCrashReport += "\nTag: "; finalCrashReport += GIT_TAG; - finalCrashReport += "\n\n"; + finalCrashReport += "\nDate: "; + finalCrashReport += GIT_COMMIT_DATE; + finalCrashReport += "\nFlags:\n"; +#ifdef LEGACY_RENDERER + finalCrashReport += "legacyrenderer\n"; +#endif +#ifndef ISDEBUG + finalCrashReport += "debug\n"; +#endif +#ifdef NO_XWAYLAND + finalCrashReport += "no xwayland\n"; +#endif + finalCrashReport += "\n"; if (g_pPluginSystem && g_pPluginSystem->pluginCount() > 0) { finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n"; 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 0370/2393] 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 +}; From a0be3de0e89f42b98d00bf0d87ad10af843d58d6 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:00:25 +0000 Subject: [PATCH 0371/2393] keybinds: handle monitor change in moveWindowIntoGroup (#7030) modified: src/managers/KeybindManager.cpp --- src/managers/KeybindManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ed76575a..4232ea64 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2478,6 +2478,11 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! + if (pWindow->m_iMonitorID != pWindowInDirection->m_iMonitorID) { + pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace); + pWindow->m_iMonitorID = pWindowInDirection->m_iMonitorID; + } + static auto USECURRPOS = CConfigValue("group:insert_after_current"); pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail(); From 381cb2d8330d09f8994ca01591fb3e3737e6a67a Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 24 Jul 2024 23:51:23 +0300 Subject: [PATCH 0372/2393] flake.lock: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 4545c61d..e8f7e259 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721755137, - "narHash": "sha256-DcJkFNaHGRMIkexx/ol2oNiUFT/zqnZH6dwODdHubIU=", + "lastModified": 1721853718, + "narHash": "sha256-QEkCryhEMBW8maWEbwN0LoJIjdt640FviwMeJpghJXM=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "4c72cd4d0b0368ce78bf94ea7f23d47670f0d429", + "rev": "353dc1b7299d43f08de44276b93ae32726ff9d70", "type": "github" }, "original": { From 391f1ae838e936e909d0f3de8a5bf0387d22f80d Mon Sep 17 00:00:00 2001 From: Anton Lazarev <22821309+antonok-edm@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:16:47 -0700 Subject: [PATCH 0373/2393] input: don't simulate mouse movement on focus change in follow_mouse = 2/3 if no_warps is false (#7015) --- src/managers/KeybindManager.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4232ea64..44826fff 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -281,13 +281,18 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { return false; const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); + if (!LASTMONITOR) + return false; if (LASTMONITOR == monitor) { Debug::log(LOG, "Tried to move to active monitor"); return false; } - const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; - const auto PNEWMAINWORKSPACE = monitor->activeWorkspace; + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); + static auto PNOWARPS = CConfigValue("cursor:no_warps"); + + const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; + const auto PNEWMAINWORKSPACE = monitor->activeWorkspace; g_pInputManager->unconstrainMouse(); PNEWMAINWORKSPACE->rememberPrevWorkspace(PWORKSPACE); @@ -300,9 +305,11 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { g_pCompositor->focusWindow(PNEWWINDOW); PNEWWINDOW->warpCursor(); - g_pInputManager->m_pForcedFocus = PNEWWINDOW; - g_pInputManager->simulateMouseMovement(); - g_pInputManager->m_pForcedFocus.reset(); + if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) { + g_pInputManager->m_pForcedFocus = PNEWWINDOW; + g_pInputManager->simulateMouseMovement(); + g_pInputManager->m_pForcedFocus.reset(); + } } else { g_pCompositor->focusWindow(nullptr); g_pCompositor->warpCursorTo(monitor->middle()); @@ -313,7 +320,10 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { } void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); + static auto PNOWARPS = CConfigValue("cursor:no_warps"); + + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO) return; @@ -337,9 +347,12 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { g_pCompositor->focusWindow(PWINDOWTOCHANGETO); PWINDOWTOCHANGETO->warpCursor(); - g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; - g_pInputManager->simulateMouseMovement(); - g_pInputManager->m_pForcedFocus.reset(); + // Move mouse focus to the new window if required by current follow_mouse and warp modes + if (*PNOWARPS == 0 || *PFOLLOWMOUSE < 2) { + g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO; + g_pInputManager->simulateMouseMovement(); + g_pInputManager->m_pForcedFocus.reset(); + } if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) { // event From 4beac91cbd791657cc53d6e483eb41bf4df1ec0c Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 24 Jul 2024 22:19:15 +0000 Subject: [PATCH 0374/2393] keybinds: add safeguard to mousebinds (#7034) modified: src/managers/KeybindManager.cpp --- src/managers/KeybindManager.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 44826fff..caa2b137 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2366,7 +2366,7 @@ void CKeybindManager::mouse(std::string args) { const auto PRESSED = args[0] == '1'; if (ARGS[0] == "movewindow") { - if (PRESSED) { + if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { g_pKeybindManager->m_bIsMouseBindActive = true; const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); @@ -2380,7 +2380,7 @@ void CKeybindManager::mouse(std::string args) { g_pInputManager->dragMode = MBIND_MOVE; g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); - } else { + } else if (!PRESSED && g_pInputManager->dragMode == MBIND_MOVE) { g_pKeybindManager->m_bIsMouseBindActive = false; if (!g_pInputManager->currentlyDraggedWindow.expired()) { @@ -2390,7 +2390,7 @@ void CKeybindManager::mouse(std::string args) { } } } else if (ARGS[0] == "resizewindow") { - if (PRESSED) { + if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { g_pKeybindManager->m_bIsMouseBindActive = true; g_pInputManager->currentlyDraggedWindow = @@ -2404,7 +2404,8 @@ void CKeybindManager::mouse(std::string args) { } } catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; } g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); - } else { + } else if (!PRESSED && + (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO || g_pInputManager->dragMode == MBIND_RESIZE)) { g_pKeybindManager->m_bIsMouseBindActive = false; if (!g_pInputManager->currentlyDraggedWindow.expired()) { From daf5fad19034def8062acfd32e66bea78c62aaff Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 25 Jul 2024 13:02:05 +0200 Subject: [PATCH 0375/2393] keyboard: properly update keymap state and fd on keymap changes needed for virtual keyboards that impose their own layouts. fixes #6991 --- src/devices/IKeyboard.cpp | 42 ++++++++++++++++++++++++--------- src/devices/IKeyboard.hpp | 28 +++++++++++++--------- src/devices/VirtualKeyboard.cpp | 9 +++++-- 3 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 284a8295..09a18477 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -51,6 +51,11 @@ void IKeyboard::clearManuallyAllocd() { } void IKeyboard::setKeymap(const SStringRuleNames& rules) { + if (keymapOverridden) { + Debug::log(LOG, "Ignoring setKeymap: keymap is overridden"); + return; + } + currentRules = rules; xkb_rule_names XKBRULES = { .rules = rules.rules.c_str(), @@ -103,10 +108,6 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS); } - // set internal translation state - // demo sunao ni ienai - xkbStaticState = xkb_state_new(xkbKeymap); - updateXKBTranslationState(xkbKeymap); const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default"); @@ -131,6 +132,20 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i)); } + updateKeymapFD(); + + xkb_context_unref(CONTEXT); + + g_pSeatManager->updateActiveKeyboardData(); +} + +void IKeyboard::updateKeymapFD() { + Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); + + if (xkbKeymapFD >= 0) + close(xkbKeymapFD); + xkbKeymapFD = -1; + auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); xkbKeymapString = cKeymapStr; free(cKeymapStr); @@ -151,21 +166,24 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { } } - xkb_context_unref(CONTEXT); - - g_pSeatManager->updateActiveKeyboardData(); + Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { + if (xkbStaticState) + xkb_state_unref(xkbStaticState); + if (xkbState) xkb_state_unref(xkbState); - xkbState = nullptr; + xkbState = nullptr; + xkbStaticState = nullptr; if (keymap) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); - xkbState = xkb_state_new(keymap); + xkbStaticState = xkb_state_new(keymap); + xkbState = xkb_state_new(keymap); return; } @@ -209,7 +227,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { KEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); } - xkbState = xkb_state_new(KEYMAP); + xkbState = xkb_state_new(KEYMAP); + xkbStaticState = xkb_state_new(KEYMAP); xkb_keymap_unref(KEYMAP); xkb_context_unref(PCONTEXT); @@ -230,7 +249,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - xkbState = xkb_state_new(NEWKEYMAP); + xkbState = xkb_state_new(NEWKEYMAP); + xkbStaticState = xkb_state_new(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP); xkb_context_unref(PCONTEXT); diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 1ae6c7bc..2ff8a190 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -61,18 +61,24 @@ class IKeyboard : public IHID { std::string rules = ""; }; - void setKeymap(const SStringRuleNames& rules); - void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); - std::string getActiveLayout(); - void updateLEDs(); - void updateLEDs(uint32_t leds); - uint32_t getModifiers(); - void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - bool updateModifiersState(); // rets whether changed - void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); + void setKeymap(const SStringRuleNames& rules); + void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); + std::string getActiveLayout(); + void updateLEDs(); + void updateLEDs(uint32_t leds); + uint32_t getModifiers(); + void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + bool updateModifiersState(); // rets whether changed + void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); + void updateKeymapFD(); - bool active = false; - bool enabled = true; + bool active = false; + bool enabled = true; + + // if the keymap is overridden by the implementation, + // don't try to set keyboard rules anymore, to avoid overwriting the requested one. + // e.g. Virtual keyboards with custom maps. + bool keymapOverridden = false; xkb_layout_index_t activeLayout = 0; xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; diff --git a/src/devices/VirtualKeyboard.cpp b/src/devices/VirtualKeyboard.cpp index 654ca9f5..548711c2 100644 --- a/src/devices/VirtualKeyboard.cpp +++ b/src/devices/VirtualKeyboard.cpp @@ -31,8 +31,13 @@ CVirtualKeyboard::CVirtualKeyboard(SP keeb_) : keybo }); }); listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) { - auto E = std::any_cast(d); - xkbKeymap = xkb_keymap_ref(E.keymap); + auto E = std::any_cast(d); + if (xkbKeymap) + xkb_keymap_unref(xkbKeymap); + xkbKeymap = xkb_keymap_ref(E.keymap); + keymapOverridden = true; + updateXKBTranslationState(xkbKeymap); + updateKeymapFD(); keyboardEvents.keymap.emit(d); }); From cd942ad12d9d2030963e3dd5fbfe2d181013c750 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 25 Jul 2024 13:10:53 +0200 Subject: [PATCH 0376/2393] keyboard: update xkb state after key event fixes #6946 --- src/devices/Keyboard.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp index ae28c07d..0a8f6b57 100644 --- a/src/devices/Keyboard.cpp +++ b/src/devices/Keyboard.cpp @@ -32,13 +32,13 @@ CKeyboard::CKeyboard(SP keeb) : keyboard(keeb) { listeners.key = keeb->events.key.registerListener([this](std::any d) { auto E = std::any_cast(d); - updateXkbStateWithKey(E.key + 8, E.pressed); - keyboardEvents.key.emit(SKeyEvent{ .timeMs = E.timeMs, .keycode = E.key, .state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED, }); + + updateXkbStateWithKey(E.key + 8, E.pressed); }); listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) { From a0d15a0b7b066cbb1b08ac54cf882c2c55467e4a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 25 Jul 2024 14:12:08 +0200 Subject: [PATCH 0377/2393] wayland/compositor: release buffers on unmap XWayland does not use the regular commit(null) method to unmap, which results in buffers never being released. release the buffers if present and un-released in the unmap() handler ref #6584 --- src/protocols/core/Compositor.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index f1c83531..a31b1fb4 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -336,6 +336,17 @@ void CWLSurfaceResource::unmap() { mapped = false; events.unmap.emit(); + + // release the buffers. + // this is necessary for XWayland to function correctly, + // as it does not unmap via the traditional commit(null buffer) method, but via the X11 protocol. + if (!bufferReleased && current.buffer) + current.buffer->sendRelease(); + if (pending.buffer) + pending.buffer->sendRelease(); + + pending.buffer.reset(); + current.buffer.reset(); } void CWLSurfaceResource::error(int code, const std::string& str) { From 33a5c8ce325e1657ec5571b57e05c6378706f4cd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 25 Jul 2024 15:29:39 +0200 Subject: [PATCH 0378/2393] config: avoid using initial ws tracking for exec-once --- src/config/ConfigManager.cpp | 2 ++ src/config/ConfigManager.hpp | 8 +++++--- src/managers/KeybindManager.cpp | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5a8f2bd2..657d7aff 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1299,12 +1299,14 @@ void CConfigManager::dispatchExecOnce() { "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"); firstExecDispatched = true; + isLaunchingExecOnce = true; for (auto& c : firstExecRequests) { handleRawExec("", c); } firstExecRequests.clear(); // free some kb of memory :P + isLaunchingExecOnce = false; // set input, fixes some certain issues g_pInputManager->setKeyboardLayout(); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index b4a49b7a..454a12c0 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -129,9 +129,6 @@ class CConfigManager { void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&); - bool m_bWantsMonitorReload = false; - bool m_bForceReload = false; - bool m_bNoMonitorReload = false; void ensureMonitorStatus(); void ensureVRR(CMonitor* pMonitor = nullptr); @@ -192,6 +189,11 @@ class CConfigManager { std::unordered_map*(PHLWINDOW)>> miWindowProperties = { {"rounding", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.rounding; }}, {"bordersize", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.borderSize; }}}; + bool m_bWantsMonitorReload = false; + bool m_bForceReload = false; + bool m_bNoMonitorReload = false; + bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + private: std::unique_ptr m_pConfig; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index caa2b137..22d9c3d7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -36,7 +36,7 @@ using namespace Hyprutils::String; static std::vector> getHyprlandLaunchEnv() { static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); - if (!*PINITIALWSTRACKING) + if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce) return {}; const auto PMONITOR = g_pCompositor->m_pLastMonitor; From 57371b93a058d17affb0ca92f13b8d40582b3ea0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 26 Jul 2024 19:53:24 +0200 Subject: [PATCH 0379/2393] renderer: drastically optimize bg texture creation stop loading 20MB images every time, dumbass --- src/render/OpenGL.cpp | 141 +++++++++++++++++++++++++----------------- src/render/OpenGL.hpp | 3 + 2 files changed, 86 insertions(+), 58 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ab7f566a..5e52403d 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2571,7 +2571,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const textW /= PANGO_SCALE; textH /= PANGO_SCALE; - cairo_move_to(CAIRO, (size.x - textW) / 2.0, size.y - textH * 2 + offsetY); + cairo_move_to(CAIRO, (size.x - textW) / 2.0, size.y - textH - offsetY); pango_cairo_show_layout(CAIRO, layoutText); pango_font_description_free(pangoFD); @@ -2580,16 +2580,48 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } +void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { + const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str()); + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); + + m_pBackgroundTexture = makeShared(); + + m_pBackgroundTexture->allocate(); + m_pBackgroundTexture->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + + const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? +#ifdef GLES2 + GL_RGB32F_EXT : +#else + GL_RGB32F : +#endif + GL_RGBA; + const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; + const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; + + const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + glBindTexture(GL_TEXTURE_2D, m_pBackgroundTexture->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifndef GLES2 + if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); + } +#endif + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, m_pBackgroundTexture->m_vSize.x, m_pBackgroundTexture->m_vSize.y, 0, glFormat, glType, DATA); +} + void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); - static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); - static auto PNOSPLASH = CConfigValue("misc:disable_splash_rendering"); - static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); + Debug::log(LOG, "Creating a texture for BGTex"); - const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); + static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); + static auto PNOSPLASH = CConfigValue("misc:disable_splash_rendering"); + static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); - static std::string texPath = ""; + const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); if (*PRENDERTEX) return; @@ -2599,12 +2631,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { PFB->release(); PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); - Debug::log(LOG, "Allocated texture for BGTex"); - // TODO: use relative paths to the installation - // or configure the paths at build time - if (texPath.empty()) { - texPath = "/usr/share/hyprland/wall"; + if (!m_pBackgroundTexture) { + // TODO: use relative paths to the installation + // or configure the paths at build time + std::string texPath = ""; + texPath = "/usr/share/hyprland/wall"; // get the adequate tex if (FORCEWALLPAPER == -1) { @@ -2625,84 +2657,77 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { if (!std::filesystem::exists(texPath)) return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } + + createBackgroundTexture(texPath); } // create a new one with cairo SP tex = makeShared(); - const auto CAIROISURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROISURFACE); - tex->allocate(); - const Vector2D IMAGESIZE = {cairo_image_surface_get_width(CAIROISURFACE), cairo_image_surface_get_height(CAIROISURFACE)}; - // calc the target box - const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y; - const double WPRATIO = IMAGESIZE.x / IMAGESIZE.y; - - Vector2D origin; - double scale; - - if (MONRATIO > WPRATIO) { - scale = m_RenderData.pMonitor->vecTransformedSize.x / IMAGESIZE.x; - - origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - IMAGESIZE.y * scale) / 2.0; - } else { - scale = m_RenderData.pMonitor->vecTransformedSize.y / IMAGESIZE.y; - - origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - IMAGESIZE.x * scale) / 2.0; - } - - const Vector2D scaledSize = IMAGESIZE * scale; - - const auto CAIROSURFACE = cairo_image_surface_create(CAIROFORMAT, scaledSize.x, scaledSize.y); - const auto CAIRO = cairo_create(CAIROSURFACE); + const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + const auto CAIRO = cairo_create(CAIROSURFACE); cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_GOOD); - cairo_scale(CAIRO, scale, scale); - cairo_rectangle(CAIRO, 0, 0, 100, 100); - cairo_set_source_surface(CAIRO, CAIROISURFACE, 0, 0); + cairo_save(CAIRO); + cairo_set_source_rgba(CAIRO, 0, 0, 0, 0); + cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE); cairo_paint(CAIRO); + cairo_restore(CAIRO); if (!*PNOSPLASH) - renderSplash(CAIRO, CAIROSURFACE, origin.y * WPRATIO / MONRATIO * scale, IMAGESIZE); + renderSplash(CAIRO, CAIROSURFACE, 0.02 * pMonitor->vecPixelSize.y, pMonitor->vecPixelSize); cairo_surface_flush(CAIROSURFACE); - CBox box = {origin.x, origin.y, IMAGESIZE.x * scale, IMAGESIZE.y * scale}; - tex->m_vSize = IMAGESIZE * scale; + tex->m_vSize = pMonitor->vecPixelSize; // copy the data to an OpenGL texture we have - const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? -#ifdef GLES2 - GL_RGB32F_EXT : -#else - GL_RGB32F : -#endif - GL_RGBA; - const GLint glFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA; - const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; + const GLint glFormat = GL_RGBA; + const GLint glType = GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 - if (CAIROFORMAT != CAIRO_FORMAT_RGB96F) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); - cairo_surface_destroy(CAIROISURFACE); cairo_destroy(CAIRO); // render the texture to our fb PFB->bind(); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - renderTextureInternalWithDamage(tex, &box, 1.0, &fakeDamage); + + blend(true); + clear(CColor{0, 0, 0, 1}); + + // first render the background + if (m_pBackgroundTexture) { + const double MONRATIO = m_RenderData.pMonitor->vecTransformedSize.x / m_RenderData.pMonitor->vecTransformedSize.y; + const double WPRATIO = m_pBackgroundTexture->m_vSize.x / m_pBackgroundTexture->m_vSize.y; + Vector2D origin; + double scale = 1.0; + + if (MONRATIO > WPRATIO) { + scale = m_RenderData.pMonitor->vecTransformedSize.x / m_pBackgroundTexture->m_vSize.x; + origin.y = (m_RenderData.pMonitor->vecTransformedSize.y - m_pBackgroundTexture->m_vSize.y * scale) / 2.0; + } else { + scale = m_RenderData.pMonitor->vecTransformedSize.y / m_pBackgroundTexture->m_vSize.y; + origin.x = (m_RenderData.pMonitor->vecTransformedSize.x - m_pBackgroundTexture->m_vSize.x * scale) / 2.0; + } + + CBox texbox = CBox{origin, m_pBackgroundTexture->m_vSize * scale}; + renderTextureInternalWithDamage(m_pBackgroundTexture, &texbox, 1.0, &fakeDamage); + } + + CBox monbox = {{}, pMonitor->vecPixelSize}; + renderTextureInternalWithDamage(tex, &monbox, 1.0, &fakeDamage); // bind back if (m_RenderData.currentFB) diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 5c4ee811..41e80ee5 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -274,6 +274,8 @@ class CHyprOpenGLImpl { CShader m_sFinalScreenShader; CTimer m_tGlobalTimer; + SP m_pBackgroundTexture; + void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); GLuint compileShader(const GLuint&, std::string, bool dynamic = false); @@ -282,6 +284,7 @@ class CHyprOpenGLImpl { void initDRMFormats(); void initEGL(bool gbm); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); + void createBackgroundTexture(const std::string& path); // std::optional> getModsForFormat(EGLint format); From 76610d9fb0ba5a2d495a963773c38b717d76776f Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 13:03:43 +0200 Subject: [PATCH 0380/2393] opengl: destroy cairo image surface after use --- src/render/OpenGL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 5e52403d..39f6614e 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2610,6 +2610,8 @@ void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { } #endif glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, m_pBackgroundTexture->m_vSize.x, m_pBackgroundTexture->m_vSize.y, 0, glFormat, glType, DATA); + + cairo_surface_destroy(CAIROSURFACE); } void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { From 682865632fe986d179ca07e45ae89e65b8058b33 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 13:58:30 +0200 Subject: [PATCH 0381/2393] xwayland: fix high cpu idle usage fixes #7051 --- src/xwayland/XWM.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 498710a4..f6b6864c 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -153,13 +153,16 @@ static bool lookupParentExists(SP XSURF, SP } void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply) { - std::string propName = std::format("{}?", atom); - for (auto& ha : HYPRATOMS) { - if (ha.second != atom) - continue; + std::string propName; + if (Debug::trace) { + propName = std::format("{}?", atom); + for (auto& ha : HYPRATOMS) { + if (ha.second != atom) + continue; - propName = ha.first; - break; + propName = ha.first; + break; + } } if (atom == XCB_ATOM_WM_CLASS) { @@ -536,7 +539,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); - return false; + return true; } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { From 534fdb5a375b65821adce3fec5d1622fc546b8b4 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 27 Jul 2024 15:57:52 +0300 Subject: [PATCH 0382/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index e8f7e259..90d09c39 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721853718, - "narHash": "sha256-QEkCryhEMBW8maWEbwN0LoJIjdt640FviwMeJpghJXM=", + "lastModified": 1721992626, + "narHash": "sha256-GFDSPWxOqEkNrbuSfyoQHGIaRhJNapn2Rv0EEmBGR9A=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "353dc1b7299d43f08de44276b93ae32726ff9d70", + "rev": "f95d1509370b7f40ef356ff69a332bd0356ab044", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1721379653, - "narHash": "sha256-8MUgifkJ7lkZs3u99UDZMB4kbOxvMEXQZ31FO3SopZ0=", + "lastModified": 1721924956, + "narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1d9c2c9b3e71b9ee663d11c5d298727dace8d374", + "rev": "5ad6a14c6bf098e98800b091668718c336effc95", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1721648131, - "narHash": "sha256-cyyxu/oj4QEFp3CVx2WeXa9T4OAUyynuBJHGkBZSxJI=", + "lastModified": 1721755049, + "narHash": "sha256-O17b38bQnmfxv7It3OnVYx7fp1seEdI7xxnw5vJFv30=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "663be9cad424b170b28b9fa8a61042d721007f3b", + "rev": "5555f467f68ce7cdf1060991c24263073b95e9da", "type": "github" }, "original": { From 963816b9a6524a99a6716fa1aa30b2c4f369d2f0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 15:03:52 +0200 Subject: [PATCH 0383/2393] layersurface: fixup focus issues in onUnmap fixes #6929 --- src/desktop/LayerSurface.cpp | 5 ++++- src/desktop/WLSurface.cpp | 9 +++++++++ src/desktop/WLSurface.hpp | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 83b0992f..2252adca 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -212,8 +212,11 @@ void CLayerSurface::onUnmap() { return; // refocus if needed - if (WASLASTFOCUS) + // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window + if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) g_pInputManager->refocusLastWindow(PMONITOR); + else if (g_pCompositor->m_pLastFocus) + g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 90924145..e1348a90 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -1,6 +1,7 @@ #include "WLSurface.hpp" #include "../Compositor.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/LayerShell.hpp" void CWLSurface::assign(SP pSurface) { m_pResource = pSurface; @@ -222,3 +223,11 @@ SP CWLSurface::fromResource(SP pSurface) { return nullptr; return pSurface->hlSurface.lock(); } + +bool CWLSurface::keyboardFocusable() const { + if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner) + return true; + if (m_pLayerOwner) + return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + return false; +} diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index bb476e0f..a962b882 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -39,6 +39,7 @@ class CWLSurface { Vector2D getViewporterCorrectedSize() const; CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned bool visible(); + bool keyboardFocusable() const; // getters for owners. PHLWINDOW getWindow() const; From ec672b1ab95e341a0dcb6679592ae4e5eea9b1cf Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 27 Jul 2024 10:02:02 -0500 Subject: [PATCH 0384/2393] protocols: move screencopy and toplevel export to hyprwayland-scanner (#7065) * move screencopy and toplevel export to hyprwayland-scanner * oops --- CMakeLists.txt | 13 +- protocols/meson.build | 4 +- src/events/Monitors.cpp | 6 +- src/events/Windows.cpp | 3 +- src/managers/ProtocolManager.cpp | 8 +- src/managers/ProtocolManager.hpp | 5 +- src/protocols/Screencopy.cpp | 671 +++++++++++++------------------ src/protocols/Screencopy.hpp | 152 +++---- src/protocols/ToplevelExport.cpp | 526 +++++++++++------------- src/protocols/ToplevelExport.hpp | 103 ++++- src/render/Renderer.hpp | 2 +- 11 files changed, 695 insertions(+), 798 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bd4e0d5..8a27d81b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,17 +288,16 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86 uuid) -protocol("protocols/wlr-screencopy-unstable-v1.xml" - "wlr-screencopy-unstable-v1" true) protocol( "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) -protocol( - "subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" - "hyprland-toplevel-export-v1" true) -protocol("unstable/text-input/text-input-unstable-v1.xml" - "text-input-unstable-v1" false) +protocol( + "unstable/text-input/text-input-unstable-v1.xml" + "text-input-unstable-v1" false) + +protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true) +protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) protocolnew("protocols" "wlr-output-power-management-unstable-v1" true) diff --git a/protocols/meson.build b/protocols/meson.build index 5cdeb160..35b2b29b 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -25,8 +25,6 @@ hyprwayland_scanner = find_program( protocols = [ [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - ['wlr-screencopy-unstable-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] ] @@ -42,6 +40,8 @@ new_protocols = [ ['wlr-layer-shell-unstable-v1.xml'], ['wayland-drm.xml'], ['wlr-data-control-unstable-v1.xml'], + ['wlr-screencopy-unstable-v1.xml'], + [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 40b6f17e..b2778062 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -5,6 +5,8 @@ #include "Events.hpp" #include "../debug/HyprCtl.hpp" #include "../config/ConfigValue.hpp" +#include "../protocols/Screencopy.hpp" +#include "../protocols/ToplevelExport.hpp" #include // --------------------------------------------------------- // @@ -118,8 +120,8 @@ void Events::listener_monitorCommit(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER - g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR); - g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR); + PROTO::screencopy->onOutputCommit(PMONITOR); + PROTO::toplevelExport->onOutputCommit(PMONITOR); } } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a5511e17..0e1037b6 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -10,6 +10,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/ToplevelExport.hpp" #include "../xwayland/XSurface.hpp" #include @@ -601,7 +602,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pEventManager->postEvent(SHyprIPCEvent{"closewindow", std::format("{:x}", PWINDOW)}); EMIT_HOOK_EVENT("closeWindow", PWINDOW); - g_pProtocolManager->m_pToplevelExportProtocolManager->onWindowUnmap(PWINDOW); + PROTO::toplevelExport->onWindowUnmap(PWINDOW); if (PWINDOW->m_bIsFullscreen) g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index ef2260cc..3704befb 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -39,6 +39,8 @@ #include "../protocols/LinuxDMABUF.hpp" #include "../protocols/DRMLease.hpp" #include "../protocols/DRMSyncobj.hpp" +#include "../protocols/Screencopy.hpp" +#include "../protocols/ToplevelExport.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -142,6 +144,8 @@ CProtocolManager::CProtocolManager() { PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); + PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -161,10 +165,8 @@ CProtocolManager::CProtocolManager() { // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. - m_pToplevelExportProtocolManager = std::make_unique(); m_pTextInputV1ProtocolManager = std::make_unique(); m_pGlobalShortcutsProtocolManager = std::make_unique(); - m_pScreencopyProtocolManager = std::make_unique(); } CProtocolManager::~CProtocolManager() { @@ -214,6 +216,8 @@ CProtocolManager::~CProtocolManager() { PROTO::dataWlr.reset(); PROTO::primarySelection.reset(); PROTO::xwaylandShell.reset(); + PROTO::screencopy.reset(); + PROTO::toplevelExport.reset(); PROTO::lease.reset(); PROTO::sync.reset(); diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 6a780bdc..62653e89 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -1,10 +1,9 @@ #pragma once #include "../defines.hpp" -#include "../protocols/ToplevelExport.hpp" #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" -#include "../protocols/Screencopy.hpp" +#include "../helpers/Monitor.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" #include @@ -15,10 +14,8 @@ class CProtocolManager { ~CProtocolManager(); // TODO: rewrite to use the new protocol framework - std::unique_ptr m_pToplevelExportProtocolManager; std::unique_ptr m_pTextInputV1ProtocolManager; std::unique_ptr m_pGlobalShortcutsProtocolManager; - std::unique_ptr m_pScreencopyProtocolManager; private: std::unordered_map m_mModeChangeListeners; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 98cb0be9..a8afba84 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -9,245 +9,39 @@ #include -#define SCREENCOPY_VERSION 3 +#define LOGM PROTO::screencopy->protoLog -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pScreencopyProtocolManager->bindManager(client, data, version, id); +CScreencopyFrame::~CScreencopyFrame() { + if (buffer && buffer->locked()) + buffer->unlock(); } -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - CScreencopyProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); - proto->displayDestroy(); -} +CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t overlay_cursor, wl_resource* output, CBox box_) : resource(resource_) { + if (!good()) + return; -void CScreencopyProtocolManager::displayDestroy() { - wl_list_remove(&m_liDisplayDestroy.link); - wl_list_init(&m_liDisplayDestroy.link); - wl_global_destroy(m_pGlobal); -} + overlayCursor = !!overlay_cursor; + pMonitor = CWLOutputResource::fromResource(output)->monitor.get(); -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); - - if (!m_pGlobal) { - Debug::log(ERR, "ScreencopyProtocolManager could not start! Screensharing will not work!"); + if (!pMonitor) { + LOGM(ERR, "Client requested sharing of a monitor that doesnt exist"); + resource->sendFailed(); + PROTO::screencopy->destroyResource(this); return; } - m_liDisplayDestroy.notify = handleDisplayDestroy; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); - - Debug::log(LOG, "ScreencopyProtocolManager started successfully!"); - - m_pSoftwareCursorTimer = makeShared( - std::nullopt, - [this](SP self, void* data) { - // TODO: make it per-monitor - for (auto& m : g_pCompositor->m_vMonitors) { - g_pPointerManager->unlockSoftwareForMonitor(m); - } - m_bTimerArmed = false; - - Debug::log(LOG, "[screencopy] Releasing software cursor lock"); - }, - nullptr); - g_pEventLoopManager->addTimer(m_pSoftwareCursorTimer); -} - -static void handleCaptureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output) { - g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output); -} - -static void handleCaptureRegion(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, int32_t x, int32_t y, int32_t width, - int32_t height) { - g_pProtocolManager->m_pScreencopyProtocolManager->captureOutput(client, resource, frame, overlay_cursor, output, {x, y, width, height}); -} - -static void handleDestroy(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) { - const auto PFRAME = frameFromResource(resource); - - if (!PFRAME) - return; - - g_pProtocolManager->m_pScreencopyProtocolManager->copyFrame(client, resource, buffer); -} - -static void handleCopyWithDamage(wl_client* client, wl_resource* resource, wl_resource* buffer) { - const auto PFRAME = frameFromResource(resource); - - if (!PFRAME) - return; - - PFRAME->withDamage = true; - handleCopyFrame(client, resource, buffer); -} - -static void handleDestroyFrame(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static const struct zwlr_screencopy_manager_v1_interface screencopyMgrImpl = { - .capture_output = handleCaptureOutput, - .capture_output_region = handleCaptureRegion, - .destroy = handleDestroy, -}; - -static const struct zwlr_screencopy_frame_v1_interface screencopyFrameImpl = { - .copy = handleCopyFrame, - .destroy = handleDestroyFrame, - .copy_with_damage = handleCopyWithDamage, -}; - -static CScreencopyClient* clientFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl)); - return (CScreencopyClient*)wl_resource_get_user_data(resource); -} - -static SScreencopyFrame* frameFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_frame_v1_interface, &screencopyFrameImpl)); - return (SScreencopyFrame*)wl_resource_get_user_data(resource); -} - -void CScreencopyProtocolManager::removeClient(CScreencopyClient* client, bool force) { - if (!client) - return; - - if (!force) { - if (!client || client->ref <= 0) - return; - - if (--client->ref != 0) - return; - } - - m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits??? - - for (auto& f : m_lFrames) { - // avoid dangling ptrs - if (f.client == client) - f.client = nullptr; - } -} - -static void handleManagerResourceDestroy(wl_resource* resource) { - const auto PCLIENT = clientFromResource(resource); - - g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true); -} - -CScreencopyClient::~CScreencopyClient() { - g_pHookSystem->unhook(tickCallback); -} - -CScreencopyClient::CScreencopyClient() { - lastMeasure.reset(); - lastFrame.reset(); - tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); }); -} - -void CScreencopyClient::onTick() { - if (lastMeasure.getMillis() < 500) - return; - - framesInLastHalfSecond = frameCounter; - frameCounter = 0; - lastMeasure.reset(); - - const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0; - const bool FRAMEAWAITING = std::ranges::any_of(g_pProtocolManager->m_pScreencopyProtocolManager->m_lFrames, [&](const auto& frame) { return frame.client == this; }) || - std::ranges::any_of(g_pProtocolManager->m_pToplevelExportProtocolManager->m_lFrames, [&](const auto& frame) { return frame.client == this; }); - - if (framesInLastHalfSecond > 3 && !sentScreencast) { - EMIT_HOOK_EVENT("screencast", (std::vector{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); - g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)}); - sentScreencast = true; - } else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) { - EMIT_HOOK_EVENT("screencast", (std::vector{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); - g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)}); - sentScreencast = false; - } -} - -void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto PCLIENT = &m_lClients.emplace_back(); - - PCLIENT->resource = wl_resource_create(client, &zwlr_screencopy_manager_v1_interface, version, id); - - if (!PCLIENT->resource) { - Debug::log(ERR, "ScreencopyProtocolManager could not bind! (out of memory?)"); - m_lClients.remove(*PCLIENT); - wl_client_post_no_memory(client); - return; - } - - PCLIENT->ref = 1; - - wl_resource_set_implementation(PCLIENT->resource, &screencopyMgrImpl, PCLIENT, handleManagerResourceDestroy); - - Debug::log(LOG, "ScreencopyProtocolManager bound successfully!"); -} - -static void handleFrameResourceDestroy(wl_resource* resource) { - const auto PFRAME = frameFromResource(resource); - - g_pProtocolManager->m_pScreencopyProtocolManager->removeFrame(PFRAME); -} - -void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) { - if (!frame) - return; - - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); - - wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->locked()) - frame->buffer->unlock(); - removeClient(frame->client, force); - m_lFrames.remove(*frame); -} - -void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* output, CBox box) { - const auto PCLIENT = clientFromResource(resource); - - const auto PFRAME = &m_lFrames.emplace_back(); - PFRAME->overlayCursor = !!overlay_cursor; - PFRAME->resource = wl_resource_create(client, &zwlr_screencopy_frame_v1_interface, wl_resource_get_version(resource), frame); - PFRAME->pMonitor = CWLOutputResource::fromResource(output)->monitor.get(); - - if (!PFRAME->pMonitor) { - Debug::log(ERR, "client requested sharing of a monitor that doesnt exist"); - zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); - return; - } - - if (!PFRAME->resource) { - Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)"); - removeFrame(PFRAME); - wl_client_post_no_memory(client); - return; - } - - wl_resource_set_implementation(PFRAME->resource, &screencopyFrameImpl, PFRAME, handleFrameResourceDestroy); - - PFRAME->client = PCLIENT; - PCLIENT->ref++; + resource->setOnDestroy([this](CZwlrScreencopyFrameV1* pMgr) { PROTO::screencopy->destroyResource(this); }); + resource->setDestroy([this](CZwlrScreencopyFrameV1* pFrame) { PROTO::screencopy->destroyResource(this); }); + resource->setCopy([this](CZwlrScreencopyFrameV1* pFrame, wl_resource* res) { this->copy(pFrame, res); }); + resource->setCopyWithDamage([this](CZwlrScreencopyFrameV1* pFrame, wl_resource* res) { + withDamage = true; + this->copy(pFrame, res); + }); g_pHyprRenderer->makeEGLCurrent(); - if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(PFRAME->pMonitor)) { - const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(PFRAME->pMonitor); + if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(pMonitor)) { + const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(pMonitor); // bind the fb for its format. Suppress gl errors. #ifndef GLES2 glBindFramebuffer(GL_READ_FRAMEBUFFER, RDATA.offloadFB.m_iFb); @@ -255,246 +49,212 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r glBindFramebuffer(GL_FRAMEBUFFER, RDATA.offloadFB.m_iFb); #endif } else - Debug::log(ERR, "No RDATA in screencopy???"); + LOGM(ERR, "No RDATA in screencopy???"); - PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PFRAME->pMonitor); - if (PFRAME->shmFormat == DRM_FORMAT_INVALID) { - Debug::log(ERR, "No format supported by renderer in capture output"); - zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor); + if (shmFormat == DRM_FORMAT_INVALID) { + LOGM(ERR, "No format supported by renderer in capture output"); + resource->sendFailed(); + PROTO::screencopy->destroyResource(this); return; } - const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat); if (!PSHMINFO) { - Debug::log(ERR, "No pixel format supported by renderer in capture output"); - zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + LOGM(ERR, "No pixel format supported by renderer in capture output"); + resource->sendFailed(); + PROTO::screencopy->destroyResource(this); return; } - PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat; + dmabufFormat = pMonitor->output->state->state().drmFormat; - if (box.width == 0 && box.height == 0) - PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)}; + if (box_.width == 0 && box_.height == 0) + box = {0, 0, (int)(pMonitor->vecSize.x), (int)(pMonitor->vecSize.y)}; else { - PFRAME->box = box; + box = box_; } - PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y) - .scale(PFRAME->pMonitor->scale) - .round(); + box.transform(wlTransformToHyprutils(pMonitor->transform), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y).scale(pMonitor->scale).round(); - PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); + shmStride = FormatUtils::minStride(PSHMINFO, box.w); - zwlr_screencopy_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + resource->sendBuffer(FormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride); - if (wl_resource_get_version(resource) >= 3) { - if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { - zwlr_screencopy_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height); + if (resource->version() >= 3) { + if (dmabufFormat != DRM_FORMAT_INVALID) { + resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height); } - zwlr_screencopy_frame_v1_send_buffer_done(PFRAME->resource); + resource->sendBufferDone(); } } -void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer) { - const auto PFRAME = frameFromResource(resource); - - if (!PFRAME) { - Debug::log(ERR, "No frame in copyFrame??"); +void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_) { + if (!good()) { + LOGM(ERR, "No frame in copyFrame??"); return; } - if (!g_pCompositor->monitorExists(PFRAME->pMonitor)) { - Debug::log(ERR, "client requested sharing of a monitor that is gone"); - zwlr_screencopy_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + if (!g_pCompositor->monitorExists(pMonitor)) { + LOGM(ERR, "Client requested sharing of a monitor that is gone"); + resource->sendFailed(); + PROTO::screencopy->destroyResource(this); return; } - const auto PBUFFER = CWLBufferResource::fromResource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer_); if (!PBUFFER) { - Debug::log(ERR, "[sc] invalid buffer in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); - removeFrame(PFRAME); + LOGM(ERR, "Invalid buffer in {:x}", (uintptr_t)this); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); + PROTO::screencopy->destroyResource(this); return; } PBUFFER->buffer->lock(); - if (PBUFFER->buffer->size != PFRAME->box.size()) { - Debug::log(ERR, "[sc] invalid dimensions in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); - removeFrame(PFRAME); + if (PBUFFER->buffer->size != box.size()) { + LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); + PROTO::screencopy->destroyResource(this); return; } - if (PFRAME->buffer) { - Debug::log(ERR, "[sc] buffer used in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); - removeFrame(PFRAME); + if (buffer) { + LOGM(ERR, "Buffer used in {:x}", (uintptr_t)this); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); + PROTO::screencopy->destroyResource(this); return; } if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { - PFRAME->bufferDMA = true; + bufferDMA = true; - if (attrs.format != PFRAME->dmabufFormat) { - Debug::log(ERR, "[sc] invalid buffer dma format in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); - removeFrame(PFRAME); + if (attrs.format != dmabufFormat) { + LOGM(ERR, "Invalid buffer dma format in {:x}", (uintptr_t)pFrame); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); + PROTO::screencopy->destroyResource(this); return; } } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { - if (attrs.format != PFRAME->shmFormat) { - Debug::log(ERR, "[sc] invalid buffer shm format in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); - removeFrame(PFRAME); + if (attrs.format != shmFormat) { + LOGM(ERR, "Invalid buffer shm format in {:x}", (uintptr_t)pFrame); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); + PROTO::screencopy->destroyResource(this); return; - } else if ((int)attrs.stride != PFRAME->shmStride) { - Debug::log(ERR, "[sc] invalid buffer shm stride in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); - removeFrame(PFRAME); + } else if ((int)attrs.stride != shmStride) { + LOGM(ERR, "Invalid buffer shm stride in {:x}", (uintptr_t)pFrame); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); + PROTO::screencopy->destroyResource(this); return; } } else { - Debug::log(ERR, "[sc] invalid buffer type in {:x}", (uintptr_t)PFRAME); - wl_resource_post_error(PFRAME->resource, ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type"); - removeFrame(PFRAME); + LOGM(ERR, "Invalid buffer type in {:x}", (uintptr_t)pFrame); + resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type"); + PROTO::screencopy->destroyResource(this); return; } - PFRAME->buffer = PBUFFER->buffer; + buffer = PBUFFER->buffer; - m_vFramesAwaitingWrite.emplace_back(PFRAME); + PROTO::screencopy->m_vFramesAwaitingWrite.emplace_back(self); g_pHyprRenderer->m_bDirectScanoutBlocked = true; - if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) { - PFRAME->lockedSWCursors = true; + if (overlayCursor && !lockedSWCursors) { + lockedSWCursors = true; // TODO: make it per-monitor - if (!m_bTimerArmed) { + if (!PROTO::screencopy->m_bTimerArmed) { for (auto& m : g_pCompositor->m_vMonitors) { g_pPointerManager->lockSoftwareForMonitor(m); } - m_bTimerArmed = true; - Debug::log(LOG, "[screencopy] Locking sw cursors due to screensharing"); + PROTO::screencopy->m_bTimerArmed = true; + LOGM(LOG, "Locking sw cursors due to screensharing"); } - m_pSoftwareCursorTimer->updateTimeout(std::chrono::seconds(1)); + PROTO::screencopy->m_pSoftwareCursorTimer->updateTimeout(std::chrono::seconds(1)); } - if (!PFRAME->withDamage) - g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); + if (!withDamage) + g_pHyprRenderer->damageMonitor(pMonitor); } -void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) { - m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer; - shareAllFrames(pMonitor); - m_pLastMonitorBackBuffer.reset(); -} - -void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { - if (m_vFramesAwaitingWrite.empty()) - return; // nothing to share - - std::vector framesToRemove; - - // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { - if (!f->pMonitor || !f->buffer) { - framesToRemove.push_back(f); - continue; - } - - if (f->pMonitor != pMonitor) - continue; - - shareFrame(f); - - f->client->lastFrame.reset(); - ++f->client->frameCounter; - - framesToRemove.push_back(f); - } - - for (auto& f : framesToRemove) { - removeFrame(f); - } - - if (m_vFramesAwaitingWrite.empty()) { - g_pHyprRenderer->m_bDirectScanoutBlocked = false; - } -} - -void CScreencopyProtocolManager::shareFrame(SScreencopyFrame* frame) { - if (!frame->buffer) +void CScreencopyFrame::share() { + if (!buffer || !pMonitor) return; timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t flags = 0; - if (frame->bufferDMA) { - if (!copyFrameDmabuf(frame)) { - Debug::log(ERR, "[sc] dmabuf copy failed in {:x}", (uintptr_t)frame); - zwlr_screencopy_frame_v1_send_failed(frame->resource); + if (bufferDMA) { + if (!copyDmabuf()) { + LOGM(ERR, "Dmabuf copy failed in {:x}", (uintptr_t)this); + resource->sendFailed(); return; } } else { - if (!copyFrameShm(frame, &now)) { - Debug::log(ERR, "[sc] shm copy failed in {:x}", (uintptr_t)frame); - zwlr_screencopy_frame_v1_send_failed(frame->resource); + if (!copyShm()) { + LOGM(ERR, "Shm copy failed in {:x}", (uintptr_t)this); + resource->sendFailed(); return; } } - zwlr_screencopy_frame_v1_send_flags(frame->resource, flags); - sendFrameDamage(frame); + resource->sendFlags((zwlrScreencopyFrameV1Flags)0); + if (withDamage) { + // TODO: add a damage ring for this. + resource->sendDamage(0, 0, buffer->size.x, buffer->size.y); + } + uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; - zwlr_screencopy_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec); + resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec); } -void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { - if (!frame->withDamage) - return; +bool CScreencopyFrame::copyDmabuf() { + auto TEXTURE = makeShared(pMonitor->output->state->state().buffer); - // TODO: - // add a damage ring for this. + CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - // for (auto& RECT : frame->pMonitor->lastFrameDamage.getRects()) { + if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) { + LOGM(ERR, "Can't copy: failed to begin rendering to dma frame"); + return false; + } - // if (frame->buffer->width < 1 || frame->buffer->height < 1 || frame->buffer->width - RECT.x1 < 1 || frame->buffer->height - RECT.y1 < 1) { - // Debug::log(ERR, "[sc] Failed to send damage"); - // break; - // } + CBox monbox = CBox{0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y} + .translate({-box.x, -box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. + .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + g_pHyprOpenGL->setMonitorTransformEnabled(true); + g_pHyprOpenGL->setRenderModifEnabled(false); + g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); + g_pHyprOpenGL->setRenderModifEnabled(true); + g_pHyprOpenGL->setMonitorTransformEnabled(false); - // zwlr_screencopy_frame_v1_send_damage(frame->resource, std::clamp(RECT.x1, 0, frame->buffer->width), std::clamp(RECT.y1, 0, frame->buffer->height), - // std::clamp(RECT.x2 - RECT.x1, 0, frame->buffer->width - RECT.x1), std::clamp(RECT.y2 - RECT.y1, 0, frame->buffer->height - RECT.y1)); - // } + g_pHyprOpenGL->m_RenderData.blockScreenShader = true; + g_pHyprRenderer->endRender(); - zwlr_screencopy_frame_v1_send_damage(frame->resource, 0, 0, frame->buffer->size.x, frame->buffer->size.y); + LOGM(TRACE, "Copied frame via dma"); + + return true; } -bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); +bool CScreencopyFrame::copyShm() { + auto TEXTURE = makeShared(pMonitor->output->state->state().buffer); - auto shm = frame->buffer->shm(); - auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm + auto shm = buffer->shm(); + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat); + fb.alloc(box.w, box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : pMonitor->output->state->state().drmFormat); - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { - Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering"); + if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { + LOGM(ERR, "Can't copy: failed to begin rendering"); return false; } - CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y}); + CBox monbox = CBox{0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}.translate({-box.x, -box.y}); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); @@ -509,7 +269,7 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { - Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format"); + LOGM(ERR, "Can't copy: failed to find a pixel format"); g_pHyprRenderer->endRender(); return false; } @@ -520,53 +280,164 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprRenderer->endRender(); g_pHyprRenderer->makeEGLCurrent(); - g_pHyprOpenGL->m_RenderData.pMonitor = frame->pMonitor; + g_pHyprOpenGL->m_RenderData.pMonitor = pMonitor; fb.bind(); glPixelStorei(GL_PACK_ALIGNMENT, 1); const auto drmFmt = FormatUtils::getPixelFormatFromDRM(shm.format); - uint32_t packStride = FormatUtils::minStride(drmFmt, frame->box.w); + uint32_t packStride = FormatUtils::minStride(drmFmt, box.w); if (packStride == (uint32_t)shm.stride) { - glReadPixels(0, 0, frame->box.w, frame->box.h, glFormat, PFORMAT->glType, pixelData); + glReadPixels(0, 0, box.w, box.h, glFormat, PFORMAT->glType, pixelData); } else { - for (size_t i = 0; i < frame->box.h; ++i) { + for (size_t i = 0; i < box.h; ++i) { uint32_t y = i; - glReadPixels(0, y, frame->box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride); + glReadPixels(0, y, box.w, 1, glFormat, PFORMAT->glType, ((unsigned char*)pixelData) + i * shm.stride); } } g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - Debug::log(TRACE, "Screencopy: copied frame via shm"); + LOGM(TRACE, "Copied frame via shm"); return true; } -bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { - auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); +bool CScreencopyFrame::good() { + return resource->resource(); +} - CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; +CScreencopyClient::~CScreencopyClient() { + g_pHookSystem->unhook(tickCallback); +} - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) { - Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame"); - return false; +CScreencopyClient::CScreencopyClient(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CZwlrScreencopyManagerV1* pMgr) { PROTO::screencopy->destroyResource(this); }); + resource->setOnDestroy([this](CZwlrScreencopyManagerV1* pMgr) { PROTO::screencopy->destroyResource(this); }); + resource->setCaptureOutput( + [this](CZwlrScreencopyManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* output) { this->captureOutput(frame, overlayCursor, output, {}); }); + resource->setCaptureOutputRegion([this](CZwlrScreencopyManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* output, int32_t x, int32_t y, int32_t w, + int32_t h) { this->captureOutput(frame, overlayCursor, output, {x, y, w, h}); }); + + lastMeasure.reset(); + lastFrame.reset(); + tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); }); +} + +void CScreencopyClient::captureOutput(uint32_t frame, int32_t overlayCursor_, wl_resource* output, CBox box) { + const auto FRAME = PROTO::screencopy->m_vFrames.emplace_back( + makeShared(makeShared(resource->client(), resource->version(), frame), overlayCursor_, output, box)); + + if (!FRAME->good()) { + LOGM(ERR, "Couldn't alloc frame for sharing! (no memory)"); + resource->noMemory(); + PROTO::screencopy->destroyResource(FRAME.get()); + return; } - CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} - .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. - .transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); - g_pHyprOpenGL->setMonitorTransformEnabled(true); - g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); - g_pHyprOpenGL->setRenderModifEnabled(true); - g_pHyprOpenGL->setMonitorTransformEnabled(false); - - g_pHyprOpenGL->m_RenderData.blockScreenShader = true; - g_pHyprRenderer->endRender(); - - Debug::log(TRACE, "Screencopy: copied frame via dma"); - - return true; + FRAME->self = FRAME; + FRAME->client = self; +} + +void CScreencopyClient::onTick() { + if (lastMeasure.getMillis() < 500) + return; + + framesInLastHalfSecond = frameCounter; + frameCounter = 0; + lastMeasure.reset(); + + const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0; + const bool FRAMEAWAITING = std::ranges::any_of(PROTO::screencopy->m_vFrames, [&](const auto& frame) { return frame->client.get() == this; }); + + if (framesInLastHalfSecond > 3 && !sentScreencast) { + EMIT_HOOK_EVENT("screencast", (std::vector{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)}); + sentScreencast = true; + } else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) { + EMIT_HOOK_EVENT("screencast", (std::vector{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)}); + sentScreencast = false; + } +} + +bool CScreencopyClient::good() { + return resource->resource(); +} + +CScreencopyProtocol::CScreencopyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + m_pSoftwareCursorTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + // TODO: make it per-monitor + for (auto& m : g_pCompositor->m_vMonitors) { + g_pPointerManager->unlockSoftwareForMonitor(m); + } + m_bTimerArmed = false; + + LOGM(LOG, "Releasing software cursor lock"); + }, + nullptr); + g_pEventLoopManager->addTimer(m_pSoftwareCursorTimer); +} + +void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto CLIENT = m_vClients.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!CLIENT->good()) { + LOGM(LOG, "Failed to bind client! (out of memory)"); + CLIENT->resource->noMemory(); + m_vClients.pop_back(); + return; + } + + CLIENT->self = CLIENT; + + LOGM(LOG, "Bound client successfully!"); +} + +void CScreencopyProtocol::destroyResource(CScreencopyClient* client) { + std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); + std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); +} + +void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) { + std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); +} + +void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { + if (m_vFramesAwaitingWrite.empty()) { + g_pHyprRenderer->m_bDirectScanoutBlocked = false; + return; // nothing to share + } + + std::vector> framesToRemove; + + // share frame if correct output + for (auto& f : m_vFramesAwaitingWrite) { + if (!f->pMonitor || !f->buffer) { + framesToRemove.push_back(f); + continue; + } + + if (f->pMonitor != pMonitor) + continue; + + f->share(); + + f->client->lastFrame.reset(); + ++f->client->frameCounter; + + framesToRemove.push_back(f); + } + + for (auto& f : framesToRemove) { + destroyResource(f.get()); + } } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index d564e432..cbc56edb 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -1,7 +1,8 @@ #pragma once #include "../defines.hpp" -#include "wlr-screencopy-unstable-v1-protocol.h" +#include "wlr-screencopy-unstable-v1.hpp" +#include "WaylandProtocol.hpp" #include #include @@ -20,88 +21,93 @@ enum eClientOwners { class CScreencopyClient { public: - CScreencopyClient(); + CScreencopyClient(SP resource_); ~CScreencopyClient(); - int ref = 0; - wl_resource* resource = nullptr; + bool good(); - eClientOwners clientOwner = CLIENT_SCREENCOPY; + WP self; + eClientOwners clientOwner = CLIENT_SCREENCOPY; - int frameCounter = 0; - int framesInLastHalfSecond = 0; - CTimer lastMeasure; - CTimer lastFrame; - bool sentScreencast = false; - - void onTick(); - SP tickCallback; - - bool operator==(const CScreencopyClient& other) const { - return resource == other.resource; - } -}; - -struct SScreencopyFrame { - wl_resource* resource = nullptr; - CScreencopyClient* client = nullptr; - - uint32_t shmFormat = 0; - uint32_t dmabufFormat = 0; - CBox box = {}; - int shmStride = 0; - - bool overlayCursor = false; - bool withDamage = false; - bool lockedSWCursors = false; - - bool bufferDMA = false; - - WP buffer; - - CMonitor* pMonitor = nullptr; - PHLWINDOWREF pWindow; - - bool operator==(const SScreencopyFrame& other) const { - return resource == other.resource && client == other.client; - } -}; - -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 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 onOutputCommit(CMonitor* pMonitor); - - wl_listener m_liDisplayDestroy; + CTimer lastFrame; + int frameCounter = 0; private: - wl_global* m_pGlobal = nullptr; - std::list m_lFrames; - std::list m_lClients; + SP resource; - SP m_pSoftwareCursorTimer; - bool m_bTimerArmed = false; + int framesInLastHalfSecond = 0; + CTimer lastMeasure; + bool sentScreencast = false; - std::vector m_vFramesAwaitingWrite; + SP tickCallback; + void onTick(); - SP m_pLastMonitorBackBuffer; + void captureOutput(uint32_t frame, int32_t overlayCursor, wl_resource* output, CBox box); - void shareAllFrames(CMonitor* pMonitor); - void shareFrame(SScreencopyFrame* frame); - void sendFrameDamage(SScreencopyFrame* frame); - bool copyFrameDmabuf(SScreencopyFrame* frame); - bool copyFrameShm(SScreencopyFrame* frame, timespec* now); + friend class CScreencopyProtocol; +}; +class CScreencopyFrame { + public: + CScreencopyFrame(SP resource, int32_t overlay_cursor, wl_resource* output, CBox box); + ~CScreencopyFrame(); + + bool good(); + + SP self; + WP client; + + private: + SP resource; + + CMonitor* pMonitor = nullptr; + bool overlayCursor = false; + bool withDamage = false; + bool lockedSWCursors = false; + + WP buffer; + bool bufferDMA = false; + uint32_t shmFormat = 0; + uint32_t dmabufFormat = 0; + int shmStride = 0; + CBox box = {}; + + void copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer); + bool copyDmabuf(); + bool copyShm(); + void share(); + + friend class CScreencopyProtocol; +}; + +class CScreencopyProtocol : public IWaylandProtocol { + public: + CScreencopyProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void destroyResource(CScreencopyClient* resource); + void destroyResource(CScreencopyFrame* resource); + + void onOutputCommit(CMonitor* pMonitor); + + private: + std::vector> m_vFrames; + std::vector> m_vFramesAwaitingWrite; + std::vector> m_vClients; + + SP m_pSoftwareCursorTimer; + bool m_bTimerArmed = false; + + void shareAllFrames(CMonitor* pMonitor); + void shareFrame(CScreencopyFrame* frame); + void sendFrameDamage(CScreencopyFrame* frame); + bool copyFrameDmabuf(CScreencopyFrame* frame); + bool copyFrameShm(CScreencopyFrame* frame, timespec* now); + + friend class CScreencopyFrame; friend class CScreencopyClient; }; + +namespace PROTO { + inline UP screencopy; +}; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 28f49c6a..fb3fde2b 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -8,363 +8,240 @@ #include -#define TOPLEVEL_EXPORT_VERSION 2 +#define LOGM PROTO::toplevelExport->protoLog -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pToplevelExportProtocolManager->bindManager(client, data, version, id); -} - -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - 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 - Debug::log(WARN, "Toplevel sharing is not supported on LEGACY_RENDERER!"); - return; -#endif - - m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_toplevel_export_manager_v1_interface, TOPLEVEL_EXPORT_VERSION, this, bindManagerInt); - - if (!m_pGlobal) { - Debug::log(ERR, "ToplevelExportManager could not start! Sharing windows will not work!"); - return; - } - - m_liDisplayDestroy.notify = handleDisplayDestroy; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); - - Debug::log(LOG, "ToplevelExportManager started successfully!"); -} - -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, PROTO::foreignToplevelWlr->windowFromHandleResource(handle)); -} - -static void handleDestroy(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static void handleCopyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) { - g_pProtocolManager->m_pToplevelExportProtocolManager->copyFrame(client, resource, buffer, ignore_damage); -} - -static void handleDestroyFrame(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static const struct hyprland_toplevel_export_manager_v1_interface toplevelExportManagerImpl = { - .capture_toplevel = handleCaptureToplevel, - .destroy = handleDestroy, - .capture_toplevel_with_wlr_toplevel_handle = handleCaptureToplevelWithWlr, -}; - -static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame}; - -// -static CScreencopyClient* clientFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl)); - return (CScreencopyClient*)wl_resource_get_user_data(resource); -} - -static SScreencopyFrame* frameFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl)); - return (SScreencopyFrame*)wl_resource_get_user_data(resource); -} - -void CToplevelExportProtocolManager::removeClient(CScreencopyClient* client, bool force) { - if (!force) { - if (!client || client->ref <= 0) - return; - - if (--client->ref != 0) - return; - } - - m_lClients.remove(*client); // TODO: this doesn't get cleaned up after sharing app exits??? -} - -static void handleManagerResourceDestroy(wl_resource* resource) { - const auto PCLIENT = clientFromResource(resource); - - g_pProtocolManager->m_pToplevelExportProtocolManager->removeClient(PCLIENT, true); -} - -void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto PCLIENT = &m_lClients.emplace_back(); - - PCLIENT->clientOwner = CLIENT_TOPLEVEL_EXPORT; - PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id); - - if (!PCLIENT->resource) { - Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)"); - m_lClients.remove(*PCLIENT); - wl_client_post_no_memory(client); - return; - } - - PCLIENT->ref = 1; - - wl_resource_set_implementation(PCLIENT->resource, &toplevelExportManagerImpl, PCLIENT, handleManagerResourceDestroy); - - Debug::log(LOG, "ToplevelExportManager bound successfully!"); -} - -static void handleFrameResourceDestroy(wl_resource* resource) { - const auto PFRAME = frameFromResource(resource); - - g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME); -} - -void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) { - if (!frame) +CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { + if (!good()) return; - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; }); + resource->setOnDestroy([this](CHyprlandToplevelExportManagerV1* pMgr) { PROTO::toplevelExport->destroyResource(this); }); + resource->setDestroy([this](CHyprlandToplevelExportManagerV1* pMgr) { PROTO::toplevelExport->destroyResource(this); }); + resource->setCaptureToplevel([this](CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, uint32_t handle) { + this->captureToplevel(pMgr, frame, overlayCursor, g_pCompositor->getWindowFromHandle(handle)); + }); + resource->setCaptureToplevelWithWlrToplevelHandle([this](CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, wl_resource* handle) { + this->captureToplevel(pMgr, frame, overlayCursor, PROTO::foreignToplevelWlr->windowFromHandleResource(handle)); + }); - wl_resource_set_user_data(frame->resource, nullptr); - if (frame->buffer && frame->buffer->locked() > 0) - frame->buffer->unlock(); - removeClient(frame->client, force); - m_lFrames.remove(*frame); + lastMeasure.reset(); + lastFrame.reset(); + tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, SCallbackInfo& info, std::any data) { onTick(); }); } -void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, PHLWINDOW pWindow) { - const auto PCLIENT = clientFromResource(resource); - +void CToplevelExportClient::captureToplevel(CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor_, PHLWINDOW handle) { // create a frame - const auto PFRAME = &m_lFrames.emplace_back(); - PFRAME->overlayCursor = !!overlay_cursor; - PFRAME->resource = wl_resource_create(client, &hyprland_toplevel_export_frame_v1_interface, wl_resource_get_version(resource), frame); - PFRAME->pWindow = pWindow; + const auto FRAME = PROTO::toplevelExport->m_vFrames.emplace_back( + makeShared(makeShared(resource->client(), resource->version(), frame), overlayCursor_, handle)); + + if (!FRAME->good()) { + LOGM(ERR, "Couldn't alloc frame for sharing! (no memory)"); + resource->noMemory(); + PROTO::toplevelExport->destroyResource(FRAME.get()); + return; + } + + FRAME->self = FRAME; + FRAME->client = self; +} + +void CToplevelExportClient::onTick() { + if (lastMeasure.getMillis() < 500) + return; + + framesInLastHalfSecond = frameCounter; + frameCounter = 0; + lastMeasure.reset(); + + const auto LASTFRAMEDELTA = lastFrame.getMillis() / 1000.0; + const bool FRAMEAWAITING = std::ranges::any_of(PROTO::toplevelExport->m_vFrames, [&](const auto& frame) { return frame->client.get() == this; }); + + if (framesInLastHalfSecond > 3 && !sentScreencast) { + EMIT_HOOK_EVENT("screencast", (std::vector{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)}); + sentScreencast = true; + } else if (framesInLastHalfSecond < 4 && sentScreencast && LASTFRAMEDELTA > 1.0 && !FRAMEAWAITING) { + EMIT_HOOK_EVENT("screencast", (std::vector{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner})); + g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)}); + sentScreencast = false; + } +} + +bool CToplevelExportClient::good() { + return resource->resource(); +} + +CToplevelExportFrame::~CToplevelExportFrame() { + if (buffer && buffer->locked()) + buffer->unlock(); +} + +CToplevelExportFrame::CToplevelExportFrame(SP resource_, int32_t overlayCursor_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { + if (!good()) + return; + + overlayCursor = !!overlayCursor_; if (!pWindow) { - Debug::log(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow); - hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + LOGM(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } if (!pWindow->m_bIsMapped || pWindow->isHidden()) { - Debug::log(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow); - hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } - if (!PFRAME->resource) { - Debug::log(ERR, "Couldn't alloc frame for sharing! (no memory)"); - m_lFrames.remove(*PFRAME); - wl_client_post_no_memory(client); - return; - } - - wl_resource_set_implementation(PFRAME->resource, &toplevelFrameImpl, PFRAME, handleFrameResourceDestroy); - - PFRAME->client = PCLIENT; - PCLIENT->ref++; + resource->setOnDestroy([this](CHyprlandToplevelExportFrameV1* pFrame) { PROTO::toplevelExport->destroyResource(this); }); + resource->setDestroy([this](CHyprlandToplevelExportFrameV1* pFrame) { PROTO::toplevelExport->destroyResource(this); }); + resource->setCopy([this](CHyprlandToplevelExportFrameV1* pFrame, wl_resource* res, int32_t ignoreDamage) { this->copy(pFrame, res, ignoreDamage); }); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); g_pHyprRenderer->makeEGLCurrent(); - PFRAME->shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR); - if (PFRAME->shmFormat == DRM_FORMAT_INVALID) { - Debug::log(ERR, "No format supported by renderer in capture toplevel"); - hyprland_toplevel_export_frame_v1_send_failed(resource); - removeFrame(PFRAME); + shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR); + if (shmFormat == DRM_FORMAT_INVALID) { + LOGM(ERR, "No format supported by renderer in capture toplevel"); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } - const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(PFRAME->shmFormat); + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat); if (!PSHMINFO) { - Debug::log(ERR, "No pixel format supported by renderer in capture toplevel"); - hyprland_toplevel_export_frame_v1_send_failed(resource); - removeFrame(PFRAME); + LOGM(ERR, "No pixel format supported by renderer in capture toplevel"); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } - PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat; + dmabufFormat = PMONITOR->output->state->state().drmFormat; - PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; + box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; - PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); + box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); - PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); + shmStride = FormatUtils::minStride(PSHMINFO, box.w); - hyprland_toplevel_export_frame_v1_send_buffer(PFRAME->resource, FormatUtils::drmToShm(PFRAME->shmFormat), PFRAME->box.width, PFRAME->box.height, PFRAME->shmStride); + resource->sendBuffer(FormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride); - if (PFRAME->dmabufFormat != DRM_FORMAT_INVALID) { - hyprland_toplevel_export_frame_v1_send_linux_dmabuf(PFRAME->resource, PFRAME->dmabufFormat, PFRAME->box.width, PFRAME->box.height); + if (dmabufFormat != DRM_FORMAT_INVALID) { + resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height); } - hyprland_toplevel_export_frame_v1_send_buffer_done(PFRAME->resource); + resource->sendBufferDone(); } -void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage) { - const auto PFRAME = frameFromResource(resource); - - if (!PFRAME) { - Debug::log(ERR, "No frame in copyFrame??"); +void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resource* buffer_, int32_t ignoreDamage) { + if (!good()) { + LOGM(ERR, "No frame in copyFrame??"); return; } - const auto PWINDOW = PFRAME->pWindow.lock(); - - if (!validMapped(PWINDOW)) { - Debug::log(ERR, "Client requested sharing of window handle {:x} which is gone!", PWINDOW); - hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + if (!validMapped(pWindow)) { + LOGM(ERR, "Client requested sharing of window handle {:x} which is gone!", pWindow); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } - if (!PWINDOW->m_bIsMapped || PWINDOW->isHidden()) { - Debug::log(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", PWINDOW); - hyprland_toplevel_export_frame_v1_send_failed(PFRAME->resource); - removeFrame(PFRAME); + if (!pWindow->m_bIsMapped || pWindow->isHidden()) { + LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", pWindow); + resource->sendFailed(); + PROTO::toplevelExport->destroyResource(this); return; } - const auto PBUFFER = CWLBufferResource::fromResource(buffer); + const auto PBUFFER = CWLBufferResource::fromResource(buffer_); if (!PBUFFER) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); - removeFrame(PFRAME); + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); + PROTO::toplevelExport->destroyResource(this); return; } PBUFFER->buffer->lock(); - if (PBUFFER->buffer->size != PFRAME->box.size()) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); - removeFrame(PFRAME); + if (PBUFFER->buffer->size != box.size()) { + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); + PROTO::toplevelExport->destroyResource(this); return; } - if (PFRAME->buffer) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); - removeFrame(PFRAME); + if (buffer) { + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); + PROTO::toplevelExport->destroyResource(this); return; } if (auto attrs = PBUFFER->buffer->dmabuf(); attrs.success) { - PFRAME->bufferDMA = true; + bufferDMA = true; - if (attrs.format != PFRAME->dmabufFormat) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); - removeFrame(PFRAME); + if (attrs.format != dmabufFormat) { + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); + PROTO::toplevelExport->destroyResource(this); return; } } else if (auto attrs = PBUFFER->buffer->shm(); attrs.success) { - if (attrs.format != PFRAME->shmFormat) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); - removeFrame(PFRAME); + if (attrs.format != shmFormat) { + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer format"); + PROTO::toplevelExport->destroyResource(this); return; - } else if ((int)attrs.stride != PFRAME->shmStride) { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); - removeFrame(PFRAME); + } else if ((int)attrs.stride != shmStride) { + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer stride"); + PROTO::toplevelExport->destroyResource(this); return; } } else { - wl_resource_post_error(PFRAME->resource, HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type"); - removeFrame(PFRAME); + resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer type"); + PROTO::toplevelExport->destroyResource(this); return; } - PFRAME->buffer = PBUFFER->buffer; + buffer = PBUFFER->buffer; - m_vFramesAwaitingWrite.emplace_back(PFRAME); + PROTO::toplevelExport->m_vFramesAwaitingWrite.emplace_back(self); } -void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) { - if (m_vFramesAwaitingWrite.empty()) - return; // nothing to share - - std::vector framesToRemove; - - // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { - const auto PWINDOW = f->pWindow.lock(); - - if (!validMapped(PWINDOW)) { - framesToRemove.push_back(f); - continue; - } - - if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) - continue; - - CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; - - if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) - continue; - - shareFrame(f); - - f->client->lastFrame.reset(); - ++f->client->frameCounter; - - framesToRemove.push_back(f); - } - - for (auto& f : framesToRemove) { - removeFrame(f); - } -} - -void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) { - if (!frame->buffer || !validMapped(frame->pWindow)) +void CToplevelExportFrame::share() { + if (!buffer || !validMapped(pWindow)) return; timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t flags = 0; - if (frame->bufferDMA) { - if (!copyFrameDmabuf(frame, &now)) { - hyprland_toplevel_export_frame_v1_send_failed(frame->resource); + if (bufferDMA) { + if (!copyDmabuf(&now)) { + resource->sendFailed(); return; } } else { - if (!copyFrameShm(frame, &now)) { - hyprland_toplevel_export_frame_v1_send_failed(frame->resource); + if (!copyShm(&now)) { + resource->sendFailed(); return; } } - hyprland_toplevel_export_frame_v1_send_flags(frame->resource, flags); - sendDamage(frame); + resource->sendFlags((hyprlandToplevelExportFrameV1Flags)0); + + if (!ignoreDamage) { + resource->sendDamage(0, 0, box.width, box.height); + } + uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; - hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec); + resource->sendReady(tvSecHi, tvSecLo, now.tv_nsec); } -void CToplevelExportProtocolManager::sendDamage(SScreencopyFrame* frame) { - // TODO: send proper dmg - hyprland_toplevel_export_frame_v1_send_damage(frame->resource, 0, 0, frame->box.width, frame->box.height); -} - -bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - auto shm = frame->buffer->shm(); - auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm +bool CToplevelExportFrame::copyShm(timespec* now) { + auto shm = buffer->shm(); + auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm // render the client - const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10}; g_pHyprRenderer->makeEGLCurrent(); @@ -372,7 +249,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times CFramebuffer outFB; outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); - if (frame->overlayCursor) { + if (overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); g_pPointerManager->damageCursor(PMONITOR->self.lock()); } @@ -383,12 +260,12 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); // render client at 0,0 - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow.lock()); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(frame->pWindow.lock(), PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); g_pHyprRenderer->m_bBlockSurfaceFeedback = false; - if (frame->overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + if (overlayCursor) + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { @@ -410,9 +287,9 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times glPixelStorei(GL_PACK_ALIGNMENT, 1); auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; - glReadPixels(0, 0, frame->box.width, frame->box.height, glFormat, PFORMAT->glType, pixelData); + glReadPixels(0, 0, box.width, box.height, glFormat, PFORMAT->glType, pixelData); - if (frame->overlayCursor) { + if (overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); g_pPointerManager->damageCursor(PMONITOR->self.lock()); } @@ -420,31 +297,112 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times return true; } -bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, timespec* now) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(frame->pWindow->m_iMonitorID); +bool CToplevelExportFrame::copyDmabuf(timespec* now) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock())) + if (overlayCursor) { + g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } + + if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock())) return false; g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(frame->pWindow.lock()); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(frame->pWindow.lock(), PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); g_pHyprRenderer->m_bBlockSurfaceFeedback = false; - if (frame->overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value()); + if (overlayCursor) + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); + + if (overlayCursor) { + g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); + g_pPointerManager->damageCursor(PMONITOR->self.lock()); + } + return true; } -void CToplevelExportProtocolManager::onWindowUnmap(PHLWINDOW pWindow) { - for (auto& f : m_lFrames) { - if (f.pWindow.lock() == pWindow) - f.pWindow.reset(); +bool CToplevelExportFrame::good() { + return resource->resource(); +} + +CToplevelExportProtocol::CToplevelExportProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto CLIENT = m_vClients.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!CLIENT->good()) { + LOGM(LOG, "Failed to bind client! (out of memory)"); + wl_client_post_no_memory(client); + m_vClients.pop_back(); + return; + } + + CLIENT->self = CLIENT; + + LOGM(LOG, "Bound client successfully!"); +} + +void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) { + std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); + std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); +} + +void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) { + std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); +} + +void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { + if (m_vFramesAwaitingWrite.empty()) + return; // nothing to share + + std::vector> framesToRemove; + + // share frame if correct output + for (auto& f : m_vFramesAwaitingWrite) { + if (!f->pWindow || !validMapped(f->pWindow)) { + framesToRemove.push_back(f); + continue; + } + + const auto PWINDOW = f->pWindow; + + if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) + continue; + + CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; + + if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) + continue; + + f->share(); + + f->client->lastFrame.reset(); + ++f->client->frameCounter; + + framesToRemove.push_back(f); + } + + for (auto& f : framesToRemove) { + destroyResource(f.get()); + } +} + +void CToplevelExportProtocol::onWindowUnmap(PHLWINDOW pWindow) { + for (auto& f : m_vFrames) { + if (f->pWindow == pWindow) + f->pWindow.reset(); } } diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 71a6df18..638b69f0 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -1,7 +1,8 @@ #pragma once #include "../defines.hpp" -#include "hyprland-toplevel-export-v1-protocol.h" +#include "hyprland-toplevel-export-v1.hpp" +#include "WaylandProtocol.hpp" #include "Screencopy.hpp" #include @@ -10,33 +11,91 @@ class CMonitor; class CWindow; -class CToplevelExportProtocolManager { +class CToplevelExportClient { public: - CToplevelExportProtocolManager(); - ~CToplevelExportProtocolManager(); + CToplevelExportClient(SP resource_); - 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); + bool good(); - wl_listener m_liDisplayDestroy; + WP self; + eClientOwners clientOwner = CLIENT_TOPLEVEL_EXPORT; + + CTimer lastFrame; + int frameCounter = 0; private: - wl_global* m_pGlobal = nullptr; - std::list m_lFrames; - std::list m_lClients; + SP resource; - std::vector m_vFramesAwaitingWrite; + int framesInLastHalfSecond = 0; + CTimer lastMeasure; + bool sentScreencast = false; - void shareFrame(SScreencopyFrame* frame); - bool copyFrameDmabuf(SScreencopyFrame* frame, timespec* now); - bool copyFrameShm(SScreencopyFrame* frame, timespec* now); - void sendDamage(SScreencopyFrame* frame); + SP tickCallback; + void onTick(); - friend class CScreencopyClient; + void captureToplevel(CHyprlandToplevelExportManagerV1* pMgr, uint32_t frame, int32_t overlayCursor, PHLWINDOW handle); + + friend class CToplevelExportProtocol; +}; + +class CToplevelExportFrame { + public: + CToplevelExportFrame(SP resource_, int32_t overlayCursor, PHLWINDOW pWindow); + ~CToplevelExportFrame(); + + bool good(); + + SP self; + WP client; + + private: + SP resource; + + PHLWINDOW pWindow; + bool overlayCursor = false; + bool ignoreDamage = false; + bool lockedSWCursors = false; + + WP buffer; + bool bufferDMA = false; + uint32_t shmFormat = 0; + uint32_t dmabufFormat = 0; + int shmStride = 0; + CBox box = {}; + + void copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resource* buffer, int32_t ignoreDamage); + bool copyDmabuf(timespec* now); + bool copyShm(timespec* now); + void share(); + + friend class CToplevelExportProtocol; +}; + +class CToplevelExportProtocol : IWaylandProtocol { + public: + CToplevelExportProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void destroyResource(CToplevelExportClient* client); + void destroyResource(CToplevelExportFrame* frame); + + void onWindowUnmap(PHLWINDOW pWindow); + void onOutputCommit(CMonitor* pMonitor); + + private: + std::vector> m_vClients; + std::vector> m_vFrames; + std::vector> m_vFramesAwaitingWrite; + + void shareFrame(CToplevelExportFrame* frame); + bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now); + bool copyFrameShm(CToplevelExportFrame* frame, timespec* now); + void sendDamage(CToplevelExportFrame* frame); + + friend class CToplevelExportClient; + friend class CToplevelExportFrame; +}; + +namespace PROTO { + inline UP toplevelExport; }; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 72efe8c4..a9397cac 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -139,7 +139,7 @@ class CHyprRenderer { std::vector> m_vRenderbuffers; friend class CHyprOpenGLImpl; - friend class CToplevelExportProtocolManager; + friend class CToplevelExportFrame; friend class CInputManager; friend class CPointerManager; }; From daed75219fa7b4ec345337ec99f816e94bda338c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 17:03:49 +0200 Subject: [PATCH 0385/2393] wayland/compositor: fixup double buffer releases fixes #7043 --- src/protocols/core/Compositor.cpp | 19 ++++++++----------- src/protocols/core/Compositor.hpp | 3 --- src/protocols/types/WLBuffer.cpp | 1 + src/protocols/types/WLBuffer.hpp | 2 ++ 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index a31b1fb4..76907cc2 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -79,6 +79,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr; pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; pending.texture = res && res->buffer ? res->buffer->texture : nullptr; + if (res) + res->released = false; } Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; @@ -86,8 +88,6 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso if (oldBufSize != newBufSize || current.buffer != pending.buffer) pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; - - bufferReleased = false; }); resource->setCommit([this](CWlSurface* r) { @@ -340,9 +340,9 @@ void CWLSurfaceResource::unmap() { // release the buffers. // this is necessary for XWayland to function correctly, // as it does not unmap via the traditional commit(null buffer) method, but via the X11 protocol. - if (!bufferReleased && current.buffer) + if (current.buffer && !current.buffer->resource->released) current.buffer->sendRelease(); - if (pending.buffer) + if (pending.buffer && !pending.buffer->resource->released) pending.buffer->sendRelease(); pending.buffer.reset(); @@ -420,15 +420,13 @@ void CWLSurfaceResource::commitPendingState() { if (current.buffer && current.buffer->texture) current.buffer->texture->m_eTransform = wlTransformToHyprutils(current.transform); - if (current.buffer && !bufferReleased) { + if (current.buffer && !current.buffer->resource->released) { current.buffer->update(accumulateCurrentBufferDamage()); // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->isSynchronous()) { + if (current.buffer->isSynchronous()) current.buffer->sendReleaseWithSurface(self.lock()); - bufferReleased = true; - } } // TODO: we should _accumulate_ and not replace above if sync @@ -453,7 +451,7 @@ void CWLSurfaceResource::commitPendingState() { } // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { + if (previousBuffer && !previousBuffer->isSynchronous() && !previousBuffer->resource->released) { if (previousBuffer->lockedByBackend) { previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { if (!self.expired()) // could be dead in the dtor @@ -461,12 +459,11 @@ void CWLSurfaceResource::commitPendingState() { else previousBuffer->sendRelease(); previousBuffer->hlEvents.backendRelease.reset(); - bufferReleased = true; }); } else previousBuffer->sendReleaseWithSurface(self.lock()); - bufferReleased = true; + previousBuffer->resource->released = true; // set it here regardless so we dont set more listeners for backendRelease } } diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 5e6413c8..85bd0d37 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -134,9 +134,6 @@ class CWLSurfaceResource { SP resource; wl_client* pClient = nullptr; - // tracks whether we should release the buffer - bool bufferReleased = false; - int stateLocks = 0; void destroy(); diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index d34a867d..e42094b1 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -29,6 +29,7 @@ bool CWLBufferResource::good() { } void CWLBufferResource::sendRelease() { + released = true; resource->sendRelease(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index 59512128..f4424abc 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -24,6 +24,8 @@ class CWLBufferResource { WP self; + bool released = false; + private: CWLBufferResource(SP resource_); From 84227eb587688596b63a5b48848d32083d9680cf Mon Sep 17 00:00:00 2001 From: MahouShoujoMivutilde <14999778+MahouShoujoMivutilde@users.noreply.github.com> Date: Sat, 27 Jul 2024 18:43:45 +0300 Subject: [PATCH 0386/2393] input: Fix `hyprctl switchxkblayout` not actually changing layout (#7070) Emits `SModifiersEvent` in `updateModifiers()` Before the patch: Changing layout with `hyprctl switchxkblayout ...` results in: * active keymap in `hyprctl devices` is changed * no event * no layout is actually changed UNTIL you press one of the mod keys (Alt | Shift | Super | Ctrl) After: * active keymap in `hyprctl devices` changed * activelayout IPC event emitted * layout is changed This fixes https://github.com/hyprwm/Hyprland/issues/7044 --- src/devices/IKeyboard.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 09a18477..e3517bf1 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -325,6 +325,13 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l if (!updateModifiersState()) return; + keyboardEvents.modifiers.emit(SModifiersEvent{ + .depressed = modifiersState.depressed, + .latched = modifiersState.latched, + .locked = modifiersState.locked, + .group = modifiersState.group, + }); + updateLEDs(); } From 729b47d46d0c749efbffe01ea863a124fad562b4 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 17:49:27 +0200 Subject: [PATCH 0387/2393] input: refocus last window on keyboard unfocusable surfaces fixes #4460 --- src/managers/input/InputManager.cpp | 7 +++++++ src/protocols/core/Compositor.hpp | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e2c62367..7d2e7a0e 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -17,6 +17,7 @@ #include "../../protocols/LayerShell.hpp" #include "../../protocols/core/Seat.hpp" #include "../../protocols/core/DataDevice.hpp" +#include "../../protocols/core/Compositor.hpp" #include "../../protocols/XDGShell.hpp" #include "../../devices/Mouse.hpp" @@ -1382,6 +1383,12 @@ void CInputManager::refocusLastWindow(CMonitor* pMonitor) { g_pCompositor->focusWindow(PLASTWINDOW); } else { // otherwise fall back to a normal refocus. + + if (foundSurface && !foundSurface->hlSurface->keyboardFocusable()) { + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + g_pCompositor->focusWindow(PLASTWINDOW); + } + refocus(); } } diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 85bd0d37..1fa6926a 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -134,11 +134,11 @@ class CWLSurfaceResource { SP resource; wl_client* pClient = nullptr; - int stateLocks = 0; + int stateLocks = 0; - void destroy(); - void commitPendingState(); - void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); + void destroy(); + void commitPendingState(); + void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); }; class CWLCompositorResource { From 024327154425c76a2932d644d76990a00b5fcdac Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 18:08:22 +0200 Subject: [PATCH 0388/2393] layer-shell: properly map and unmap surface and propagate unmap events --- src/desktop/LayerSurface.cpp | 4 ++++ src/protocols/LayerShell.cpp | 2 ++ src/protocols/LayerShell.hpp | 1 + 3 files changed, 7 insertions(+) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 2252adca..f3db4b61 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -119,6 +119,8 @@ void CLayerSurface::onMap() { mapped = true; interactivity = layerSurface->current.interactivity; + layerSurface->surface->map(); + // this layer might be re-mapped. fadingOut = false; g_pCompositor->removeFromFadingOutSafe(self.lock()); @@ -190,6 +192,7 @@ void CLayerSurface::onUnmap() { g_pCompositor->addToFadingOutSafe(self.lock()); mapped = false; + layerSurface->surface->unmap(); startAnimation(false); return; @@ -201,6 +204,7 @@ void CLayerSurface::onUnmap() { startAnimation(false); mapped = false; + layerSurface->surface->unmap(); g_pCompositor->addToFadingOutSafe(self.lock()); diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 4e733b35..e018c3d0 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -38,6 +38,8 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPdestroyResource(this); }); + listeners.unmapSurface = surf_->events.unmap.registerListener([this](std::any d) { events.unmap.emit(); }); + listeners.commitSurface = surf_->events.commit.registerListener([this](std::any d) { current = pending; pending.committed = 0; diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 221d95c0..ee0b7859 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -70,6 +70,7 @@ class CLayerShellResource : public ISurfaceRole { struct { CHyprSignalListener commitSurface; CHyprSignalListener destroySurface; + CHyprSignalListener unmapSurface; } listeners; bool closed = false; From 141cd09bd3315aedc075d451fd120a9504886ec1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 18:13:41 +0200 Subject: [PATCH 0389/2393] renderer: use session lock alpha for rendering lacking locks --- src/render/Renderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d8de7ba8..0bf4c9f3 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -824,8 +824,9 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSessionLockPresent()) { // locked with no exclusive, draw only red - CBox boxe = {0, 0, INT16_MAX, INT16_MAX}; - g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, 1.0)); + CBox boxe = {0, 0, INT16_MAX, INT16_MAX}; + const float A = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); + g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, A)); return; } From ae638d997d45e6183adafc6942b1b8fcc70f8928 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 18:15:47 +0200 Subject: [PATCH 0390/2393] configmgr: fix warning --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 657d7aff..65eab579 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -642,7 +642,7 @@ std::optional CConfigManager::generateConfig(std::string configPath Debug::log(WARN, "Creating config home directory"); try { std::filesystem::create_directories(parentPath); - } catch (std::exception e) { throw e; } + } catch (std::exception& e) { throw e; } } Debug::log(WARN, "No config file found; attempting to generate."); From ad711ef421fea4cfe03661ebebd465d070925437 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Sat, 27 Jul 2024 16:46:19 +0000 Subject: [PATCH 0391/2393] input: unify removing currentlyDraggedWindow (#7071) modified: src/desktop/Window.cpp modified: src/events/Windows.cpp modified: src/layout/IHyprLayout.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/KeybindManager.hpp modified: src/managers/input/InputManager.cpp --- src/desktop/Window.cpp | 8 +-- src/events/Windows.cpp | 3 + src/layout/IHyprLayout.cpp | 13 ++-- src/managers/KeybindManager.cpp | 108 ++++++++++++---------------- src/managers/KeybindManager.hpp | 3 +- src/managers/input/InputManager.cpp | 2 +- 6 files changed, 58 insertions(+), 79 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7497957a..f635d367 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -477,13 +477,7 @@ void unregisterVar(void* ptr) { void CWindow::onUnmap() { static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); - - if (g_pCompositor->m_pLastWindow.lock().get() == this) - g_pCompositor->m_pLastWindow.reset(); - if (g_pInputManager->currentlyDraggedWindow.lock().get() == this) - g_pInputManager->currentlyDraggedWindow.reset(); - - static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); + static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); if (!m_szInitialWorkspaceToken.empty()) { const auto TOKEN = g_pTokenManager->getToken(m_szInitialWorkspaceToken); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 0e1037b6..b2abb65c 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -627,6 +627,9 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pInputManager->releaseAllMouseButtons(); } + if (PWINDOW == g_pInputManager->currentlyDraggedWindow.lock()) + g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); + // remove the fullscreen window status from workspace if we closed it const auto PWORKSPACE = PWINDOW->m_pWorkspace; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 528cea72..0738b71c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -187,7 +187,7 @@ void IHyprLayout::onBeginDragWindow() { // Window will be floating. Let's check if it's valid. It should be, but I don't like crashing. if (!validMapped(DRAGGINGWINDOW)) { Debug::log(ERR, "Dragging attempted on an invalid window!"); - g_pInputManager->currentlyDraggedWindow.reset(); + g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); return; } @@ -200,7 +200,7 @@ void IHyprLayout::onBeginDragWindow() { if (PWORKSPACE->m_bHasFullscreenWindow && (!DRAGGINGWINDOW->m_bCreatedOverFullscreen || !DRAGGINGWINDOW->m_bIsFloating)) { Debug::log(LOG, "Rejecting drag on a fullscreen workspace. (window under fullscreen)"); - g_pInputManager->currentlyDraggedWindow.reset(); + g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); return; } @@ -288,7 +288,6 @@ void IHyprLayout::onEndDragWindow() { } g_pInputManager->unsetCursorImage(); - g_pInputManager->currentlyDraggedWindow.reset(); g_pInputManager->m_bWasDraggingWindow = true; @@ -325,12 +324,14 @@ void IHyprLayout::onEndDragWindow() { } void IHyprLayout::onMouseMove(const Vector2D& mousePos) { + if (g_pInputManager->currentlyDraggedWindow.expired()) + return; + const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); // Window invalid or drag begin size 0,0 meaning we rejected it. - if (!validMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D()) { - onEndDragWindow(); - g_pInputManager->currentlyDraggedWindow.reset(); + if ((!validMapped(DRAGGINGWINDOW) || m_vBeginDragSizeXY == Vector2D())) { + g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); return; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 22d9c3d7..038f6401 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -242,27 +242,14 @@ void CKeybindManager::updateXKBTranslationState() { } bool CKeybindManager::ensureMouseBindState() { - if (!m_bIsMouseBindActive) + if (!g_pInputManager->currentlyDraggedWindow) return false; if (!g_pInputManager->currentlyDraggedWindow.expired()) { - PHLWINDOW lastDraggedWindow = g_pInputManager->currentlyDraggedWindow.lock(); - - m_bIsMouseBindActive = false; - g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); - g_pInputManager->currentlyDraggedWindow.reset(); - g_pInputManager->dragMode = MBIND_INVALID; - - g_pCompositor->updateWorkspaceWindows(lastDraggedWindow->workspaceID()); - g_pCompositor->updateWorkspaceWindowData(lastDraggedWindow->workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(lastDraggedWindow->m_iMonitorID); - g_pCompositor->updateAllWindowsAnimatedDecorationValues(); - + changeMouseBindMode(MBIND_INVALID); return true; } - m_bIsMouseBindActive = false; - return false; } @@ -540,10 +527,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { } void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) { - if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) - mouse("1resizewindow"); - else - mouse("0resizewindow"); + changeMouseBindMode(e.state == WL_POINTER_BUTTON_STATE_PRESSED ? MBIND_RESIZE : MBIND_INVALID); } void CKeybindManager::onSwitchEvent(const std::string& switchName) { @@ -971,7 +955,8 @@ static void toggleActiveFloatingCore(std::string args, std::optional float return; // remove drag status - g_pInputManager->currentlyDraggedWindow.reset(); + if (!g_pInputManager->currentlyDraggedWindow.expired()) + g_pKeybindManager->changeMouseBindMode(MBIND_INVALID); if (PWINDOW->m_sGroupData.pNextWindow.lock() && PWINDOW->m_sGroupData.pNextWindow.lock() != PWINDOW) { const auto PCURRENT = PWINDOW->getGroupCurrent(); @@ -2365,55 +2350,50 @@ void CKeybindManager::mouse(std::string args) { const auto ARGS = CVarList(args.substr(1), 2, ' '); const auto PRESSED = args[0] == '1'; + if (!PRESSED) { + changeMouseBindMode(MBIND_INVALID); + return; + } + if (ARGS[0] == "movewindow") { - if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { - g_pKeybindManager->m_bIsMouseBindActive = true; - - const auto mouseCoords = g_pInputManager->getMouseCoordsInternal(); - PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); - - if (pWindow && !pWindow->m_bIsFullscreen) - pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_START, mouseCoords); - - if (g_pInputManager->currentlyDraggedWindow.expired()) - g_pInputManager->currentlyDraggedWindow = pWindow; - - g_pInputManager->dragMode = MBIND_MOVE; - g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); - } else if (!PRESSED && g_pInputManager->dragMode == MBIND_MOVE) { - g_pKeybindManager->m_bIsMouseBindActive = false; - - if (!g_pInputManager->currentlyDraggedWindow.expired()) { - g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); - g_pInputManager->currentlyDraggedWindow.reset(); - g_pInputManager->dragMode = MBIND_INVALID; + changeMouseBindMode(MBIND_MOVE); + } else { + try { + switch (std::stoi(ARGS[1])) { + case 1: changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break; + case 2: changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break; + default: changeMouseBindMode(MBIND_RESIZE); } - } - } else if (ARGS[0] == "resizewindow") { - if (PRESSED && g_pInputManager->dragMode == MBIND_INVALID) { - g_pKeybindManager->m_bIsMouseBindActive = true; + } catch (std::exception& e) { changeMouseBindMode(MBIND_RESIZE); } + } +} - g_pInputManager->currentlyDraggedWindow = - g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); +void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { + if (MODE != MBIND_INVALID) { + if (!g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode != MBIND_INVALID) + return; - try { - switch (std::stoi(ARGS[1])) { - case 1: g_pInputManager->dragMode = MBIND_RESIZE_FORCE_RATIO; break; - case 2: g_pInputManager->dragMode = MBIND_RESIZE_BLOCK_RATIO; break; - default: g_pInputManager->dragMode = MBIND_RESIZE; - } - } catch (std::exception& e) { g_pInputManager->dragMode = MBIND_RESIZE; } - g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); - } else if (!PRESSED && - (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO || g_pInputManager->dragMode == MBIND_RESIZE)) { - g_pKeybindManager->m_bIsMouseBindActive = false; + const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); + const PHLWINDOW PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); - if (!g_pInputManager->currentlyDraggedWindow.expired()) { - g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); - g_pInputManager->currentlyDraggedWindow.reset(); - g_pInputManager->dragMode = MBIND_INVALID; - } - } + if (!PWINDOW) + return; + + if (!PWINDOW->m_bIsFullscreen && MODE == MBIND_MOVE) + PWINDOW->checkInputOnDecos(INPUT_TYPE_DRAG_START, MOUSECOORDS); + + if (g_pInputManager->currentlyDraggedWindow.expired()) + g_pInputManager->currentlyDraggedWindow = PWINDOW; + + g_pInputManager->dragMode = MODE; + + g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); + } else { + if (g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode == MBIND_INVALID) + return; + + g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); + g_pInputManager->dragMode = MODE; } } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 7201df04..26a6345b 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -105,6 +105,8 @@ class CKeybindManager { //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) std::unordered_map m_mKeyToCodeCache; + static void changeMouseBindMode(const eMouseBindMode mode); + private: std::deque m_dPressedKeys; @@ -116,7 +118,6 @@ class CKeybindManager { uint32_t m_uLastCode = 0; uint32_t m_uLastMouseCode = 0; - bool m_bIsMouseBindActive = false; std::vector m_vPressedSpecialBinds; int m_iPassPressed = -1; // used for pass diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 7d2e7a0e..619bfab7 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1677,7 +1677,7 @@ void CInputManager::releaseAllMouseButtons() { void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { // do not override cursor icons set by mouse binds - if (g_pKeybindManager->m_bIsMouseBindActive) { + if (g_pInputManager->currentlyDraggedWindow.expired()) { m_eBorderIconDirection = BORDERICON_NONE; return; } From 10e8af00d61ee2d647af82712c4070eaec875cdb Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 27 Jul 2024 19:51:43 +0300 Subject: [PATCH 0392/2393] flake.lock: update hyprutils --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 90d09c39..a42f8fe9 100644 --- a/flake.lock +++ b/flake.lock @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1721324102, - "narHash": "sha256-WAZ0X6yJW1hFG6otkHBfyJDKRpNP5stsRqdEuHrFRpk=", + "lastModified": 1722098849, + "narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "962582a090bc233c4de9d9897f46794280288989", + "rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f", "type": "github" }, "original": { From 55ceca4cdd8f4b3980d2840b85f6b91778a24eab Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 27 Jul 2024 20:32:11 +0300 Subject: [PATCH 0393/2393] flake.lock: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a42f8fe9..422b0cf7 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1721992626, - "narHash": "sha256-GFDSPWxOqEkNrbuSfyoQHGIaRhJNapn2Rv0EEmBGR9A=", + "lastModified": 1722100913, + "narHash": "sha256-75Hcx5Zu0f+BeCkZxN1frkYacjbkwgCq+z3doVgr4Hw=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "f95d1509370b7f40ef356ff69a332bd0356ab044", + "rev": "4918e57979bbdbd05aabb20f63e1cb5dc289bcbd", "type": "github" }, "original": { From 04b40ea2ec85dd1d74ff18edc046a233b65024ac Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 27 Jul 2024 22:17:05 +0300 Subject: [PATCH 0394/2393] CI: only run once for PRs with branches from original repo (#7075) --- .github/workflows/ci.yaml | 5 +++++ .github/workflows/nix-ci.yml | 2 +- .github/workflows/security-checks.yml | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6d25e027..7739d2b2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,6 +3,7 @@ name: Build Hyprland on: [push, pull_request, workflow_dispatch] jobs: gcc: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Build Hyprland (Arch)" runs-on: ubuntu-latest container: @@ -44,6 +45,7 @@ jobs: path: Hyprland.tar.xz meson: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Build Hyprland with Meson (Arch)" runs-on: ubuntu-latest container: @@ -64,6 +66,7 @@ jobs: run: ninja -C build no-pch: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Build Hyprland without precompiled headers (Arch)" runs-on: ubuntu-latest container: @@ -83,6 +86,7 @@ jobs: run: make nopch noxwayland: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Build Hyprland in pure Wayland (Arch)" runs-on: ubuntu-latest container: @@ -103,6 +107,7 @@ jobs: run: make release clang-format: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Code Style (Arch)" runs-on: ubuntu-latest container: diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index a66307c4..b25ed9aa 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -9,7 +9,7 @@ jobs: secrets: inherit build: - if: always() && !cancelled() && !contains(needs.*.result, 'failure') + if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure') needs: update-inputs uses: ./.github/workflows/nix-build.yml secrets: inherit diff --git a/.github/workflows/security-checks.yml b/.github/workflows/security-checks.yml index 564013cf..4f539132 100644 --- a/.github/workflows/security-checks.yml +++ b/.github/workflows/security-checks.yml @@ -4,6 +4,7 @@ on: [push, pull_request] jobs: flawfinder: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: Flawfinder Checks runs-on: ubuntu-latest permissions: From 6edfdd63a1fc87a6d874364c404c9b6f852c7096 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 27 Jul 2024 22:07:57 +0200 Subject: [PATCH 0395/2393] surface: avoid crashes on fading out layers --- src/desktop/WLSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index e1348a90..3c91a142 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -227,7 +227,7 @@ SP CWLSurface::fromResource(SP pSurface) { bool CWLSurface::keyboardFocusable() const { if (m_pWindowOwner || m_pPopupOwner || m_pSubsurfaceOwner) return true; - if (m_pLayerOwner) + if (m_pLayerOwner && m_pLayerOwner->layerSurface) return m_pLayerOwner->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; return false; } From bc86afea7e177a7ad4335737417fc0e468698dc4 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sat, 27 Jul 2024 13:43:01 -0700 Subject: [PATCH 0396/2393] xdg-shell: completely rewrite xdg-positioner (#7067) This implementation actually works. --- CMakeLists.txt | 2 +- src/desktop/Popup.cpp | 10 +- src/desktop/Popup.hpp | 4 +- src/meson.build | 2 +- src/protocols/XDGShell.cpp | 199 +++++++++++++++++-------------------- src/protocols/XDGShell.hpp | 23 +++-- 6 files changed, 114 insertions(+), 126 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a27d81b..d9411075 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ pkg_check_modules( gbm hyprlang>=0.3.2 hyprcursor>=0.1.7 - hyprutils>=0.2.0) + hyprutils>=0.2.1) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 131a26b5..e48b7400 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -22,7 +22,7 @@ CPopup::CPopup(SP popup, CPopup* pOwner) : m_pParent(pOwner), m_pWindowOwner = pOwner->m_pWindowOwner; m_vLastSize = popup->surface->current.geometry.size(); - unconstrain(); + reposition(); initAllSignals(); } @@ -188,18 +188,18 @@ void CPopup::onReposition() { m_vLastPos = coordsRelativeToParent(); - unconstrain(); + reposition(); } -void CPopup::unconstrain() { +void CPopup::reposition() { const auto COORDS = t1ParentCoords(); const auto PMONITOR = g_pCompositor->getMonitorFromVector(COORDS); if (!PMONITOR) return; - CBox box = {PMONITOR->vecPosition.x - COORDS.x, PMONITOR->vecPosition.y - COORDS.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - m_pResource->applyPositioning(box, COORDS - PMONITOR->vecPosition); + CBox box = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + m_pResource->applyPositioning(box, COORDS); } Vector2D CPopup::coordsRelativeToParent() { diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index d045cd41..eea3fb84 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -74,11 +74,11 @@ class CPopup { } listeners; void initAllSignals(); - void unconstrain(); + void reposition(); void recheckChildrenRecursive(); void sendScale(); Vector2D localToGlobal(const Vector2D& rel); Vector2D t1ParentCoords(); static void bfHelper(std::vector nodes, std::function fn, void* data); -}; \ No newline at end of file +}; diff --git a/src/meson.build b/src/meson.build index 71854fa4..098d8298 100644 --- a/src/meson.build +++ b/src/meson.build @@ -14,7 +14,7 @@ executable('Hyprland', src, dependency('cairo'), dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), - dependency('hyprutils', version: '>= 0.2.0'), + dependency('hyprutils', version: '>= 0.2.1'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 8276ed55..4b180617 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -8,6 +8,20 @@ #define LOGM PROTO::xdgShell->protoLog +void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) { + anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT); + anchor.setLeft(edges == XDG_POSITIONER_ANCHOR_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); + anchor.setBottom(edges == XDG_POSITIONER_ANCHOR_BOTTOM || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); + anchor.setRight(edges == XDG_POSITIONER_ANCHOR_RIGHT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); +} + +void SXDGPositionerState::setGravity(xdgPositionerGravity edges) { + gravity.setTop(edges == XDG_POSITIONER_GRAVITY_TOP || edges == XDG_POSITIONER_GRAVITY_TOP_LEFT || edges == XDG_POSITIONER_GRAVITY_TOP_RIGHT); + gravity.setLeft(edges == XDG_POSITIONER_GRAVITY_LEFT || edges == XDG_POSITIONER_GRAVITY_TOP_LEFT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT); + gravity.setBottom(edges == XDG_POSITIONER_GRAVITY_BOTTOM || edges == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); + gravity.setRight(edges == XDG_POSITIONER_GRAVITY_RIGHT || edges == XDG_POSITIONER_GRAVITY_TOP_RIGHT || edges == XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); +} + CXDGPopupResource::CXDGPopupResource(SP resource_, SP owner_, SP surface_, SP positioner) : surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) { if (!good()) @@ -490,9 +504,9 @@ CXDGPositionerResource::CXDGPositionerResource(SP resource_, SP< resource->setSetOffset([this](CXdgPositioner* r, int32_t x, int32_t y) { state.offset = {x, y}; }); - resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.anchor = a; }); + resource->setSetAnchor([this](CXdgPositioner* r, xdgPositionerAnchor a) { state.setAnchor(a); }); - resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.gravity = g; }); + resource->setSetGravity([this](CXdgPositioner* r, xdgPositionerGravity g) { state.setGravity(g); }); resource->setSetConstraintAdjustment([this](CXdgPositioner* r, xdgPositionerConstraintAdjustment a) { state.constraintAdjustment = (uint32_t)a; }); @@ -513,125 +527,96 @@ CXDGPositionerRules::CXDGPositionerRules(SP positioner) state = positioner->state; } -static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) { - switch (anchor) { - case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, 0.0}; - case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.0 - predictionSize.x / 2.0, box.size().y}; - case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0.0, box.size().y / 2.0 - predictionSize.y / 2.0}; - case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.0}; - case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos(); - case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0.0, box.size().y}; - case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0.0}; - case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y}; - default: return box.pos(); - } - - return {}; -} - -CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& parentCoord) { - +CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoord) { Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord); - CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.requestedSize, state.anchor) + state.offset, state.requestedSize}; + // padding + constraint.expand(-4); - bool success = predictedBox.inside(constraint); + auto anchorRect = state.anchorRect.copy().translate(parentCoord); - if (success) - return predictedBox.translate(-parentCoord - constraint.pos()); + auto width = state.requestedSize.x; + auto height = state.requestedSize.y; - CBox test = predictedBox; + auto anchorX = state.anchor.left() ? anchorRect.x : state.anchor.right() ? anchorRect.extent().x : anchorRect.middle().x; + auto anchorY = state.anchor.top() ? anchorRect.y : state.anchor.bottom() ? anchorRect.extent().y : anchorRect.middle().y; - if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y)) { - // attempt to flip - const bool flipX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X; - const bool flipY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; - auto countEdges = [constraint](const CBox& test) -> int { - int edgeCount = 0; - edgeCount += test.x < constraint.x ? 1 : 0; - edgeCount += test.x + test.w > constraint.x + constraint.w ? 1 : 0; - edgeCount += test.y < constraint.y ? 1 : 0; - edgeCount += test.y + test.h > constraint.y + constraint.h ? 1 : 0; - return edgeCount; - }; - int edgeCount = countEdges(test); + auto calcEffectiveX = [&]() { return state.gravity.left() ? anchorX - width : state.gravity.right() ? anchorX : anchorX - width / 2; }; + auto calcEffectiveY = [&]() { return state.gravity.top() ? anchorY - height : state.gravity.bottom() ? anchorY : anchorY - height / 2; }; - if (flipX && edgeCount > countEdges(test.copy().translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0}))) - test.translate(Vector2D{-predictedBox.w - state.anchorRect.w, 0.0}); - if (flipY && edgeCount > countEdges(test.copy().translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h}))) - test.translate(Vector2D{0.0, -predictedBox.h - state.anchorRect.h}); + auto effectiveX = calcEffectiveX(); + auto effectiveY = calcEffectiveY(); - success = test.copy().expand(-1).inside(constraint); + // Note: the usage of offset is a guess which maintains compatibility with other compositors that were tested. + // It considers the offset when deciding whether or not to flip but does not actually flip the offset, instead + // applying it after the flip step. - if (success) - return test.translate(-parentCoord - constraint.pos()); - } + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) { + auto flip = (state.gravity.left() && effectiveX + state.offset.x < constraint.x) || (state.gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x); - // for slide and resize, defines the padding around the edge for the positioned - // surface. - constexpr int EDGE_PADDING = 4; - - if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y)) { - // attempt to slide - const bool slideX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X; - const bool slideY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; - - //const bool gravityLeft = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_BOTTOM_LEFT; - //const bool gravityTop = state.gravity == XDG_POSITIONER_GRAVITY_NONE || state.gravity == XDG_POSITIONER_GRAVITY_TOP || state.gravity == XDG_POSITIONER_GRAVITY_TOP_LEFT || state.gravity == XDG_POSITIONER_GRAVITY_TOP_RIGHT; - - const bool leftEdgeOut = test.x < constraint.x; - const bool topEdgeOut = test.y < constraint.y; - const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w; - const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h; - - // TODO: this isn't truly conformant. - if (leftEdgeOut && slideX) - test.x = constraint.x + EDGE_PADDING; - if (rightEdgeOut && slideX) - test.x = std::clamp((double)(constraint.x + constraint.w - test.w), (double)(constraint.x + EDGE_PADDING), (double)INFINITY); - if (topEdgeOut && slideY) - test.y = constraint.y + EDGE_PADDING; - if (bottomEdgeOut && slideY) - test.y = std::clamp((double)(constraint.y + constraint.h - test.h), (double)(constraint.y + EDGE_PADDING), (double)INFINITY); - - success = test.copy().expand(-1).inside(constraint); - - if (success) - return test.translate(-parentCoord - constraint.pos()); - } - - if (state.constraintAdjustment & (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y)) { - const bool resizeX = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X; - const bool resizeY = state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y; - - const bool leftEdgeOut = test.x < constraint.x; - const bool topEdgeOut = test.y < constraint.y; - const bool rightEdgeOut = test.x + test.w > constraint.x + constraint.w; - const bool bottomEdgeOut = test.y + test.h > constraint.y + constraint.h; - - // TODO: this isn't truly conformant. - if (leftEdgeOut && resizeX) { - test.w = test.x + test.w - constraint.x - EDGE_PADDING; - test.x = constraint.x + EDGE_PADDING; + if (flip) { + state.gravity ^= CEdges::LEFT | CEdges::RIGHT; + anchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX; + effectiveX = calcEffectiveX(); } - if (rightEdgeOut && resizeX) - test.w = constraint.w - (test.x - constraint.w) - EDGE_PADDING; - if (topEdgeOut && resizeY) { - test.h = test.y + test.h - constraint.y - EDGE_PADDING; - test.y = constraint.y + EDGE_PADDING; - } - if (bottomEdgeOut && resizeY) - test.h = constraint.h - (test.y - constraint.y) - EDGE_PADDING; - - success = test.copy().expand(-1).inside(constraint); - - if (success) - return test.translate(-parentCoord - constraint.pos()); } - LOGM(WARN, "Compositor/client bug: xdg_positioner couldn't find a place"); + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) { + auto flip = (state.gravity.top() && effectiveY + state.offset.y < constraint.y) || (state.gravity.bottom() && effectiveY + state.offset.y + height > constraint.extent().y); - return test.translate(-parentCoord - constraint.pos()); + if (flip) { + state.gravity ^= CEdges::TOP | CEdges::BOTTOM; + anchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; + effectiveX = calcEffectiveX(); + } + } + + effectiveX += state.offset.x; + effectiveY += state.offset.y; + + // Slide order is important for the case where the window is too large to fit on screen. + + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) { + if (effectiveX + width > constraint.extent().x) + effectiveX = constraint.extent().x - width; + + if (effectiveX < constraint.x) + effectiveX = constraint.x; + } + + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) { + if (effectiveY + height > constraint.extent().y) + effectiveY = constraint.extent().y - height; + + if (effectiveY < constraint.y) + effectiveY = constraint.y; + } + + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) { + if (effectiveX < constraint.x) { + auto diff = constraint.x - effectiveX; + effectiveX = constraint.x; + width -= diff; + } + + auto effectiveX2 = effectiveX + width; + if (effectiveX2 > constraint.extent().x) + width -= effectiveX2 - constraint.extent().x; + } + + if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) { + if (effectiveY < constraint.y) { + auto diff = constraint.y - effectiveY; + effectiveY = constraint.y; + height -= diff; + } + + auto effectiveY2 = effectiveY + height; + if (effectiveY2 > constraint.extent().y) + height -= effectiveY2 - constraint.extent().y; + } + + return {effectiveX - parentCoord.x, effectiveY - parentCoord.y, width, height}; } CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index da551718..e6812c38 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -4,10 +4,10 @@ #include #include #include +#include #include "WaylandProtocol.hpp" #include "xdg-shell.hpp" #include "../helpers/math/Math.hpp" -#include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" #include "types/SurfaceRole.hpp" @@ -20,21 +20,24 @@ class CSeatGrab; class CWLSurfaceResource; struct SXDGPositionerState { - Vector2D requestedSize; - CBox anchorRect; - xdgPositionerAnchor anchor = XDG_POSITIONER_ANCHOR_NONE; - xdgPositionerGravity gravity = XDG_POSITIONER_GRAVITY_NONE; - uint32_t constraintAdjustment = 0; - Vector2D offset; - bool reactive = false; - Vector2D parentSize; + Vector2D requestedSize; + CBox anchorRect; + CEdges anchor; + CEdges gravity; + uint32_t constraintAdjustment = 0; + Vector2D offset; + bool reactive = false; + Vector2D parentSize; + + void setAnchor(xdgPositionerAnchor edges); + void setGravity(xdgPositionerGravity edges); }; class CXDGPositionerRules { public: CXDGPositionerRules(SP positioner); - CBox getPosition(const CBox& constraint, const Vector2D& parentPos); + CBox getPosition(CBox constraint, const Vector2D& parentPos); private: SXDGPositionerState state; From 9b6ae4f77b95fef271c2e21abba5e05b4cc47719 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Sun, 28 Jul 2024 19:46:38 +0900 Subject: [PATCH 0397/2393] input: fix keyboard leds with multiple keyboards (#7079) --- src/devices/IKeyboard.cpp | 15 ++++++++++++--- src/devices/IKeyboard.hpp | 26 ++++++++++++++------------ src/managers/input/InputManager.cpp | 9 ++++++++- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index e3517bf1..e05cbd04 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -274,9 +274,9 @@ std::string IKeyboard::getActiveLayout() { return "none"; } -void IKeyboard::updateLEDs() { +std::optional IKeyboard::getLEDs() { if (xkbState == nullptr) - return; + return {}; uint32_t leds = 0; for (uint32_t i = 0; i < LED_COUNT; ++i) { @@ -284,7 +284,16 @@ void IKeyboard::updateLEDs() { leds |= (1 << i); } - updateLEDs(leds); + return leds; +} + +void IKeyboard::updateLEDs() { + std::optional leds = getLEDs(); + + if (!leds.has_value()) + return; + + updateLEDs(leds.value()); } void IKeyboard::updateLEDs(uint32_t leds) { diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 2ff8a190..ad8eaf7e 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -5,6 +5,7 @@ #include "../macros.hpp" #include "../helpers/math/Math.hpp" +#include #include AQUAMARINE_FORWARD(IKeyboard); @@ -61,19 +62,20 @@ class IKeyboard : public IHID { std::string rules = ""; }; - void setKeymap(const SStringRuleNames& rules); - void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); - std::string getActiveLayout(); - void updateLEDs(); - void updateLEDs(uint32_t leds); - uint32_t getModifiers(); - void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - bool updateModifiersState(); // rets whether changed - void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); - void updateKeymapFD(); + void setKeymap(const SStringRuleNames& rules); + void updateXKBTranslationState(xkb_keymap* const keymap = nullptr); + std::string getActiveLayout(); + std::optional getLEDs(); + void updateLEDs(); + void updateLEDs(uint32_t leds); + uint32_t getModifiers(); + void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + bool updateModifiersState(); // rets whether changed + void updateXkbStateWithKey(uint32_t xkbKey, bool pressed); + void updateKeymapFD(); - bool active = false; - bool enabled = true; + bool active = false; + bool enabled = true; // if the keymap is overridden by the implementation, // don't try to set keyboard rules anymore, to avoid overwriting the requested one. diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 619bfab7..014de40a 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1265,7 +1265,14 @@ void CInputManager::updateKeyboardsLeds(SP pKeyboard) { if (!pKeyboard) return; - pKeyboard->updateLEDs(); + std::optional leds = pKeyboard->getLEDs(); + + if (!leds.has_value()) + return; + + for (auto& k : m_vKeyboards) { + k->updateLEDs(leds.value()); + } } void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { From 3cc2028def295735ce496a42c79d1b922d2de45d Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 28 Jul 2024 14:03:30 +0300 Subject: [PATCH 0398/2393] hyprpm: checkout commit instead of branch Fixes #6948 --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 036609f3..edb98812 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -464,7 +464,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.m_szCurrentMessage = "Checking out sources"; progress.print(); - ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.branch + " 2>&1"); + ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); From fcff2dcac24ca497a39c1cb271d449ade037b7ad Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 28 Jul 2024 18:42:05 +0300 Subject: [PATCH 0399/2393] flake.lock: update xdph --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 422b0cf7..01b68384 100644 --- a/flake.lock +++ b/flake.lock @@ -67,11 +67,11 @@ ] }, "locked": { - "lastModified": 1718746314, - "narHash": "sha256-HUklK5u86w2Yh9dOkk4FdsL8eehcOZ95jPhLixGDRQY=", + "lastModified": 1721326555, + "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "1b61f0093afff20ab44d88ad707aed8bf2215290", + "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1721755049, - "narHash": "sha256-O17b38bQnmfxv7It3OnVYx7fp1seEdI7xxnw5vJFv30=", + "lastModified": 1722181019, + "narHash": "sha256-Lj/g1UzrsTZUixtveQix6eB3pon2j23qv5/5pzTx0LQ=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "5555f467f68ce7cdf1060991c24263073b95e9da", + "rev": "0e2f3b9c85f7bab3983098a01366876d34daf383", "type": "github" }, "original": { From 73d09953e84ae4f320498fee8522295899972f25 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 28 Jul 2024 23:41:15 +0200 Subject: [PATCH 0400/2393] core/surface: drop map/unmap events in member funcs causes loops --- src/protocols/core/Compositor.cpp | 4 ---- src/protocols/core/Subcompositor.cpp | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 76907cc2..7275cbf8 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -319,8 +319,6 @@ void CWLSurfaceResource::map() { mapped = true; - events.map.emit(); - timespec now; clock_gettime(CLOCK_MONOTONIC, &now); frame(&now); @@ -335,8 +333,6 @@ void CWLSurfaceResource::unmap() { mapped = false; - events.unmap.emit(); - // release the buffers. // this is necessary for XWayland to function correctly, // as it does not unmap via the traditional commit(null buffer) method, but via the X11 protocol. diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index cbc4063a..01cc0798 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -82,11 +82,13 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPevents.commit.registerListener([this](std::any d) { if (surface->current.buffer && !surface->mapped) { surface->map(); + surface->events.map.emit(); return; } if (!surface->current.buffer && surface->mapped) { surface->unmap(); + surface->events.unmap.emit(); return; } }); From 256db08aed3bf045a8268dddaf15a96558bbcf2a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 28 Jul 2024 23:41:36 +0200 Subject: [PATCH 0401/2393] layersurface: null check for surface validity before unmap() --- src/desktop/LayerSurface.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index f3db4b61..3a3edc6d 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -192,7 +192,8 @@ void CLayerSurface::onUnmap() { g_pCompositor->addToFadingOutSafe(self.lock()); mapped = false; - layerSurface->surface->unmap(); + if (layerSurface && layerSurface->surface) + layerSurface->surface->unmap(); startAnimation(false); return; @@ -204,7 +205,8 @@ void CLayerSurface::onUnmap() { startAnimation(false); mapped = false; - layerSurface->surface->unmap(); + if (layerSurface && layerSurface->surface) + layerSurface->surface->unmap(); g_pCompositor->addToFadingOutSafe(self.lock()); From 7df9b01d483155713c8d89666c7fc865b90c162e Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 28 Jul 2024 23:47:17 +0200 Subject: [PATCH 0402/2393] core: emit unmap event after unmap in surface destroy --- src/protocols/core/Compositor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 7275cbf8..368b8ed4 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -151,8 +151,10 @@ CWLSurfaceResource::~CWLSurfaceResource() { } void CWLSurfaceResource::destroy() { - if (mapped) + if (mapped) { unmap(); + events.unmap.emit(); + } events.destroy.emit(); PROTO::compositor->destroyResource(this); } From a9d87bd6669568741704de08b6f0328a92e29396 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 28 Jul 2024 23:56:35 +0200 Subject: [PATCH 0403/2393] surface: emit unmap before unmapping and releasing the buffers --- src/protocols/LayerShell.cpp | 2 +- src/protocols/XDGShell.cpp | 2 +- src/protocols/core/Compositor.cpp | 2 +- src/protocols/core/Subcompositor.cpp | 2 +- src/xwayland/XSurface.cpp | 3 +-- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index e018c3d0..5018828e 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -73,8 +73,8 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPunmap(); events.unmap.emit(); + surface->unmap(); configured = false; return; } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 4b180617..e9921988 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -365,8 +365,8 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPcurrent.buffer && mapped) { mapped = false; - surface->unmap(); events.unmap.emit(); + surface->unmap(); return; } diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 368b8ed4..6352b7e6 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -152,8 +152,8 @@ CWLSurfaceResource::~CWLSurfaceResource() { void CWLSurfaceResource::destroy() { if (mapped) { - unmap(); events.unmap.emit(); + unmap(); } events.destroy.emit(); PROTO::compositor->destroyResource(this); diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 01cc0798..c0c1f258 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -87,8 +87,8 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPcurrent.buffer && surface->mapped) { - surface->unmap(); surface->events.unmap.emit(); + surface->unmap(); return; } }); diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 5d25e0e8..107b22da 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -114,12 +114,11 @@ void CXWaylandSurface::unmap() { std::erase(g_pXWayland->pWM->mappedSurfacesStacking, self); mapped = false; + events.unmap.emit(); surface->unmap(); Debug::log(LOG, "XWayland surface {:x} unmapping", (uintptr_t)this); - events.unmap.emit(); - g_pXWayland->pWM->updateClientList(); } From 6e6c61b9e87942425b978efa2309dbcca57c3217 Mon Sep 17 00:00:00 2001 From: Virt <41426325+VirtCode@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:47:25 +0200 Subject: [PATCH 0404/2393] layer-shell: avoid crashes on unmap (#7092) --- src/desktop/LayerSurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 3a3edc6d..4426491d 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -219,7 +219,7 @@ void CLayerSurface::onUnmap() { // refocus if needed // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window - if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) + if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) g_pInputManager->refocusLastWindow(PMONITOR); else if (g_pCompositor->m_pLastFocus) g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); From 33e513d489faf5998a3831d55aa7ddd796ef3368 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Mon, 29 Jul 2024 01:48:27 -0700 Subject: [PATCH 0405/2393] xdg-shell: fix xdg-positioner y-flip (#7094) --- src/protocols/XDGShell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index e9921988..cb8a5bc3 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -567,7 +567,7 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo if (flip) { state.gravity ^= CEdges::TOP | CEdges::BOTTOM; anchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; - effectiveX = calcEffectiveX(); + effectiveY = calcEffectiveY(); } } From 87699575e1663649270e9a271609b5bcd079ce70 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 29 Jul 2024 14:23:19 +0200 Subject: [PATCH 0406/2393] egl: require gles 3.0 only No clue what could break, hopefully nothing ref #6973 --- src/render/OpenGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 39f6614e..b2346e0f 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -134,7 +134,7 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); attrs.push_back(3); attrs.push_back(EGL_CONTEXT_MINOR_VERSION); - attrs.push_back(2); + attrs.push_back(0); #else attrs.push_back(EGL_CONTEXT_CLIENT_VERSION); attrs.push_back(2); From 70468857da2e64c35c7e79b7e63bff04e56e3be5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 29 Jul 2024 14:27:05 +0200 Subject: [PATCH 0407/2393] egl: attempt a 3.2 egl context first --- src/render/OpenGL.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index b2346e0f..43a2c3a7 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -130,11 +130,13 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); } + auto attrsNoVer = attrs; + #ifndef GLES2 attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); attrs.push_back(3); attrs.push_back(EGL_CONTEXT_MINOR_VERSION); - attrs.push_back(0); + attrs.push_back(2); #else attrs.push_back(EGL_CONTEXT_CLIENT_VERSION); attrs.push_back(2); @@ -143,8 +145,24 @@ void CHyprOpenGLImpl::initEGL(bool gbm) { attrs.push_back(EGL_NONE); m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data()); - if (m_pEglContext == EGL_NO_CONTEXT) - RASSERT(false, "EGL: failed to create a context"); + if (m_pEglContext == EGL_NO_CONTEXT) { +#ifdef GLES2 + RASSERT(false, "EGL: failed to create a context with GLES2.0"); +#endif + Debug::log(WARN, "EGL: Failed to create a context with GLES3.2, retrying 3.0"); + + attrs = attrsNoVer; + attrs.push_back(EGL_CONTEXT_MAJOR_VERSION); + attrs.push_back(3); + attrs.push_back(EGL_CONTEXT_MINOR_VERSION); + attrs.push_back(0); + attrs.push_back(EGL_NONE); + + m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data()); + + if (m_pEglContext == EGL_NO_CONTEXT) + RASSERT(false, "EGL: failed to create a context with either GLES3.2 or 3.0"); + } if (m_sExts.IMG_context_priority) { EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG; From 23a8f06594fd75580ddb6115c78812d3e3d6c57f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 29 Jul 2024 16:27:09 +0200 Subject: [PATCH 0408/2393] virtualptr: allow binding to output --- src/devices/IPointer.hpp | 3 ++- src/devices/VirtualPointer.cpp | 2 ++ src/managers/PointerManager.cpp | 10 ++++++++++ src/protocols/VirtualPointer.cpp | 21 +++++++++++++++------ src/protocols/VirtualPointer.hpp | 12 +++++++----- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index 5df47c04..760ec8dc 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -106,7 +106,8 @@ class IPointer : public IHID { } pointerEvents; std::string hlName; - bool connected = false; // means connected to the cursor + bool connected = false; // means connected to the cursor + std::string boundOutput = ""; WP self; }; diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index f9a1c409..9223ebe1 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -38,6 +38,8 @@ CVirtualPointer::CVirtualPointer(SP resource) : point listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); + boundOutput = resource->boundOutput ? resource->boundOutput->szName : "auto"; + deviceName = pointer->name; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3b425688..59c54c78 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -674,6 +674,16 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { } break; } + case HID_TYPE_POINTER: { + IPointer* POINTER = reinterpret_cast(dev.get()); + if (!POINTER->boundOutput.empty() && POINTER->boundOutput != "auto") { + if (const auto PMONITOR = g_pCompositor->getMonitorFromString(POINTER->boundOutput); PMONITOR) { + currentMonitor = PMONITOR->self.lock(); + mappedArea = currentMonitor->logicalBox(); + } + } + break; + } default: break; } diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index bdeec32d..8626241a 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -1,8 +1,9 @@ #include "VirtualPointer.hpp" +#include "core/Output.hpp" #define LOGM PROTO::virtualPointer->protoLog -CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_) : resource(resource_) { +CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, WP boundOutput_) : boundOutput(boundOutput_), resource(resource_) { if (!good()) return; @@ -112,10 +113,18 @@ void CVirtualPointerProtocol::bindManager(wl_client* client, void* data, uint32_ RESOURCE->setOnDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); - RESOURCE->setCreateVirtualPointer([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreatePointer(pMgr, seat, id); }); + RESOURCE->setCreateVirtualPointer([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreatePointer(pMgr, seat, id, {}); }); RESOURCE->setCreateVirtualPointerWithOutput([this](CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, wl_resource* output, uint32_t id) { - LOGM(WARN, "TODO: CreateWithOutput is not supported yet. Ignoring for now."); - this->onCreatePointer(pMgr, seat, id); + if (output) { + auto RES = CWLOutputResource::fromResource(output); + if (!RES) { + this->onCreatePointer(pMgr, seat, id, {}); + return; + } + + this->onCreatePointer(pMgr, seat, id, RES->monitor); + } else + this->onCreatePointer(pMgr, seat, id, {}); }); } @@ -127,9 +136,9 @@ void CVirtualPointerProtocol::destroyResource(CVirtualPointerV1Resource* pointer std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == pointer; }); } -void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id) { +void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP output) { - const auto RESOURCE = m_vPointers.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); + const auto RESOURCE = m_vPointers.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id), output)); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index ee5ee7e2..1a51d977 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -11,7 +11,7 @@ class CVirtualPointerV1Resource { public: - CVirtualPointerV1Resource(SP resource_); + CVirtualPointerV1Resource(SP resource_, WP boundOutput_); ~CVirtualPointerV1Resource(); struct { @@ -34,10 +34,12 @@ class CVirtualPointerV1Resource { CSignal holdEnd; } events; - bool good(); - wl_client* client(); + bool good(); + wl_client* client(); - std::string name; + std::string name; + + WP boundOutput; private: SP resource; @@ -60,7 +62,7 @@ class CVirtualPointerProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyResource(CVirtualPointerV1Resource* pointer); - void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id); + void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP output); // std::vector> m_vManagers; From 3a1afb53fdc75d6bfb434fb5ff29ab43ce6b040a Mon Sep 17 00:00:00 2001 From: atikiNBTW <74009330+atikiNBTW@users.noreply.github.com> Date: Mon, 29 Jul 2024 19:56:50 +0500 Subject: [PATCH 0409/2393] pluginapi: Add force reload of config at the end of plugin initialization (#7099) * Add force reload of config at the end of plugin load * Remove unnecessary include --- src/plugins/PluginSystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index 46f50469..122faafd 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -80,6 +80,8 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) { PLUGIN->version = PLUGINDATA.version; PLUGIN->name = PLUGINDATA.name; + g_pConfigManager->m_bForceReload = true; + Debug::log(LOG, " [PluginSystem] Plugin {} loaded. Handle: {:x}, path: \"{}\", author: \"{}\", description: \"{}\", version: \"{}\"", PLUGINDATA.name, (uintptr_t)MODULE, path, PLUGINDATA.author, PLUGINDATA.description, PLUGINDATA.version); From 01560c9d7ccd0beec1a9c190862ee325e6f3c45e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 29 Jul 2024 18:13:17 +0200 Subject: [PATCH 0410/2393] virtualptr: map to entire screen if no output is provided fixes #6749 --- src/devices/VirtualPointer.cpp | 2 +- src/managers/PointerManager.cpp | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 9223ebe1..7ad18775 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -38,7 +38,7 @@ CVirtualPointer::CVirtualPointer(SP resource) : point listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); - boundOutput = resource->boundOutput ? resource->boundOutput->szName : "auto"; + boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire"; deviceName = pointer->name; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 59c54c78..a09992a2 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -676,8 +676,24 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { } case HID_TYPE_POINTER: { IPointer* POINTER = reinterpret_cast(dev.get()); - if (!POINTER->boundOutput.empty() && POINTER->boundOutput != "auto") { - if (const auto PMONITOR = g_pCompositor->getMonitorFromString(POINTER->boundOutput); PMONITOR) { + if (!POINTER->boundOutput.empty()) { + if (POINTER->boundOutput == "entire") { + // find x and y size of the entire space + Vector2D bottomRight = {-9999999, -9999999}, topLeft = {9999999, 9999999}; + for (auto& m : g_pCompositor->m_vMonitors) { + const auto EXTENT = m->logicalBox().extent(); + const auto POS = m->logicalBox().pos(); + if (EXTENT.x > bottomRight.x) + bottomRight.x = EXTENT.x; + if (EXTENT.y > bottomRight.y) + bottomRight.y = EXTENT.y; + if (POS.x < topLeft.x) + topLeft.x = POS.x; + if (POS.y < topLeft.y) + topLeft.y = POS.y; + } + mappedArea = {topLeft, bottomRight - topLeft}; + } else if (const auto PMONITOR = g_pCompositor->getMonitorFromString(POINTER->boundOutput); PMONITOR) { currentMonitor = PMONITOR->self.lock(); mappedArea = currentMonitor->logicalBox(); } From 60b663e2765c4cdb7e14fff75c4f88bf7ae312e2 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 29 Jul 2024 11:14:19 -0500 Subject: [PATCH 0411/2393] protocols: move text-input-v1 to hyprwayland-scanner (#7096) * move text-input-v1 to hyprwayland-scanner * vro --- CMakeLists.txt | 5 +- protocols/meson.build | 2 +- src/managers/ProtocolManager.cpp | 4 +- src/managers/ProtocolManager.hpp | 2 - src/managers/input/InputMethodRelay.cpp | 10 +- src/managers/input/InputMethodRelay.hpp | 7 +- src/managers/input/TextInput.cpp | 86 +++---- src/managers/input/TextInput.hpp | 14 +- src/protocols/TextInputV1.cpp | 295 ++++++++---------------- src/protocols/TextInputV1.hpp | 84 +++---- src/protocols/VirtualPointer.hpp | 1 + 11 files changed, 196 insertions(+), 314 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d9411075..550f1dc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,10 +292,7 @@ protocol( "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true) -protocol( - "unstable/text-input/text-input-unstable-v1.xml" - "text-input-unstable-v1" false) - +protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) diff --git a/protocols/meson.build b/protocols/meson.build index 35b2b29b..4fd40859 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -24,7 +24,6 @@ hyprwayland_scanner = find_program( ) protocols = [ - [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] ] @@ -55,6 +54,7 @@ new_protocols = [ [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], + [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 3704befb..d052e045 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -41,6 +41,7 @@ #include "../protocols/DRMSyncobj.hpp" #include "../protocols/Screencopy.hpp" #include "../protocols/ToplevelExport.hpp" +#include "../protocols/TextInputV1.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -125,6 +126,7 @@ CProtocolManager::CProtocolManager() { 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"); PROTO::shortcutsInhibit = std::make_unique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); + PROTO::textInputV1 = std::make_unique(&zwp_text_input_manager_v1_interface, 1, "TextInputV1"); PROTO::textInputV3 = std::make_unique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); @@ -165,7 +167,6 @@ CProtocolManager::CProtocolManager() { // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. - m_pTextInputV1ProtocolManager = std::make_unique(); m_pGlobalShortcutsProtocolManager = std::make_unique(); } @@ -197,6 +198,7 @@ CProtocolManager::~CProtocolManager() { PROTO::pointerGestures.reset(); PROTO::foreignToplevelWlr.reset(); PROTO::shortcutsInhibit.reset(); + PROTO::textInputV1.reset(); PROTO::textInputV3.reset(); PROTO::constraints.reset(); PROTO::outputPower.reset(); diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 62653e89..044a4d9b 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../helpers/Monitor.hpp" #include "../helpers/memory/Memory.hpp" @@ -14,7 +13,6 @@ class CProtocolManager { ~CProtocolManager(); // TODO: rewrite to use the new protocol framework - std::unique_ptr m_pTextInputV1ProtocolManager; std::unique_ptr m_pGlobalShortcutsProtocolManager; private: diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index f1fe6421..7cfd54b4 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -2,6 +2,7 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" #include "../../protocols/TextInputV3.hpp" +#include "../../protocols/TextInputV1.hpp" #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/core/Compositor.hpp" @@ -9,7 +10,8 @@ CInputMethodRelay::CInputMethodRelay() { static auto P = g_pHookSystem->hookDynamic("keyboardFocus", [&](void* self, SCallbackInfo& info, std::any param) { onKeyboardFocus(std::any_cast>(param)); }); - listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(ti); }); + listeners.newTIV3 = PROTO::textInputV3->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(std::any_cast>(ti)); }); + listeners.newTIV1 = PROTO::textInputV1->events.newTextInput.registerListener([this](std::any ti) { onNewTextInput(std::any_cast>(ti)); }); listeners.newIME = PROTO::ime->events.newIME.registerListener([this](std::any ime) { onNewIME(std::any_cast>(ime)); }); } @@ -86,11 +88,11 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() { return nullptr; } -void CInputMethodRelay::onNewTextInput(std::any tiv3) { - m_vTextInputs.emplace_back(std::make_unique(std::any_cast>(tiv3))); +void CInputMethodRelay::onNewTextInput(WP tiv3) { + m_vTextInputs.emplace_back(std::make_unique(tiv3)); } -void CInputMethodRelay::onNewTextInput(STextInputV1* pTIV1) { +void CInputMethodRelay::onNewTextInput(WP pTIV1) { m_vTextInputs.emplace_back(std::make_unique(pTIV1)); } diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index e13a1f1c..5ecc11a2 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -10,7 +10,7 @@ class CInputManager; class CHyprRenderer; -struct STextInputV1; +class CTextInputV1; class CInputMethodV2; class CInputMethodRelay { @@ -18,8 +18,8 @@ class CInputMethodRelay { CInputMethodRelay(); void onNewIME(SP); - void onNewTextInput(std::any tiv3); - void onNewTextInput(STextInputV1* pTIV1); + void onNewTextInput(WP tiv3); + void onNewTextInput(WP pTIV1); void activateIME(CTextInput* pInput); void deactivateIME(CTextInput* pInput); @@ -48,6 +48,7 @@ class CInputMethodRelay { struct { CHyprSignalListener newTIV3; + CHyprSignalListener newTIV1; CHyprSignalListener newIME; CHyprSignalListener commitIME; CHyprSignalListener destroyIME; diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 635a8b01..5bff9fed 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -7,8 +7,7 @@ #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/core/Compositor.hpp" -CTextInput::CTextInput(STextInputV1* ti) : pV1Input(ti) { - ti->pTextInput = this; +CTextInput::CTextInput(WP ti) : pV1Input(ti) { initCallbacks(); } @@ -16,17 +15,6 @@ CTextInput::CTextInput(WP ti) : pV3Input(ti) { initCallbacks(); } -CTextInput::~CTextInput() { - if (pV1Input) - pV1Input->pTextInput = nullptr; -} - -void CTextInput::tiV1Destroyed() { - pV1Input = nullptr; - - g_pInputManager->m_sIMERelay.removeTextInput(this); -} - void CTextInput::initCallbacks() { if (isV3()) { const auto INPUT = pV3Input.lock(); @@ -41,25 +29,19 @@ void CTextInput::initCallbacks() { g_pInputManager->m_sIMERelay.removeTextInput(this); }); } else { - hyprListener_textInputEnable.initCallback(&pV1Input->sEnable, [this](void* owner, void* data) { onEnabled(); }, this, "textInput"); + const auto INPUT = pV1Input.lock(); - hyprListener_textInputCommit.initCallback(&pV1Input->sCommit, [this](void* owner, void* data) { onCommit(); }, this, "textInput"); - - hyprListener_textInputDisable.initCallback(&pV1Input->sDisable, [this](void* owner, void* data) { onDisabled(); }, this, "textInput"); - - hyprListener_textInputDestroy.initCallback( - &pV1Input->sDestroy, - [this](void* owner, void* data) { - hyprListener_textInputCommit.removeCallback(); - hyprListener_textInputDestroy.removeCallback(); - hyprListener_textInputDisable.removeCallback(); - hyprListener_textInputEnable.removeCallback(); - listeners.surfaceUnmap.reset(); - listeners.surfaceDestroy.reset(); - - g_pInputManager->m_sIMERelay.removeTextInput(this); - }, - this, "textInput"); + listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { + const auto SURFACE = std::any_cast>(p); + onEnabled(SURFACE); + }); + listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); + listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); + listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + g_pInputManager->m_sIMERelay.removeTextInput(this); + }); } } @@ -149,7 +131,7 @@ void CTextInput::setFocusedSurface(SP pSurface) { } bool CTextInput::isV3() { - return !pV1Input; + return pV3Input && !pV1Input; } void CTextInput::enter(SP pSurface) { @@ -174,8 +156,7 @@ void CTextInput::enter(SP pSurface) { if (isV3()) pV3Input->enter(pSurface); else { - zwp_text_input_v1_send_enter(pV1Input->resourceImpl, pSurface->getResource()->resource()); - pV1Input->active = true; + pV1Input->enter(pSurface); } setFocusedSurface(pSurface); @@ -194,8 +175,7 @@ void CTextInput::leave() { if (isV3() && focusedSurface()) pV3Input->leave(focusedSurface()); else if (focusedSurface() && pV1Input) { - zwp_text_input_v1_send_leave(pV1Input->resourceImpl); - pV1Input->active = false; + pV1Input->leave(); } setFocusedSurface(nullptr); @@ -208,7 +188,7 @@ SP CTextInput::focusedSurface() { } wl_client* CTextInput::client() { - return isV3() ? pV3Input->client() : pV1Input->client; + return isV3() ? pV3Input->client() : pV1Input->client(); } void CTextInput::commitStateToIME(SP ime) { @@ -223,13 +203,15 @@ void CTextInput::commitStateToIME(SP ime) { if (INPUT->current.contentType.updated) ime->textContentType(INPUT->current.contentType.hint, INPUT->current.contentType.purpose); } else { - if (pV1Input->pendingSurrounding.isPending) - ime->surroundingText(pV1Input->pendingSurrounding.text, pV1Input->pendingSurrounding.cursor, pV1Input->pendingSurrounding.anchor); + const auto INPUT = pV1Input.lock(); + + if (INPUT->pendingSurrounding.isPending) + ime->surroundingText(INPUT->pendingSurrounding.text, INPUT->pendingSurrounding.cursor, INPUT->pendingSurrounding.anchor); ime->textChangeCause(ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD); if (pV1Input->pendingContentType.isPending) - ime->textContentType((zwpTextInputV3ContentHint)pV1Input->pendingContentType.hint, (zwpTextInputV3ContentPurpose)pV1Input->pendingContentType.purpose); + ime->textContentType((zwpTextInputV3ContentHint)INPUT->pendingContentType.hint, (zwpTextInputV3ContentPurpose)INPUT->pendingContentType.purpose); } g_pInputManager->m_sIMERelay.updateAllPopups(); @@ -252,25 +234,27 @@ void CTextInput::updateIMEState(SP ime) { INPUT->sendDone(); } else { + const auto INPUT = pV1Input.lock(); + if (ime->current.preeditString.committed) { - zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preeditString.begin); - zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); - zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preeditString.string.c_str(), ""); + INPUT->preeditCursor(ime->current.preeditString.begin); + INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); + INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), ""); } else { - zwp_text_input_v1_send_preedit_cursor(pV1Input->resourceImpl, ime->current.preeditString.begin); - zwp_text_input_v1_send_preedit_styling(pV1Input->resourceImpl, 0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); - zwp_text_input_v1_send_preedit_string(pV1Input->resourceImpl, pV1Input->serial, "", ""); + INPUT->preeditCursor(ime->current.preeditString.begin); + INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); + INPUT->preeditString(pV1Input->serial, "", ""); } if (ime->current.committedString.committed) - zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.committedString.string.c_str()); + INPUT->commitString(pV1Input->serial, ime->current.committedString.string.c_str()); if (ime->current.deleteSurrounding.committed) { - zwp_text_input_v1_send_delete_surrounding_text(pV1Input->resourceImpl, std::string(ime->current.preeditString.string).length() - ime->current.deleteSurrounding.before, - ime->current.deleteSurrounding.after + ime->current.deleteSurrounding.before); + INPUT->deleteSurroundingText(std::string(ime->current.preeditString.string).length() - ime->current.deleteSurrounding.before, + ime->current.deleteSurrounding.after + ime->current.deleteSurrounding.before); if (ime->current.preeditString.committed) - zwp_text_input_v1_send_commit_string(pV1Input->resourceImpl, pV1Input->serial, ime->current.preeditString.string.c_str()); + INPUT->commitString(pV1Input->serial, ime->current.preeditString.string.c_str()); } } } @@ -281,4 +265,4 @@ bool CTextInput::hasCursorRectangle() { CBox CTextInput::cursorBox() { return CBox{isV3() ? pV3Input->current.box.cursorBox : pV1Input->cursorRectangle}; -} \ No newline at end of file +} diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 79e08af9..0f69866e 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -8,7 +8,7 @@ struct wl_client; -struct STextInputV1; +class CTextInputV1; class CTextInputV3; class CInputMethodV2; class CWLSurfaceResource; @@ -16,8 +16,7 @@ class CWLSurfaceResource; class CTextInput { public: CTextInput(WP ti); - CTextInput(STextInputV1* ti); - ~CTextInput(); + CTextInput(WP ti); bool isV3(); void enter(SP pSurface); @@ -43,12 +42,7 @@ class CTextInput { WP pFocusedSurface; int enterLocks = 0; WP pV3Input; - STextInputV1* pV1Input = nullptr; - - DYNLISTENER(textInputEnable); - DYNLISTENER(textInputDisable); - DYNLISTENER(textInputCommit); - DYNLISTENER(textInputDestroy); + WP pV1Input; struct { CHyprSignalListener enable; @@ -58,4 +52,4 @@ class CTextInput { CHyprSignalListener surfaceUnmap; CHyprSignalListener surfaceDestroy; } listeners; -}; \ No newline at end of file +}; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 12068671..78e910cb 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -3,228 +3,125 @@ #include "../Compositor.hpp" #include "core/Compositor.hpp" -#define TEXT_INPUT_VERSION 1 +#define LOGM PROTO::textInputV1->protoLog -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->bindManager(client, data, version, id); +CTextInputV1::~CTextInputV1() { + events.destroy.emit(); } -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - 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); - - if (!m_pGlobal) { - Debug::log(ERR, "TextInputV1Manager could not start!"); - return; - } - - m_liDisplayDestroy.notify = handleDisplayDestroy; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); - - Debug::log(LOG, "TextInputV1Manager started successfully!"); -} - -static void createTI(wl_client* client, wl_resource* resource, uint32_t id) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->createTI(client, resource, id); -} - -static const struct zwp_text_input_manager_v1_interface textInputManagerImpl = { - .create_text_input = createTI, -}; - -void CTextInputV1ProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto RESOURCE = wl_resource_create(client, &zwp_text_input_manager_v1_interface, version, id); - wl_resource_set_implementation(RESOURCE, &textInputManagerImpl, this, nullptr); - - Debug::log(LOG, "TextInputV1Manager bound successfully!"); -} - -// - -static void handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleActivate(client, resource, seat, surface); -} - -static void handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleDeactivate(client, resource, seat); -} - -static void handleShowInputPanel(wl_client* client, wl_resource* resource) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleShowInputPanel(client, resource); -} - -static void handleHideInputPanel(wl_client* client, wl_resource* resource) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleHideInputPanel(client, resource); -} - -static void handleReset(wl_client* client, wl_resource* resource) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleReset(client, resource); -} - -static void handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetSurroundingText(client, resource, text, cursor, anchor); -} - -static void handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetContentType(client, resource, hint, purpose); -} - -static void handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetCursorRectangle(client, resource, x, y, width, height); -} - -static void handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleSetPreferredLanguage(client, resource, language); -} - -static void handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleCommitState(client, resource, serial); -} - -static void handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index) { - g_pProtocolManager->m_pTextInputV1ProtocolManager->handleInvokeAction(client, resource, button, index); -} - -static const struct zwp_text_input_v1_interface textInputImpl = { - .activate = handleActivate, - .deactivate = handleDeactivate, - .show_input_panel = handleShowInputPanel, - .hide_input_panel = handleHideInputPanel, - .reset = handleReset, - .set_surrounding_text = handleSetSurroundingText, - .set_content_type = handleSetContentType, - .set_cursor_rectangle = handleSetCursorRectangle, - .set_preferred_language = handleSetPreferredLanguage, - .commit_state = handleCommitState, - .invoke_action = handleInvokeAction, -}; - -void CTextInputV1ProtocolManager::removeTI(STextInputV1* pTI) { - const auto TI = std::find_if(m_pClients.begin(), m_pClients.end(), [&](const auto& other) { return other->resourceCaller == pTI->resourceCaller; }); - if (TI == m_pClients.end()) +CTextInputV1::CTextInputV1(SP resource_) : resource(resource_) { + if (!good()) return; - // if ((*TI)->resourceImpl) - // wl_resource_destroy((*TI)->resourceImpl); + resource->setOnDestroy([this](CZwpTextInputV1* pMgr) { PROTO::textInputV1->destroyResource(this); }); - std::erase_if(m_pClients, [&](const auto& other) { return other.get() == pTI; }); + resource->setActivate([this](CZwpTextInputV1* pMgr, wl_resource* seat, wl_resource* surface) { + if (!surface) { + LOGM(WARN, "Text-input-v1 PTI{:x}: No surface to activate text input on!", (uintptr_t)this); + return; + } + + active = true; + events.enable.emit(CWLSurfaceResource::fromResource(surface)); + }); + + resource->setDeactivate([this](CZwpTextInputV1* pMgr, wl_resource* seat) { + active = false; + events.disable.emit(); + }); + + resource->setReset([this](CZwpTextInputV1* pMgr) { + pendingSurrounding.isPending = false; + pendingContentType.isPending = false; + }); + + resource->setSetSurroundingText( + [this](CZwpTextInputV1* pMgr, const char* text, uint32_t cursor, uint32_t anchor) { pendingSurrounding = {true, std::string(text), cursor, anchor}; }); + + resource->setSetContentType([this](CZwpTextInputV1* pMgr, uint32_t hint, uint32_t purpose) { + pendingContentType = {true, hint == (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_DEFAULT ? (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE : hint, + purpose > (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD ? hint + 1 : hint}; + }); + + resource->setSetCursorRectangle([this](CZwpTextInputV1* pMgr, int32_t x, int32_t y, int32_t width, int32_t height) { cursorRectangle = CBox{x, y, width, height}; }); + + resource->setCommitState([this](CZwpTextInputV1* pMgr, uint32_t serial_) { + serial = serial_; + events.onCommit.emit(); + }); + + // nothing + resource->setShowInputPanel([this](CZwpTextInputV1* pMgr) {}); + resource->setHideInputPanel([this](CZwpTextInputV1* pMgr) {}); + resource->setSetPreferredLanguage([this](CZwpTextInputV1* pMgr, const char* language) {}); + resource->setInvokeAction([this](CZwpTextInputV1* pMgr, uint32_t button, uint32_t index) {}); } -STextInputV1* tiFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &zwp_text_input_v1_interface, &textInputImpl)); - return (STextInputV1*)wl_resource_get_user_data(resource); +bool CTextInputV1::good() { + return resource->resource(); } -static void destroyTI(wl_resource* resource) { - const auto TI = tiFromResource(resource); - - if (!TI) - return; - - if (TI->resourceImpl) { - wl_resource_set_user_data(resource, nullptr); - } - - TI->pTextInput->tiV1Destroyed(); - - g_pProtocolManager->m_pTextInputV1ProtocolManager->removeTI(TI); +wl_client* CTextInputV1::client() { + return resource->client(); } -void CTextInputV1ProtocolManager::createTI(wl_client* client, wl_resource* resource, uint32_t id) { - const auto PTI = m_pClients.emplace_back(std::make_unique()).get(); - Debug::log(LOG, "New TI V1 at {:x}", (uintptr_t)PTI); - - PTI->client = client; - PTI->resourceCaller = resource; - PTI->resourceImpl = wl_resource_create(client, &zwp_text_input_v1_interface, TEXT_INPUT_VERSION, id); - - if (!PTI->resourceImpl) { - Debug::log(ERR, "Could not alloc wl_resource for TIV1"); - removeTI(PTI); - return; - } - - wl_resource_set_implementation(PTI->resourceImpl, &textInputImpl, PTI, &destroyTI); - wl_resource_set_user_data(PTI->resourceImpl, PTI); - - wl_signal_init(&PTI->sEnable); - wl_signal_init(&PTI->sDisable); - wl_signal_init(&PTI->sDestroy); - wl_signal_init(&PTI->sCommit); - - g_pInputManager->m_sIMERelay.onNewTextInput(PTI); +void CTextInputV1::enter(SP surface) { + resource->sendEnter(surface->getResource()->resource()); + active = true; } -void CTextInputV1ProtocolManager::handleActivate(wl_client* client, wl_resource* resource, wl_resource* seat, wl_resource* surface) { - const auto PTI = tiFromResource(resource); - if (!surface) { - Debug::log(WARN, "Text-input-v1 PTI{:x}: No surface to activate text input on!", (uintptr_t)PTI); - return; - } - PTI->active = true; - PTI->pTextInput->onEnabled(CWLSurfaceResource::fromResource(surface)); +void CTextInputV1::leave() { + resource->sendLeave(); + active = false; } -void CTextInputV1ProtocolManager::handleDeactivate(wl_client* client, wl_resource* resource, wl_resource* seat) { - const auto PTI = tiFromResource(resource); - PTI->active = false; - PTI->pTextInput->onDisabled(); +void CTextInputV1::preeditCursor(int32_t index) { + resource->sendPreeditCursor(index); } -void CTextInputV1ProtocolManager::handleShowInputPanel(wl_client* client, wl_resource* resource) { +void CTextInputV1::preeditStyling(uint32_t index, uint32_t length, zwpTextInputV1PreeditStyle style) { + resource->sendPreeditStyling(index, length, style); +} + +void CTextInputV1::preeditString(uint32_t serial, const char* text, const char* commit) { + resource->sendPreeditString(serial, text, commit); +} + +void CTextInputV1::commitString(uint32_t serial, const char* text) { + resource->sendCommitString(serial, text); +} + +void CTextInputV1::deleteSurroundingText(int32_t index, uint32_t length) { + resource->sendDeleteSurroundingText(index, length); +} + +CTextInputV1Protocol::CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } -void CTextInputV1ProtocolManager::handleHideInputPanel(wl_client* client, wl_resource* resource) { - ; +void CTextInputV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(client, ver, id)); + + RESOURCE->setOnDestroy([this](CZwpTextInputManagerV1* pMgr) { PROTO::textInputV1->destroyResource(pMgr); }); + RESOURCE->setCreateTextInput([this](CZwpTextInputManagerV1* pMgr, uint32_t id) { + const auto PTI = m_vClients.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); + LOGM(LOG, "New TI V1 at {:x}", (uintptr_t)PTI.get()); + + if (!PTI->good()) { + LOGM(ERR, "Could not alloc wl_resource for TIV1"); + pMgr->noMemory(); + PROTO::textInputV1->destroyResource(PTI.get()); + return; + } + + events.newTextInput.emit(WP(PTI)); + }); } -void CTextInputV1ProtocolManager::handleReset(wl_client* client, wl_resource* resource) { - const auto PTI = tiFromResource(resource); - PTI->pendingSurrounding.isPending = false; - PTI->pendingContentType.isPending = false; +void CTextInputV1Protocol::destroyResource(CTextInputV1* client) { + std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); } -void CTextInputV1ProtocolManager::handleSetSurroundingText(wl_client* client, wl_resource* resource, const char* text, uint32_t cursor, uint32_t anchor) { - const auto PTI = tiFromResource(resource); - PTI->pendingSurrounding = {true, std::string(text), cursor, anchor}; -} - -void CTextInputV1ProtocolManager::handleSetContentType(wl_client* client, wl_resource* resource, uint32_t hint, uint32_t purpose) { - const auto PTI = tiFromResource(resource); - PTI->pendingContentType = {true, hint == (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_DEFAULT ? (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE : hint, - purpose > (uint32_t)ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD ? hint + 1 : hint}; -} - -void CTextInputV1ProtocolManager::handleSetCursorRectangle(wl_client* client, wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height) { - const auto PTI = tiFromResource(resource); - PTI->cursorRectangle = CBox{x, y, width, height}; -} - -void CTextInputV1ProtocolManager::handleSetPreferredLanguage(wl_client* client, wl_resource* resource, const char* language) { - ; -} - -void CTextInputV1ProtocolManager::handleCommitState(wl_client* client, wl_resource* resource, uint32_t serial) { - const auto PTI = tiFromResource(resource); - PTI->serial = serial; - PTI->pTextInput->onCommit(); -} - -void CTextInputV1ProtocolManager::handleInvokeAction(wl_client* client, wl_resource* resource, uint32_t button, uint32_t index) { - ; +void CTextInputV1Protocol::destroyResource(CZwpTextInputManagerV1* client) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == client; }); } diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index e56a8990..c85a1f31 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -1,28 +1,44 @@ #pragma once #include "../defines.hpp" -#include "text-input-unstable-v1-protocol.h" +#include "../protocols/core/Compositor.hpp" +#include "text-input-unstable-v1.hpp" +#include "WaylandProtocol.hpp" #include class CTextInput; -struct STextInputV1 { - wl_client* client = nullptr; - wl_resource* resourceCaller = nullptr; +class CTextInputV1 { + public: + CTextInputV1(SP resource); + ~CTextInputV1(); - wl_resource* resourceImpl = nullptr; + void enter(SP surface); + void leave(); - CTextInput* pTextInput = nullptr; + void preeditCursor(int32_t index); + void preeditStyling(uint32_t index, uint32_t length, zwpTextInputV1PreeditStyle style); + void preeditString(uint32_t serial, const char* text, const char* commit); + void commitString(uint32_t serial, const char* text); + void deleteSurroundingText(int32_t index, uint32_t length); - wl_signal sEnable; - wl_signal sDisable; - wl_signal sCommit; - wl_signal sDestroy; + bool good(); + wl_client* client(); - uint32_t serial = 0; + private: + SP resource; + WP self; - bool active = false; + uint32_t serial = 0; + bool active = false; + + struct { + CSignal onCommit; + CSignal enable; + CSignal disable; + CSignal destroy; + } events; struct SPendingSurr { bool isPending = false; @@ -39,39 +55,29 @@ struct STextInputV1 { CBox cursorRectangle = {0, 0, 0, 0}; - bool operator==(const STextInputV1& other) { - return other.client == client && other.resourceCaller == resourceCaller && other.resourceImpl == resourceImpl; - } + friend class CTextInput; + friend class CTextInputV1Protocol; }; -class CTextInputV1ProtocolManager { +class CTextInputV1Protocol : IWaylandProtocol { public: - CTextInputV1ProtocolManager(); - ~CTextInputV1ProtocolManager(); + CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void createTI(wl_client* client, wl_resource* resource, uint32_t id); - void removeTI(STextInputV1* pTI); + virtual void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void destroyResource(CTextInputV1* resource); + void destroyResource(CZwpTextInputManagerV1* client); - 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); - - wl_listener m_liDisplayDestroy; + struct { + CSignal newTextInput; // WP + } events; private: - wl_global* m_pGlobal = nullptr; + std::vector> m_vManagers; + std::vector> m_vClients; - std::vector> m_pClients; + friend class CTextInputV1; +}; + +namespace PROTO { + inline UP textInputV1; }; diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 1a51d977..7ee450dc 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -8,6 +8,7 @@ #include "wlr-virtual-pointer-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" #include "../devices/IPointer.hpp" +#include "../helpers/Monitor.hpp" class CVirtualPointerV1Resource { public: From 9c38b0fdbe32dc2cb81d53c9be90113d114f1cd2 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 29 Jul 2024 19:19:47 +0200 Subject: [PATCH 0412/2393] core: add a destructor to CHyprOpenglImpl and avoid wl_container_of undefined behaviour (#7101) * protocols: avoid undefined behaviour in C macro to safely use wl_container_of with a class the class has to be no virtual functions, no inheritance, and uniform access control (e.g all public) work around this by putting this into a destroywrapper struct. * opengl: clean memory on destruction add a destructor and free the allocated memory and close the fd --- src/protocols/GlobalShortcuts.cpp | 13 ++++++++----- src/protocols/GlobalShortcuts.hpp | 8 +++++++- src/protocols/WaylandProtocol.cpp | 13 ++++++++----- src/protocols/WaylandProtocol.hpp | 8 +++++++- src/render/OpenGL.cpp | 16 ++++++++++++++++ src/render/OpenGL.hpp | 1 + 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 898f0e07..7eb84be6 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -8,13 +8,14 @@ static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint } static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - CGlobalShortcutsProtocolManager* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + CGlobalShortcutsProtocolManagerDestroyWrapper* wrap = wl_container_of(listener, wrap, listener); + CGlobalShortcutsProtocolManager* proto = wrap->parent; proto->displayDestroy(); } void CGlobalShortcutsProtocolManager::displayDestroy() { - wl_list_remove(&m_liDisplayDestroy.link); - wl_list_init(&m_liDisplayDestroy.link); + wl_list_remove(&m_liDisplayDestroy.listener.link); + wl_list_init(&m_liDisplayDestroy.listener.link); wl_global_destroy(m_pGlobal); } @@ -30,8 +31,10 @@ CGlobalShortcutsProtocolManager::CGlobalShortcutsProtocolManager() { return; } - m_liDisplayDestroy.notify = handleDisplayDestroy; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); + wl_list_init(&m_liDisplayDestroy.listener.link); + m_liDisplayDestroy.listener.notify = handleDisplayDestroy; + m_liDisplayDestroy.parent = this; + wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); Debug::log(LOG, "GlobalShortcutsManager started successfully!"); } diff --git a/src/protocols/GlobalShortcuts.hpp b/src/protocols/GlobalShortcuts.hpp index 5fd03465..7e512021 100644 --- a/src/protocols/GlobalShortcuts.hpp +++ b/src/protocols/GlobalShortcuts.hpp @@ -14,6 +14,12 @@ struct SShortcutClient { std::vector> shortcuts; }; +class CGlobalShortcutsProtocolManager; +struct CGlobalShortcutsProtocolManagerDestroyWrapper { + wl_listener listener; + CGlobalShortcutsProtocolManager* parent = nullptr; +}; + class CGlobalShortcutsProtocolManager { public: CGlobalShortcutsProtocolManager(); @@ -31,7 +37,7 @@ class CGlobalShortcutsProtocolManager { std::vector getAllShortcuts(); - wl_listener m_liDisplayDestroy; + CGlobalShortcutsProtocolManagerDestroyWrapper m_liDisplayDestroy; private: std::vector> m_vClients; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 71c43300..954f160d 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -6,13 +6,14 @@ static void bindManagerInternal(wl_client* client, void* data, uint32_t ver, uin } static void displayDestroyInternal(struct wl_listener* listener, void* data) { - IWaylandProtocol* proto = wl_container_of(listener, proto, m_liDisplayDestroy); + IWaylandProtocolDestroyWrapper* wrap = wl_container_of(listener, wrap, listener); + IWaylandProtocol* proto = wrap->parent; proto->onDisplayDestroy(); } void IWaylandProtocol::onDisplayDestroy() { - wl_list_remove(&m_liDisplayDestroy.link); - wl_list_init(&m_liDisplayDestroy.link); + wl_list_remove(&m_liDisplayDestroy.listener.link); + wl_list_init(&m_liDisplayDestroy.listener.link); wl_global_destroy(m_pGlobal); } @@ -24,8 +25,10 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co return; } - m_liDisplayDestroy.notify = displayDestroyInternal; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); + wl_list_init(&m_liDisplayDestroy.listener.link); + m_liDisplayDestroy.listener.notify = displayDestroyInternal; + m_liDisplayDestroy.parent = this; + wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); protoLog(LOG, "Registered global"); } diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 6154fa30..4d4e7925 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -11,6 +11,12 @@ #define PROTO NProtocols +class IWaylandProtocol; +struct IWaylandProtocolDestroyWrapper { + wl_listener listener; + IWaylandProtocol* parent = nullptr; +}; + class IWaylandProtocol { public: IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name); @@ -26,7 +32,7 @@ class IWaylandProtocol { Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...))); }; - wl_listener m_liDisplayDestroy; + IWaylandProtocolDestroyWrapper m_liDisplayDestroy; private: std::string m_szName; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 43a2c3a7..b925fcc9 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -345,6 +345,22 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } +CHyprOpenGLImpl::~CHyprOpenGLImpl() { + if (m_pEglDisplay && m_pEglContext != EGL_NO_CONTEXT) + eglDestroyContext(m_pEglDisplay, m_pEglContext); + + if (m_pEglDisplay) + eglTerminate(m_pEglDisplay); + + eglReleaseThread(); + + if (m_pGbmDevice) + gbm_device_destroy(m_pGbmDevice); + + if (m_iGBMFD >= 0) + close(m_iGBMFD); +} + std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { // TODO: return std::expected when clang supports it diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 41e80ee5..1e8325c1 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -145,6 +145,7 @@ class CGradientValueData; class CHyprOpenGLImpl { public: CHyprOpenGLImpl(); + ~CHyprOpenGLImpl(); void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); void beginSimple(CMonitor*, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); From e67322034037fef22079c8e480be38c1d04b5a4a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 29 Jul 2024 19:02:58 +0200 Subject: [PATCH 0413/2393] core/surface: fixup a few pointer handling edge cases --- src/managers/PointerManager.cpp | 4 ++++ src/protocols/core/Compositor.cpp | 10 ++++++++-- src/protocols/core/Compositor.hpp | 1 + 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index a09992a2..a405e2eb 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -151,6 +151,8 @@ void CPointerManager::setCursorSurface(SP surf, const Vector2D& hots currentCursorImage.surface = surf; currentCursorImage.scale = surf->resource()->current.scale; + surf->resource()->map(); + currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) { damageIfSoftware(); @@ -222,6 +224,8 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.surface->resource()->leave(m); } + currentCursorImage.surface->resource()->unmap(); + currentCursorImage.destroySurface.reset(); currentCursorImage.commitSurface.reset(); currentCursorImage.surface.reset(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 6352b7e6..43d3059b 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -156,6 +156,7 @@ void CWLSurfaceResource::destroy() { unmap(); } events.destroy.emit(); + releaseBuffers(false); PROTO::compositor->destroyResource(this); } @@ -338,13 +339,18 @@ void CWLSurfaceResource::unmap() { // release the buffers. // this is necessary for XWayland to function correctly, // as it does not unmap via the traditional commit(null buffer) method, but via the X11 protocol. + releaseBuffers(); +} + +void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) { if (current.buffer && !current.buffer->resource->released) current.buffer->sendRelease(); - if (pending.buffer && !pending.buffer->resource->released) + if (pending.buffer && !pending.buffer->resource->released && !onlyCurrent) pending.buffer->sendRelease(); pending.buffer.reset(); - current.buffer.reset(); + if (!onlyCurrent) + current.buffer.reset(); } void CWLSurfaceResource::error(int code, const std::string& str) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 1fa6926a..79cd1de6 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -137,6 +137,7 @@ class CWLSurfaceResource { int stateLocks = 0; void destroy(); + void releaseBuffers(bool onlyCurrent = true); void commitPendingState(); void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); }; From 743e98f0c0c2de63a0715f7112dade3a819a8307 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 11:54:28 +0200 Subject: [PATCH 0414/2393] hyprpm: add short error code explanations --- hyprpm/src/core/PluginManager.cpp | 15 ++++++++++++++- hyprpm/src/core/PluginManager.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index edb98812..15ce87f7 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -529,7 +529,8 @@ bool CPluginManager::updateHeaders(bool force) { std::cout << "\n"; } else { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID)); + progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" + + headerErrorShort(HEADERSVALID) + ")"); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Failed"; progress.print(); @@ -880,6 +881,18 @@ std::string CPluginManager::headerError(const eHeadersErrors err) { return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; } +std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { + switch (err) { + case HEADERS_CORRUPTED: return "Headers corrupted"; + case HEADERS_MISMATCHED: return "Headers version mismatched"; + case HEADERS_NOT_HYPRLAND: return "Not running on Hyprland"; + case HEADERS_MISSING: return "Headers missing"; + case HEADERS_DUPLICATED: return "Headers duplicated"; + default: break; + } + return "?"; +} + bool CPluginManager::hasDeps() { std::vector deps = {"meson", "cpio", "cmake"}; for (auto& d : deps) { diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index 13ea5b12..c16a9d0f 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -66,6 +66,7 @@ class CPluginManager { private: std::string headerError(const eHeadersErrors err); + std::string headerErrorShort(const eHeadersErrors err); std::string m_szWorkingPluginDirectory = ""; }; From 68ee4dda5e4f4ce719bc814b873deca73f3d5eba Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 12:05:23 +0200 Subject: [PATCH 0415/2393] hyprpm: warn about uncheckoutable commits --- hyprpm/src/core/PluginManager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 15ce87f7..a29afad7 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -464,8 +464,18 @@ bool CPluginManager::updateHeaders(bool force) { progress.m_szCurrentMessage = "Checking out sources"; progress.print(); + if (m_bVerbose) + progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); + ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); + if (ret.contains("fatal: unable to read tree")) { + std::cerr << "\n" + << Colors::RED << "✖" << Colors::RESET + << " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n"; + return false; + } + if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); From 46c6efeab39cae0e709a2a29d299dd4dfab36a8c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 12:11:38 +0200 Subject: [PATCH 0416/2393] hyprpm: execute all git commands regardless of fails --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index a29afad7..6988547c 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -479,7 +479,7 @@ bool CPluginManager::updateHeaders(bool force) { if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); - ret = execAndGet("cd " + WORKINGDIR + " && git rm subprojects/tracy && git submodule update --init 2>&1 && git reset --hard --recurse-submodules " + HLVER.hash); + ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); From 10e631053aaccdf31fab195454deab1154e21219 Mon Sep 17 00:00:00 2001 From: jim3692 <31220180+jim3692@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:50:13 +0300 Subject: [PATCH 0417/2393] compositor: fix log typos (#7111) --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 36f483fd..f6e418de 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -247,7 +247,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) { if (!m_pAqBackend) { Debug::log(CRIT, - "m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland " + "m_pAqBackend was null! This usually means aquamarine could not find a GPU or encountered some issues. Make sure you're running either on a tty or on a Wayland " "session, NOT an X11 one."); throwError("CBackend::create() failed!"); } @@ -258,7 +258,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) { if (!m_pAqBackend->start()) { Debug::log(CRIT, - "m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a " + "m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or encountered some issues. Make sure you're running either on a tty or on a " "Wayland session, NOT an X11 one."); throwError("CBackend::create() failed!"); } From f3a9f9ec4544225d6f340fa5f8a0dab9bf39157c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 15:32:38 +0200 Subject: [PATCH 0418/2393] pointer: use preMonitorCommit for resetting render state in DS preRender is not called --- src/helpers/Monitor.cpp | 2 ++ src/managers/PointerManager.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 635427d1..9d282090 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -863,6 +863,8 @@ bool CMonitorState::commit() { if (!updateSwapchain()) return false; + EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner); + ensureBufferPresent(); bool ret = m_pOwner->output->commit(); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index a405e2eb..8314e79a 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -25,7 +25,7 @@ CPointerManager::CPointerManager() { nullptr); }); - hooks.monitorPreRender = g_pHookSystem->hookDynamic("preRender", [this](void* self, SCallbackInfo& info, std::any data) { + hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) { auto state = stateFor(std::any_cast(data)->self.lock()); if (!state) return; From c1afc82a4ceb2e1989ec750b476a97f7f49051e3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 30 Jul 2024 13:34:22 +0000 Subject: [PATCH 0419/2393] [gha] Nix: update inputs --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 01b68384..045e692e 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1722100913, - "narHash": "sha256-75Hcx5Zu0f+BeCkZxN1frkYacjbkwgCq+z3doVgr4Hw=", + "lastModified": 1722283490, + "narHash": "sha256-xqaO+h2ams6bpfNdUAtvWN6SKuNIeyr3lXYsAKYS/+0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "4918e57979bbdbd05aabb20f63e1cb5dc289bcbd", + "rev": "9ccb4411ee001715db0fbc74e7ff1cea02c6c24f", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1721924956, - "narHash": "sha256-Sb1jlyRO+N8jBXEX9Pg9Z1Qb8Bw9QyOgLDNMEpmjZ2M=", + "lastModified": 1722185531, + "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5ad6a14c6bf098e98800b091668718c336effc95", + "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d", "type": "github" }, "original": { From 1c221240d0c6c352cea203b51a918b906a8d340f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 15:46:35 +0200 Subject: [PATCH 0420/2393] output: submit damage to kms --- src/helpers/Monitor.cpp | 2 ++ src/render/Renderer.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9d282090..787b790f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -822,6 +822,8 @@ bool CMonitor::attemptDirectScanout() { Debug::log(TRACE, "presentFeedback for DS"); PSURFACE->presentFeedback(&now, this, true); + output->state->addDamage(CBox{{}, vecPixelSize}); + if (state.commit()) { if (lastScanout.expired()) { lastScanout = PCANDIDATE; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0bf4c9f3..df0c6af5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1371,6 +1371,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { frameDamage.add(damage); g_pHyprRenderer->damageMirrorsWith(pMonitor, frameDamage); + + pMonitor->output->state->addDamage(frameDamage); } pMonitor->renderingActive = false; From cc7c117fe76ff0a4da56b18026c725501de92c84 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 30 Jul 2024 15:50:14 +0200 Subject: [PATCH 0421/2393] output: minor tearing fixes --- src/helpers/Monitor.cpp | 3 ++- src/render/Renderer.cpp | 7 ++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 787b790f..33fe0c04 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -812,7 +812,8 @@ bool CMonitor::attemptDirectScanout() { // and comes from the appropriate device. This may implode on multi-gpu!! output->state->setBuffer(PSURFACE->current.buffer); - output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); + output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : + Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); if (!state.test()) return false; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index df0c6af5..b5397598 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1193,6 +1193,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { shouldTear = true; } + pMonitor->tearingState.activelyTearing = shouldTear; + if (!*PNODIRECTSCANOUT && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; @@ -1202,11 +1204,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } - if (pMonitor->tearingState.activelyTearing != shouldTear) { - // change of state - pMonitor->tearingState.activelyTearing = shouldTear; - } - EMIT_HOOK_EVENT("preRender", pMonitor); timespec now; From 8ec3dc4c09c30aab7669f99ba6359be320023fa8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 30 Jul 2024 22:13:47 +0300 Subject: [PATCH 0422/2393] CI: update actions flake.lock: update aquamarine and xdph --- .github/workflows/nix-build.yml | 6 +++--- flake.lock | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 33ee5cac..d0234498 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -15,14 +15,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.ref }} submodules: recursive - - uses: cachix/install-nix-action@v26 + - uses: cachix/install-nix-action@v27 - uses: DeterminateSystems/magic-nix-cache-action@main - - uses: cachix/cachix-action@v12 + - uses: cachix/cachix-action@v15 with: name: hyprland authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' diff --git a/flake.lock b/flake.lock index 045e692e..5c384d4d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1722283490, - "narHash": "sha256-xqaO+h2ams6bpfNdUAtvWN6SKuNIeyr3lXYsAKYS/+0=", + "lastModified": 1722347739, + "narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9ccb4411ee001715db0fbc74e7ff1cea02c6c24f", + "rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1722181019, - "narHash": "sha256-Lj/g1UzrsTZUixtveQix6eB3pon2j23qv5/5pzTx0LQ=", + "lastModified": 1722365976, + "narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "0e2f3b9c85f7bab3983098a01366876d34daf383", + "rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341", "type": "github" }, "original": { From 3b9b5346b830554aa7470ccf1202a7f3be72d1b4 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:33:56 -0500 Subject: [PATCH 0423/2393] protocols: Move globalshortcuts impl (#7102) * move global shortcuts to hyprwayland-scanner * remove wayland-scanner from deps * fix the thing --- CMakeLists.txt | 31 +----- protocols/meson.build | 28 +----- src/debug/HyprCtl.cpp | 3 +- src/managers/KeybindManager.cpp | 5 +- src/managers/ProtocolManager.cpp | 7 +- src/managers/ProtocolManager.hpp | 4 - src/protocols/GlobalShortcuts.cpp | 153 +++++++++--------------------- src/protocols/GlobalShortcuts.hpp | 65 ++++++------- 8 files changed, 84 insertions(+), 212 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 550f1dc5..3616da24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,6 @@ endif() find_package(PkgConfig REQUIRED) -pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner) -message(STATUS "Found WaylandScanner at ${WaylandScanner}") pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) @@ -232,30 +230,6 @@ target_link_libraries(Hyprland rt PkgConfig::deps) # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) -function(protocol protoPath protoName external) - if(external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) - else() - set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) - endif() - - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - COMMAND ${WaylandScanner} server-header ${path} - protocols/${protoName}-protocol.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - add_custom_command( - OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c - COMMAND ${WaylandScanner} private-code ${path} - protocols/${protoName}-protocol.c - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources( - Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h - ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c) - target_sources(generate-protocol-headers - PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h) -endfunction() - function(protocolnew protoPath protoName external) if(external) set(path ${CMAKE_SOURCE_DIR}/${protoPath}) @@ -288,10 +262,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86 uuid) -protocol( - "subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" - "hyprland-global-shortcuts-v1" true) - +protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-global-shortcuts-v1" true) protocolnew("unstable/text-input" "text-input-unstable-v1" false) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) diff --git a/protocols/meson.build b/protocols/meson.build index 4fd40859..5b807914 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -12,21 +12,12 @@ hyprland_protos = dependency('hyprland-protocols', wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') -wayland_scanner_dep = dependency('wayland-scanner', native: true) -wayland_scanner = find_program( - wayland_scanner_dep.get_variable('wayland_scanner'), - native: true, -) hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, ) -protocols = [ - [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'] -] - new_protocols = [ ['wlr-gamma-control-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], @@ -40,6 +31,7 @@ new_protocols = [ ['wayland-drm.xml'], ['wlr-data-control-unstable-v1.xml'], ['wlr-screencopy-unstable-v1.xml'], + [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], [hl_protocol_dir, 'protocols/hyprland-focus-grab-v1.xml'], [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], @@ -73,24 +65,6 @@ new_protocols = [ wl_protos_src = [] wl_protos_headers = [] -foreach p : protocols - xml = join_paths(p) - wl_protos_src += custom_target( - xml.underscorify() + '_server_c', - input: xml, - output: '@BASENAME@-protocol.c', - command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], - ) - wl_protos_headers += custom_target( - xml.underscorify() + '_server_h', - input: xml, - install: true, - install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'), - output: '@BASENAME@-protocol.h', - command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'], - ) -endforeach - new_wl_protos = [] foreach p : new_protocols xml = join_paths(p) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b81cfeff..d89d1772 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -32,6 +32,7 @@ using namespace Hyprutils::String; #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "debug/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" @@ -776,7 +777,7 @@ std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string request) std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string request) { std::string ret = ""; - const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts(); + const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { for (auto& sh : SHORTCUTS) ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 038f6401..2b99ce97 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../devices/IKeyboard.hpp" #include "KeybindManager.hpp" @@ -2664,10 +2665,10 @@ void CKeybindManager::global(std::string args) { if (NAME.empty()) return; - if (!g_pProtocolManager->m_pGlobalShortcutsProtocolManager->globalShortcutExists(APPID, NAME)) + if (!PROTO::globalShortcuts->isTaken(APPID, NAME)) return; - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); + PROTO::globalShortcuts->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); } void CKeybindManager::moveGroupWindow(std::string args) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index d052e045..635e6223 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -42,6 +42,7 @@ #include "../protocols/Screencopy.hpp" #include "../protocols/ToplevelExport.hpp" #include "../protocols/TextInputV1.hpp" +#include "../protocols/GlobalShortcuts.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -148,6 +149,7 @@ CProtocolManager::CProtocolManager() { PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); + PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -164,10 +166,6 @@ CProtocolManager::CProtocolManager() { PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); } else Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); - - // Old protocol implementations. - // TODO: rewrite them to use hyprwayland-scanner. - m_pGlobalShortcutsProtocolManager = std::make_unique(); } CProtocolManager::~CProtocolManager() { @@ -220,6 +218,7 @@ CProtocolManager::~CProtocolManager() { PROTO::xwaylandShell.reset(); PROTO::screencopy.reset(); PROTO::toplevelExport.reset(); + PROTO::globalShortcuts.reset(); PROTO::lease.reset(); PROTO::sync.reset(); diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 044a4d9b..1b6d31b6 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../protocols/GlobalShortcuts.hpp" #include "../helpers/Monitor.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" @@ -12,9 +11,6 @@ class CProtocolManager { CProtocolManager(); ~CProtocolManager(); - // TODO: rewrite to use the new protocol framework - std::unique_ptr m_pGlobalShortcutsProtocolManager; - private: std::unordered_map m_mModeChangeListeners; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 7eb84be6..860004c9 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,120 +1,61 @@ #include "GlobalShortcuts.hpp" #include "../Compositor.hpp" -#define GLOBAL_SHORTCUTS_VERSION 1 +#define LOGM PROTO::globalShortcuts->protoLog -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->bindManager(client, data, version, id); -} - -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - CGlobalShortcutsProtocolManagerDestroyWrapper* wrap = wl_container_of(listener, wrap, listener); - CGlobalShortcutsProtocolManager* proto = wrap->parent; - proto->displayDestroy(); -} - -void CGlobalShortcutsProtocolManager::displayDestroy() { - wl_list_remove(&m_liDisplayDestroy.listener.link); - wl_list_init(&m_liDisplayDestroy.listener.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); - - if (!m_pGlobal) { - Debug::log(ERR, "GlobalShortcutsManager could not start!"); +CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { + if (!good()) return; - } - wl_list_init(&m_liDisplayDestroy.listener.link); - m_liDisplayDestroy.listener.notify = handleDisplayDestroy; - m_liDisplayDestroy.parent = this; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); + resource->setOnDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); }); + resource->setDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); }); - Debug::log(LOG, "GlobalShortcutsManager started successfully!"); -} - -static void handleRegisterShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->registerShortcut(client, resource, shortcut, id, app_id, description, trigger_description); -} - -static void handleDestroy(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static const struct hyprland_global_shortcuts_manager_v1_interface globalShortcutsManagerImpl = { - .register_shortcut = handleRegisterShortcut, - .destroy = handleDestroy, -}; - -static const struct hyprland_global_shortcut_v1_interface shortcutImpl = { - .destroy = handleDestroy, -}; - -void CGlobalShortcutsProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto RESOURCE = wl_resource_create(client, &hyprland_global_shortcuts_manager_v1_interface, version, id); - wl_resource_set_implementation(RESOURCE, &globalShortcutsManagerImpl, this, nullptr); - - Debug::log(LOG, "GlobalShortcutsManager bound successfully!"); - - m_vClients.emplace_back(std::make_unique(client)); -} - -SShortcutClient* CGlobalShortcutsProtocolManager::clientFromWlClient(wl_client* client) { - for (auto& c : m_vClients) { - if (c->client == client) { - return c.get(); + resource->setRegisterShortcut([this](CHyprlandGlobalShortcutsManagerV1* pMgr, uint32_t shortcut, const char* id, const char* app_id, const char* description, + const char* trigger_description) { + if (PROTO::globalShortcuts->isTaken(id, app_id)) { + resource->error(HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken"); + return; } - } - return nullptr; -} + const auto PSHORTCUT = shortcuts.emplace_back(makeShared(makeShared(resource->client(), resource->version(), shortcut))); + PSHORTCUT->id = id; + PSHORTCUT->description = description; + PSHORTCUT->appid = app_id; + PSHORTCUT->shortcut = shortcut; -static void onShortcutDestroy(wl_resource* pResource) { - g_pProtocolManager->m_pGlobalShortcutsProtocolManager->destroyShortcut(pResource); -} - -void CGlobalShortcutsProtocolManager::registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description) { - const auto PCLIENT = clientFromWlClient(client); - - if (!PCLIENT) { - Debug::log(ERR, "Error at global shortcuts: no client in register?"); - return; - } - - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { - if (sh->appid == app_id && sh->id == id) { - wl_resource_post_error(resource, HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken"); - return; - } + if (!PSHORTCUT->resource->resource()) { + PSHORTCUT->resource->noMemory(); + shortcuts.pop_back(); + return; } - } - const auto PSHORTCUT = PCLIENT->shortcuts.emplace_back(std::make_unique()).get(); - PSHORTCUT->id = id; - PSHORTCUT->description = description; - PSHORTCUT->appid = app_id; - PSHORTCUT->shortcut = shortcut; + PSHORTCUT->resource->setDestroy([this](CHyprlandGlobalShortcutV1* pMgr) { std::erase_if(shortcuts, [&](const auto& other) { return other->resource.get() == pMgr; }); }); + }); +} - PSHORTCUT->resource = wl_resource_create(client, &hyprland_global_shortcut_v1_interface, 1, shortcut); - if (!PSHORTCUT->resource) { +bool CShortcutClient::good() { + return resource->resource(); +} + +CGlobalShortcutsProtocol::CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CGlobalShortcutsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESROUCE = m_vClients.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESROUCE->good()) { wl_client_post_no_memory(client); - std::erase_if(PCLIENT->shortcuts, [&](const auto& other) { return other.get() == PSHORTCUT; }); + m_vClients.pop_back(); return; } - - wl_resource_set_implementation(PSHORTCUT->resource, &shortcutImpl, this, &onShortcutDestroy); } -bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, std::string trigger) { +void CGlobalShortcutsProtocol::destroyResource(CShortcutClient* client) { + std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); +} + +bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { @@ -126,7 +67,7 @@ bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, st return false; } -void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { +void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { @@ -135,15 +76,15 @@ void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0; uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF; if (pressed) - hyprland_global_shortcut_v1_send_pressed(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); + sh->resource->sendPressed(tvSecHi, tvSecLo, now.tv_nsec); else - hyprland_global_shortcut_v1_send_released(sh->resource, tvSecHi, tvSecLo, now.tv_nsec); + sh->resource->sendReleased(tvSecHi, tvSecLo, now.tv_nsec); } } } } -std::vector CGlobalShortcutsProtocolManager::getAllShortcuts() { +std::vector CGlobalShortcutsProtocol::getAllShortcuts() { std::vector copy; for (auto& c : m_vClients) { for (auto& sh : c->shortcuts) { @@ -153,9 +94,3 @@ std::vector CGlobalShortcutsProtocolManager::getAllShortcuts() { return copy; } - -void CGlobalShortcutsProtocolManager::destroyShortcut(wl_resource* resource) { - for (auto& c : m_vClients) { - std::erase_if(c->shortcuts, [&](const auto& other) { return other->resource == resource; }); - } -} diff --git a/src/protocols/GlobalShortcuts.hpp b/src/protocols/GlobalShortcuts.hpp index 7e512021..14f6ee0b 100644 --- a/src/protocols/GlobalShortcuts.hpp +++ b/src/protocols/GlobalShortcuts.hpp @@ -1,48 +1,43 @@ #pragma once #include "../defines.hpp" -#include "hyprland-global-shortcuts-v1-protocol.h" +#include "hyprland-global-shortcuts-v1.hpp" +#include "../protocols/WaylandProtocol.hpp" #include struct SShortcut { - wl_resource* resource; - std::string id, description, appid; - uint32_t shortcut = 0; + SP resource; + std::string id, description, appid; + uint32_t shortcut = 0; }; -struct SShortcutClient { - wl_client* client = nullptr; - std::vector> shortcuts; -}; - -class CGlobalShortcutsProtocolManager; -struct CGlobalShortcutsProtocolManagerDestroyWrapper { - wl_listener listener; - CGlobalShortcutsProtocolManager* parent = nullptr; -}; - -class CGlobalShortcutsProtocolManager { +class CShortcutClient { public: - CGlobalShortcutsProtocolManager(); - ~CGlobalShortcutsProtocolManager(); + CShortcutClient(SP resource); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); - void displayDestroy(); - - void registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description, - const char* trigger_description); - void destroyShortcut(wl_resource* resource); - - bool globalShortcutExists(std::string appid, std::string trigger); - void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed); - - std::vector getAllShortcuts(); - - CGlobalShortcutsProtocolManagerDestroyWrapper m_liDisplayDestroy; + bool good(); private: - std::vector> m_vClients; + SP resource; + std::vector> shortcuts; - SShortcutClient* clientFromWlClient(wl_client* client); - - wl_global* m_pGlobal = nullptr; + friend class CGlobalShortcutsProtocol; +}; + +class CGlobalShortcutsProtocol : IWaylandProtocol { + public: + CGlobalShortcutsProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void destroyResource(CShortcutClient* client); + + void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed); + bool isTaken(std::string id, std::string app_id); + std::vector getAllShortcuts(); + + private: + std::vector> m_vClients; +}; + +namespace PROTO { + inline UP globalShortcuts; }; From 8a5f9bbb394ddeb4be9a9df6248b41b07d84ea66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:54:07 +0100 Subject: [PATCH 0424/2393] keybinds: handle null monitor in pinActive (#7122) --- src/managers/KeybindManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2b99ce97..823e2d2e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2333,8 +2333,16 @@ void CKeybindManager::pinActive(std::string args) { if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) return; - PWINDOW->m_bPinned = !PWINDOW->m_bPinned; - PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeWorkspace; + PWINDOW->m_bPinned = !PWINDOW->m_bPinned; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + + if (!PMONITOR) { + Debug::log(ERR, "pin: monitor not found"); + return; + } + + PWINDOW->m_pWorkspace = PMONITOR->activeWorkspace; PWINDOW->updateDynamicRules(); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); From e989a0bcffac81092ed2a7e371f5225c113f689d Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:55:52 +0000 Subject: [PATCH 0425/2393] internal: refactor fullscreen states (#7104) * refactor fullscreen modified: src/Compositor.cpp modified: src/Compositor.hpp modified: src/config/ConfigManager.cpp modified: src/config/ConfigManager.hpp modified: src/debug/HyprCtl.cpp modified: src/desktop/LayerSurface.cpp modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/desktop/Workspace.cpp modified: src/desktop/Workspace.hpp modified: src/events/Windows.cpp modified: src/helpers/Monitor.cpp modified: src/layout/DwindleLayout.cpp modified: src/layout/DwindleLayout.hpp modified: src/layout/IHyprLayout.cpp modified: src/layout/IHyprLayout.hpp modified: src/layout/MasterLayout.cpp modified: src/layout/MasterLayout.hpp modified: src/managers/KeybindManager.cpp modified: src/managers/KeybindManager.hpp modified: src/managers/input/IdleInhibitor.cpp modified: src/managers/input/InputManager.cpp modified: src/managers/input/Swipe.cpp modified: src/protocols/ForeignToplevelWlr.cpp modified: src/render/Renderer.cpp modified: src/render/decorations/CHyprGroupBarDecoration.cpp * clean up modified: src/config/ConfigManager.cpp modified: src/debug/HyprCtl.cpp modified: src/desktop/Window.hpp modified: src/desktop/Workspace.cpp modified: src/events/Windows.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/input/Swipe.cpp * fix mapWindow fullscreen modified: src/events/Windows.cpp * fix typo modified: src/desktop/Workspace.cpp * add fullscreenstate modified: src/config/ConfigManager.cpp modified: src/events/Windows.cpp * change syncFullscreen to lower modified: src/config/ConfigManager.hpp * initialize fs state modified: src/desktop/Window.hpp --- src/Compositor.cpp | 116 +++++++++++------- src/Compositor.hpp | 6 +- src/config/ConfigManager.cpp | 10 +- src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 13 +- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Window.cpp | 40 +++--- src/desktop/Window.hpp | 43 ++++--- src/desktop/Workspace.cpp | 9 +- src/desktop/Workspace.hpp | 9 +- src/events/Windows.cpp | 99 ++++++++------- src/helpers/Monitor.cpp | 2 +- src/layout/DwindleLayout.cpp | 76 +++--------- src/layout/DwindleLayout.hpp | 2 +- src/layout/IHyprLayout.cpp | 14 +-- src/layout/IHyprLayout.hpp | 2 +- src/layout/MasterLayout.cpp | 76 ++++-------- src/layout/MasterLayout.hpp | 2 +- src/managers/KeybindManager.cpp | 81 +++++++----- src/managers/KeybindManager.hpp | 2 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 8 +- src/managers/input/Swipe.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 12 +- src/render/Renderer.cpp | 24 ++-- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- 26 files changed, 325 insertions(+), 330 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f6e418de..97355d2c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1206,7 +1206,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { for (auto& w : m_vWindows) { - if (w->workspaceID() == ID && w->m_bIsFullscreen) + if (w->workspaceID() == ID && w->isFullscreen()) return w; } @@ -1494,7 +1494,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (!PMONITOR) return nullptr; // ?? - const auto WINDOWIDEALBB = pWindow->m_bIsFullscreen ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); + const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->vecPosition, PMONITOR->vecSize} : pWindow->getWindowIdealBoundingBoxIgnoreReserved(); const auto POSA = Vector2D(WINDOWIDEALBB.x, WINDOWIDEALBB.y); const auto SIZEA = Vector2D(WINDOWIDEALBB.width, WINDOWIDEALBB.height); @@ -1507,13 +1507,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { // for tiled windows, we calc edges for (auto& w : m_vWindows) { - if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) + if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) continue; - if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) + if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) @@ -1599,13 +1599,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { constexpr float THRESHOLD = 0.3 * M_PI; for (auto& w : m_vWindows) { - if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->m_bIsFullscreen && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) + if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) continue; - if (PWORKSPACE->m_bHasFullscreenWindow && !w->m_bIsFullscreen && !w->m_bCreatedOverFullscreen) + if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) @@ -1887,7 +1887,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // opacity const auto PWORKSPACE = pWindow->m_pWorkspace; - if (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { + if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { if (pWindow == m_pLastWindow) @@ -1957,7 +1957,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) if (w->m_bIsFloating) w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; - if (w->m_bIsFullscreen) { + if (w->isFullscreen()) { w->m_vRealPosition = pMonitorB->vecPosition; w->m_vRealSize = pMonitorB->vecSize; } @@ -1982,7 +1982,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) if (w->m_bIsFloating) w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; - if (w->m_bIsFullscreen) { + if (w->isFullscreen()) { w->m_vRealPosition = pMonitorA->vecPosition; w->m_vRealSize = pMonitorA->vecSize; } @@ -2159,7 +2159,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon if (w->m_bIsFloating) w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition; - if (w->m_bIsFullscreen) { + if (w->isFullscreen()) { w->m_vRealPosition = pMonitor->vecPosition; w->m_vRealSize = pMonitor->vecSize; } @@ -2234,12 +2234,12 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { for (auto& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { - if (w->m_bFadingOut || w->m_bPinned || w->m_bIsFullscreen) + if (w->m_bFadingOut || w->m_bPinned || w->isFullscreen()) continue; if (!FULLSCREEN) w->m_fAlpha = 1.f; - else if (!w->m_bIsFullscreen) + else if (!w->isFullscreen()) w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; } } @@ -2249,54 +2249,86 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (!ls->fadingOut) - ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; + ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } } -void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMode mode) { +void CCompositor::changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON) { + setWindowFullscreenInternal( + PWINDOW, (eFullscreenMode)(ON ? (uint8_t)PWINDOW->m_sFullscreenState.internal | (uint8_t)MODE : ((uint8_t)PWINDOW->m_sFullscreenState.internal & (uint8_t)~MODE))); +} + +void CCompositor::changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON) { + setWindowFullscreenClient(PWINDOW, + (eFullscreenMode)(ON ? (uint8_t)PWINDOW->m_sFullscreenState.client | (uint8_t)MODE : ((uint8_t)PWINDOW->m_sFullscreenState.client & (uint8_t)~MODE))); +} + +void CCompositor::setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) { + if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) + setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE}); + else + setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = PWINDOW->m_sFullscreenState.client}); +} + +void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE) { + if (PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) + setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = MODE, .client = MODE}); + else + setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = MODE}); +} + +void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) { static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); - if (!validMapped(pWindow) || g_pCompositor->m_bUnsafeState) + if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState) return; - if (pWindow->m_bPinned) { - Debug::log(LOG, "Pinned windows cannot be fullscreen'd"); + state.internal = std::clamp(state.internal, (eFullscreenMode)0, FSMODE_MAX); + state.client = std::clamp(state.client, (eFullscreenMode)0, FSMODE_MAX); + + const auto PMONITOR = getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PWORKSPACE = PWINDOW->m_pWorkspace; + + const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal); + const eFullscreenMode EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)state.internal); + + const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE || (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen())); + + // TODO: update the state on syncFullscreen changes + if (!CHANGEINTERNAL && PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) return; - } - if (pWindow->m_bIsFullscreen == on) { - Debug::log(LOG, "Window is already in the required fullscreen state"); + PWINDOW->m_sFullscreenState.client = state.client; + g_pXWaylandManager->setWindowFullscreen(PWINDOW, state.client & FSMODE_FULLSCREEN); + + if (!CHANGEINTERNAL) return; - } - const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, CURRENT_EFFECTIVE_MODE, EFFECTIVE_MODE); - const auto PWORKSPACE = pWindow->m_pWorkspace; + PWINDOW->m_sFullscreenState.internal = state.internal; + PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE; + PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE; - const auto MODE = mode == FULLSCREEN_INVALID ? PWORKSPACE->m_efFullscreenMode : mode; + g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); + EMIT_HOOK_EVENT("fullscreen", PWINDOW); - if (PWORKSPACE->m_bHasFullscreenWindow && on) { - Debug::log(LOG, "Rejecting fullscreen ON on a fullscreen workspace"); - return; - } - - g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(pWindow, MODE, on); - - g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState()); - - updateWindowAnimatedDecorationValues(pWindow); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + PWINDOW->updateWindowDecos(); + updateWindowAnimatedDecorationValues(PWINDOW); // make all windows on the same workspace under the fullscreen window for (auto& w : m_vWindows) { - if (w->m_pWorkspace == PWORKSPACE && !w->m_bIsFullscreen && !w->m_bFadingOut && !w->m_bPinned) + if (w->m_pWorkspace == PWORKSPACE && !w->isFullscreen() && !w->m_bFadingOut && !w->m_bPinned) w->m_bCreatedOverFullscreen = false; } + updateFullscreenFadeOnWorkspace(PWORKSPACE); - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); - forceReportSizesToWindowsOnWorkspace(pWindow->workspaceID()); + forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID()); g_pInputManager->recheckIdleInhibitorStatus(); @@ -2307,7 +2339,7 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // ignore if DS is disabled. if (!*PNODIRECTSCANOUT) - g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr); + g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); } @@ -2639,11 +2671,11 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor if (pWindow->m_bPinned && pWorkspace->m_bIsSpecialWorkspace) return; - const bool FULLSCREEN = pWindow->m_bIsFullscreen; - const auto FULLSCREENMODE = pWindow->m_pWorkspace->m_efFullscreenMode; + const bool FULLSCREEN = pWindow->isFullscreen(); + const auto FULLSCREENMODE = pWindow->m_sFullscreenState.internal; if (FULLSCREEN) - setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + setWindowFullscreenInternal(pWindow, FSMODE_NONE); if (!pWindow->m_bIsFloating) { g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); @@ -2676,7 +2708,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor } if (FULLSCREEN) - setWindowFullscreen(pWindow, true, FULLSCREENMODE); + setWindowFullscreenInternal(pWindow, FULLSCREENMODE); g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID()); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index da390b44..295935c4 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -146,7 +146,11 @@ class CCompositor { void swapActiveWorkspaces(CMonitor*, CMonitor*); CMonitor* getMonitorFromString(const std::string&); bool workspaceIDOutOfBounds(const int64_t&); - void setWindowFullscreen(PHLWINDOW, bool, eFullscreenMode mode = FULLSCREEN_INVALID); + void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); + void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); + void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state); + void changeWindowFullscreenModeInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); + void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); PHLWINDOW getX11Parent(PHLWINDOW); void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 65eab579..fe3af8c0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1100,7 +1100,7 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo // since some rules will be applied later, we need to store some flags bool hasFloating = pWindow->m_bIsFloating; - bool hasFullscreen = pWindow->m_bIsFullscreen; + bool hasFullscreen = pWindow->isFullscreen(); // local tags for dynamic tag rule match auto tags = pWindow->m_tags; @@ -1448,7 +1448,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { if (!PWORKSPACE) return; // ??? - const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; + const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN); if (WORKSPACEFULL) { m->output->state->setAdaptiveSync(true); @@ -2099,11 +2099,11 @@ std::optional CConfigManager::handleUnbind(const std::string& comma bool windowRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{ - "fakefullscreen", "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", + "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", }; static const auto rulesPrefix = std::vector{ - "animation", "bordercolor", "bordersize", "center", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", - "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", + "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", + "move", "opacity", "plugin:", "pseudo", "rounding", "size", "suppressevent", "tag", "workspace", "xray", }; const auto VALS = CVarList(RULE, 2, ' '); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 454a12c0..75dea9ef 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -182,6 +182,7 @@ class CConfigManager { {"noshortcutsinhibit", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.noShortcutsInhibit; }}, {"opaque", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.opaque; }}, {"forcergbx", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.RGBX; }}, + {"syncfullscreen", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.syncFullscreen; }}, {"immediate", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.tearing; }}, {"xray", [](PHLWINDOW pWindow) { return &pWindow->m_sWindowData.xray; }}, }; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d89d1772..cf873e6c 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -240,8 +240,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "xwayland": {}, "pinned": {}, "fullscreen": {}, - "fullscreenMode": {}, - "fakeFullscreen": {}, + "fullscreenClient": {}, "grouped": [{}], "tags": [{}], "swallowing": "0x{:x}", @@ -252,19 +251,19 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), - (w->m_bIsFullscreen ? "true" : "false"), (w->m_bIsFullscreen ? (w->m_pWorkspace ? (int)w->m_pWorkspace->m_efFullscreenMode : 0) : 0), - w->m_bFakeFullscreenState ? "true" : "false", getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), + (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } 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: " "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\txwayland: {}\n\tpinned: " - "{}\n\tfullscreen: {}\n\tfullscreenmode: {}\n\tfakefullscreen: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", + "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), - (int)w->m_bIsX11, (int)w->m_bPinned, (int)w->m_bIsFullscreen, (w->m_bIsFullscreen ? (w->m_pWorkspace ? w->m_pWorkspace->m_efFullscreenMode : 0) : 0), - (int)w->m_bFakeFullscreenState, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); + (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), + (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 4426491d..80138910 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -165,7 +165,7 @@ void CLayerSurface::onMap() { CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); const auto WORKSPACE = PMONITOR->activeWorkspace; - const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; + const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN; startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); readyToDelete = false; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index f635d367..9316959d 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -192,7 +192,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { auto POS = m_vPosition; auto SIZE = m_vSize; - if (m_bIsFullscreen) { + if (isFullscreen()) { POS = PMONITOR->vecPosition; SIZE = PMONITOR->vecSize; @@ -970,8 +970,9 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { return; const auto PCURRENT = getGroupCurrent(); - const bool FULLSCREEN = PCURRENT->m_bIsFullscreen; + const bool FULLSCREEN = PCURRENT->isFullscreen(); const auto WORKSPACE = PCURRENT->m_pWorkspace; + const auto MODE = PCURRENT->m_sFullscreenState.client; const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); @@ -979,7 +980,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { const auto CURRENTISFOCUS = PCURRENT == g_pCompositor->m_pLastWindow.lock(); if (FULLSCREEN) - g_pCompositor->setWindowFullscreen(PCURRENT, false, WORKSPACE->m_efFullscreenMode); + g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE); PCURRENT->setHidden(true); pWindow->setHidden(false); // can remove m_pLastWindow @@ -997,7 +998,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { g_pCompositor->focusWindow(pWindow); if (FULLSCREEN) - g_pCompositor->setWindowFullscreen(pWindow, true, WORKSPACE->m_efFullscreenMode); + g_pCompositor->setWindowFullscreenInternal(pWindow, MODE); g_pHyprRenderer->damageWindow(pWindow); @@ -1140,7 +1141,7 @@ void CWindow::updateWindowData(const SWorkspaceRule& workspaceRule) { } int CWindow::getRealBorderSize() { - if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && m_bIsFullscreen && (m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL))) + if (m_sWindowData.noBorder.valueOrDefault() || (m_pWorkspace && isEffectiveInternalFSMode(FSMODE_FULLSCREEN))) return 0; static auto PBORDERSIZE = CConfigValue("general:border_size"); @@ -1153,11 +1154,6 @@ bool CWindow::canBeTorn() { return m_sWindowData.tearing.valueOr(m_bTearingHint) && *PTEARING; } -bool CWindow::shouldSendFullscreenState() { - const auto MODE = m_pWorkspace->m_efFullscreenMode; - return m_bDontSendFullscreen ? false : (m_bFakeFullscreenState || (m_bIsFullscreen && (MODE == FULLSCREEN_FULL))); -} - void CWindow::setSuspended(bool suspend) { if (suspend == m_bSuspended) return; @@ -1184,7 +1180,7 @@ void CWindow::setAnimationsToMove() { void CWindow::onWorkspaceAnimUpdate() { // clip box for animated offsets - if (!m_bIsFloating || m_bPinned || m_bIsFullscreen) { + if (!m_bIsFloating || m_bPinned || isFullscreen()) { m_vFloatingOffset = Vector2D(0, 0); return; } @@ -1238,6 +1234,14 @@ int CWindow::surfacesCount() { return no; } +bool CWindow::isFullscreen() { + return m_sFullscreenState.internal != FSMODE_NONE; +} + +bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) { + return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE; +} + int CWindow::workspaceID() { return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; } @@ -1315,19 +1319,17 @@ void CWindow::onUpdateState() { if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { bool fs = requestsFS.value(); - - if (fs != m_bIsFullscreen && m_bIsMapped) - g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_FULL); + if (m_bIsMapped) { + g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value()); + } if (!m_bIsMapped) m_bWantsInitialFullscreen = fs; } if (requestsMX.has_value() && !(m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) { - bool fs = requestsMX.value(); - - if (fs != m_bIsFullscreen && m_bIsMapped) - g_pCompositor->setWindowFullscreen(m_pSelf.lock(), fs, FULLSCREEN_MAXIMIZED); + if (m_bIsMapped) + g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_MAXIMIZED, requestsMX.value()); } } @@ -1432,7 +1434,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); - if (!m_bIsFloating || m_bIsFullscreen || g_pInputManager->currentlyDraggedWindow == m_pSelf) { + if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 108b804c..11bf662a 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -16,6 +16,7 @@ #include "Popup.hpp" #include "Subsurface.hpp" #include "WLSurface.hpp" +#include "Workspace.hpp" class CXDGSurfaceResource; class CXWaylandSurface; @@ -170,6 +171,7 @@ struct SWindowData { CWindowOverridableVar noShortcutsInhibit = false; CWindowOverridableVar opaque = false; CWindowOverridableVar RGBX = false; + CWindowOverridableVar syncFullscreen = true; CWindowOverridableVar tearing = false; CWindowOverridableVar xray = false; @@ -208,6 +210,11 @@ struct SInitialWorkspaceToken { std::string workspace; }; +struct sFullscreenState { + eFullscreenMode internal = FSMODE_NONE; + eFullscreenMode client = FSMODE_NONE; +}; + class CWindow { public: static PHLWINDOW create(SP); @@ -256,24 +263,23 @@ class CWindow { Vector2D m_vPseudoSize = Vector2D(1280, 720); // for recovering relative cursor position - Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); + Vector2D m_vRelativeCursorCoordsOnLastWarp = Vector2D(-1, -1); - bool m_bFirstMap = false; // for layouts - bool m_bIsFloating = false; - bool m_bDraggingTiled = false; // for dragging around tiled windows - bool m_bIsFullscreen = false; - bool m_bDontSendFullscreen = false; - bool m_bWasMaximized = false; - uint64_t m_iMonitorID = -1; - std::string m_szTitle = ""; - std::string m_szClass = ""; - std::string m_szInitialTitle = ""; - std::string m_szInitialClass = ""; - PHLWORKSPACE m_pWorkspace; + bool m_bFirstMap = false; // for layouts + bool m_bIsFloating = false; + bool m_bDraggingTiled = false; // for dragging around tiled windows + bool m_bWasMaximized = false; + sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; + uint64_t m_iMonitorID = -1; + std::string m_szTitle = ""; + std::string m_szClass = ""; + std::string m_szInitialTitle = ""; + std::string m_szInitialClass = ""; + PHLWORKSPACE m_pWorkspace; - bool m_bIsMapped = false; + bool m_bIsMapped = false; - bool m_bRequestsFloat = false; + bool m_bRequestsFloat = false; // This is for fullscreen apps bool m_bCreatedOverFullscreen = false; @@ -322,9 +328,6 @@ class CWindow { // urgency hint bool m_bIsUrgent = false; - // fakefullscreen - bool m_bFakeFullscreenState = false; - // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. PHLWINDOWREF m_pLastCycledWindow; @@ -416,7 +419,6 @@ class CWindow { bool opaque(); float rounding(); bool canBeTorn(); - bool shouldSendFullscreenState(); void setSuspended(bool suspend); bool visibleOnMonitor(CMonitor* pMonitor); int workspaceID(); @@ -424,6 +426,9 @@ class CWindow { void activate(bool force = false); int surfacesCount(); + bool isFullscreen(); + bool isEffectiveInternalFSMode(const eFullscreenMode); + int getRealBorderSize(); void updateWindowData(); void updateWindowData(const struct SWorkspaceRule&); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 34db914e..a08f1804 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -480,16 +480,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { return false; break; case 0: // fullscreen full - if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL) + if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_FULLSCREEN) return false; break; case 1: // maximized - if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_MAXIMIZED) - return false; - break; - case 2: // fullscreen without sending fullscreen state to window - if (!m_bHasFullscreenWindow || m_efFullscreenMode != FULLSCREEN_FULL || !g_pCompositor->getFullscreenWindowOnWorkspace(m_iID) || - !g_pCompositor->getFullscreenWindowOnWorkspace(m_iID)->m_bDontSendFullscreen) + if (!m_bHasFullscreenWindow || m_efFullscreenMode != FSMODE_MAXIMIZED) return false; break; default: break; diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index bb5cd441..3e9ac8a8 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -7,9 +7,10 @@ #include "../helpers/MiscFunctions.hpp" enum eFullscreenMode : int8_t { - FULLSCREEN_INVALID = -1, - FULLSCREEN_FULL = 0, - FULLSCREEN_MAXIMIZED + FSMODE_NONE = 0, + FSMODE_MAXIMIZED = 1 << 0, + FSMODE_FULLSCREEN = 1 << 1, + FSMODE_MAX = (1 << 2) - 1 }; class CWindow; @@ -31,7 +32,7 @@ class CWorkspace { SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; bool m_bHasFullscreenWindow = false; - eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL; + eFullscreenMode m_efFullscreenMode = FSMODE_NONE; wl_array m_wlrCoordinateArr; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index b2abb65c..71ad4ba1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -133,12 +133,11 @@ void Events::listener_mapWindow(void* owner, void* data) { } // window rules - PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); - bool requestsFullscreen = PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen); - bool requestsFakeFullscreen = false; - bool requestsMaximize = false; - bool overridingNoFullscreen = false; - bool overridingNoMaximize = false; + PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); + std::optional requestedInternalFSMode, requestedClientFSMode; + std::optional requestedFSState; + if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) + requestedClientFSMode = FSMODE_FULLSCREEN; for (auto& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("monitor")) { @@ -199,6 +198,16 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bIsPseudotiled = true; } else if (r.szRule.starts_with("noinitialfocus")) { PWINDOW->m_bNoInitialFocus = true; + } else if (r.szRule.starts_with("fullscreenstate")) { + const auto ARGS = CVarList(r.szRule.substr(r.szRule.find_first_of(' ') + 1), 2, ' '); + int internalMode, clientMode; + try { + internalMode = std::stoi(ARGS[0]); + } catch (std::exception& e) { internalMode = 0; } + try { + clientMode = std::stoi(ARGS[1]); + } catch (std::exception& e) { clientMode = 0; } + requestedFSState = sFullscreenState{.internal = (eFullscreenMode)internalMode, .client = (eFullscreenMode)clientMode}; } else if (r.szRule.starts_with("suppressevent")) { CVarList vars(r.szRule, 0, 's', true); for (size_t i = 1; i < vars.size(); ++i) { @@ -213,16 +222,12 @@ void Events::listener_mapWindow(void* owner, void* data) { else Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]); } - } else if (r.szRule == "fullscreen") { - requestsFullscreen = true; - overridingNoFullscreen = true; - } else if (r.szRule == "fakefullscreen") { - requestsFakeFullscreen = true; } else if (r.szRule == "pin") { PWINDOW->m_bPinned = true; + } else if (r.szRule == "fullscreen") { + requestedInternalFSMode = FSMODE_FULLSCREEN; } else if (r.szRule == "maximize") { - requestsMaximize = true; - overridingNoMaximize = true; + requestedInternalFSMode = FSMODE_MAXIMIZED; } else if (r.szRule == "stayfocused") { PWINDOW->m_bStayFocused = true; } else if (r.szRule.starts_with("group")) { @@ -461,17 +466,14 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto PLSFROMFOCUS = g_pCompositor->getLayerSurfaceFromSurface(g_pCompositor->m_pLastFocus.lock()); if (PLSFROMFOCUS && PLSFROMFOCUS->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) PWINDOW->m_bNoInitialFocus = true; - if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestsFullscreen && !PWINDOW->m_bIsFloating) { + + if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow && !requestedInternalFSMode.has_value() && !requestedClientFSMode.has_value() && !PWINDOW->m_bIsFloating) { if (*PNEWTAKESOVERFS == 0) PWINDOW->m_bNoInitialFocus = true; + else if (*PNEWTAKESOVERFS == 1) + requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode; else if (*PNEWTAKESOVERFS == 2) - g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), false, FULLSCREEN_INVALID); - else if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { - requestsMaximize = true; - if (*PNEWTAKESOVERFS == 1) - overridingNoMaximize = true; - } else - requestsFullscreen = true; + g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE); } if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && @@ -485,24 +487,27 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_fDimPercent.setValueAndWarp(0); } - if ((requestsFullscreen && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) || overridingNoFullscreen)) || - (requestsMaximize && (!(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) || overridingNoMaximize)) || requestsFakeFullscreen) { - // fix fullscreen on requested (basically do a switcheroo) - if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) { - const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID); - g_pCompositor->setWindowFullscreen(PFULLWINDOW, false, FULLSCREEN_FULL); - } + if (requestedClientFSMode.has_value() && !(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) + requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_FULLSCREEN); + if (requestedClientFSMode.has_value() && !(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) + requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_MAXIMIZED); - if (requestsFakeFullscreen && !PWINDOW->m_bFakeFullscreenState) { - PWINDOW->m_bFakeFullscreenState = !PWINDOW->m_bFakeFullscreenState; - g_pXWaylandManager->setWindowFullscreen(PWINDOW, true); - } else { - overridingNoFullscreen = false; - overridingNoMaximize = false; - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); - g_pCompositor->setWindowFullscreen(PWINDOW, true, requestsFullscreen ? FULLSCREEN_FULL : FULLSCREEN_MAXIMIZED); - } + if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) { + // fix fullscreen on requested (basically do a switcheroo) + if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) + g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE); + + PWINDOW->m_vRealPosition.warp(); + PWINDOW->m_vRealSize.warp(); + if (requestedFSState.has_value()) { + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE); + g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value()); + } else if (requestedInternalFSMode.has_value() && requestedClientFSMode.has_value() && !PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = requestedInternalFSMode.value(), .client = requestedClientFSMode.value()}); + else if (requestedInternalFSMode.has_value()) + g_pCompositor->setWindowFullscreenInternal(PWINDOW, requestedInternalFSMode.value()); + else if (requestedClientFSMode.has_value()) + g_pCompositor->setWindowFullscreenClient(PWINDOW, requestedClientFSMode.value()); } // recheck idle inhibitors @@ -558,7 +563,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // recalc the values for this window g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); // avoid this window being visible - if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->m_bIsFullscreen && !PWINDOW->m_bIsFloating) + if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating) PWINDOW->m_fAlpha.setValueAndWarp(0.f); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); @@ -583,8 +588,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { static auto PEXITRETAINSFS = CConfigValue("misc:exit_window_retains_fullscreen"); - const auto CURRENTWINDOWFSSTATE = PWINDOW->m_bIsFullscreen; - const auto CURRENTWINDOWFSMODE = PWINDOW->m_pWorkspace->m_efFullscreenMode; + const auto CURRENTWINDOWFSSTATE = PWINDOW->isFullscreen(); + const auto CURRENTFSMODE = PWINDOW->m_sFullscreenState.internal; if (!PWINDOW->m_pWLSurface->exists() || !PWINDOW->m_bIsMapped) { Debug::log(WARN, "{} unmapped without being mapped??", PWINDOW); @@ -604,8 +609,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { PROTO::toplevelExport->onWindowUnmap(PWINDOW); - if (PWINDOW->m_bIsFullscreen) - g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); + if (PWINDOW->isFullscreen()) + g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); // Allow the renderer to catch the last frame. g_pHyprOpenGL->makeWindowSnapshot(PWINDOW); @@ -633,7 +638,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { // remove the fullscreen window status from workspace if we closed it const auto PWORKSPACE = PWINDOW->m_pWorkspace; - if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->m_bIsFullscreen) + if (PWORKSPACE->m_bHasFullscreenWindow && PWINDOW->isFullscreen()) PWORKSPACE->m_bHasFullscreenWindow = false; g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); @@ -650,7 +655,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { if (PWINDOWCANDIDATE != g_pCompositor->m_pLastWindow.lock() && PWINDOWCANDIDATE) { g_pCompositor->focusWindow(PWINDOWCANDIDATE); if (*PEXITRETAINSFS && CURRENTWINDOWFSSTATE) - g_pCompositor->setWindowFullscreen(PWINDOWCANDIDATE, true, CURRENTWINDOWFSMODE); + g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE); } if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) @@ -708,7 +713,7 @@ void Events::listener_commitWindow(void* owner, void* data) { PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. - if (!PWINDOW->m_bIsX11 && !PWINDOW->m_bIsFullscreen && PWINDOW->m_bIsFloating) { + if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) { const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; @@ -835,7 +840,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { else PWINDOW->setHidden(true); - if (PWINDOW->m_bIsFullscreen || !PWINDOW->m_bIsFloating) { + if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); g_pHyprRenderer->damageWindow(PWINDOW); return; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 33fe0c04..377825fb 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -354,7 +354,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { // skip scheduling extra frames for fullsreen apps with vrr bool shouldSkip = - *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; + *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 7fa6fdbc..336c8c68 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -136,11 +136,12 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for return; } - if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) + if (PWINDOW->isFullscreen() && !pNode->ignoreFullscreenChecks) return; PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); + PWINDOW->updateWindowDecos(); static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); static auto PGAPSINDATA = CConfigValue("general:gaps_in"); @@ -158,8 +159,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID()); - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && - (NODESONWORKSPACE == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { + if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); @@ -216,7 +216,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for calcPos = calcPos + RESERVED.topLeft; calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); - if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) { + if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) { // if special, we adjust the coords a bit static auto PSCALEFACTOR = CConfigValue("dwindle:special_scale_factor"); @@ -500,8 +500,8 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); - if (pWindow->m_bIsFullscreen) - g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + if (pWindow->isFullscreen()) + g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); const auto PPARENT = PNODE->pParent; @@ -560,10 +560,10 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { // massive hack from the fullscreen func const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); - if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) { + if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; - } else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { + } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SDwindleNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; fakeNode.box = {PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft, PMONITOR->vecSize - PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight}; @@ -788,41 +788,19 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn } } -void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode fullscreenMode, bool on) { - if (!validMapped(pWindow)) - return; - - if (on == pWindow->m_bIsFullscreen) - return; // ignore - +void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PWORKSPACE = pWindow->m_pWorkspace; - if (PWORKSPACE->m_bHasFullscreenWindow && on) { - // if the window wants to be fullscreen but there already is one, - // ignore the request. - return; - } - // save position and size if floating - if (pWindow->m_bIsFloating && on) { + if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vSize = pWindow->m_vRealSize.goal(); } - // otherwise, accept it. - pWindow->m_bIsFullscreen = on; - PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; - - pWindow->updateDynamicRules(); - pWindow->updateWindowDecos(); - - g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)}); - EMIT_HOOK_EVENT("fullscreen", pWindow); - - if (!pWindow->m_bIsFullscreen) { + if (EFFECTIVE_MODE == FSMODE_NONE) { // if it got its fullscreen disabled, set back its node if it had one const auto PNODE = getNodeFromWindow(pWindow); if (PNODE) @@ -836,12 +814,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre pWindow->updateWindowData(); } } else { - // if it now got fullscreen, make it fullscreen - - PWORKSPACE->m_efFullscreenMode = fullscreenMode; - // apply new pos and size being monitors' box - if (fullscreenMode == FULLSCREEN_FULL) { + if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealSize = PMONITOR->vecSize; } else { @@ -861,13 +835,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscre } } - g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); - - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); - g_pCompositor->changeWindowZOrder(pWindow, true); - - recalculateMonitor(PMONITOR->ID); } void CHyprDwindleLayout::recalculateWindow(PHLWINDOW pWindow) { @@ -957,13 +925,11 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { if (!PNODE2 || !PNODE) return; - const bool FS1 = pWindow->m_bIsFullscreen; - const bool FS2 = pWindow2->m_bIsFullscreen; + const eFullscreenMode MODE1 = pWindow->m_sFullscreenState.internal; + const eFullscreenMode MODE2 = pWindow->m_sFullscreenState.internal; - if (FS1) - g_pCompositor->setWindowFullscreen(pWindow, false); - if (FS2) - g_pCompositor->setWindowFullscreen(pWindow2, false); + g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); + g_pCompositor->setWindowFullscreenInternal(pWindow2, FSMODE_NONE); SDwindleNodeData* ACTIVE1 = nullptr; SDwindleNodeData* ACTIVE2 = nullptr; @@ -1001,10 +967,8 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow2); - if (FS1) - g_pCompositor->setWindowFullscreen(pWindow2, true); - if (FS2) - g_pCompositor->setWindowFullscreen(pWindow, true); + g_pCompositor->setWindowFullscreenInternal(pWindow2, MODE1); + g_pCompositor->setWindowFullscreenInternal(pWindow, MODE2); } void CHyprDwindleLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exact) { @@ -1072,7 +1036,7 @@ void CHyprDwindleLayout::toggleSplit(PHLWINDOW pWindow) { if (!PNODE || !PNODE->pParent) return; - if (pWindow->m_bIsFullscreen) + if (pWindow->isFullscreen()) return; PNODE->pParent->splitTop = !PNODE->pParent->splitTop; @@ -1086,7 +1050,7 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) { if (!PNODE || !PNODE->pParent) return; - if (pWindow->m_bIsFullscreen) + if (pWindow->isFullscreen()) return; std::swap(PNODE->pParent->children[0], PNODE->pParent->children[1]); diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index 13834bc7..f638f6a2 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -52,7 +52,7 @@ class CHyprDwindleLayout : public IHyprLayout { virtual void recalculateWindow(PHLWINDOW); virtual void onBeginDragWindow(); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); - virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool); + virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW); virtual void switchWindows(PHLWINDOW, PHLWINDOW); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 0738b71c..233933d4 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -29,8 +29,8 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { } void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { - if (pWindow->m_bIsFullscreen) - g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + if (pWindow->isFullscreen()) + g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); if (!pWindow->m_sGroupData.pNextWindow.expired()) { if (pWindow->m_sGroupData.pNextWindow.lock() == pWindow) @@ -191,9 +191,9 @@ void IHyprLayout::onBeginDragWindow() { return; } - if (DRAGGINGWINDOW->m_bIsFullscreen) { + if (DRAGGINGWINDOW->isFullscreen()) { Debug::log(LOG, "Dragging a fullscreen window"); - g_pCompositor->setWindowFullscreen(DRAGGINGWINDOW, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(DRAGGINGWINDOW, FSMODE_NONE); } const auto PWORKSPACE = DRAGGINGWINDOW->m_pWorkspace; @@ -475,9 +475,9 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { - if (pWindow->m_bIsFullscreen) { + if (pWindow->isFullscreen()) { Debug::log(LOG, "changeWindowFloatingMode: fullscreen"); - g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); } pWindow->m_bPinned = false; @@ -497,7 +497,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - g_pCompositor->setWindowFullscreen(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), false); + g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FSMODE_NONE); // save real pos cuz the func applies the default 5,5 mid const auto PSAVEDPOS = pWindow->m_vRealPosition.goal(); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 74a00d19..4b1b59e3 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -110,7 +110,7 @@ class IHyprLayout { The layout sets all the fullscreen flags. It can either accept or ignore. */ - virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool) = 0; + virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) = 0; /* Called when a dispatcher requests a custom message diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index d7f264e7..e3aaa767 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -267,7 +267,8 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); - g_pCompositor->setWindowFullscreen(pWindow, false, FULLSCREEN_FULL); + if (pWindow->isFullscreen()) + g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); if (PNODE->isMaster && (MASTERSLEFT <= 1 || *SMALLSPLIT == 1)) { // find a new master from top of the list @@ -327,10 +328,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { // massive hack from the fullscreen func const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); - if (pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) { + if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; - } else if (pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { + } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SMasterNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; fakeNode.position = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; @@ -644,11 +645,12 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { // if user specified them in config const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWINDOW->m_pWorkspace); - if (PWINDOW->m_bIsFullscreen && !pNode->ignoreFullscreenChecks) + if (PWINDOW->isFullscreen() && !pNode->ignoreFullscreenChecks) return; PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); + PWINDOW->updateWindowDecos(); static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); @@ -668,8 +670,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->m_vSize = pNode->size; PWINDOW->m_vPosition = pNode->position; - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && - (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || (PWINDOW->m_bIsFullscreen && PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_MAXIMIZED))) { + if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); @@ -702,7 +703,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { calcPos = calcPos + RESERVED.topLeft; calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight); - if (PWINDOW->onSpecialWorkspace() && !PWINDOW->m_bIsFullscreen) { + if (PWINDOW->onSpecialWorkspace() && !PWINDOW->isFullscreen()) { static auto PSCALEFACTOR = CConfigValue("master:special_scale_factor"); CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; @@ -880,41 +881,19 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne m_bForceWarps = false; } -void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscreenMode fullscreenMode, bool on) { - if (!validMapped(pWindow)) - return; - - if (on == pWindow->m_bIsFullscreen) - return; // ignore - +void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); const auto PWORKSPACE = pWindow->m_pWorkspace; - if (PWORKSPACE->m_bHasFullscreenWindow && on) { - // if the window wants to be fullscreen but there already is one, - // ignore the request. - return; - } - // save position and size if floating - if (pWindow->m_bIsFloating && on) { + if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); pWindow->m_vSize = pWindow->m_vRealSize.goal(); } - // otherwise, accept it. - pWindow->m_bIsFullscreen = on; - PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; - - pWindow->updateDynamicRules(); - pWindow->updateWindowDecos(); - - g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)}); - EMIT_HOOK_EVENT("fullscreen", pWindow); - - if (!pWindow->m_bIsFullscreen) { + if (EFFECTIVE_MODE == FSMODE_NONE) { // if it got its fullscreen disabled, set back its node if it had one const auto PNODE = getNodeFromWindow(pWindow); if (PNODE) @@ -928,12 +907,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree pWindow->updateWindowData(); } } else { - // if it now got fullscreen, make it fullscreen - - PWORKSPACE->m_efFullscreenMode = fullscreenMode; - // apply new pos and size being monitors' box - if (fullscreenMode == FULLSCREEN_FULL) { + if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { pWindow->m_vRealPosition = PMONITOR->vecPosition; pWindow->m_vRealSize = PMONITOR->vecSize; } else { @@ -954,13 +929,7 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, eFullscree } } - g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); - - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); - g_pCompositor->changeWindowZOrder(pWindow, true); - - recalculateMonitor(PMONITOR->ID); } void CHyprMasterLayout::recalculateWindow(PHLWINDOW pWindow) { @@ -1081,14 +1050,14 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!validMapped(PWINDOWTOCHANGETO)) return; - if (header.pWindow->m_bIsFullscreen) { + if (header.pWindow->isFullscreen()) { const auto PWORKSPACE = header.pWindow->m_pWorkspace; - const auto FSMODE = PWORKSPACE->m_efFullscreenMode; + const auto FSMODE = header.pWindow->m_sFullscreenState.internal; static auto INHERITFULLSCREEN = CConfigValue("master:inherit_fullscreen"); - g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); if (*INHERITFULLSCREEN) - g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); + g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, FSMODE); } else { g_pCompositor->focusWindow(PWINDOWTOCHANGETO); g_pCompositor->warpCursorTo(PWINDOWTOCHANGETO->middle()); @@ -1208,7 +1177,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true); if (PWINDOWTOSWAPWITH) { - g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE); switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchToWindow(header.pWindow); } @@ -1224,7 +1193,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false); if (PWINDOWTOSWAPWITH) { - g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenClient(header.pWindow, FSMODE_NONE); switchWindows(header.pWindow, PWINDOWTOSWAPWITH); switchToWindow(header.pWindow); } @@ -1243,7 +1212,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (MASTERS + 2 > WINDOWS && *SMALLSPLIT == 0) return 0; - g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); + + g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE); if (!PNODE || PNODE->isMaster) { // first non-master node @@ -1275,7 +1245,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (WINDOWS < 2 || MASTERS < 2) return 0; - g_pCompositor->setWindowFullscreen(header.pWindow, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE); if (!PNODE || !PNODE->isMaster) { // first non-master node @@ -1296,7 +1266,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!PWINDOW) return 0; - g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID()); @@ -1392,7 +1362,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi if (!PWINDOW) return; - g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); const auto PWORKSPACEDATA = getMasterWorkspaceData(PWINDOW->workspaceID()); diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 30d5b3cf..fdb916e5 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -58,7 +58,7 @@ class CHyprMasterLayout : public IHyprLayout { virtual void recalculateMonitor(const int&); virtual void recalculateWindow(PHLWINDOW); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); - virtual void fullscreenRequestForWindow(PHLWINDOW, eFullscreenMode, bool); + virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); virtual std::any layoutMessage(SLayoutMessageHeader, std::string); virtual SWindowRenderLayoutHints requestRenderHints(PHLWINDOW); virtual void switchWindows(PHLWINDOW, PHLWINDOW); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 823e2d2e..33b07351 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -68,7 +68,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["workspace"] = changeworkspace; m_mDispatchers["renameworkspace"] = renameWorkspace; m_mDispatchers["fullscreen"] = fullscreenActive; - m_mDispatchers["fakefullscreen"] = fakeFullscreenActive; + m_mDispatchers["fullscreenstate"] = fullscreenStateActive; m_mDispatchers["movetoworkspace"] = moveActiveToWorkspace; m_mDispatchers["movetoworkspacesilent"] = moveActiveToWorkspaceSilent; m_mDispatchers["pseudo"] = toggleActivePseudo; @@ -319,17 +319,17 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { // remove constraints g_pInputManager->unconstrainMouse(); - if (PLASTWINDOW && PLASTWINDOW->m_pWorkspace == PWINDOWTOCHANGETO->m_pWorkspace && PLASTWINDOW->m_bIsFullscreen) { + if (PLASTWINDOW && PLASTWINDOW->m_pWorkspace == PWINDOWTOCHANGETO->m_pWorkspace && PLASTWINDOW->isFullscreen()) { const auto PWORKSPACE = PLASTWINDOW->m_pWorkspace; - const auto FSMODE = PWORKSPACE->m_efFullscreenMode; + const auto MODE = PWORKSPACE->m_efFullscreenMode; if (!PWINDOWTOCHANGETO->m_bPinned) - g_pCompositor->setWindowFullscreen(PLASTWINDOW, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); if (!PWINDOWTOCHANGETO->m_bPinned) - g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE); + g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); } else { updateRelativeCursorCoords(); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); @@ -996,7 +996,7 @@ void CKeybindManager::setActiveTiled(std::string args) { void CKeybindManager::centerWindow(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) + if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) return; const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); @@ -1022,7 +1022,7 @@ void CKeybindManager::toggleActivePseudo(std::string args) { PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled; - if (!PWINDOW->m_bIsFullscreen) + if (!PWINDOW->isFullscreen()) g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); } @@ -1149,10 +1149,34 @@ void CKeybindManager::fullscreenActive(std::string args) { if (!PWINDOW) return; - PWINDOW->m_bDontSendFullscreen = false; - if (args == "2") - PWINDOW->m_bDontSendFullscreen = true; - g_pCompositor->setWindowFullscreen(PWINDOW, !PWINDOW->m_bIsFullscreen, args == "1" ? FULLSCREEN_MAXIMIZED : FULLSCREEN_FULL); + const eFullscreenMode MODE = args == "1" ? FSMODE_MAXIMIZED : FSMODE_FULLSCREEN; + + if (PWINDOW->isEffectiveInternalFSMode(MODE)) + g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); + else + g_pCompositor->setWindowFullscreenInternal(PWINDOW, MODE); +} + +void CKeybindManager::fullscreenStateActive(std::string args) { + const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); + const auto ARGS = CVarList(args, 2, ' '); + + if (!PWINDOW) + return; + + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); + + int internalMode, clientMode; + try { + internalMode = std::stoi(ARGS[0]); + } catch (std::exception& e) { internalMode = -1; } + try { + clientMode = std::stoi(ARGS[1]); + } catch (std::exception& e) { clientMode = -1; } + + g_pCompositor->setWindowFullscreenState(PWINDOW, + sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), + .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}); } void CKeybindManager::moveActiveToWorkspace(std::string args) { @@ -1277,7 +1301,7 @@ void CKeybindManager::moveFocusTo(std::string args) { return; } - const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->m_bIsFullscreen ? + const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) : g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); @@ -1334,7 +1358,7 @@ void CKeybindManager::swapActive(std::string args) { Debug::log(LOG, "Swapping active window in direction {}", arg); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) + if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return; const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); @@ -1372,7 +1396,7 @@ void CKeybindManager::moveActiveTo(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) + if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return; if (PLASTWINDOW->m_bIsFloating) { @@ -1427,7 +1451,8 @@ void CKeybindManager::toggleGroup(std::string args) { if (!PWINDOW) return; - g_pCompositor->setWindowFullscreen(PWINDOW, false, FULLSCREEN_FULL); + if (PWINDOW->isFullscreen()) + g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); if (PWINDOW->m_sGroupData.pNextWindow.expired()) PWINDOW->createGroup(); @@ -1819,7 +1844,7 @@ void CKeybindManager::forceRendererReload(std::string args) { void CKeybindManager::resizeActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) + if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); @@ -1836,7 +1861,7 @@ void CKeybindManager::resizeActive(std::string args) { void CKeybindManager::moveActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->m_bIsFullscreen) + if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); @@ -1856,7 +1881,7 @@ void CKeybindManager::moveWindow(std::string args) { return; } - if (PWINDOW->m_bIsFullscreen) + if (PWINDOW->isFullscreen()) return; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); @@ -1876,7 +1901,7 @@ void CKeybindManager::resizeWindow(std::string args) { return; } - if (PWINDOW->m_bIsFullscreen) + if (PWINDOW->isFullscreen()) return; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); @@ -1953,12 +1978,12 @@ void CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->focusWindow(PWINDOW); } else { if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned) - g_pCompositor->setWindowFullscreen(FSWINDOW, false, FULLSCREEN_FULL); + g_pCompositor->setWindowFullscreenClient(FSWINDOW, FSMODE_NONE); g_pCompositor->focusWindow(PWINDOW); if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned) - g_pCompositor->setWindowFullscreen(PWINDOW, true, FSMODE); + g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE); } } else g_pCompositor->focusWindow(PWINDOW); @@ -2330,7 +2355,7 @@ void CKeybindManager::pinActive(std::string args) { return; } - if (!PWINDOW->m_bIsFloating || PWINDOW->m_bIsFullscreen) + if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) return; PWINDOW->m_bPinned = !PWINDOW->m_bPinned; @@ -2388,7 +2413,7 @@ void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { if (!PWINDOW) return; - if (!PWINDOW->m_bIsFullscreen && MODE == MBIND_MOVE) + if (!PWINDOW->isFullscreen() && MODE == MBIND_MOVE) PWINDOW->checkInputOnDecos(INPUT_TYPE_DRAG_START, MOUSECOORDS); if (g_pInputManager->currentlyDraggedWindow.expired()) @@ -2436,14 +2461,6 @@ void CKeybindManager::alterZOrder(std::string args) { g_pInputManager->simulateMouseMovement(); } -void CKeybindManager::fakeFullscreenActive(std::string args) { - if (!g_pCompositor->m_pLastWindow.expired()) { - // will also set the flag - g_pCompositor->m_pLastWindow->m_bFakeFullscreenState = !g_pCompositor->m_pLastWindow->m_bFakeFullscreenState; - g_pXWaylandManager->setWindowFullscreen(g_pCompositor->m_pLastWindow.lock(), g_pCompositor->m_pLastWindow->shouldSendFullscreenState()); - } -} - void CKeybindManager::lockGroups(std::string args) { if (args == "lock" || args.empty() || args == "lockgroups") g_pKeybindManager->m_bGroupsLocked = true; @@ -2603,7 +2620,7 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || PWINDOW->m_bIsFullscreen) + if (!PWINDOW || PWINDOW->isFullscreen()) return; if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 26a6345b..26b42b00 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -155,7 +155,7 @@ class CKeybindManager { static void setActiveTiled(std::string); static void changeworkspace(std::string); static void fullscreenActive(std::string); - static void fakeFullscreenActive(std::string); + static void fullscreenStateActive(std::string args); static void moveActiveToWorkspace(std::string); static void moveActiveToWorkspaceSilent(std::string); static void moveFocusTo(std::string); diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index da2429bc..2c335a7e 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -63,7 +63,7 @@ void CInputManager::recheckIdleInhibitorStatus() { return; } - if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) { + if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->isFullscreen() && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) { PROTO::idle->setInhibit(true); return; } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 014de40a..8c38893f 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -298,7 +298,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // then, we check if the workspace doesnt have a fullscreen window const auto PWORKSPACE = PMONITOR->activeWorkspace; - if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) { + if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN) { pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); if (!pFoundWindow) { @@ -325,7 +325,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // then windows if (!foundSurface) { - if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_MAXIMIZED) { + if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FSMODE_MAXIMIZED) { if (!foundSurface) { if (PMONITOR->activeSpecialWorkspace) { pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); @@ -470,7 +470,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { else if (pFoundWindow) { // change cursor icon if hovering over border if (*PRESIZEONBORDER && *PRESIZECURSORICON) { - if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) { + if (!pFoundWindow->isFullscreen() && !pFoundWindow->hasPopupAt(mouseCoords)) { setCursorIconOnBorder(pFoundWindow); } else if (m_eBorderIconDirection != BORDERICON_NONE) { unsetCursorImage(); @@ -681,7 +681,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // clicking on border triggers resize // TODO detect click on LS properly if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) { - if (w && !w->m_bIsFullscreen) { + if (w && !w->isFullscreen()) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 775881cd..c0e6c4f0 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -194,7 +194,7 @@ void CInputManager::endWorkspaceSwipe() { // apply alpha for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { - ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FULLSCREEN_FULL ? 0.f : 1.f; + ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 2b378386..295834ea 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -51,7 +51,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetWindowFullscreen(PWINDOW, true, FULLSCREEN_FULL); + g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_FULLSCREEN, true); g_pHyprRenderer->damageWindow(PWINDOW); }); @@ -64,7 +64,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPm_eSuppressedEvents & SUPPRESS_FULLSCREEN) return; - g_pCompositor->setWindowFullscreen(PWINDOW, false); + g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_FULLSCREEN, false); }); resource->setSetMaximized([this](CZwlrForeignToplevelHandleV1* p) { @@ -81,7 +81,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetWindowFullscreen(PWINDOW, true, FULLSCREEN_MAXIMIZED); + g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_MAXIMIZED, true); }); resource->setUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) { @@ -93,7 +93,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPm_eSuppressedEvents & SUPPRESS_MAXIMIZE) return; - g_pCompositor->setWindowFullscreen(PWINDOW, false); + g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_MAXIMIZED, false); }); resource->setClose([this](CZwlrForeignToplevelHandleV1* p) { @@ -155,9 +155,9 @@ void CForeignToplevelHandleWlr::sendState() { *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED; } - if (PWINDOW->m_bIsFullscreen) { + if (PWINDOW->isFullscreen()) { auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); - if (PWINDOW->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) + if (PWINDOW->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN; else *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b5397598..e4f97895 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -269,7 +269,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { return true; // if hidden behind fullscreen - if (PWINDOWWORKSPACE->m_bHasFullscreenWindow && !pWindow->m_bIsFullscreen && (!pWindow->m_bIsFloating || !pWindow->m_bCreatedOverFullscreen) && + if (PWINDOWWORKSPACE->m_bHasFullscreenWindow && !pWindow->isFullscreen() && (!pWindow->m_bIsFloating || !pWindow->m_bCreatedOverFullscreen) && pWindow->m_fAlpha.value() == 0) return false; @@ -285,7 +285,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { // if not, check if it maybe is active on a different monitor. if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */) - return !pWindow->m_bIsFullscreen; // Do not draw fullscreen windows on other monitors + return !pWindow->isFullscreen(); // Do not draw fullscreen windows on other monitors if (pMonitor->activeSpecialWorkspace == pWindow->m_pWorkspace) return true; @@ -352,7 +352,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK if (w->m_fAlpha.value() == 0.f) continue; - if (w->m_bIsFullscreen || w->m_bIsFloating) + if (w->isFullscreen() || w->m_bIsFloating) continue; if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) @@ -369,7 +369,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK if (w->m_fAlpha.value() == 0.f) continue; - if (w->m_bIsFullscreen || !w->m_bIsFloating) + if (w->isFullscreen() || !w->m_bIsFloating) continue; if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) @@ -385,7 +385,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK for (auto& w : g_pCompositor->m_vWindows) { const auto PWORKSPACE = w->m_pWorkspace; - if (w->m_pWorkspace != pWorkspace || !w->m_bIsFullscreen) { + if (w->m_pWorkspace != pWorkspace || !w->isFullscreen()) { if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering))) continue; @@ -393,14 +393,14 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK continue; } - if (!w->m_bIsFullscreen) + if (!w->isFullscreen()) continue; if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; if (shouldRenderWindow(w, pMonitor)) - renderWindow(w, pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL, RENDER_PASS_ALL); + renderWindow(w, pMonitor, time, pWorkspace->m_efFullscreenMode != FSMODE_FULLSCREEN, RENDER_PASS_ALL); if (w->m_pWorkspace != pWorkspace) continue; @@ -416,7 +416,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK // then render windows over fullscreen. for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->m_bIsFullscreen) + if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) continue; if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) @@ -538,10 +538,10 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec decorate = false; renderdata.surface = pWindow->m_pWLSurface->resource(); - renderdata.dontRound = (pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL) || pWindow->m_sWindowData.noRounding.valueOrDefault(); + renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later renderdata.pWindow = pWindow; @@ -568,7 +568,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec renderdata.y += pWindow->m_vFloatingOffset.y; // if window is floating and we have a slide animation, clip it to its full bb - if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->m_bIsFullscreen && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) { + if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->isFullscreen() && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) { CRegion rg = pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); g_pHyprOpenGL->m_RenderData.clipBox = rg.getExtents(); @@ -871,7 +871,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC // if we have a fullscreen, opaque window that convers the screen, we can skip this. // TODO: check better with solitary after MR for tearing. const auto PFULLWINDOW = pWorkspace ? g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID) : nullptr; - if (!pWorkspace->m_bHasFullscreenWindow || pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL || !PFULLWINDOW || PFULLWINDOW->m_vRealSize.isBeingAnimated() || + if (!pWorkspace->m_bHasFullscreenWindow || pWorkspace->m_efFullscreenMode != FSMODE_FULLSCREEN || !PFULLWINDOW || PFULLWINDOW->m_vRealSize.isBeingAnimated() || !PFULLWINDOW->opaque() || pWorkspace->m_vRenderOffset.value() != Vector2D{} || g_pHyprOpenGL->preBlurQueued()) { if (!g_pHyprOpenGL->m_RenderData.pCurrentMonData->blurFBShouldRender) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index a13750d0..8163a8c1 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -464,7 +464,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPointer::SButtonEvent& e) { static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - if (m_pWindow->m_bIsFullscreen && m_pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) + if (m_pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) return true; const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; From 548968279926a73d7ff19a9a185c977c50d56756 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 31 Jul 2024 21:00:14 +0200 Subject: [PATCH 0426/2393] internal: some minor fd/socket cleanups and make logging thread safe (#7123) * bezier: dont loop on float values Using a floating-point loop variable with a fixed increment can cause precision errors over time due to the nature of floating-point arithmetic. and cause undesired effects. ex iteration 1 = 0.10000000149011611938 iteration 2 = 0.20000000298023223877 eventually.. iteration 8 = 0.80000001192092895508 iteration 9 = 0.89999997615814208984 * hyprctl: close sockets on destruction store socketpath and close the fd and unlink the socket path on exit. * eventloopmgr: close the timerfd close the timerfd on exit. * debug: make logging thread safe instead of opening and closing the logfile on each write open it on init and close it on compositor exit. also add a mutex so accidently using logging from a thread like the watchdog or similiar doesnt cause issues. * xwl: clean up fd logic check if the fd is actually opened before closing, and close the pipesource FD on exit. --- src/Compositor.cpp | 2 ++ src/debug/HyprCtl.cpp | 10 +++++++--- src/debug/HyprCtl.hpp | 1 + src/debug/Log.cpp | 12 +++++++----- src/debug/Log.hpp | 7 +++++++ src/helpers/BezierCurve.cpp | 4 +++- src/managers/eventLoop/EventLoopManager.cpp | 2 ++ src/xwayland/Server.cpp | 12 ++++++++---- src/xwayland/Server.hpp | 1 + 9 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 97355d2c..7221d3a7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -518,6 +518,8 @@ void CCompositor::cleanup() { // this frees all wayland resources, including sockets wl_display_destroy(m_sWLDisplay); + + Debug::close(); } void CCompositor::initManagers(eManagersInitStage stage) { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cf873e6c..d91a1cec 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1604,6 +1604,10 @@ CHyprCtl::CHyprCtl() { CHyprCtl::~CHyprCtl() { if (m_eventSource) wl_event_source_remove(m_eventSource); + if (m_iSocketFD >= 0) + close(m_iSocketFD); + if (!m_socketPath.empty()) + unlink(m_socketPath.c_str()); } SP CHyprCtl::registerCommand(SHyprCtlCommand cmd) { @@ -1821,9 +1825,9 @@ void CHyprCtl::startHyprCtlSocket() { sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; - std::string socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock"; + m_socketPath = g_pCompositor->m_szInstancePath + "/.socket.sock"; - strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); + strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); @@ -1833,7 +1837,7 @@ void CHyprCtl::startHyprCtlSocket() { // 10 max queued. listen(m_iSocketFD, 10); - Debug::log(LOG, "Hypr socket started at {}", socketPath); + Debug::log(LOG, "Hypr socket started at {}", m_socketPath); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index ccbd40cd..cbacd7cb 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -31,6 +31,7 @@ class CHyprCtl { std::vector> m_vCommands; wl_event_source* m_eventSource = nullptr; + std::string m_socketPath; }; inline std::unique_ptr g_pHyprCtl; diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index c2939831..0def77c0 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -8,6 +8,11 @@ void Debug::init(const std::string& IS) { logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); + logOfs.open(logFile, std::ios::out | std::ios::app); +} + +void Debug::close() { + logOfs.close(); } void Debug::log(LogLevel level, std::string str) { @@ -55,11 +60,8 @@ void Debug::log(LogLevel level, std::string str) { if (!disableLogs || !**disableLogs) { // log to a file - std::ofstream ofs; - ofs.open(logFile, std::ios::out | std::ios::app); - ofs << str << "\n"; - - ofs.close(); + logOfs << str << "\n"; + logOfs.flush(); } // log it to the stdout too. diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 33f3c9c1..617f451a 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../includes.hpp" #include "../helpers/MiscFunctions.hpp" @@ -22,6 +23,7 @@ enum LogLevel { namespace Debug { inline std::string logFile; + inline std::ofstream logOfs; inline int64_t* const* disableLogs = nullptr; inline int64_t* const* disableTime = nullptr; inline bool disableStdout = false; @@ -30,14 +32,18 @@ namespace Debug { inline int64_t* const* coloredLogs = nullptr; inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log + inline std::mutex logMutex; void init(const std::string& IS); + void close(); // void log(LogLevel level, std::string str); template void log(LogLevel level, std::format_string fmt, Args&&... args) { + std::lock_guard guard(logMutex); + if (level == TRACE && !trace) return; @@ -66,5 +72,6 @@ namespace Debug { logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); log(level, logMsg); + logMutex.unlock(); } }; diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp index e79863a3..dd0ff2b0 100644 --- a/src/helpers/BezierCurve.cpp +++ b/src/helpers/BezierCurve.cpp @@ -30,8 +30,10 @@ void CBezierCurve::setup(std::vector* pVec) { const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f; const auto BEGINCALC = std::chrono::high_resolution_clock::now(); - for (float i = 0.1f; i < 1.f; i += 0.1f) + for (int j = 1; j < 10; ++j) { + float i = j / 10.0f; getYForPoint(i); + } const auto ELAPSEDCALCAVG = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f; Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE, diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 3131531a..c2c088f8 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -27,6 +27,8 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sWayland.eventSource); if (m_sIdle.eventSource) wl_event_source_remove(m_sIdle.eventSource); + if (m_sTimers.timerfd >= 0) + close(m_sTimers.timerfd); } static int timerWrite(int fd, uint32_t mask, void* data) { diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 3f4e7b43..cec582f6 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -262,13 +262,16 @@ void CXWaylandServer::die() { if (pipeSource) wl_event_source_remove(pipeSource); - if (waylandFDs[0]) + if (pipeFd >= 0) + close(pipeFd); + + if (waylandFDs[0] >= 0) close(waylandFDs[0]); - if (waylandFDs[1]) + if (waylandFDs[1] >= 0) close(waylandFDs[1]); - if (xwmFDs[0]) + if (xwmFDs[0] >= 0) close(xwmFDs[0]); - if (xwmFDs[1]) + if (xwmFDs[1] >= 0) close(xwmFDs[1]); // possible crash. Better to leak a bit. @@ -364,6 +367,7 @@ bool CXWaylandServer::start() { } pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); + pipeFd = notify[0]; serverPID = fork(); if (serverPID < 0) { diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp index 0c06a56c..7a36a965 100644 --- a/src/xwayland/Server.hpp +++ b/src/xwayland/Server.hpp @@ -41,6 +41,7 @@ class CXWaylandServer { std::array xFDReadEvents = {nullptr, nullptr}; wl_event_source* idleSource = nullptr; wl_event_source* pipeSource = nullptr; + int pipeFd = -1; std::array xwmFDs = {-1, -1}; std::array waylandFDs = {-1, -1}; From 37e1411e8d94fe8f3fb678588a7df9b8f931910f Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 31 Jul 2024 20:47:26 +0100 Subject: [PATCH 0427/2393] core/surface/buffer: Buffer lock/release fixes (#7110) --- src/desktop/LayerSurface.cpp | 2 +- src/desktop/WLSurface.cpp | 23 +++-- src/desktop/Window.cpp | 10 +-- src/events/Windows.cpp | 2 +- src/helpers/Monitor.cpp | 7 +- src/managers/PointerManager.cpp | 50 ++++++++--- src/protocols/DRMSyncobj.cpp | 2 +- src/protocols/InputMethodV2.cpp | 4 +- src/protocols/LayerShell.cpp | 2 +- src/protocols/SessionLock.cpp | 2 +- src/protocols/Viewporter.cpp | 4 +- src/protocols/XDGShell.cpp | 6 +- src/protocols/core/Compositor.cpp | 124 +++++++++++++++++---------- src/protocols/core/Compositor.hpp | 35 +++++--- src/protocols/core/DataDevice.cpp | 8 +- src/protocols/core/Seat.cpp | 21 ++++- src/protocols/core/Seat.hpp | 15 ++++ src/protocols/core/Subcompositor.cpp | 4 +- src/protocols/types/Buffer.cpp | 56 ++++++++++++ src/protocols/types/Buffer.hpp | 28 +++++- src/protocols/types/SurfaceRole.hpp | 1 + src/protocols/types/WLBuffer.cpp | 1 - src/protocols/types/WLBuffer.hpp | 2 - src/render/Renderer.cpp | 14 +-- src/render/Texture.cpp | 3 + src/render/Texture.hpp | 1 + src/xwayland/XSurface.cpp | 6 +- 27 files changed, 304 insertions(+), 129 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 80138910..ba1b1776 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -242,7 +242,7 @@ void CLayerSurface::onCommit() { if (!mapped) { // we're re-mapping if this is the case - if (layerSurface->surface && !layerSurface->surface->current.buffer) { + if (layerSurface->surface && !layerSurface->surface->current.texture) { fadingOut = false; geometry = {}; g_pHyprRenderer->arrangeLayersForMonitor(monitorID); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 3c91a142..45050e35 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -57,12 +57,12 @@ bool CWLSurface::small() const { if (!validMapped(m_pWindowOwner) || !exists()) return false; - if (!m_pResource->current.buffer) + if (!m_pResource->current.texture) return false; const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pResource->current.buffer->size.x + 1 || O->m_vReportedSize.y > m_pResource->current.buffer->size.y + 1; + return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1; } Vector2D CWLSurface::correctSmallVec() const { @@ -76,37 +76,36 @@ Vector2D CWLSurface::correctSmallVec() const { } Vector2D CWLSurface::correctSmallVecBuf() const { - if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.buffer) + if (!exists() || !small() || m_bFillIgnoreSmall || !m_pResource->current.texture) return {}; const auto SIZE = getViewporterCorrectedSize(); - const auto BS = m_pResource->current.buffer->size; + const auto BS = m_pResource->current.bufferSize; return Vector2D{(BS.x - SIZE.x) / 2, (BS.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}); } Vector2D CWLSurface::getViewporterCorrectedSize() const { - if (!exists() || !m_pResource->current.buffer) + if (!exists() || !m_pResource->current.texture) return {}; - return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.buffer->size; + return m_pResource->current.viewport.hasDestination ? m_pResource->current.viewport.destination : m_pResource->current.bufferSize; } CRegion CWLSurface::computeDamage() const { - if (!m_pResource->current.buffer) + if (!m_pResource->current.texture) return {}; CRegion damage = m_pResource->accumulateCurrentBufferDamage(); - damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.buffer->size.x, m_pResource->current.buffer->size.y); + damage.transform(wlTransformToHyprutils(m_pResource->current.transform), m_pResource->current.bufferSize.x, m_pResource->current.bufferSize.y); - const auto BUFSIZE = m_pResource->current.buffer->size; + const auto BUFSIZE = m_pResource->current.bufferSize; const auto CORRECTVEC = correctSmallVecBuf(); if (m_pResource->current.viewport.hasSource) damage.intersect(m_pResource->current.viewport.source); - const auto SCALEDSRCSIZE = - m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.buffer->size; + const auto SCALEDSRCSIZE = m_pResource->current.viewport.hasSource ? m_pResource->current.viewport.source.size() * m_pResource->current.scale : m_pResource->current.bufferSize; damage.scale({BUFSIZE.x / SCALEDSRCSIZE.x, BUFSIZE.y / SCALEDSRCSIZE.y}); damage.translate(CORRECTVEC); @@ -114,7 +113,7 @@ CRegion CWLSurface::computeDamage() const { // go from buffer coords in the damage to hl logical const auto BOX = getSurfaceBoxGlobal(); - const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.buffer->size : + const Vector2D SCALE = BOX.has_value() ? BOX->size() / m_pResource->current.bufferSize : Vector2D{1.0 / m_pResource->current.scale, 1.0 / m_pResource->current.scale /* Wrong... but we can't really do better */}; damage.scale(SCALE); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 9316959d..27010454 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1097,18 +1097,18 @@ bool CWindow::opaque() { if (PWORKSPACE->m_fAlpha.value() != 1.f) return false; - if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.buffer) - return m_pXWaylandSurface->surface->current.buffer->opaque; + if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture) + return m_pXWaylandSurface->surface->current.texture->m_bOpaque; - if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.buffer) + if (!m_pWLSurface->resource() || !m_pWLSurface->resource()->current.texture) return false; // TODO: this is wrong const auto EXTENTS = m_pXDGSurface->surface->current.opaque.getExtents(); - if (EXTENTS.w >= m_pXDGSurface->surface->current.buffer->size.x && EXTENTS.h >= m_pXDGSurface->surface->current.buffer->size.y) + if (EXTENTS.w >= m_pXDGSurface->surface->current.bufferSize.x && EXTENTS.h >= m_pXDGSurface->surface->current.bufferSize.y) return true; - return m_pWLSurface->resource()->current.buffer->opaque; + return m_pWLSurface->resource()->current.texture->m_bOpaque; } float CWindow::rounding() { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 71ad4ba1..0389f57e 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -752,7 +752,7 @@ void Events::listener_commitWindow(void* owner, void* data) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); - if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { + if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; if (!damageBox.empty()) { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 377825fb..1cf1b069 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -801,17 +801,16 @@ bool CMonitor::attemptDirectScanout() { const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE); - if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform) + if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.bufferSize != vecPixelSize || PSURFACE->current.transform != transform) return false; // we can't scanout shm buffers. - if (!PSURFACE->current.buffer->dmabuf().success) + if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) return false; // FIXME: make sure the buffer actually follows the available scanout dmabuf formats // and comes from the appropriate device. This may implode on multi-gpu!! - - output->state->setBuffer(PSURFACE->current.buffer); + output->state->setBuffer(PSURFACE->current.buffer->buffer.lock()); output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 8314e79a..3ba34c11 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -4,6 +4,7 @@ #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/core/Seat.hpp" #include "eventLoop/EventLoopManager.hpp" #include "SeatManager.hpp" #include @@ -156,15 +157,15 @@ void CPointerManager::setCursorSurface(SP surf, const Vector2D& hots currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); }); currentCursorImage.commitSurface = surf->resource()->events.commit.registerListener([this](std::any data) { damageIfSoftware(); - currentCursorImage.size = currentCursorImage.surface->resource()->current.buffer ? currentCursorImage.surface->resource()->current.buffer->size : Vector2D{}; + currentCursorImage.size = currentCursorImage.surface->resource()->current.texture ? currentCursorImage.surface->resource()->current.bufferSize : Vector2D{}; currentCursorImage.scale = currentCursorImage.surface ? currentCursorImage.surface->resource()->current.scale : 1.F; recheckEnteredOutputs(); updateCursorBackend(); damageIfSoftware(); }); - if (surf->resource()->current.buffer) { - currentCursorImage.size = surf->resource()->current.buffer->size; + if (surf->resource()->current.texture) { + currentCursorImage.size = surf->resource()->current.bufferSize; timespec now; clock_gettime(CLOCK_MONOTONIC, &now); surf->resource()->frame(&now); @@ -430,16 +431,39 @@ SP CPointerManager::renderHWCursorBuffer(SP(bufData)); - auto texBuffer = currentCursorImage.pBuffer ? currentCursorImage.pBuffer : currentCursorImage.surface->resource()->current.buffer; + if (currentCursorImage.pBuffer) { + auto texAttrs = currentCursorImage.pBuffer->shm(); - if (texBuffer) { - auto textAttrs = texBuffer->shm(); - auto texData = texBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); - auto texPtr = std::get<0>(texData); - Debug::log(TRACE, "cursor texture {}x{} {} {} {}", textAttrs.size.x, textAttrs.size.y, (void*)texPtr, textAttrs.format, textAttrs.stride); + if (!texAttrs.success) { + Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers"); + return nullptr; + } + + auto texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); + auto texPtr = std::get<0>(texData); + Debug::log(TRACE, "cursor texture {}x{} {} {} {}", texAttrs.size.x, texAttrs.size.y, (void*)texPtr, texAttrs.format, texAttrs.stride); // copy cursor texture - for (int i = 0; i < texBuffer->shm().size.y; i++) - memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * textAttrs.stride, textAttrs.stride); + for (int i = 0; i < texAttrs.size.y; i++) + memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * texAttrs.stride, texAttrs.stride); + } else if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) { + const auto SURFACE = currentCursorImage.surface->resource(); + auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE); + Debug::log(TRACE, "cursor texture pixel data length: {}B", shmBuffer.size()); + + if (shmBuffer.data()) { + // copy cursor texture + // assume format is 32bpp + size_t STRIDE = 4 * SURFACE->current.bufferSize.x; + for (int i = 0; i < SURFACE->current.bufferSize.y; i++) + memcpy(bufPtr + i * buf->dmabuf().strides[0], shmBuffer.data() + i * STRIDE, STRIDE); + } else { + // if there is no data, hide the cursor + memset(bufPtr, '\0', buf->size.x * buf->size.y * 4 /* assume 32bpp */); + } + + } else { + Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)"); + return nullptr; } buf->endDataPtr(); @@ -740,7 +764,7 @@ void CPointerManager::onMonitorLayoutChange() { } SP CPointerManager::getCurrentCursorTexture() { - if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.buffer)) + if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !currentCursorImage.surface->resource()->current.texture)) return nullptr; if (currentCursorImage.pBuffer) { @@ -749,7 +773,7 @@ SP CPointerManager::getCurrentCursorTexture() { return currentCursorImage.bufferTex; } - return currentCursorImage.surface->resource()->current.buffer->texture; + return currentCursorImage.surface->resource()->current.texture; } void CPointerManager::attachPointer(SP pointer) { diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 41178109..33339554 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -47,7 +47,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPpending.buffer) { + if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); surface->pending.rejected = true; return; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index def4d837..fd306f09 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -107,14 +107,14 @@ CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, }); listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { - if (pSurface->current.buffer && !mapped) { + if (pSurface->current.texture && !mapped) { mapped = true; pSurface->map(); events.map.emit(); return; } - if (!pSurface->current.buffer && mapped) { + if (!pSurface->current.texture && mapped) { mapped = false; pSurface->unmap(); events.unmap.emit(); diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 5018828e..0ed1b219 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -44,7 +44,7 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPcurrent.buffer; + bool attachedBuffer = surface->current.texture; if (attachedBuffer && !configured) { surface->error(-1, "layerSurface was not configured, but a buffer was attached"); diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 42df5fd6..df97413c 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -24,7 +24,7 @@ CSessionLockSurface::CSessionLockSurface(SP resource_, resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; }); listeners.surfaceCommit = pSurface->events.commit.registerListener([this](std::any d) { - if (!pSurface->current.buffer) { + if (!pSurface->current.texture) { LOGM(ERR, "SessionLock attached a null buffer"); resource->error(EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); return; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 03c5775e..78f3039f 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -54,13 +54,13 @@ CViewportResource::CViewportResource(SP resource_, SPevents.precommit.registerListener([this](std::any d) { - if (!surface || !surface->pending.buffer) + if (!surface || !surface->pending.texture) return; if (surface->pending.viewport.hasSource) { auto& src = surface->pending.viewport.source; - if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) { + if (src.w + src.x > surface->pending.bufferSize.x || src.h + src.y > surface->pending.bufferSize.y) { resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); surface->pending.rejected = true; return; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index cb8a5bc3..71873374 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -347,12 +347,12 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPcurrent = toplevel->pending; - if (initialCommit && surface->pending.buffer) { + if (initialCommit && surface->pending.texture) { resource->error(-1, "Buffer attached before initial commit"); return; } - if (surface->current.buffer && !mapped) { + if (surface->current.texture && !mapped) { // this forces apps to not draw CSD. if (toplevel) toplevel->setMaximized(true); @@ -363,7 +363,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPcurrent.buffer && mapped) { + if (!surface->current.texture && mapped) { mapped = false; events.unmap.emit(); surface->unmap(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 43d3059b..81be8e46 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -1,5 +1,6 @@ #include "Compositor.hpp" #include "Output.hpp" +#include "Seat.hpp" #include "../types/WLBuffer.hpp" #include #include @@ -9,6 +10,7 @@ #include "../PresentationTime.hpp" #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" +#include #define LOGM PROTO::compositor->protoLog @@ -19,8 +21,6 @@ class CDefaultSurfaceRole : public ISurfaceRole { } }; -SP defaultRole = makeShared(); - CWLCallbackResource::CWLCallbackResource(SP resource_) : resource(resource_) { ; } @@ -63,7 +63,7 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso resource->setData(this); - role = defaultRole; + role = makeShared(); resource->setDestroy([this](CWlSurface* r) { destroy(); }); resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); @@ -75,41 +75,42 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.buffer.reset(); pending.texture.reset(); } else { - auto res = CWLBufferResource::fromResource(buffer); - pending.buffer = res && res->buffer ? res->buffer.lock() : nullptr; - pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; - pending.texture = res && res->buffer ? res->buffer->texture : nullptr; - if (res) - res->released = false; + auto res = CWLBufferResource::fromResource(buffer); + pending.buffer = res && res->buffer ? makeShared(res->buffer.lock(), self.lock()) : nullptr; + pending.size = res && res->buffer ? res->buffer->size : Vector2D{}; + pending.texture = res && res->buffer ? res->buffer->texture : nullptr; + pending.bufferSize = res && res->buffer ? res->buffer->size : Vector2D{}; } - Vector2D oldBufSize = current.buffer ? current.buffer->size : Vector2D{}; - Vector2D newBufSize = pending.buffer ? pending.buffer->size : Vector2D{}; + Vector2D oldBufSize = current.buffer ? current.bufferSize : Vector2D{}; + Vector2D newBufSize = pending.buffer ? pending.bufferSize : Vector2D{}; if (oldBufSize != newBufSize || current.buffer != pending.buffer) pending.bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}}; }); resource->setCommit([this](CWlSurface* r) { - if (pending.buffer) - pending.bufferDamage.intersect(CBox{{}, pending.buffer->size}); + if (pending.texture) + pending.bufferDamage.intersect(CBox{{}, pending.bufferSize}); - if (!pending.buffer) + if (!pending.texture) pending.size = {}; else if (pending.viewport.hasDestination) pending.size = pending.viewport.destination; else if (pending.viewport.hasSource) pending.size = pending.viewport.source.size(); else { - Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.buffer->size.y, pending.buffer->size.x} : pending.buffer->size; + Vector2D tfs = pending.transform % 2 == 1 ? Vector2D{pending.bufferSize.y, pending.bufferSize.x} : pending.bufferSize; pending.size = tfs / pending.scale; } pending.damage.intersect(CBox{{}, pending.size}); events.precommit.emit(); - if (pending.rejected) + if (pending.rejected) { + dropPendingBuffer(); return; + } if (stateLocks <= 0) commitPendingState(); @@ -160,6 +161,14 @@ void CWLSurfaceResource::destroy() { PROTO::compositor->destroyResource(this); } +void CWLSurfaceResource::dropPendingBuffer() { + pending.buffer.reset(); +} + +void CWLSurfaceResource::dropCurrentBuffer() { + current.buffer.reset(); +} + SP CWLSurfaceResource::fromResource(wl_resource* res) { auto data = (CWLSurfaceResource*)(((CWlSurface*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -240,7 +249,7 @@ void CWLSurfaceResource::frame(timespec* now) { } void CWLSurfaceResource::resetRole() { - role = defaultRole; + role = makeShared(); } void CWLSurfaceResource::bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data) { @@ -254,6 +263,8 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std for (auto& c : n->subsurfaces) { if (c->zIndex >= 0) break; + if (c->surface.expired()) + continue; nodes2.push_back(c->surface.lock()); } } @@ -277,6 +288,8 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std for (auto& c : n->subsurfaces) { if (c->zIndex < 0) continue; + if (c->surface.expired()) + continue; nodes2.push_back(c->surface.lock()); } } @@ -343,14 +356,9 @@ void CWLSurfaceResource::unmap() { } void CWLSurfaceResource::releaseBuffers(bool onlyCurrent) { - if (current.buffer && !current.buffer->resource->released) - current.buffer->sendRelease(); - if (pending.buffer && !pending.buffer->resource->released && !onlyCurrent) - pending.buffer->sendRelease(); - - pending.buffer.reset(); if (!onlyCurrent) - current.buffer.reset(); + dropPendingBuffer(); + dropCurrentBuffer(); } void CWLSurfaceResource::error(int code, const std::string& str) { @@ -375,18 +383,18 @@ CBox CWLSurfaceResource::extends() { } Vector2D CWLSurfaceResource::sourceSize() { - if (!current.buffer) + if (!current.texture) return {}; if (current.viewport.hasSource) return current.viewport.source.size(); - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; return trc / current.scale; } CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { - if (!current.buffer) + if (!current.texture) return {}; CRegion surfaceDamage = current.damage; @@ -398,7 +406,7 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { if (current.viewport.hasSource) surfaceDamage.translate(current.viewport.source.pos()); - Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; + Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); } @@ -421,16 +429,21 @@ void CWLSurfaceResource::commitPendingState() { pending.damage.clear(); pending.bufferDamage.clear(); - if (current.buffer && current.buffer->texture) - current.buffer->texture->m_eTransform = wlTransformToHyprutils(current.transform); + if (current.texture) + current.texture->m_eTransform = wlTransformToHyprutils(current.transform); - if (current.buffer && !current.buffer->resource->released) { - current.buffer->update(accumulateCurrentBufferDamage()); + if (current.buffer && current.buffer->buffer) { + current.buffer->buffer->update(accumulateCurrentBufferDamage()); + + // if the surface is a cursor, update the shm buffer + // TODO: don't update the entire texture + if (role->role() == SURFACE_ROLE_CURSOR) + updateCursorShm(); // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->isSynchronous()) - current.buffer->sendReleaseWithSurface(self.lock()); + if (current.buffer->buffer->isSynchronous()) + dropCurrentBuffer(); } // TODO: we should _accumulate_ and not replace above if sync @@ -455,20 +468,37 @@ void CWLSurfaceResource::commitPendingState() { } // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !previousBuffer->resource->released) { - if (previousBuffer->lockedByBackend) { - previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { - if (!self.expired()) // could be dead in the dtor - previousBuffer->sendReleaseWithSurface(self.lock()); - else - previousBuffer->sendRelease(); - previousBuffer->hlEvents.backendRelease.reset(); - }); - } else - previousBuffer->sendReleaseWithSurface(self.lock()); - - previousBuffer->resource->released = true; // set it here regardless so we dont set more listeners for backendRelease + // if the backend took it, ref it with the lambda. Otherwise, the end of this scope will release it. + if (previousBuffer && previousBuffer->buffer && !previousBuffer->buffer->isSynchronous()) { + if (previousBuffer->buffer->lockedByBackend && !previousBuffer->buffer->hlEvents.backendRelease) { + previousBuffer->buffer->lock(); + previousBuffer->buffer->unlockOnBufferRelease(self); + } } + + lastBuffer = current.buffer ? current.buffer->buffer : WP{}; +} + +void CWLSurfaceResource::updateCursorShm() { + auto buf = current.buffer ? current.buffer : lastBuffer; + + if (!buf) + return; + + // TODO: actually use damage + auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock()); + auto shmAttrs = current.buffer->buffer->shm(); + + if (!shmAttrs.success) { + LOGM(TRACE, "updateCursorShm: ignoring, not a shm buffer"); + return; + } + + // no need to end, shm. + auto [pixelData, fmt, bufLen] = current.buffer->buffer->beginDataPtr(0); + + shmData.resize(bufLen); + memcpy(shmData.data(), pixelData, bufLen); } void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 79cd1de6..460ec755 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -84,13 +84,13 @@ class CWLSurfaceResource { } events; struct SState { - CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - int scale = 1; - SP buffer; - SP texture; - Vector2D offset; - Vector2D size; + CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + int scale = 1; + SP buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture. + SP texture; + Vector2D offset; + Vector2D size, bufferSize; struct { bool hasDestination = false; bool hasSource = false; @@ -116,7 +116,7 @@ class CWLSurfaceResource { std::vector> enteredOutputs; bool mapped = false; std::vector> subsurfaces; - WP role; + SP role; WP viewportResource; WP syncobj; // may not be present @@ -134,12 +134,21 @@ class CWLSurfaceResource { SP resource; wl_client* pClient = nullptr; - int stateLocks = 0; + // this is for cursor dumb copy. Due to our (and wayland's...) architecture, + // this stupid-ass hack is used + WP lastBuffer; - void destroy(); - void releaseBuffers(bool onlyCurrent = true); - void commitPendingState(); - void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); + int stateLocks = 0; + + void destroy(); + void releaseBuffers(bool onlyCurrent = true); + void dropPendingBuffer(); + void dropCurrentBuffer(); + void commitPendingState(); + void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); + void updateCursorShm(); + + friend class CWLPointerResource; }; class CWLCompositorResource { diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 9634d569..fe3905d0 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -469,12 +469,12 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource if (dragSurface) { dnd.dndSurfaceDestroy = dragSurface->events.destroy.registerListener([this](std::any d) { abortDrag(); }); dnd.dndSurfaceCommit = dragSurface->events.commit.registerListener([this](std::any d) { - if (dnd.dndSurface->current.buffer && !dnd.dndSurface->mapped) { + if (dnd.dndSurface->current.texture && !dnd.dndSurface->mapped) { dnd.dndSurface->map(); return; } - if (dnd.dndSurface->current.buffer <= 0 && dnd.dndSurface->mapped) { + if (dnd.dndSurface->current.texture <= 0 && dnd.dndSurface->mapped) { dnd.dndSurface->unmap(); return; } @@ -660,13 +660,13 @@ void CWLDataDeviceProtocol::abortDrag() { } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { - if (!dnd.dndSurface || !dnd.dndSurface->current.buffer || !dnd.dndSurface->current.buffer->texture) + if (!dnd.dndSurface || !dnd.dndSurface->current.texture) return; const auto POS = g_pInputManager->getMouseCoordsInternal(); CBox box = CBox{POS, dnd.dndSurface->current.size}.translate(-pMonitor->vecPosition + g_pPointerManager->cursorSizeLogical() / 2.F).scale(pMonitor->scale); - g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.buffer->texture, &box, 1.F); + g_pHyprOpenGL->renderTexture(dnd.dndSurface->current.texture, &box, 1.F); box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F); g_pHyprRenderer->damageBox(&box); diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 7a295372..bb6a9d4d 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -119,7 +119,19 @@ CWLPointerResource::CWLPointerResource(SP resource_, SPonSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY}); + auto surfResource = surf ? CWLSurfaceResource::fromResource(surf) : nullptr; + + if (surfResource && surfResource->role->role() != SURFACE_ROLE_CURSOR && surfResource->role->role() != SURFACE_ROLE_UNASSIGNED) { + r->error(-1, "Cursor surface already has a different role"); + return; + } + + if (surfResource) { + surfResource->role = makeShared(); + surfResource->updateCursorShm(); + } + + g_pSeatManager->onSetCursor(owner.lock(), serial, surfResource, {hotX, hotY}); }); if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client()) @@ -546,3 +558,10 @@ SP CWLSeatProtocol::seatResourceForClient(wl_client* client) { return nullptr; } + +std::vector& CCursorSurfaceRole::cursorPixelData(SP surface) { + RASSERT(surface->role->role() == SURFACE_ROLE_CURSOR, "cursorPixelData called on a non-cursor surface"); + + auto role = (CCursorSurfaceRole*)surface->role.get(); + return role->cursorShmPixelData; +} diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 09b36056..755a9c2f 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -16,6 +16,7 @@ #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" +#include "../types/SurfaceRole.hpp" constexpr const char* HL_SEAT_NAME = "Hyprland"; @@ -27,6 +28,20 @@ class CWLKeyboardResource; class CWLTouchResource; class CWLSeatResource; +class CCursorSurfaceRole : public ISurfaceRole { + public: + virtual eSurfaceRole role() { + return SURFACE_ROLE_CURSOR; + } + + // gets the current pixel data from a shm surface + // will assert if the surface is not a cursor + static std::vector& cursorPixelData(SP surface); + + private: + std::vector cursorShmPixelData; +}; + class CWLTouchResource { public: CWLTouchResource(SP resource_, SP owner_); diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index c0c1f258..90f89d91 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -80,13 +80,13 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPevents.commit.registerListener([this](std::any d) { - if (surface->current.buffer && !surface->mapped) { + if (surface->current.texture && !surface->mapped) { surface->map(); surface->events.map.emit(); return; } - if (!surface->current.buffer && surface->mapped) { + if (!surface->current.texture && surface->mapped) { surface->events.unmap.emit(); surface->unmap(); return; diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 0217f7e2..40f2eaf8 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -1,5 +1,10 @@ #include "Buffer.hpp" +IHLBuffer::~IHLBuffer() { + if (locked() && resource) + sendRelease(); +} + void IHLBuffer::sendRelease() { resource->sendRelease(); } @@ -8,3 +13,54 @@ void IHLBuffer::sendReleaseWithSurface(SP surf) { if (resource && resource->good()) resource->sendReleaseWithSurface(surf); } + +void IHLBuffer::lock() { + nLocks++; +} + +void IHLBuffer::unlock() { + nLocks--; + + ASSERT(nLocks >= 0); + + if (nLocks == 0) + sendRelease(); +} + +void IHLBuffer::unlockWithSurface(SP surf) { + nLocks--; + + ASSERT(nLocks >= 0); + + if (nLocks == 0) + sendReleaseWithSurface(surf); +} + +bool IHLBuffer::locked() { + return nLocks > 0; +} + +void IHLBuffer::unlockOnBufferRelease(WP surf) { + unlockSurface = surf; + hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) { + if (unlockSurface.expired()) + unlock(); + else + unlockWithSurface(unlockSurface.lock()); + hlEvents.backendRelease.reset(); + }); +} + +CHLBufferReference::CHLBufferReference(SP buffer_, SP surface_) : buffer(buffer_), surface(surface_) { + buffer->lock(); +} + +CHLBufferReference::~CHLBufferReference() { + if (buffer.expired()) + return; + + if (surface) + buffer->unlockWithSurface(surface.lock()); + else + buffer->unlock(); +} diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index ba8278f3..d2157181 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -8,9 +8,7 @@ class IHLBuffer : public Aquamarine::IBuffer { public: - virtual ~IHLBuffer() { - ; - } + virtual ~IHLBuffer(); virtual Aquamarine::eBufferCapability caps() = 0; virtual Aquamarine::eBufferType type() = 0; virtual void update(const CRegion& damage) = 0; @@ -18,6 +16,12 @@ class IHLBuffer : public Aquamarine::IBuffer { virtual bool good() = 0; virtual void sendRelease(); virtual void sendReleaseWithSurface(SP); + virtual void lock(); + virtual void unlock(); + virtual void unlockWithSurface(SP surf); + virtual bool locked(); + + void unlockOnBufferRelease(WP surf /* optional */); SP texture; bool opaque = false; @@ -26,4 +30,22 @@ class IHLBuffer : public Aquamarine::IBuffer { struct { CHyprSignalListener backendRelease; } hlEvents; + + private: + int nLocks = 0; + + WP unlockSurface; +}; + +// for ref-counting. Releases in ~dtor +// surface optional +class CHLBufferReference { + public: + CHLBufferReference(SP buffer, SP surface); + ~CHLBufferReference(); + + WP buffer; + + private: + WP surface; }; diff --git a/src/protocols/types/SurfaceRole.hpp b/src/protocols/types/SurfaceRole.hpp index faaf70ee..64586f01 100644 --- a/src/protocols/types/SurfaceRole.hpp +++ b/src/protocols/types/SurfaceRole.hpp @@ -6,6 +6,7 @@ enum eSurfaceRole { SURFACE_ROLE_LAYER_SHELL, SURFACE_ROLE_EASTER_EGG, SURFACE_ROLE_SUBSURFACE, + SURFACE_ROLE_CURSOR, }; class ISurfaceRole { diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index e42094b1..d34a867d 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -29,7 +29,6 @@ bool CWLBufferResource::good() { } void CWLBufferResource::sendRelease() { - released = true; resource->sendRelease(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index f4424abc..59512128 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -24,8 +24,6 @@ class CWLBufferResource { WP self; - bool released = false; - private: CWLBufferResource(SP resource_); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index e4f97895..127ae187 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -102,10 +102,10 @@ CHyprRenderer::~CHyprRenderer() { } static void renderSurface(SP surface, int x, int y, void* data) { - if (!surface->current.buffer || !surface->current.buffer->texture) + if (!surface->current.texture) return; - const auto& TEXTURE = surface->current.buffer->texture; + const auto& TEXTURE = surface->current.texture; const auto RDATA = (SRenderData*)data; const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; @@ -192,8 +192,8 @@ static void renderSurface(SP surface, int x, int y, void* da windowBox.round(); const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && - windowBox.size() != surface->current.buffer->size /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.buffer->size.x, 3) && - DELTALESSTHAN(windowBox.height, surface->current.buffer->size.y, 3) /* off by one-or-two */ && + windowBox.size() != surface->current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.bufferSize.x, 3) && + DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); @@ -1014,7 +1014,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPcurrent.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 - Vector2D bufferSize = pSurface->current.buffer->size; + Vector2D bufferSize = pSurface->current.bufferSize; auto bufferSource = pSurface->current.viewport.source; // calculate UV for the basic src_box. Assume dest == size. Scale to dest later @@ -1030,8 +1030,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPcurrent.buffer->size; - const Vector2D MISALIGNMENT = pSurface->current.buffer->size - projSize; + const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->current.bufferSize; + const Vector2D MISALIGNMENT = pSurface->current.bufferSize - projSize; if (MISALIGNMENT != Vector2D{}) uvBR -= MISALIGNMENT * PIXELASUV; } diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 0f5b4c4c..94d00184 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -28,6 +28,8 @@ CTexture::CTexture(const SP buffer) { if (!buffer) return; + m_bOpaque = buffer->opaque; + auto attrs = buffer->dmabuf(); if (!attrs.success) { @@ -86,6 +88,7 @@ void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) return; } + m_bOpaque = FormatUtils::isFormatOpaque(attrs.format); m_iTarget = GL_TEXTURE_2D; m_iType = TEXTURE_RGBA; m_vSize = attrs.size; diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index a54be8c5..e0ef5503 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -41,6 +41,7 @@ class CTexture { Vector2D m_vSize = {}; void* m_pEglImage = nullptr; eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL; + bool m_bOpaque = false; private: void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 107b22da..30ffbc68 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -62,12 +62,12 @@ void CXWaylandSurface::ensureListeners() { }); listeners.commitSurface = surface->events.commit.registerListener([this](std::any d) { - if (surface->pending.buffer && !mapped) { + if (surface->pending.texture && !mapped) { map(); return; } - if (!surface->pending.buffer && mapped) { + if (!surface->pending.texture && mapped) { unmap(); return; } @@ -131,7 +131,7 @@ void CXWaylandSurface::considerMap() { return; } - if (surface->pending.buffer) { + if (surface->pending.texture) { Debug::log(LOG, "XWayland surface: considerMap, sure, we have a buffer"); map(); return; From 5b7057c4790e0dafea53c2343a792c17e2dbf4a7 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 1 Aug 2024 11:42:22 +0200 Subject: [PATCH 0428/2393] pointer: fix buffer crash (#7131) current buffer->buffer can turn out to be null actually check for its existence or use the lastbuffer when calling updateCursorShm() --- src/protocols/core/Compositor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 81be8e46..bff52133 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -480,14 +480,14 @@ void CWLSurfaceResource::commitPendingState() { } void CWLSurfaceResource::updateCursorShm() { - auto buf = current.buffer ? current.buffer : lastBuffer; + auto buf = current.buffer ? current.buffer->buffer : lastBuffer; if (!buf) return; // TODO: actually use damage auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock()); - auto shmAttrs = current.buffer->buffer->shm(); + auto shmAttrs = buf->shm(); if (!shmAttrs.success) { LOGM(TRACE, "updateCursorShm: ignoring, not a shm buffer"); @@ -495,7 +495,7 @@ void CWLSurfaceResource::updateCursorShm() { } // no need to end, shm. - auto [pixelData, fmt, bufLen] = current.buffer->buffer->beginDataPtr(0); + auto [pixelData, fmt, bufLen] = buf->beginDataPtr(0); shmData.resize(bufLen); memcpy(shmData.data(), pixelData, bufLen); From 8c02b3c267198541dd03601e4c7ff7d870197728 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Thu, 1 Aug 2024 18:43:02 +0900 Subject: [PATCH 0429/2393] layout: fix dynamic rules not updating after setting fullscreen (#7129) --- src/Compositor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7221d3a7..2a1e4f8c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2316,9 +2316,10 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); EMIT_HOOK_EVENT("fullscreen", PWINDOW); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + PWINDOW->updateDynamicRules(); PWINDOW->updateWindowDecos(); updateWindowAnimatedDecorationValues(PWINDOW); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); // make all windows on the same workspace under the fullscreen window for (auto& w : m_vWindows) { From 95959789b7667172b2b2f37f78fe96ac196e9cd3 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 1 Aug 2024 09:43:32 +0000 Subject: [PATCH 0430/2393] keybinds: allow toggling fullscreenstate (#7128) modified: src/managers/KeybindManager.cpp --- src/managers/KeybindManager.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 33b07351..9984fe40 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1174,9 +1174,13 @@ void CKeybindManager::fullscreenStateActive(std::string args) { clientMode = std::stoi(ARGS[1]); } catch (std::exception& e) { clientMode = -1; } - g_pCompositor->setWindowFullscreenState(PWINDOW, - sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), - .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}); + const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), + .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}; + + if (PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE}); + else + g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); } void CKeybindManager::moveActiveToWorkspace(std::string args) { From 5edfa627b4efc5d2125f4f0f97dad6bac6c3a407 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 1 Aug 2024 11:45:55 +0200 Subject: [PATCH 0431/2393] layershell: don't throw misaligned error on exclusive edge 0 ref #7108 --- src/protocols/LayerShell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 0ed1b219..295ef4a9 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -159,7 +159,7 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPerror(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_EXCLUSIVE_EDGE, "Exclusive edge doesn't align with anchor"); return; } From 60571cd5ccc76f91209ef2faac93ecea542de221 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 1 Aug 2024 12:36:09 +0200 Subject: [PATCH 0432/2393] border: fixup infinite recursion ref #7127 --- src/render/decorations/CHyprBorderDecoration.cpp | 14 ++++++++++++-- src/render/decorations/CHyprBorderDecoration.hpp | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 708215b6..ddb38c6e 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -1,6 +1,7 @@ #include "CHyprBorderDecoration.hpp" #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" +#include "../../managers/eventLoop/EventLoopManager.hpp" CHyprBorderDecoration::CHyprBorderDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow) { m_pWindow = pWindow; @@ -82,8 +83,17 @@ eDecorationType CHyprBorderDecoration::getDecorationType() { } void CHyprBorderDecoration::updateWindow(PHLWINDOW) { - if (m_pWindow->getRealBorderSize() != m_seExtents.topLeft.x) - g_pDecorationPositioner->repositionDeco(this); + auto borderSize = m_pWindow->getRealBorderSize(); + + if (borderSize == m_iLastBorderSize) + return; + + if (borderSize <= 0 && m_iLastBorderSize <= 0) + return; + + m_iLastBorderSize = borderSize; + + g_pEventLoopManager->doLater([this]() { g_pDecorationPositioner->repositionDeco(this); }); } void CHyprBorderDecoration::damageEntire() { diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index 8ad3263e..0e196565 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -36,6 +36,8 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { CBox m_bAssignedGeometry = {0}; + int m_iLastBorderSize = -1; + CBox assignedBoxGlobal(); bool doesntWantBorders(); }; From c8873b958dd9330c364339ac4ab58e32b27d82b4 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 1 Aug 2024 12:59:52 +0000 Subject: [PATCH 0433/2393] internal: fix fullscreen typos (#7134) modified: src/events/Windows.cpp modified: src/layout/DwindleLayout.cpp --- src/events/Windows.cpp | 4 ++-- src/layout/DwindleLayout.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 0389f57e..f5ae6759 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -487,9 +487,9 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_fDimPercent.setValueAndWarp(0); } - if (requestedClientFSMode.has_value() && !(PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) + if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_FULLSCREEN); - if (requestedClientFSMode.has_value() && !(PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) + if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE)) requestedClientFSMode = (eFullscreenMode)((uint8_t)requestedClientFSMode.value_or(FSMODE_NONE) & ~(uint8_t)FSMODE_MAXIMIZED); if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) { diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 336c8c68..7253275d 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -926,7 +926,7 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { return; const eFullscreenMode MODE1 = pWindow->m_sFullscreenState.internal; - const eFullscreenMode MODE2 = pWindow->m_sFullscreenState.internal; + const eFullscreenMode MODE2 = pWindow2->m_sFullscreenState.internal; g_pCompositor->setWindowFullscreenInternal(pWindow, FSMODE_NONE); g_pCompositor->setWindowFullscreenInternal(pWindow2, FSMODE_NONE); From ab0a3268e04f2295ec4455be90ce8d0c2b107b8d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 1 Aug 2024 15:43:13 +0200 Subject: [PATCH 0434/2393] xdg-shell: fixup unassigned wl surfaces to xdg surfaces fixes #7133 --- src/protocols/XDGShell.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 71873374..5e82b530 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -666,8 +666,9 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { return; } - RESOURCE->self = RESOURCE; - SURF->role = RESOURCE; + RESOURCE->self = RESOURCE; + RESOURCE->surface = SURF; + SURF->role = RESOURCE; surfaces.emplace_back(RESOURCE); From 09bb5658b7fa6c0dc4e2744797e51ad4dd25af42 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 2 Aug 2024 00:31:44 +0200 Subject: [PATCH 0435/2393] window/ls: reset core signals after destroy fixes #7137 --- src/desktop/LayerSurface.cpp | 5 +++++ src/events/Windows.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index ba1b1776..8fd448ef 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -111,6 +111,11 @@ void CLayerSurface::onDestroy() { layerSurface.reset(); if (surface) surface->unassign(); + + listeners.unmap.reset(); + listeners.destroy.reset(); + listeners.map.reset(); + listeners.commit.reset(); } void CLayerSurface::onMap() { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index f5ae6759..5d29a3b7 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -790,6 +790,11 @@ void Events::listener_destroyWindow(void* owner, void* data) { Debug::log(LOG, "Unmapped {} removed instantly", PWINDOW); g_pCompositor->removeWindowFromVectorSafe(PWINDOW); // most likely X11 unmanaged or sumn } + + PWINDOW->listeners.unmap.reset(); + PWINDOW->listeners.destroy.reset(); + PWINDOW->listeners.map.reset(); + PWINDOW->listeners.commit.reset(); } void Events::listener_setTitleWindow(void* owner, void* data) { From 592b4a709c8093273c6051fb7e76ce3c3d82cedf Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:25:51 +0200 Subject: [PATCH 0436/2393] sessionLock: don't sendLocked when session lock has already been destoyed (#7150) * sessionLock: reset m_pSessionLock on destroy * sessionLock: only send locked when resource is good --- src/managers/SessionLockManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 83ff3ee7..a82432a8 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -71,7 +71,8 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pHyprRenderer->damageMonitor(m.get()); }); - m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([](std::any data) { + m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) { + m_pSessionLock.reset(); g_pCompositor->focusSurface(nullptr); for (auto& m : g_pCompositor->m_vMonitors) @@ -104,7 +105,7 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64 // We don't want the red screen to flash. float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { if (!m_pSessionLock) - return 0.F; + return 1.F; const auto& NOMAPPEDSURFACETIMER = m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.find(id); @@ -123,7 +124,7 @@ void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) { m_pSessionLock->m_lockedMonitors.emplace(id); const auto MONITORS = g_pCompositor->m_vMonitors; const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); - if (LOCKED) { + if (LOCKED && m_pSessionLock->lock->good()) { m_pSessionLock->lock->sendLocked(); m_pSessionLock->m_hasSentLocked = true; } From 1fa4b7d79baaad47fde8e72221cd77f569fbfe35 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 2 Aug 2024 18:42:05 +0200 Subject: [PATCH 0437/2393] hyprerror: minor stylistic changes --- src/hyprerror/HyprError.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index a325d858..bbc3a006 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -88,14 +88,14 @@ void CHyprError::createQueued() { cairo_arc(CAIRO, X + RADIUS, Y + RADIUS, RADIUS, 180 * DEGREES, 270 * DEGREES); cairo_close_path(CAIRO); - cairo_set_source_rgba(CAIRO, m_cQueued.r, m_cQueued.g, m_cQueued.b, m_cQueued.a); + cairo_set_source_rgba(CAIRO, 0.06, 0.06, 0.06, 1.0); cairo_fill_preserve(CAIRO); - cairo_set_source_rgba(CAIRO, 0, 0, 0, 1); + cairo_set_source_rgba(CAIRO, m_cQueued.r, m_cQueued.g, m_cQueued.b, m_cQueued.a); cairo_set_line_width(CAIRO, 2); cairo_stroke(CAIRO); // draw the text with a common font - const CColor textColor = m_cQueued.r + m_cQueued.g + m_cQueued.b < 0.2f ? CColor(1.0, 1.0, 1.0, 1.0) : CColor(0, 0, 0, 1.0); + const CColor textColor = CColor(0.9, 0.9, 0.9, 1.0); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); static auto fontFamily = CConfigValue("misc:font_family"); From be2dfa36ef635add2d55c96f7616ec61b96e7bb1 Mon Sep 17 00:00:00 2001 From: Tuur Vanhoutte <4633209+zjeffer@users.noreply.github.com> Date: Fri, 2 Aug 2024 21:49:47 +0200 Subject: [PATCH 0438/2393] hyprctl: increase hyprctl timeout to 5s to fix #6801 (#7152) --- hyprctl/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 45fe9142..336d479e 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -141,7 +141,7 @@ int rollingRead(const int socket) { int request(std::string arg, int minArgs = 0, bool needRoll = false) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); - auto t = timeval{.tv_sec = 1, .tv_usec = 0}; + auto t = timeval{.tv_sec = 5, .tv_usec = 0}; setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)); const auto ARGS = std::count(arg.begin(), arg.end(), ' '); From 4141e6755022edc19cd37cd7ad077a93b3bae5bd Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 2 Aug 2024 23:16:20 +0200 Subject: [PATCH 0439/2393] xcursor: rework bootleg xcursor (#7140) there were a bunch of missing cursors, rework the shape loading add a function to get legacyname from new wayland names. also bootleg add a cursor if no theme can be found and no shape. to atleast show something. --- src/managers/CursorManager.cpp | 371 ++++++++++++++++++++++++--------- src/managers/CursorManager.hpp | 15 +- 2 files changed, 284 insertions(+), 102 deletions(-) diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 3a13d10b..e0d3a62c 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -46,7 +46,7 @@ CCursorManager::CCursorManager() { if (m_iSize == 0) m_iSize = 24; - xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "", m_iSize * std::ceil(m_fCursorScale)); + xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr); @@ -135,14 +135,20 @@ void CCursorManager::setXCursor(const std::string& name) { if (!xcursor.themeLoaded) { Debug::log(ERR, "XCursor failed to find theme in setXCursor"); - g_pPointerManager->resetCursorImage(); - return; + if (!xcursor.defaultCursor) { + g_pPointerManager->resetCursorImage(); + return; + } } auto& icon = xcursor.defaultCursor; // try to get an icon we know if we have one - if (xcursor.cursors.contains(name)) - icon = xcursor.cursors.at(name); + for (auto const& c : xcursor.cursors) { + if (c.first != name) + continue; + + icon = c.second; + } m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot)); @@ -305,87 +311,86 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { } // Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c -// however modified to fit wayland cursor shape names better. // _ -> - // clang-format off static std::array XCURSOR_STANDARD_NAMES = { "X_cursor", - "default", // arrow - "ns-resize", // based-arrow-down - "ns-resize", // based-arrow-up + "arrow", + "based_arrow_down", + "based_arrow_up", "boat", "bogosity", - "sw-resize", // bottom-left-corner - "se-resize", // bottom-right-corner - "s-resize", // bottom-side - "bottom-tee", - "box-spiral", - "center-ptr", + "bottom_left_corner", + "bottom_right_corner", + "bottom_side", + "bottom_tee", + "box_spiral", + "center_ptr", "circle", "clock", - "coffee-mug", + "coffee_mug", "cross", - "cross-reverse", + "cross_reverse", "crosshair", - "diamond-cross", + "diamond_cross", "dot", "dotbox", - "double-arrow", - "draft-large", - "draft-small", - "draped-box", + "double_arrow", + "draft_large", + "draft_small", + "draped_box", "exchange", - "move", // fleur + "fleur", "gobbler", "gumby", - "pointer", // hand1 - "grabbing", // hand2 + "hand1", + "hand2", "heart", "icon", - "iron-cross", - "default", // left-ptr - "w-resize", // left-side - "left-tee", + "iron_cross", + "left_ptr", + "left_side", + "left_tee", "leftbutton", - "ll-angle", - "lr-angle", + "ll_angle", + "lr_angle", "man", "middlebutton", "mouse", "pencil", "pirate", "plus", - "help", // question-arrow - "right-ptr", - "e-resize", // right-side - "right-tee", + "question_arrow", + "right_ptr", + "right_side", + "right_tee", "rightbutton", - "rtl-logo", + "rtl_logo", "sailboat", - "ns-resize", // sb-down-arrow - "ew-resize", // sb-h-double-arrow - "ew-resize", // sb-left-arrow - "ew-resize", // sb-right-arrow - "n-resize", // sb-up-arrow - "s-resize", // sb-v-double-arrow + "sb_down_arrow", + "sb_h_double_arrow", + "sb_left_arrow", + "sb_right_arrow", + "sb_up_arrow", + "sb_v_double_arrow", "shuttle", "sizing", "spider", "spraycan", "star", "target", - "cell", // tcross - "nw-resize", // top-left-arrow - "nw-resize", // top-left-corner - "ne-resize", // top-right-corner - "n-resize", // top-side - "top-tee", + "tcross", + "top_left_arrow", + "top_left_corner", + "top_right_corner", + "top_side", + "top_tee", "trek", - "ul-angle", + "ul_angle", "umbrella", - "ur-angle", - "wait", // watch - "text", // xterm + "ur_angle", + "watch", + "xterm", }; // clang-format on @@ -397,51 +402,21 @@ void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int siz themeLoaded = false; themeName = name.empty() ? "default" : name; - auto img = XcursorShapeLoadImage(2, themeName.c_str(), size); + std::vector>> newCursors; - if (!img) { - Debug::log(ERR, "XCursor failed finding theme \"{}\". Trying size 24.", themeName); - size = 24; - img = XcursorShapeLoadImage(2, themeName.c_str(), size); - if (!img) { - Debug::log(ERR, "XCursor failed finding theme \"{}\".", themeName); - return; - } - } - - defaultCursor = makeShared(); - defaultCursor->size = {(int)img->width, (int)img->height}; - defaultCursor->hotspot = {(int)img->xhot, (int)img->yhot}; - - defaultCursor->pixels.resize(img->width * img->height); - std::memcpy(defaultCursor->pixels.data(), img->pixels, img->width * img->height * sizeof(uint32_t)); - - themeLoaded = true; - - XcursorImageDestroy(img); - - // gather as many shapes as we can find. - cursors.clear(); - - for (auto& shape : CURSOR_SHAPE_NAMES) { - int id = -1; - for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { - if (XCURSOR_STANDARD_NAMES.at(i) == std::string{shape}) { - id = i; - break; - } - } - - if (id < 0) { - Debug::log(LOG, "XCursor has no shape {}, skipping", shape); - continue; - } - - auto xImage = XcursorShapeLoadImage(id << 1 /* wtf xcursor? */, themeName.c_str(), size); + // load the default xcursor shapes that exist in the theme + for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { + auto shape = XCURSOR_STANDARD_NAMES.at(i); + auto xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), size); if (!xImage) { - Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape); - continue; + Debug::log(LOG, "XCursor failed to find a shape with name {}, trying size 24.", shape); + xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), 24); + + if (!xImage) { + Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape); + continue; + } } auto xcursor = makeShared(); @@ -451,8 +426,214 @@ void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int siz xcursor->pixels.resize(xImage->width * xImage->height); std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t)); - cursors.emplace(std::string{shape}, xcursor); + newCursors.emplace_back(std::string{shape}, xcursor); XcursorImageDestroy(xImage); } + + if (newCursors.empty()) { + Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName); + if (!defaultCursor) { + defaultCursor = createDefaultCursor(); + } + return; + } + + cursors.clear(); + cursors = std::move(newCursors); + defaultCursor.reset(); + themeLoaded = true; + + for (auto const& shape : CURSOR_SHAPE_NAMES) { + auto legacyName = getLegacyShapeName(shape); + if (legacyName.empty()) + continue; + + auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c.first == legacyName; }); + + if (it == cursors.end()) { + Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName); + continue; + } + + cursors.emplace_back(shape, it->second); + } + + // set default cursor + for (auto const& c : cursors) { + if (c.first == "left_ptr" || c.first == "arrow") { + defaultCursor = c.second; + break; + } + } + + // just assign the first one then. + if (!defaultCursor) + defaultCursor = cursors.at(0).second; +} + +std::string CCursorManager::SXCursorManager::getLegacyShapeName(std::string const& shape) { + if (shape == "invalid") + return std::string(); + else if (shape == "default") + return "left_ptr"; + else if (shape == "context-menu") + return "left_ptr"; + else if (shape == "help") + return "left_ptr"; + else if (shape == "pointer") + return "hand2"; + else if (shape == "progress") + return "watch"; + else if (shape == "wait") + return "watch"; + else if (shape == "cell") + return "plus"; + else if (shape == "crosshair") + return "cross"; + else if (shape == "text") + return "xterm"; + else if (shape == "vertical-text") + return "xterm"; + else if (shape == "alias") + return "dnd-link"; + else if (shape == "copy") + return "dnd-copy"; + else if (shape == "move") + return "dnd-move"; + else if (shape == "no-drop") + return "dnd-none"; + else if (shape == "not-allowed") + return "crossed_circle"; + else if (shape == "grab") + return "hand1"; + else if (shape == "grabbing") + return "hand1"; + else if (shape == "e-resize") + return "right_side"; + else if (shape == "n-resize") + return "top_side"; + else if (shape == "ne-resize") + return "top_right_corner"; + else if (shape == "nw-resize") + return "top_left_corner"; + else if (shape == "s-resize") + return "bottom_side"; + else if (shape == "se-resize") + return "bottom_right_corner"; + else if (shape == "sw-resize") + return "bottom_left_corner"; + else if (shape == "w-resize") + return "left_side"; + else if (shape == "ew-resize") + return "sb_h_double_arrow"; + else if (shape == "ns-resize") + return "sb_v_double_arrow"; + else if (shape == "nesw-resize") + return "fd_double_arrow"; + else if (shape == "nwse-resize") + return "bd_double_arrow"; + else if (shape == "col-resize") + return "sb_h_double_arrow"; + else if (shape == "row-resize") + return "sb_v_double_arrow"; + else if (shape == "all-scroll") + return "fleur"; + else if (shape == "zoom-in") + return "left_ptr"; + else if (shape == "zoom-out") + return "left_ptr"; + + return std::string(); +} + +SP CCursorManager::SXCursorManager::createDefaultCursor() { + int cursorWidth = 32; + int cursorHeight = 32; + int cursorHotspotX = 3; + int cursorHotspotY = 2; + + static const uint32_t pixels[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead, + 0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56, + 0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b, + 0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853, + 0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5, + 0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d, + 0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b, + 0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1, + 0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6, + 0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5, + 0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3, + 0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb, + 0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, + 0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0, + 0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7, + 0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333, + 0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4, + 0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1, + 0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5, + 0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959, + 0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000}; + + auto hackcursor = makeShared(); + hackcursor->size = {cursorWidth, cursorHeight}; + hackcursor->hotspot = {cursorHotspotX, cursorHotspotY}; + hackcursor->pixels.resize(cursorWidth * cursorHeight); + std::memcpy(hackcursor->pixels.data(), pixels, cursorWidth * cursorHeight * sizeof(uint32_t)); + + return hackcursor; } diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 4324dfb4..44ab2e7b 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -83,14 +83,15 @@ class CCursorManager { }; struct SXCursorManager { - void loadTheme(const std::string& name, int size); + void loadTheme(const std::string& name, int size); + std::string getLegacyShapeName(std::string const& shape); + SP createDefaultCursor(); - int lastLoadSize = 0; - - bool themeLoaded = false; - std::string themeName = ""; - SP defaultCursor; - std::unordered_map> cursors; + int lastLoadSize = 0; + bool themeLoaded = false; + std::string themeName = ""; + SP defaultCursor; + std::vector>> cursors; } xcursor; }; From 9f5a57ff4569db57372bd86bd48add85a3a1a5e4 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 3 Aug 2024 12:02:10 +0000 Subject: [PATCH 0440/2393] core: Add missing header for libc++ after e989a0bcffac (#7158) src/Compositor.cpp:2295:74: error: no member named 'bit_floor' in namespace 'std' 2295 | const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal); | ~~~~~^ src/Compositor.cpp:2296:74: error: no member named 'bit_floor' in namespace 'std' 2296 | const eFullscreenMode EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)state.internal); | ~~~~~^ src/desktop/Window.cpp:1242:34: error: no member named 'bit_floor' in namespace 'std' 1242 | return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE; | ~~~~~^ --- src/Compositor.cpp | 1 + src/desktop/Window.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 2a1e4f8c..a139742c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -7,6 +7,7 @@ #include "managers/SeatManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include +#include #include #include #include diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 27010454..93c208cf 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include "Window.hpp" From ae50f8614d92132d918663ea7551bd68eb13953a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 3 Aug 2024 17:58:06 +0200 Subject: [PATCH 0441/2393] wayland/surface: fixup self-owning surface roles fixes #7133 --- src/protocols/LayerShell.cpp | 10 +++++----- src/protocols/LayerShell.hpp | 20 +++++++++++++++----- src/protocols/XDGShell.cpp | 10 +++++----- src/protocols/XDGShell.hpp | 15 ++++++++++++--- src/protocols/core/Compositor.cpp | 6 +++--- src/protocols/core/Subcompositor.cpp | 16 ++++++++-------- src/protocols/core/Subcompositor.hpp | 15 +++++++++++++-- 7 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 295ef4a9..17d3b22a 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -175,10 +175,6 @@ CLayerShellResource::~CLayerShellResource() { surface->resetRole(); } -eSurfaceRole CLayerShellResource::role() { - return SURFACE_ROLE_LAYER_SHELL; -} - bool CLayerShellResource::good() { return resource->resource(); } @@ -245,8 +241,12 @@ void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id return; } - SURF->role = RESOURCE; + SURF->role = makeShared(RESOURCE); g_pCompositor->m_vLayers.emplace_back(CLayerSurface::create(RESOURCE)); LOGM(LOG, "New wlr_layer_surface {:x}", (uintptr_t)RESOURCE.get()); } + +CLayerShellRole::CLayerShellRole(SP ls) : layerSurface(ls) { + ; +} diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index ee0b7859..801bdfd6 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -12,16 +12,26 @@ class CMonitor; class CWLSurfaceResource; +class CLayerShellResource; -class CLayerShellResource : public ISurfaceRole { +class CLayerShellRole : public ISurfaceRole { + public: + CLayerShellRole(SP ls); + + virtual eSurfaceRole role() { + return SURFACE_ROLE_LAYER_SHELL; + } + + WP layerSurface; +}; +class CLayerShellResource { public: CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); ~CLayerShellResource(); - bool good(); - void configure(const Vector2D& size); - void sendClosed(); - virtual eSurfaceRole role(); + bool good(); + void configure(const Vector2D& size); + void sendClosed(); enum eCommittedState { STATE_SIZE = (1 << 0), diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 5e82b530..4aa5d373 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -443,10 +443,6 @@ CXDGSurfaceResource::~CXDGSurfaceResource() { surface->resetRole(); } -eSurfaceRole CXDGSurfaceResource::role() { - return SURFACE_ROLE_XDG_SHELL; -} - bool CXDGSurfaceResource::good() { return resource->resource(); } @@ -668,7 +664,7 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { RESOURCE->self = RESOURCE; RESOURCE->surface = SURF; - SURF->role = RESOURCE; + SURF->role = makeShared(RESOURCE); surfaces.emplace_back(RESOURCE); @@ -765,3 +761,7 @@ void CXDGShellProtocol::onPopupDestroy(WP popup) { if (popup->surface) grab->remove(popup->surface->surface.lock()); } + +CXDGSurfaceRole::CXDGSurfaceRole(SP xdg) : xdgSurface(xdg) { + ; +} diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index e6812c38..81d10613 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -141,15 +141,24 @@ class CXDGToplevelResource { void applyState(); }; -class CXDGSurfaceResource : public ISurfaceRole { +class CXDGSurfaceRole : public ISurfaceRole { + public: + CXDGSurfaceRole(SP xdg); + + virtual eSurfaceRole role() { + return SURFACE_ROLE_XDG_SHELL; + } + + WP xdgSurface; +}; + +class CXDGSurfaceResource { public: CXDGSurfaceResource(SP resource_, SP owner_, SP surface_); ~CXDGSurfaceResource(); static SP fromResource(wl_resource*); - virtual eSurfaceRole role(); - bool good(); WP owner; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index bff52133..4a6fa40f 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -277,7 +277,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std for (auto& n : nodes) { Vector2D offset = {}; if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)n->role.get(); + auto subsurface = ((CSubsurfaceRole*)n->role.get())->subsurface.lock(); offset = subsurface->posRelativeToParent(); } @@ -448,7 +448,7 @@ void CWLSurfaceResource::commitPendingState() { // TODO: we should _accumulate_ and not replace above if sync if (role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)role.get(); + auto subsurface = ((CSubsurfaceRole*)role.get())->subsurface.lock(); if (subsurface->sync) return; @@ -458,7 +458,7 @@ void CWLSurfaceResource::commitPendingState() { breadthfirst( [](SP surf, const Vector2D& offset, void* data) { if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + auto subsurface = ((CSubsurfaceRole*)surf->role.get())->subsurface.lock(); if (!subsurface->sync) return; } diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 90f89d91..2a7c06dc 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -119,7 +119,7 @@ Vector2D CWLSubsurfaceResource::posRelativeToParent() { while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { surfacesVisited.emplace_back(surf); - auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + auto subsurface = ((CSubsurfaceRole*)parent->role.get())->subsurface.lock(); pos += subsurface->position; surf = subsurface->parent.lock(); } @@ -130,10 +130,6 @@ bool CWLSubsurfaceResource::good() { return resource->resource(); } -eSurfaceRole CWLSubsurfaceResource::role() { - return SURFACE_ROLE_SUBSURFACE; -} - SP CWLSubsurfaceResource::t1Parent() { SP surf = parent.lock(); std::vector> surfacesVisited; @@ -141,7 +137,7 @@ SP CWLSubsurfaceResource::t1Parent() { while (surf->role->role() == SURFACE_ROLE_SUBSURFACE && std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { surfacesVisited.emplace_back(surf); - auto subsurface = (CWLSubsurfaceResource*)parent->role.get(); + auto subsurface = ((CSubsurfaceRole*)parent->role.get())->subsurface.lock(); surf = subsurface->parent.lock(); } return surf; @@ -171,7 +167,7 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource SP t1Parent = nullptr; if (PARENT->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)PARENT->role.get(); + auto subsurface = ((CSubsurfaceRole*)PARENT->role.get())->subsurface.lock(); t1Parent = subsurface->t1Parent(); } else t1Parent = PARENT; @@ -191,7 +187,7 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource } RESOURCE->self = RESOURCE; - SURF->role = RESOURCE; + SURF->role = makeShared(RESOURCE); PARENT->subsurfaces.emplace_back(RESOURCE); LOGM(LOG, "New wl_subsurface with id {} at {:x}", id, (uintptr_t)RESOURCE.get()); @@ -225,3 +221,7 @@ void CWLSubcompositorProtocol::destroyResource(CWLSubcompositorResource* resourc void CWLSubcompositorProtocol::destroyResource(CWLSubsurfaceResource* resource) { std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); } + +CSubsurfaceRole::CSubsurfaceRole(SP sub) : subsurface(sub) { + ; +} diff --git a/src/protocols/core/Subcompositor.hpp b/src/protocols/core/Subcompositor.hpp index 824f0ffc..2e6b10bb 100644 --- a/src/protocols/core/Subcompositor.hpp +++ b/src/protocols/core/Subcompositor.hpp @@ -16,15 +16,26 @@ #include "../types/SurfaceRole.hpp" class CWLSurfaceResource; +class CWLSubsurfaceResource; -class CWLSubsurfaceResource : public ISurfaceRole { +class CSubsurfaceRole : public ISurfaceRole { + public: + CSubsurfaceRole(SP sub); + + virtual eSurfaceRole role() { + return SURFACE_ROLE_SUBSURFACE; + } + + WP subsurface; +}; + +class CWLSubsurfaceResource { public: CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_); ~CWLSubsurfaceResource(); Vector2D posRelativeToParent(); bool good(); - virtual eSurfaceRole role(); SP t1Parent(); bool sync = false; From 51ffd7fa6f186419276e5d3d5fe141a3fdb3c55c Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Sat, 3 Aug 2024 17:50:08 +0000 Subject: [PATCH 0442/2393] decorations: fix infinite recursion on no_gaps when only (#7169) modified: src/layout/DwindleLayout.cpp modified: src/layout/MasterLayout.cpp modified: src/render/decorations/CHyprBorderDecoration.cpp --- src/layout/DwindleLayout.cpp | 5 ++--- src/layout/MasterLayout.cpp | 5 ++--- src/render/decorations/CHyprBorderDecoration.cpp | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 7253275d..f287056f 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -141,7 +141,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - PWINDOW->updateWindowDecos(); static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); static auto PGAPSINDATA = CConfigValue("general:gaps_in"); @@ -178,6 +177,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for return; } + PWINDOW->updateWindowDecos(); + auto calcPos = PWINDOW->m_vPosition; auto calcSize = PWINDOW->m_vSize; @@ -245,8 +246,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for g_pHyprRenderer->damageWindow(PWINDOW); } - - PWINDOW->updateWindowDecos(); } void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) { diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index e3aaa767..be00168f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -650,7 +650,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - PWINDOW->updateWindowDecos(); static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); @@ -689,6 +688,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { return; } + PWINDOW->updateWindowDecos(); + auto calcPos = PWINDOW->m_vPosition; auto calcSize = PWINDOW->m_vSize; @@ -731,8 +732,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { g_pHyprRenderer->damageWindow(PWINDOW); } - - PWINDOW->updateWindowDecos(); } bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) { diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index ddb38c6e..f5e6e945 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -93,7 +93,7 @@ void CHyprBorderDecoration::updateWindow(PHLWINDOW) { m_iLastBorderSize = borderSize; - g_pEventLoopManager->doLater([this]() { g_pDecorationPositioner->repositionDeco(this); }); + g_pDecorationPositioner->repositionDeco(this); } void CHyprBorderDecoration::damageEntire() { From 4ae89e1f227d8b19afe8c692033ab894e053c7ec Mon Sep 17 00:00:00 2001 From: MaroonSkull <33577562+MaroonSkull@users.noreply.github.com> Date: Sat, 3 Aug 2024 14:10:48 +0300 Subject: [PATCH 0443/2393] CMake: Suppress CMake warning about GNUInstallDirs --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3616da24..e284cb68 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,5 @@ cmake_minimum_required(VERSION 3.27) -include(CheckIncludeFile) -include(GNUInstallDirs) - # Get version file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) string(STRIP ${VER_RAW} VER) @@ -12,6 +9,9 @@ project( DESCRIPTION "A Modern C++ Wayland Compositor" VERSION ${VER}) +include(CheckIncludeFile) +include(GNUInstallDirs) + set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) From 5dd2c27b631f16e49a2c6e6cbbefba9fa50bf543 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 4 Aug 2024 15:19:37 +0300 Subject: [PATCH 0444/2393] CMake, Meson: install config and wallpapers to DATADIR/hypr OpenGL: get wallpapers dir from DATAROOTDIR --- CMakeLists.txt | 17 +++++++++++------ assets/meson.build | 2 +- example/meson.build | 2 +- meson.build | 2 ++ src/render/OpenGL.cpp | 8 +++++--- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e284cb68..fa58b63d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,9 +262,11 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86 uuid) -protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-global-shortcuts-v1" true) +protocolnew("subprojects/hyprland-protocols/protocols" + "hyprland-global-shortcuts-v1" true) protocolnew("unstable/text-input" "text-input-unstable-v1" false) -protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-toplevel-export-v1" true) +protocolnew("subprojects/hyprland-protocols/protocols" + "hyprland-toplevel-export-v1" true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) @@ -326,19 +328,22 @@ install( # session file install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop - DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions) + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + +# allow Hyprland to find wallpapers +add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") # wallpapers file(GLOB_RECURSE WALLPAPERS "assets/wall*") -install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) +install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) # default config install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf - DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland) + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) # portal config install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf - DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal) + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/xdg-desktop-portal) # man pages file(GLOB_RECURSE MANPAGES "docs/*.1") diff --git a/assets/meson.build b/assets/meson.build index 8c4a60ec..47de3d02 100644 --- a/assets/meson.build +++ b/assets/meson.build @@ -1,7 +1,7 @@ wallpapers = ['0', '1', '2'] foreach type : wallpapers - install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime') + install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') endforeach install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') diff --git a/example/meson.build b/example/meson.build index ccfc4e00..2fb3a35e 100644 --- a/example/meson.build +++ b/example/meson.build @@ -1,2 +1,2 @@ -install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime') +install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime') diff --git a/meson.build b/meson.build index 4446ea0f..886f4f9c 100644 --- a/meson.build +++ b/meson.build @@ -9,6 +9,7 @@ project('Hyprland', 'cpp', 'c', 'cpp_std=c++23', ]) +datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' add_project_arguments( [ '-Wno-unused-parameter', @@ -16,6 +17,7 @@ add_project_arguments( '-Wno-missing-field-initializers', '-Wno-narrowing', '-Wno-pointer-arith', + datarootdir, ], language: 'cpp') diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index b925fcc9..ea388df0 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2669,10 +2669,12 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); if (!m_pBackgroundTexture) { - // TODO: use relative paths to the installation - // or configure the paths at build time std::string texPath = ""; - texPath = "/usr/share/hyprland/wall"; +#ifndef DATAROOTDIR + texPath = "/usr/share/hypr/wall"; +#else + texPath = std::format("{}{}", DATAROOTDIR, "/hypr/wall"); +#endif // get the adequate tex if (FORCEWALLPAPER == -1) { From 2b520571e897be2a0e88c8692da607b062000038 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Sun, 4 Aug 2024 19:40:34 +0000 Subject: [PATCH 0445/2393] keybinds: improve fullscreenstate toggling (#7174) modified: src/managers/KeybindManager.cpp --- src/managers/KeybindManager.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9984fe40..09ba7d50 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1164,8 +1164,6 @@ void CKeybindManager::fullscreenStateActive(std::string args) { if (!PWINDOW) return; - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); - int internalMode, clientMode; try { internalMode = std::stoi(ARGS[0]); @@ -1177,10 +1175,26 @@ void CKeybindManager::fullscreenStateActive(std::string args) { const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}; - if (PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) + if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) { g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE}); - else - g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + return; + } + + if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) { + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.client, .client = PWINDOW->m_sFullscreenState.client}); + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + return; + } + + if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) { + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = PWINDOW->m_sFullscreenState.internal}); + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + return; + } + + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); + g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); } void CKeybindManager::moveActiveToWorkspace(std::string args) { From 0e86808e5912823f1c6bea1b6d5fcae297fc9f57 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 5 Aug 2024 19:58:21 +0200 Subject: [PATCH 0446/2393] cursor: Better xcursor implementation (#7178) * xcursor: bootleg xcursors into its own manager implent XCursorManager and load themes based on librarypath and its dir, now we catch all supplied theme files. and also implent animated cursors. also refactor a bit of spaghetti regarding xcursors in CursorManager. * hyprcursor: fix buffer leak animated cursors are creating a new buffer for each image, ensure we drop the buffers so it continously doesnt build up in infinity. * cursormgr: use eventloopmgr for animation use EvenloopManager for timers instead of adding it directly to m_sWLEventLoop and using its related wl_* functions. --- src/managers/CursorManager.cpp | 474 ++++++-------------------------- src/managers/CursorManager.hpp | 26 +- src/managers/XCursorManager.cpp | 447 ++++++++++++++++++++++++++++++ src/managers/XCursorManager.hpp | 46 ++++ 4 files changed, 585 insertions(+), 408 deletions(-) create mode 100644 src/managers/XCursorManager.cpp create mode 100644 src/managers/XCursorManager.hpp diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index e0d3a62c..9b574901 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -3,15 +3,10 @@ #include "../config/ConfigValue.hpp" #include "PointerManager.hpp" #include "../xwayland/XWayland.hpp" -#include -#include "../helpers/CursorShapes.hpp" -extern "C" { -#include -} - -static int cursorAnimTimer(void* data) { - g_pCursorManager->tickAnimatedCursor(); +static int cursorAnimTimer(SP self, void* data) { + const auto cursorMgr = reinterpret_cast(data); + cursorMgr->tickAnimatedCursor(); return 1; } @@ -24,31 +19,41 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) { CCursorManager::CCursorManager() { m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); + m_pXcursor = std::make_unique(); - if (!m_pHyprcursor->valid()) - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", m_szTheme); + if (m_pHyprcursor->valid()) { + // find default size. First, HYPRCURSOR_SIZE then default to 24 + auto const* SIZE = getenv("HYPRCURSOR_SIZE"); + if (SIZE) { + try { + m_iSize = std::stoi(SIZE); + } catch (...) { ; } + } - // find default size. First, HYPRCURSOR_SIZE, then XCURSOR_SIZE, then 24 - auto SIZE = getenv("HYPRCURSOR_SIZE"); - if (SIZE) { - try { - m_iSize = std::stoi(SIZE); - } catch (...) { ; } + if (m_iSize <= 0) { + Debug::log(WARN, "HYPRCURSOR_SIZE size not set, defaulting to size 24"); + m_iSize = 24; + } + } else { + Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to Xcursor.", m_szTheme); + + auto const* SIZE = getenv("XCURSOR_SIZE"); + if (SIZE) { + try { + m_iSize = std::stoi(SIZE); + } catch (...) { ; } + } + + if (m_iSize <= 0) { + Debug::log(WARN, "XCURSOR_SIZE size not set, defaulting to size 24"); + m_iSize = 24; + } + + m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); } - SIZE = getenv("XCURSOR_SIZE"); - if (SIZE && m_iSize == 0) { - try { - m_iSize = std::stoi(SIZE); - } catch (...) { ; } - } - - if (m_iSize == 0) - m_iSize = 24; - - xcursor.loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); - - m_pAnimationTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ::cursorAnimTimer, nullptr); + m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this); + g_pEventLoopManager->addTimer(m_pAnimationTimer); updateTheme(); @@ -56,8 +61,10 @@ CCursorManager::CCursorManager() { } CCursorManager::~CCursorManager() { - if (m_pAnimationTimer) - wl_event_source_remove(m_pAnimationTimer); + if (m_pAnimationTimer && g_pEventLoopManager) { + g_pEventLoopManager->removeTimer(m_pAnimationTimer); + m_pAnimationTimer.reset(); + } } void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { @@ -133,30 +140,26 @@ void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotsp void CCursorManager::setXCursor(const std::string& name) { float scale = std::ceil(m_fCursorScale); - if (!xcursor.themeLoaded) { - Debug::log(ERR, "XCursor failed to find theme in setXCursor"); - if (!xcursor.defaultCursor) { - g_pPointerManager->resetCursorImage(); - return; - } - } + auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto& icon = xcursor->images.front(); - auto& icon = xcursor.defaultCursor; - // try to get an icon we know if we have one - for (auto const& c : xcursor.cursors) { - if (c.first != name) - continue; + m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); - icon = c.second; - } - - m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon->pixels.data(), icon->size, icon->hotspot)); - - g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon->hotspot / scale, scale); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); if (m_vCursorBuffers.size() > 1) dropBufferRef(m_vCursorBuffers.at(0).get()); + m_currentXcursor = xcursor; m_bOurBufferConnected = true; + + if (m_currentXcursor->images.size() > 1) { + // animated + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[0].delay)); + m_iCurrentAnimationFrame = 0; + } else { + // disarm + m_pAnimationTimer->updateTimeout(std::nullopt); + } } void CCursorManager::setCursorFromName(const std::string& name) { @@ -209,15 +212,35 @@ void CCursorManager::setCursorFromName(const std::string& name) { if (m_sCurrentCursorShapeData.images.size() > 1) { // animated - wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[0].delay); + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[0].delay)); m_iCurrentAnimationFrame = 0; } else { // disarm - wl_event_source_timer_update(m_pAnimationTimer, 0); + m_pAnimationTimer->updateTimeout(std::nullopt); } } void CCursorManager::tickAnimatedCursor() { + if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1 && m_bOurBufferConnected) { + m_iCurrentAnimationFrame++; + + if ((size_t)m_iCurrentAnimationFrame >= m_currentXcursor->images.size()) + m_iCurrentAnimationFrame = 0; + + float scale = std::ceil(m_fCursorScale); + auto& icon = m_currentXcursor->images.at(m_iCurrentAnimationFrame); + m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); + + g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); + + if (m_vCursorBuffers.size() > 1) + dropBufferRef(m_vCursorBuffers.at(0).get()); + + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[m_iCurrentAnimationFrame].delay)); + + return; + } + if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected) return; @@ -235,7 +258,10 @@ void CCursorManager::tickAnimatedCursor() { Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, m_fCursorScale); - wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); + if (m_vCursorBuffers.size() > 1) + dropBufferRef(m_vCursorBuffers.at(0).get()); + + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay)); } SCursorImageData CCursorManager::dataFor(const std::string& name) { @@ -256,10 +282,12 @@ void CCursorManager::setXWaylandCursor() { if (CURSOR.surface) { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); - } else if (xcursor.themeLoaded) - g_pXWayland->setCursor((uint8_t*)xcursor.defaultCursor->pixels.data(), xcursor.defaultCursor->size.x * 4, xcursor.defaultCursor->size, xcursor.defaultCursor->hotspot); - else - Debug::log(ERR, "CursorManager: no valid cursor for xwayland"); + } else { + auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale)); + auto& icon = xcursor->images.front(); + + g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot); + } } void CCursorManager::updateTheme() { @@ -300,340 +328,12 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { return true; } - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to X.", name); + Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", name); - xcursor.loadTheme(name, size); + m_pXcursor->loadTheme(name, size); m_szTheme = name; m_iSize = size; updateTheme(); return true; -} - -// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c -// _ -> - -// clang-format off -static std::array XCURSOR_STANDARD_NAMES = { - "X_cursor", - "arrow", - "based_arrow_down", - "based_arrow_up", - "boat", - "bogosity", - "bottom_left_corner", - "bottom_right_corner", - "bottom_side", - "bottom_tee", - "box_spiral", - "center_ptr", - "circle", - "clock", - "coffee_mug", - "cross", - "cross_reverse", - "crosshair", - "diamond_cross", - "dot", - "dotbox", - "double_arrow", - "draft_large", - "draft_small", - "draped_box", - "exchange", - "fleur", - "gobbler", - "gumby", - "hand1", - "hand2", - "heart", - "icon", - "iron_cross", - "left_ptr", - "left_side", - "left_tee", - "leftbutton", - "ll_angle", - "lr_angle", - "man", - "middlebutton", - "mouse", - "pencil", - "pirate", - "plus", - "question_arrow", - "right_ptr", - "right_side", - "right_tee", - "rightbutton", - "rtl_logo", - "sailboat", - "sb_down_arrow", - "sb_h_double_arrow", - "sb_left_arrow", - "sb_right_arrow", - "sb_up_arrow", - "sb_v_double_arrow", - "shuttle", - "sizing", - "spider", - "spraycan", - "star", - "target", - "tcross", - "top_left_arrow", - "top_left_corner", - "top_right_corner", - "top_side", - "top_tee", - "trek", - "ul_angle", - "umbrella", - "ur_angle", - "watch", - "xterm", -}; -// clang-format on - -void CCursorManager::SXCursorManager::loadTheme(const std::string& name, int size) { - if (lastLoadSize == size && themeName == name) - return; - - lastLoadSize = size; - themeLoaded = false; - themeName = name.empty() ? "default" : name; - - std::vector>> newCursors; - - // load the default xcursor shapes that exist in the theme - for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { - auto shape = XCURSOR_STANDARD_NAMES.at(i); - auto xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), size); - - if (!xImage) { - Debug::log(LOG, "XCursor failed to find a shape with name {}, trying size 24.", shape); - xImage = XcursorShapeLoadImage(i << 1 /* wtf xcursor? */, themeName.c_str(), 24); - - if (!xImage) { - Debug::log(LOG, "XCursor failed to find a shape with name {}, skipping", shape); - continue; - } - } - - auto xcursor = makeShared(); - xcursor->size = {(int)xImage->width, (int)xImage->height}; - xcursor->hotspot = {(int)xImage->xhot, (int)xImage->yhot}; - - xcursor->pixels.resize(xImage->width * xImage->height); - std::memcpy(xcursor->pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t)); - - newCursors.emplace_back(std::string{shape}, xcursor); - - XcursorImageDestroy(xImage); - } - - if (newCursors.empty()) { - Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName); - if (!defaultCursor) { - defaultCursor = createDefaultCursor(); - } - return; - } - - cursors.clear(); - cursors = std::move(newCursors); - defaultCursor.reset(); - themeLoaded = true; - - for (auto const& shape : CURSOR_SHAPE_NAMES) { - auto legacyName = getLegacyShapeName(shape); - if (legacyName.empty()) - continue; - - auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c.first == legacyName; }); - - if (it == cursors.end()) { - Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName); - continue; - } - - cursors.emplace_back(shape, it->second); - } - - // set default cursor - for (auto const& c : cursors) { - if (c.first == "left_ptr" || c.first == "arrow") { - defaultCursor = c.second; - break; - } - } - - // just assign the first one then. - if (!defaultCursor) - defaultCursor = cursors.at(0).second; -} - -std::string CCursorManager::SXCursorManager::getLegacyShapeName(std::string const& shape) { - if (shape == "invalid") - return std::string(); - else if (shape == "default") - return "left_ptr"; - else if (shape == "context-menu") - return "left_ptr"; - else if (shape == "help") - return "left_ptr"; - else if (shape == "pointer") - return "hand2"; - else if (shape == "progress") - return "watch"; - else if (shape == "wait") - return "watch"; - else if (shape == "cell") - return "plus"; - else if (shape == "crosshair") - return "cross"; - else if (shape == "text") - return "xterm"; - else if (shape == "vertical-text") - return "xterm"; - else if (shape == "alias") - return "dnd-link"; - else if (shape == "copy") - return "dnd-copy"; - else if (shape == "move") - return "dnd-move"; - else if (shape == "no-drop") - return "dnd-none"; - else if (shape == "not-allowed") - return "crossed_circle"; - else if (shape == "grab") - return "hand1"; - else if (shape == "grabbing") - return "hand1"; - else if (shape == "e-resize") - return "right_side"; - else if (shape == "n-resize") - return "top_side"; - else if (shape == "ne-resize") - return "top_right_corner"; - else if (shape == "nw-resize") - return "top_left_corner"; - else if (shape == "s-resize") - return "bottom_side"; - else if (shape == "se-resize") - return "bottom_right_corner"; - else if (shape == "sw-resize") - return "bottom_left_corner"; - else if (shape == "w-resize") - return "left_side"; - else if (shape == "ew-resize") - return "sb_h_double_arrow"; - else if (shape == "ns-resize") - return "sb_v_double_arrow"; - else if (shape == "nesw-resize") - return "fd_double_arrow"; - else if (shape == "nwse-resize") - return "bd_double_arrow"; - else if (shape == "col-resize") - return "sb_h_double_arrow"; - else if (shape == "row-resize") - return "sb_v_double_arrow"; - else if (shape == "all-scroll") - return "fleur"; - else if (shape == "zoom-in") - return "left_ptr"; - else if (shape == "zoom-out") - return "left_ptr"; - - return std::string(); -} - -SP CCursorManager::SXCursorManager::createDefaultCursor() { - int cursorWidth = 32; - int cursorHeight = 32; - int cursorHotspotX = 3; - int cursorHotspotY = 2; - - static const uint32_t pixels[] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead, - 0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56, - 0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b, - 0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853, - 0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5, - 0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d, - 0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b, - 0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1, - 0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6, - 0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5, - 0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3, - 0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb, - 0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, - 0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0, - 0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7, - 0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333, - 0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4, - 0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1, - 0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5, - 0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959, - 0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000}; - - auto hackcursor = makeShared(); - hackcursor->size = {cursorWidth, cursorHeight}; - hackcursor->hotspot = {cursorHotspotX, cursorHotspotY}; - hackcursor->pixels.resize(cursorWidth * cursorHeight); - std::memcpy(hackcursor->pixels.data(), pixels, cursorWidth * cursorHeight * sizeof(uint32_t)); - - return hackcursor; -} +} \ No newline at end of file diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 44ab2e7b..a114b6c2 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -7,6 +7,8 @@ #include "../helpers/math/Math.hpp" #include "../helpers/memory/Memory.hpp" #include "../macros.hpp" +#include "managers/eventLoop/EventLoopManager.hpp" +#include "managers/XCursorManager.hpp" #include class CWLSurface; @@ -63,6 +65,8 @@ class CCursorManager { std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; + std::unique_ptr m_pXcursor; + SP m_currentXcursor; std::string m_szTheme = ""; int m_iSize = 0; @@ -70,29 +74,9 @@ class CCursorManager { Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo; - wl_event_source* m_pAnimationTimer = nullptr; + SP m_pAnimationTimer; int m_iCurrentAnimationFrame = 0; Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; - - // gangsta bootleg XCursor impl. Whenever Hyprland has to use - // an xcursor, just use the pointer. - struct SXCursor { - Vector2D size; - Vector2D hotspot; - std::vector pixels; // XPixel is a u32 - }; - - struct SXCursorManager { - void loadTheme(const std::string& name, int size); - std::string getLegacyShapeName(std::string const& shape); - SP createDefaultCursor(); - - int lastLoadSize = 0; - bool themeLoaded = false; - std::string themeName = ""; - SP defaultCursor; - std::vector>> cursors; - } xcursor; }; inline std::unique_ptr g_pCursorManager; \ No newline at end of file diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp new file mode 100644 index 00000000..b3f33086 --- /dev/null +++ b/src/managers/XCursorManager.cpp @@ -0,0 +1,447 @@ +#include +#include +#include +#include "helpers/CursorShapes.hpp" +#include "debug/Log.hpp" +#include "XCursorManager.hpp" + +// clang-format off +static std::vector HYPR_XCURSOR_PIXELS = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1b001816, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8e008173, 0x5f00564d, 0x16001412, 0x09000807, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2b002624, 0x05000404, 0x00000000, 0x35002f2b, 0xd400bead, + 0xc300b09e, 0x90008275, 0x44003e37, 0x04000403, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x67005a56, + 0x6f00615c, 0x00000000, 0x00000000, 0x8b007c72, 0xf200d7c6, 0xfa00e0cc, 0xe800d0bd, 0xa0009181, 0x44003e37, 0x1a001815, 0x06000505, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x8d007976, 0xd600b8b3, 0x2500201f, 0x00000000, 0x17001413, 0xbd00a79c, 0xf600dacb, 0xff00e3d1, 0xfc00e1ce, 0xe800d0bc, 0xbf00ac9b, + 0x95008778, 0x51004a41, 0x0f000e0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x92007b7b, 0xf500d0cf, 0x9e008685, 0x00000000, 0x00000000, 0x23001f1d, 0x64005853, + 0x9b008980, 0xd900bfb3, 0xfb00dfce, 0xff00e4d0, 0xfb00e1cd, 0xec00d5c0, 0xa7009788, 0x47004139, 0x1e001b18, 0x05000504, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xa200878a, 0xff00d6d9, 0xd600b4b5, + 0x0e000c0c, 0x00000000, 0x00000000, 0x02000202, 0x0c000b0a, 0x30002a28, 0x8e007d75, 0xd600bdb0, 0xef00d4c4, 0xfb00e0ce, 0xff00e4d0, 0xe600cfbb, 0xb800a695, 0x5f00564d, + 0x06000505, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02000202, 0xc600a3aa, 0xff00d3da, 0xea00c3c8, 0x08000707, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x2a002523, 0x61005550, 0x9500837b, + 0xd800bfb1, 0xfd00e1cf, 0xff00e5d0, 0xf500dcc7, 0x7c007065, 0x2a002622, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x06000505, 0xd600aeb9, 0xff00d0dc, 0xcc00a7af, 0x04000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x01000101, 0x01000101, 0x2c002724, 0xa1008e85, 0xe600ccbd, 0xf800ddcb, 0xef00d6c3, 0xc300af9f, 0x2c002824, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, 0xd800adbc, 0xff00cdde, 0xb90095a0, 0x02000202, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x10000e0d, 0x4b00423e, 0xa4009088, 0xfd00dfd0, 0xff00e3d1, + 0xae009c8f, 0x42003b36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x14001012, 0xf400c0d6, + 0xff00cadf, 0xb2008e9c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x02000202, 0x1200100f, 0xa2008e86, 0xec00cfc3, 0xfc00ded0, 0xc300ada0, 0x15001311, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x2e002429, 0xfd00c4e0, 0xff00c7e2, 0x8f00707e, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1e001a19, 0x75006662, 0xfb00dbd1, 0xf700d9cc, 0x9600847c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e002f37, 0xfc00c1e1, 0xff00c5e3, 0x60004b55, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x15001212, 0xa6008f8b, 0xff00ddd5, + 0xf800d8ce, 0x36002f2d, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x51003d49, 0xfe00bfe5, 0xfe00c1e4, 0x4c003a44, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x01000101, 0x1d001918, 0xf400d1cd, 0xfe00dad5, 0xb3009a96, 0x03000303, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x66004b5d, 0xff00bee7, 0xfd00bee5, 0x4500343f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02000202, 0x82006e6e, 0xff00d8d7, 0xd800b9b6, 0x33002c2b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x70005267, 0xff00bbe9, 0xfa00b8e3, 0x29001e25, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3f003536, 0xea00c3c7, 0xf800d1d3, + 0x4a003e3f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5f004458, 0xff00b8eb, 0xf400b1e0, 0x29001e26, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1b001617, 0xe100bac0, 0xff00d4da, 0x82006c6f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5a004054, 0xfe00b4eb, + 0xfb00b3e8, 0x3b002a36, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0a000809, 0xc900a4ad, 0xff00d1dc, 0x88007075, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x44002f3f, 0xf300aae3, 0xfc00b1ea, 0x48003343, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x05000404, 0xdf00b3c2, 0xff00cedd, 0x8f00747c, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x25001a23, 0xf200a6e4, 0xff00b1ef, 0x84005c7c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x09000708, + 0xe400b5c8, 0xff00cbdf, 0x78006068, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x12000c11, 0xc00082b6, 0xff00aef1, 0xaa0075a0, + 0x11000c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x1e00171b, 0xf700c1db, 0xff00c8e1, 0x4b003b42, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x05000305, 0x8d005f86, 0xfc00aaef, 0xed00a0e1, 0x26001a24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6f005463, 0xff00c4e3, 0xf500beda, 0x0c00090b, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x3e00293b, 0xed009de2, 0xff00aaf3, 0x8b005d84, 0x04000304, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x07000506, 0xeb00b1d4, 0xff00c1e6, 0xba008ea7, + 0x02000202, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xb20075ab, 0xff00a7f4, 0xf300a1e9, 0x35002333, + 0x06000406, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x8900647d, 0xff00bde8, 0xfb00bce2, 0x26001d22, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2b001c29, 0xf1009ce8, 0xfe00a5f4, 0xc60082be, 0x3b002738, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x01000101, 0x54003c4d, 0xfd00b8e8, 0xff00baea, 0x96006f89, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x78004d74, 0xe20091da, 0xff00a5f6, 0xb60077af, 0x42002b3f, 0x0c00080c, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9400688a, 0xff00b5ed, 0xff00b6ec, 0xcc0093bc, 0x02000102, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x8100527d, 0xeb0096e4, 0xf900a0f1, 0xdc008dd4, + 0x9b006595, 0x32002130, 0x0a00070a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2100161f, 0x5300394e, 0xe2009cd4, 0xff00b1ef, 0xff00b2ee, 0xc8008cba, 0x17001015, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x19001018, 0x5e003b5b, 0xcb0081c5, 0xff00a2f8, 0xfc00a1f4, 0xde0090d6, 0xa9006da3, 0x8300567e, 0x6f00496a, 0x76004e71, 0xbb007db2, 0xeb009edf, 0xfb00a9ee, 0xff00adf1, + 0xfd00adee, 0x9e006d95, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000304, 0x34002133, 0xa60069a1, 0xd70089d1, 0xf2009bea, 0xff00a3f7, 0xfb00a1f2, 0xfb00a2f2, 0xff00a6f5, + 0xff00a8f4, 0xfd00a7f2, 0xed009ee2, 0xcf008bc5, 0x14000e13, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x11000b11, 0x35002134, 0x5b003959, + 0x8b005887, 0xb30072ae, 0xc90080c3, 0xd10086ca, 0xa6006ba0, 0x65004261, 0x3c002839, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x01000101, 0x06000406, 0x0d00080d, 0x0f000a0f, 0x0a00060a, 0x01000101, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000}; +// clang-format on + +CXCursorManager::CXCursorManager() { + hyprCursor = makeShared(); + SXCursorImage image; + image.size = {32, 32}; + image.hotspot = {3, 2}; + image.pixels = HYPR_XCURSOR_PIXELS; + image.delay = 0; + + hyprCursor->images.push_back(image); + hyprCursor->shape = "left_ptr"; + defaultCursor = hyprCursor; +} + +void CXCursorManager::loadTheme(std::string const& name, int size) { + if (lastLoadSize == size && themeName == name) + return; + + lastLoadSize = size; + themeName = name.empty() ? "default" : name; + defaultCursor.reset(); + cursors.clear(); + + auto paths = themePaths(themeName); + if (paths.empty()) { + Debug::log(ERR, "XCursor librarypath is empty loading standard XCursors"); + cursors = loadStandardCursors(themeName, lastLoadSize); + } else { + for (auto const& p : paths) { + auto dirCursors = loadAllFromDir(p, lastLoadSize); + std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors), + [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + } + } + + if (cursors.empty()) { + Debug::log(ERR, "XCursor failed finding any shapes in theme \"{}\".", themeName); + defaultCursor = hyprCursor; + return; + } + + for (auto const& shape : CURSOR_SHAPE_NAMES) { + auto legacyName = getLegacyShapeName(shape); + if (legacyName.empty()) + continue; + + auto it = std::find_if(cursors.begin(), cursors.end(), [&legacyName](auto const& c) { return c->shape == legacyName; }); + + if (it == cursors.end()) { + Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName); + continue; + } + + auto cursor = makeShared(); + cursor->images = it->get()->images; + cursor->shape = shape; + + cursors.emplace_back(cursor); + } +} + +SP CXCursorManager::getShape(std::string const& shape, int size) { + // monitor scaling changed etc, so reload theme with new size. + if (size != lastLoadSize) + loadTheme(themeName, size); + + // try to get an icon we know if we have one + for (auto const& c : cursors) { + if (c->shape != shape) + continue; + + return c; + } + + Debug::log(WARN, "XCursor couldn't find shape {} , using default cursor instead", shape); + return defaultCursor; +} + +SP CXCursorManager::createCursor(std::string const& shape, XcursorImages* xImages) { + auto xcursor = makeShared(); + + for (int i = 0; i < xImages->nimage; i++) { + auto xImage = xImages->images[i]; + SXCursorImage image; + image.size = {(int)xImage->width, (int)xImage->height}; + image.hotspot = {(int)xImage->xhot, (int)xImage->yhot}; + image.pixels.resize(xImage->width * xImage->height); + std::memcpy(image.pixels.data(), xImage->pixels, xImage->width * xImage->height * sizeof(uint32_t)); + image.delay = xImage->delay; + + xcursor->images.emplace_back(image); + } + + xcursor->shape = shape; + + return xcursor; +} + +std::vector CXCursorManager::themePaths(std::string const& theme) { + auto const* path = XcursorLibraryPath(); + std::vector paths; + + auto expandTilde = [](std::string const& path) { + if (!path.empty() && path[0] == '~') { + const char* home = std::getenv("HOME"); + if (home) + return std::string(home) + path.substr(1); + } + return path; + }; + + if (path) { + std::stringstream ss(path); + std::string item; + + while (std::getline(ss, item, ':')) { + auto p = expandTilde(item + "/" + theme + "/cursors"); + + if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) + paths.push_back(p); + } + } + + return paths; +} + +std::string CXCursorManager::getLegacyShapeName(std::string const& shape) { + if (shape == "invalid") + return std::string(); + else if (shape == "default") + return "left_ptr"; + else if (shape == "context-menu") + return "left_ptr"; + else if (shape == "help") + return "left_ptr"; + else if (shape == "pointer") + return "hand2"; + else if (shape == "progress") + return "watch"; + else if (shape == "wait") + return "watch"; + else if (shape == "cell") + return "plus"; + else if (shape == "crosshair") + return "cross"; + else if (shape == "text") + return "xterm"; + else if (shape == "vertical-text") + return "xterm"; + else if (shape == "alias") + return "dnd-link"; + else if (shape == "copy") + return "dnd-copy"; + else if (shape == "move") + return "dnd-move"; + else if (shape == "no-drop") + return "dnd-none"; + else if (shape == "not-allowed") + return "crossed_circle"; + else if (shape == "grab") + return "hand1"; + else if (shape == "grabbing") + return "hand1"; + else if (shape == "e-resize") + return "right_side"; + else if (shape == "n-resize") + return "top_side"; + else if (shape == "ne-resize") + return "top_right_corner"; + else if (shape == "nw-resize") + return "top_left_corner"; + else if (shape == "s-resize") + return "bottom_side"; + else if (shape == "se-resize") + return "bottom_right_corner"; + else if (shape == "sw-resize") + return "bottom_left_corner"; + else if (shape == "w-resize") + return "left_side"; + else if (shape == "ew-resize") + return "sb_h_double_arrow"; + else if (shape == "ns-resize") + return "sb_v_double_arrow"; + else if (shape == "nesw-resize") + return "fd_double_arrow"; + else if (shape == "nwse-resize") + return "bd_double_arrow"; + else if (shape == "col-resize") + return "sb_h_double_arrow"; + else if (shape == "row-resize") + return "sb_v_double_arrow"; + else if (shape == "all-scroll") + return "fleur"; + else if (shape == "zoom-in") + return "left_ptr"; + else if (shape == "zoom-out") + return "left_ptr"; + + return std::string(); +}; + +// Taken from https://gitlab.freedesktop.org/xorg/lib/libxcursor/-/blob/master/src/library.c +// clang-format off +static std::array XCURSOR_STANDARD_NAMES = { + "X_cursor", + "arrow", + "based_arrow_down", + "based_arrow_up", + "boat", + "bogosity", + "bottom_left_corner", + "bottom_right_corner", + "bottom_side", + "bottom_tee", + "box_spiral", + "center_ptr", + "circle", + "clock", + "coffee_mug", + "cross", + "cross_reverse", + "crosshair", + "diamond_cross", + "dot", + "dotbox", + "double_arrow", + "draft_large", + "draft_small", + "draped_box", + "exchange", + "fleur", + "gobbler", + "gumby", + "hand1", + "hand2", + "heart", + "icon", + "iron_cross", + "left_ptr", + "left_side", + "left_tee", + "leftbutton", + "ll_angle", + "lr_angle", + "man", + "middlebutton", + "mouse", + "pencil", + "pirate", + "plus", + "question_arrow", + "right_ptr", + "right_side", + "right_tee", + "rightbutton", + "rtl_logo", + "sailboat", + "sb_down_arrow", + "sb_h_double_arrow", + "sb_left_arrow", + "sb_right_arrow", + "sb_up_arrow", + "sb_v_double_arrow", + "shuttle", + "sizing", + "spider", + "spraycan", + "star", + "target", + "tcross", + "top_left_arrow", + "top_left_corner", + "top_right_corner", + "top_side", + "top_tee", + "trek", + "ul_angle", + "umbrella", + "ur_angle", + "watch", + "xterm", +}; +// clang-format on + +std::vector> CXCursorManager::loadStandardCursors(std::string const& name, int size) { + std::vector> newCursors; + + // load the default xcursor shapes that exist in the theme + for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { + std::string shape{XCURSOR_STANDARD_NAMES.at(i)}; + auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size); + + if (!xImages) { + Debug::log(WARN, "XCursor failed to find a shape with name {}, trying size 24.", shape); + xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), 24); + + if (!xImages) { + Debug::log(WARN, "XCursor failed to find a shape with name {}, skipping", shape); + continue; + } + } + + auto cursor = createCursor(shape, xImages); + newCursors.emplace_back(cursor); + + if (!defaultCursor && (shape == "left_ptr" || shape == "arrow")) + defaultCursor = cursor; + + XcursorImagesDestroy(xImages); + } + + // broken theme.. just set it. + if (!newCursors.empty() && !defaultCursor) + defaultCursor = newCursors.front(); + + return newCursors; +} + +std::vector> CXCursorManager::loadAllFromDir(std::string const& path, int size) { + std::vector> newCursors; + std::string full; + + if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (!entry.is_regular_file() && !entry.is_symlink()) + continue; + + std::string full = entry.path().string(); + using PcloseType = int (*)(FILE*); + const std::unique_ptr f(fopen(full.c_str(), "r"), static_cast(fclose)); + + if (!f) + continue; + + auto xImages = XcursorFileLoadImages(f.get(), size); + + if (!xImages) { + Debug::log(WARN, "XCursor failed to load image {}, trying size 24.", full); + xImages = XcursorFileLoadImages(f.get(), 24); + + if (!xImages) { + Debug::log(WARN, "XCursor failed to load image {}, skipping", full); + continue; + } + } + + std::string shape = entry.path().filename().string(); + auto cursor = createCursor(shape, xImages); + newCursors.emplace_back(cursor); + + if (!defaultCursor && (shape == "left_ptr" || shape == "arrow")) + defaultCursor = cursor; + + XcursorImagesDestroy(xImages); + } + } + + // broken theme.. just set it. + if (!newCursors.empty() && !defaultCursor) + defaultCursor = newCursors.front(); + + return newCursors; +} diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp new file mode 100644 index 00000000..9ced076f --- /dev/null +++ b/src/managers/XCursorManager.hpp @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include +#include +#include "helpers/memory/Memory.hpp" + +extern "C" { +#include +} + +// gangsta bootleg XCursor impl. adidas balkanized +struct SXCursorImage { + Vector2D size; + Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + uint32_t delay; // animation delay to next frame (ms) +}; + +struct SXCursors { + std::vector images; + std::string shape; +}; + +class CXCursorManager { + public: + CXCursorManager(); + ~CXCursorManager() = default; + + void loadTheme(const std::string& name, int size); + SP getShape(std::string const& shape, int size); + + private: + SP createCursor(std::string const& shape, XcursorImages* xImages); + std::vector themePaths(std::string const& theme); + std::string getLegacyShapeName(std::string const& shape); + std::vector> loadStandardCursors(std::string const& name, int size); + std::vector> loadAllFromDir(std::string const& path, int size); + + int lastLoadSize = 0; + std::string themeName = ""; + SP defaultCursor; + SP hyprCursor; + std::vector> cursors; +}; \ No newline at end of file From 640d1618519d42dd592f7af5e9984ad52eb8b820 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:52:19 +0100 Subject: [PATCH 0447/2393] renderer: Explicit sync fixes (#7151) Enables explicit sync by default for most platforms `misc:no_direct_scanout` -> `render:direct_scanout` --- src/Compositor.cpp | 4 +- src/config/ConfigManager.cpp | 17 ++- src/helpers/Monitor.cpp | 64 +++++++++- src/helpers/Monitor.hpp | 3 +- src/helpers/ScopeGuard.cpp | 10 ++ src/helpers/ScopeGuard.hpp | 13 ++ src/helpers/sync/SyncReleaser.cpp | 25 ++++ src/helpers/sync/SyncReleaser.hpp | 31 +++++ src/helpers/sync/SyncTimeline.cpp | 5 + src/helpers/sync/SyncTimeline.hpp | 1 + src/managers/KeybindManager.cpp | 1 + src/managers/ProtocolManager.cpp | 2 +- src/protocols/DRMSyncobj.cpp | 53 ++++++--- src/protocols/DRMSyncobj.hpp | 11 +- src/protocols/core/Compositor.cpp | 17 +-- src/protocols/core/Compositor.hpp | 5 +- src/protocols/types/Buffer.cpp | 25 +--- src/protocols/types/Buffer.hpp | 12 +- src/protocols/types/WLBuffer.cpp | 10 -- src/protocols/types/WLBuffer.hpp | 1 - src/render/OpenGL.cpp | 32 ++--- src/render/OpenGL.hpp | 4 +- src/render/Renderer.cpp | 191 +++++++++++++++++++----------- src/render/Renderer.hpp | 6 + 24 files changed, 378 insertions(+), 165 deletions(-) create mode 100644 src/helpers/ScopeGuard.cpp create mode 100644 src/helpers/ScopeGuard.hpp create mode 100644 src/helpers/sync/SyncReleaser.cpp create mode 100644 src/helpers/sync/SyncReleaser.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a139742c..299a16c6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2282,7 +2282,7 @@ void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFull } void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) { - static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState) return; @@ -2342,7 +2342,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // ignore if DS is disabled. - if (!*PNODIRECTSCANOUT) + if (*PDIRECTSCANOUT) g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fe3af8c0..be6433fa 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -3,6 +3,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" +#include "config/ConfigValue.hpp" #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" @@ -346,7 +347,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY}); m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0}); - m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1}); @@ -560,7 +560,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"}); m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"}); - m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0}); + m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2}); + m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2}); + m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0}); // devices m_pConfig->addSpecialCategory("device", {"name"}); @@ -798,6 +800,9 @@ std::optional CConfigManager::resetHLConfig() { } void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static int prevEnabledExplicit = *PENABLEEXPLICIT; + for (auto& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); } @@ -816,6 +821,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (!isFirstLaunch) g_pHyprOpenGL->m_bReloadScreenShader = true; + if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + // parseError will be displayed next frame if (result.error) @@ -1417,7 +1425,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { if (USEVRR == 0) { if (m->vrrActive) { - + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(false); if (!m->state.commit()) @@ -1427,6 +1435,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } else if (USEVRR == 1) { if (!m->vrrActive) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(true); if (!m->state.test()) { @@ -1451,6 +1460,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN); if (WORKSPACEFULL) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(true); if (!m->state.test()) { @@ -1462,6 +1472,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); } else if (!WORKSPACEFULL) { + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(false); if (!m->state.commit()) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 1cf1b069..8f23c462 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,6 +1,8 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" #include "math/Math.hpp" +#include "sync/SyncReleaser.hpp" +#include "ScopeGuard.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" @@ -8,6 +10,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" #include "../protocols/DRMLease.hpp" +#include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" #include "../protocols/core/Compositor.hpp" @@ -77,6 +80,7 @@ void CMonitor::onConnect(bool noRule) { tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; if (m_bEnabled) { + output->state->resetExplicitFences(); output->state->setEnabled(true); state.commit(); return; @@ -101,6 +105,7 @@ void CMonitor::onConnect(bool noRule) { // if it's disabled, disable and ignore if (monitorRule.disabled) { + output->state->resetExplicitFences(); output->state->setEnabled(false); if (!state.commit()) @@ -137,6 +142,7 @@ void CMonitor::onConnect(bool noRule) { m_bEnabled = true; + output->state->resetExplicitFences(); output->state->setEnabled(true); // set mode, also applies @@ -300,6 +306,7 @@ void CMonitor::onDisconnect(bool destroy) { activeWorkspace->m_bVisible = false; activeWorkspace.reset(); + output->state->resetExplicitFences(); output->state->setEnabled(false); if (!state.commit()) @@ -808,28 +815,77 @@ bool CMonitor::attemptDirectScanout() { if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) return false; + Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get()); + // FIXME: make sure the buffer actually follows the available scanout dmabuf formats // and comes from the appropriate device. This may implode on multi-gpu!! output->state->setBuffer(PSURFACE->current.buffer->buffer.lock()); output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); - if (!state.test()) + if (!state.test()) { + Debug::log(TRACE, "attemptDirectScanout: failed basic test"); return false; + } + + auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(); + + // wait for the explicit fence if present, and if kms explicit is allowed + bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; + int explicitWaitFD = -1; + if (DOEXPLICIT) { + explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); + if (explicitWaitFD < 0) + Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); + } + DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + + auto cleanup = CScopeGuard([explicitWaitFD, this]() { + output->state->resetExplicitFences(); + if (explicitWaitFD >= 0) + close(explicitWaitFD); + }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - Debug::log(TRACE, "presentFeedback for DS"); - PSURFACE->presentFeedback(&now, this, true); + PSURFACE->presentFeedback(&now, this); output->state->addDamage(CBox{{}, vecPixelSize}); + output->state->resetExplicitFences(); - if (state.commit()) { + if (DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); + output->state->setExplicitInFence(explicitWaitFD); + } + + bool ok = output->commit(); + + if (!ok && DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: EXPLICIT SYNC FAILED: commit() returned false. Resetting fences and retrying, might result in glitches."); + output->state->resetExplicitFences(); + + ok = output->commit(); + } + + if (ok) { if (lastScanout.expired()) { lastScanout = PCANDIDATE; Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle); } + + // delay explicit sync feedback until kms release of the buffer + if (DOEXPLICIT) { + Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release"); + PSURFACE->current.buffer->releaser->drop(); + + PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) { + const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline; + if (DOEXPLICIT) + PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint); + }); + } } else { + Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface"); lastScanout.reset(); return false; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 32fc768a..fbe26f67 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -121,8 +121,7 @@ class CMonitor { // explicit sync SP inTimeline; SP outTimeline; - uint64_t lastWaitPoint = 0; - uint64_t commitSeq = 0; + uint64_t commitSeq = 0; WP self; diff --git a/src/helpers/ScopeGuard.cpp b/src/helpers/ScopeGuard.cpp new file mode 100644 index 00000000..319255cd --- /dev/null +++ b/src/helpers/ScopeGuard.cpp @@ -0,0 +1,10 @@ +#include "ScopeGuard.hpp" + +CScopeGuard::CScopeGuard(const std::function& fn_) : fn(fn_) { + ; +} + +CScopeGuard::~CScopeGuard() { + if (fn) + fn(); +} diff --git a/src/helpers/ScopeGuard.hpp b/src/helpers/ScopeGuard.hpp new file mode 100644 index 00000000..8a1468eb --- /dev/null +++ b/src/helpers/ScopeGuard.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +// calls a function when it goes out of scope +class CScopeGuard { + public: + CScopeGuard(const std::function& fn_); + ~CScopeGuard(); + + private: + std::function fn; +}; diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp new file mode 100644 index 00000000..198495ab --- /dev/null +++ b/src/helpers/sync/SyncReleaser.cpp @@ -0,0 +1,25 @@ +#include "SyncReleaser.hpp" +#include "SyncTimeline.hpp" +#include "../../render/OpenGL.hpp" + +CSyncReleaser::CSyncReleaser(WP timeline_, uint64_t point_) : timeline(timeline_), point(point_) { + ; +} + +CSyncReleaser::~CSyncReleaser() { + if (timeline.expired()) + return; + + if (sync) + timeline->importFromSyncFileFD(point, sync->fd()); + else + timeline->signal(point); +} + +void CSyncReleaser::addReleaseSync(SP sync_) { + sync = sync_; +} + +void CSyncReleaser::drop() { + timeline.reset(); +} \ No newline at end of file diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp new file mode 100644 index 00000000..e21d2e34 --- /dev/null +++ b/src/helpers/sync/SyncReleaser.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include +#include "../memory/Memory.hpp" + +/* + A helper (inspired by KDE's KWin) that will release the timeline point in the dtor +*/ + +class CSyncTimeline; +class CEGLSync; + +class CSyncReleaser { + public: + CSyncReleaser(WP timeline_, uint64_t point_); + ~CSyncReleaser(); + + // drops the releaser, will never signal anymore + void drop(); + + // wait for this gpu job to finish before releasing + void addReleaseSync(SP sync); + + private: + WP timeline; + uint64_t point = 0; + SP sync; +}; diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 352120ea..16b5bd92 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -188,3 +188,8 @@ bool CSyncTimeline::transfer(SP from, uint64_t fromPoint, uint64_ return true; } + +void CSyncTimeline::signal(uint64_t point) { + if (drmSyncobjTimelineSignal(drmFD, &handle, &point, 1)) + Debug::log(ERR, "CSyncTimeline::signal: drmSyncobjTimelineSignal failed"); +} diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 3d868a95..88ad4921 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -35,6 +35,7 @@ class CSyncTimeline { int exportAsSyncFileFD(uint64_t src); bool importFromSyncFileFD(uint64_t dst, int fd); bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); int drmFD = -1; uint32_t handle = 0; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 09ba7d50..08c6998d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2293,6 +2293,7 @@ void CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; + m->output->state->resetExplicitFences(); m->output->state->setEnabled(enable); m->dpmsStatus = enable; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 635e6223..6e5cd16f 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -76,7 +76,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { CProtocolManager::CProtocolManager() { - static const auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 33339554..8b0330de 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -24,9 +24,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPsetSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { @@ -35,29 +35,33 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPevents.precommit.registerListener([this](std::any d) { - if (!!acquireTimeline != !!releaseTimeline) { - resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline"); - surface->pending.rejected = true; - return; - } - - if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) { + if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); surface->pending.rejected = true; return; } - if (!acquireTimeline) + if (!surface->pending.newBuffer) + return; // this commit does not change the state here + + if (!!pending.acquireTimeline != !!pending.releaseTimeline) { + resource->error(pending.acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, + "Missing timeline"); + surface->pending.rejected = true; + return; + } + + if (!pending.acquireTimeline) return; // wait for the acquire timeline to materialize - auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -68,7 +72,24 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + }); + + listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + // apply timelines if new ones have been attached, otherwise don't touch + // the current ones + if (pending.releaseTimeline) { + current.releaseTimeline = pending.releaseTimeline; + current.releasePoint = pending.releasePoint; + } + + if (pending.acquireTimeline) { + current.acquireTimeline = pending.acquireTimeline; + current.acquirePoint = pending.acquirePoint; + } + + pending.releaseTimeline.reset(); + pending.acquireTimeline.reset(); }); } diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index c1c884ff..25dc10c1 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -14,17 +14,20 @@ class CDRMSyncobjSurfaceResource { public: CDRMSyncobjSurfaceResource(SP resource_, SP surface_); - bool good(); + bool good(); - WP surface; - WP acquireTimeline, releaseTimeline; - uint64_t acquirePoint = 0, releasePoint = 0; + WP surface; + struct { + WP acquireTimeline, releaseTimeline; + uint64_t acquirePoint = 0, releasePoint = 0; + } current, pending; private: SP resource; struct { CHyprSignalListener surfacePrecommit; + CHyprSignalListener surfaceCommit; } listeners; }; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 4a6fa40f..b0111032 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -7,6 +7,7 @@ #include "Subcompositor.hpp" #include "../Viewporter.hpp" #include "../../helpers/Monitor.hpp" +#include "../../helpers/sync/SyncReleaser.hpp" #include "../PresentationTime.hpp" #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" @@ -69,7 +70,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso resource->setOnDestroy([this](CWlSurface* r) { destroy(); }); resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) { - pending.offset = {x, y}; + pending.offset = {x, y}; + pending.newBuffer = true; if (!buffer) { pending.buffer.reset(); @@ -428,6 +430,10 @@ void CWLSurfaceResource::commitPendingState() { current = pending; pending.damage.clear(); pending.bufferDamage.clear(); + pending.newBuffer = false; + + if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer) + current.buffer->releaser = makeShared(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint); if (current.texture) current.texture->m_eTransform = wlTransformToHyprutils(current.transform); @@ -501,23 +507,18 @@ void CWLSurfaceResource::updateCursorShm() { memcpy(shmData.data(), pixelData, bufLen); } -void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); FEEDBACK->presented(); PROTO::presentation->queueData(FEEDBACK); - if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) + if (!pMonitor || !pMonitor->outTimeline || !syncobj) return; // attach explicit sync g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); - - if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { - Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); - pMonitor->lastWaitPoint = syncobj->acquirePoint; - } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 460ec755..af0dfa58 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -97,7 +97,8 @@ class CWLSurfaceResource { Vector2D destination; CBox source; } viewport; - bool rejected = false; + bool rejected = false; + bool newBuffer = false; // void reset() { @@ -122,7 +123,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); + void presentFeedback(timespec* when, CMonitor* pMonitor); void lockPendingState(); void unlockPendingState(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 40f2eaf8..ea12f017 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -9,11 +9,6 @@ void IHLBuffer::sendRelease() { resource->sendRelease(); } -void IHLBuffer::sendReleaseWithSurface(SP surf) { - if (resource && resource->good()) - resource->sendReleaseWithSurface(surf); -} - void IHLBuffer::lock() { nLocks++; } @@ -27,26 +22,13 @@ void IHLBuffer::unlock() { sendRelease(); } -void IHLBuffer::unlockWithSurface(SP surf) { - nLocks--; - - ASSERT(nLocks >= 0); - - if (nLocks == 0) - sendReleaseWithSurface(surf); -} - bool IHLBuffer::locked() { return nLocks > 0; } void IHLBuffer::unlockOnBufferRelease(WP surf) { - unlockSurface = surf; hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) { - if (unlockSurface.expired()) - unlock(); - else - unlockWithSurface(unlockSurface.lock()); + unlock(); hlEvents.backendRelease.reset(); }); } @@ -59,8 +41,5 @@ CHLBufferReference::~CHLBufferReference() { if (buffer.expired()) return; - if (surface) - buffer->unlockWithSurface(surface.lock()); - else - buffer->unlock(); + buffer->unlock(); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index d2157181..7d84dce7 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -6,6 +6,8 @@ #include +class CSyncReleaser; + class IHLBuffer : public Aquamarine::IBuffer { public: virtual ~IHLBuffer(); @@ -15,10 +17,8 @@ class IHLBuffer : public Aquamarine::IBuffer { virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu virtual bool good() = 0; virtual void sendRelease(); - virtual void sendReleaseWithSurface(SP); virtual void lock(); virtual void unlock(); - virtual void unlockWithSurface(SP surf); virtual bool locked(); void unlockOnBufferRelease(WP surf /* optional */); @@ -29,12 +29,11 @@ class IHLBuffer : public Aquamarine::IBuffer { struct { CHyprSignalListener backendRelease; + CHyprSignalListener backendRelease2; // for explicit ds } hlEvents; private: - int nLocks = 0; - - WP unlockSurface; + int nLocks = 0; }; // for ref-counting. Releases in ~dtor @@ -44,7 +43,8 @@ class CHLBufferReference { CHLBufferReference(SP buffer, SP surface); ~CHLBufferReference(); - WP buffer; + WP buffer; + SP releaser; private: WP surface; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index d34a867d..eb7d1fde 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -32,16 +32,6 @@ void CWLBufferResource::sendRelease() { resource->sendRelease(); } -void CWLBufferResource::sendReleaseWithSurface(SP surf) { - sendRelease(); - - if (!surf || !surf->syncobj) - return; - - if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1)) - Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed"); -} - wl_resource* CWLBufferResource::getResource() { return resource->resource(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index 59512128..787abe1f 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -17,7 +17,6 @@ class CWLBufferResource { bool good(); void sendRelease(); - void sendReleaseWithSurface(SP); wl_resource* getResource(); WP buffer; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ea388df0..8875d8f4 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2870,7 +2870,7 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { std::vector attribs; int dupFd = -1; if (fenceFD > 0) { - int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); + dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); if (dupFd < 0) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; @@ -2889,8 +2889,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { return nullptr; } - auto eglsync = SP(new CEGLSync); - eglsync->sync = sync; + // we need to flush otherwise we might not get a valid fd + glFlush(); + + int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); + if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); + return nullptr; + } + + auto eglsync = SP(new CEGLSync); + eglsync->sync = sync; + eglsync->m_iFd = fd; return eglsync; } @@ -2983,19 +2993,13 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); + + if (m_iFd >= 0) + close(m_iFd); } -int CEGLSync::dupFenceFD() { - if (sync == EGL_NO_SYNC_KHR) - return -1; - - int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync); - if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - Debug::log(ERR, "eglDupNativeFenceFDANDROID failed"); - return -1; - } - - return fd; +int CEGLSync::fd() { + return m_iFd; } bool CEGLSync::wait() { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1e8325c1..f405cb7c 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -131,12 +131,14 @@ class CEGLSync { EGLSyncKHR sync = nullptr; - int dupFenceFD(); + int fd(); bool wait(); private: CEGLSync() = default; + int m_iFd = -1; + friend class CHyprOpenGLImpl; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 127ae187..7794d476 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,9 +1,12 @@ #include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" +#include "../helpers/ScopeGuard.hpp" +#include "../helpers/sync/SyncReleaser.hpp" #include #include #include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -115,8 +118,8 @@ static void renderSurface(SP surface, int x, int y, void* da return; // explicit sync: wait for the timeline, if any - if (surface->syncobj && surface->syncobj->acquireTimeline) { - if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + if (surface->syncobj && surface->syncobj->current.acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->current.acquireTimeline->timeline, surface->syncobj->current.acquirePoint)) { Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); return; } @@ -1095,7 +1098,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static auto PDEBUGOVERLAY = CConfigValue("debug:overlay"); static auto PDAMAGETRACKINGMODE = CConfigValue("debug:damage_tracking"); static auto PDAMAGEBLINK = CConfigValue("debug:damage_blink"); - static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); static auto PVFR = CConfigValue("misc:vfr"); static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); static auto PANIMENABLED = CConfigValue("animations:enabled"); @@ -1195,7 +1198,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if (!*PNODIRECTSCANOUT && !shouldTear) { + if (*PDIRECTSCANOUT && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { @@ -1403,59 +1406,62 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); - // apply timelines for explicit sync + // save inFD otherwise reset will reset it + auto inFD = pMonitor->output->state->state().explicitInFence; pMonitor->output->state->resetExplicitFences(); - - bool anyExplicit = !explicitPresented.empty(); - if (anyExplicit) { - Debug::log(TRACE, "Explicit sync presented begin"); - auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); - if (inFence < 0) - Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); - - pMonitor->output->state->setExplicitInFence(inFence); - - for (auto& e : explicitPresented) { - Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); - if (!e->syncobj || !e->syncobj->releaseTimeline) - continue; - e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); - } - - explicitPresented.clear(); - auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); - if (outFence < 0) - Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); - - pMonitor->output->state->setExplicitOutFence(outFence); - Debug::log(TRACE, "Explicit sync presented end"); - } - - pMonitor->lastWaitPoint = 0; + if (inFD >= 0) + pMonitor->output->state->setExplicitInFence(inFD); bool ok = pMonitor->state.commit(); if (!ok) { - Debug::log(TRACE, "Monitor state commit failed"); - // rollback the buffer to avoid writing to the front buffer that is being - // displayed - pMonitor->output->swapchain->rollback(); - pMonitor->damage.damageEntire(); + if (inFD >= 0) { + Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); + pMonitor->output->state->resetExplicitFences(); + ok = pMonitor->state.commit(); + } + + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } } - if (!*PENABLEEXPLICIT) + auto explicitOptions = getExplicitSyncSettings(); + + if (!explicitOptions.explicitEnabled) return ok; - if (pMonitor->output->state->state().explicitInFence >= 0) - close(pMonitor->output->state->state().explicitInFence); + if (inFD >= 0) + close(inFD); if (pMonitor->output->state->state().explicitOutFence >= 0) { - if (ok) - pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + Debug::log(TRACE, "Aquamarine returned an explicit out fence at {}", pMonitor->output->state->state().explicitOutFence); close(pMonitor->output->state->state().explicitOutFence); + } else + Debug::log(TRACE, "Aquamarine did not return an explicit out fence"); + + Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); + auto sync = g_pHyprOpenGL->createEGLSync(-1); + + if (!sync) + Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); + else { + for (auto& e : explicitPresented) { + if (!e->current.buffer || !e->current.buffer->releaser) + continue; + + e->current.buffer->releaser->addReleaseSync(sync); + } } + explicitPresented.clear(); + + pMonitor->output->state->resetExplicitFences(); + return ok; } @@ -1898,6 +1904,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + pMonitor->output->state->resetExplicitFences(); bool autoScale = false; @@ -2643,10 +2650,16 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); PMONITOR->commitSeq++; + auto cleanup = CScopeGuard([this]() { + if (m_pCurrentRenderbuffer) + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + }); + if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); else { @@ -2661,35 +2674,28 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto explicitOptions = getExplicitSyncSettings(); + + if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { auto sync = g_pHyprOpenGL->createEGLSync(-1); if (!sync) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; } - auto dupedfd = sync->dupFenceFD(); - sync.reset(); - if (dupedfd < 0) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; - Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); - return; - } - - bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); - close(dupedfd); + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, sync->fd()); if (!ok) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); return; } + + auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); + if (fd <= 0) { + Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); + return; + } + + PMONITOR->output->state->setExplicitInFence(fd); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); @@ -2697,11 +2703,6 @@ void CHyprRenderer::endRender() { glFlush(); } } - - m_pCurrentRenderbuffer->unbind(); - - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { @@ -2715,3 +2716,57 @@ SP CHyprRenderer::getCurrentRBO() { bool CHyprRenderer::isNvidia() { return m_bNvidia; } + +SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { + static auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static auto PENABLEEXPLICITKMS = CConfigValue("render:explicit_sync_kms"); + + SExplicitSyncSettings settings; + settings.explicitEnabled = *PENABLEEXPLICIT; + settings.explicitKMSEnabled = *PENABLEEXPLICITKMS; + + if (*PENABLEEXPLICIT == 2 /* auto */) + settings.explicitEnabled = true; + if (*PENABLEEXPLICITKMS == 2 /* auto */) { + if (!m_bNvidia) + settings.explicitKMSEnabled = true; + else { + + // check nvidia version. Explicit KMS is supported in >=560 + // in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled + int driverMajor = 0; + + static bool once = true; + if (once) { + once = false; + + Debug::log(LOG, "Renderer: checking for explicit KMS support for nvidia"); + + if (std::filesystem::exists("/sys/module/nvidia_drm/version")) { + Debug::log(LOG, "Renderer: Nvidia version file exists"); + + std::ifstream ifs("/sys/module/nvidia_drm/version"); + if (ifs.good()) { + try { + std::string driverInfo((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + + Debug::log(LOG, "Renderer: Read nvidia version {}", driverInfo); + + CVarList ver(driverInfo, 0, '.', true); + driverMajor = std::stoi(ver[0]); + + Debug::log(LOG, "Renderer: Parsed nvidia major version: {}", driverMajor); + + } catch (std::exception& e) { settings.explicitKMSEnabled = false; } + + ifs.close(); + } + } + } + + settings.explicitKMSEnabled = driverMajor >= 560; + } + } + + return settings; +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index a9397cac..84501821 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -39,6 +39,10 @@ class CToplevelExportProtocolManager; class CInputManager; struct SSessionLockSurface; +struct SExplicitSyncSettings { + bool explicitEnabled = false, explicitKMSEnabled = false; +}; + class CHyprRenderer { public: CHyprRenderer(); @@ -73,6 +77,7 @@ class CHyprRenderer { bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); + SExplicitSyncSettings getExplicitSyncSettings(); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. @@ -142,6 +147,7 @@ class CHyprRenderer { friend class CToplevelExportFrame; friend class CInputManager; friend class CPointerManager; + friend class CMonitor; }; inline std::unique_ptr g_pHyprRenderer; From d597ae41b9ce7d995a4ad28bda9ef54d4d01a020 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 6 Aug 2024 16:57:15 +0200 Subject: [PATCH 0448/2393] renderer: fixup crashes on inaccessible files for bg --- src/render/OpenGL.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 8875d8f4..c355f4f9 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2688,12 +2688,10 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { texPath += ".png"; // check if wallpapers exist - if (!std::filesystem::exists(texPath)) { - // try local - texPath = texPath.substr(0, 5) + "local/" + texPath.substr(5); - - if (!std::filesystem::exists(texPath)) - return; // the texture will be empty, oh well. We'll clear with a solid color anyways. + std::error_code err; + if (!std::filesystem::exists(texPath, err)) { + Debug::log(ERR, "createBGTextureForMonitor: failed, file doesn't exist or access denied, ec: {}", err.message()); + return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } createBackgroundTexture(texPath); From b0a70f63e3865eaa77f0b78a04b230aa583bc95c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 6 Aug 2024 17:08:22 +0200 Subject: [PATCH 0449/2393] wayland/compositor: drop pending buffer ref if synchronous fixes https://github.com/hyprwm/hyprpicker/issues/85 --- src/protocols/core/Compositor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index b0111032..656433d3 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -448,8 +448,10 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->buffer->isSynchronous()) + if (current.buffer->buffer->isSynchronous()) { dropCurrentBuffer(); + dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release + } } // TODO: we should _accumulate_ and not replace above if sync From fa6ee513678e6e1cfdc575a421c1e0ddf4608994 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 7 Aug 2024 02:44:20 -0500 Subject: [PATCH 0450/2393] input: fix leds on kb creation (#7206) --- src/managers/input/InputManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 8c38893f..c502cb0d 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -919,6 +919,8 @@ void CInputManager::setupKeyboard(SP keeb) { applyConfigToKeyboard(keeb); g_pSeatManager->setKeyboard(keeb); + + keeb->updateLEDs(); } void CInputManager::setKeyboardLayout() { From 5b736a4a661220ab07abc3afda6cdb8774095bfb Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 13:22:01 +0200 Subject: [PATCH 0451/2393] debug: dont manually unlock the lock_guard (#7210) when lock_guard goes out of scope it RAII itself and calls unlock. causes crashes on freebsd/libc++ and double unlocking a mutex is UB. --- src/debug/Log.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 617f451a..4fc8ed5b 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -72,6 +72,5 @@ namespace Debug { logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); log(level, logMsg); - logMutex.unlock(); } }; From a05da63d853fc750bae29228d924b346243afaec Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 7 Aug 2024 06:22:19 -0500 Subject: [PATCH 0452/2393] keybinds: fix NoSymbol keybinds (#7199) --- src/managers/KeybindManager.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 08c6998d..c7b93730 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -639,18 +639,17 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (found || key.submapAtPress != m_szCurrentSelectedSubmap) continue; } else { - // in this case, we only have the keysym to go off. - // if the keysym failed resolving, we can't do anything. It's likely missing - // from the keymap. - if (key.keysym == 0) - return false; + // in this case, we only have the keysym to go off of for this keybind, and it's invalid + // since there might be something like keycode to match with other keybinds, try the next + if (key.keysym == XKB_KEY_NoSymbol) + continue; // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); - if (KBKEY == 0 && KBKEYLOWER == 0) { + if (KBKEY == XKB_KEY_NoSymbol && KBKEYLOWER == XKB_KEY_NoSymbol) { // Keysym failed to resolve from the key name of the currently iterated bind. // This happens for names such as `switch:off:Lid Switch` as well as some keys // (such as yen and ro). From 3d82d199f0ec6d8bf6252ed0795b4d883ade84ff Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 13:23:00 +0200 Subject: [PATCH 0453/2393] cursormgr: implement inheriting themes for xcursor (#7197) * cursormgr: reduce duplicated code add a few functions such as setCursorBuffer and setAnimationTimer to reduce duplicated code and also avoid future mishaps of forgetting to clear buffer or disarm timer. and generally reduce spaghetti even tho pasta can be delicious. * xcursormgr: implent inherited themes implent index.theme parsing and inherited themes. * cursormgr: ensure a fallback xcursor exist ensure a xcursor fallback exist otherwise it wont load the proper theme if we at launch have hyprcursor enabled and then set it to false in config and reload. also use the env var when using hyprctl setcursor incase its empty. --- src/managers/CursorManager.cpp | 343 ++++++++++++++++---------------- src/managers/CursorManager.hpp | 54 +++-- src/managers/XCursorManager.cpp | 90 +++++++-- src/managers/XCursorManager.hpp | 21 +- 4 files changed, 285 insertions(+), 223 deletions(-) diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 9b574901..3f3a25f6 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -17,11 +17,61 @@ static void hcLogger(enum eHyprcursorLogLevel level, char* message) { Debug::log(NONE, "[hc] {}", message); } -CCursorManager::CCursorManager() { - m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); - m_pXcursor = std::make_unique(); +CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + surface = surf; + size = size_; + stride = cairo_image_surface_get_stride(surf); +} - if (m_pHyprcursor->valid()) { +CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { + pixelData = pixelData_; + size = size_; + stride = 4 * size_.x; +} + +Aquamarine::eBufferCapability CCursorBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CCursorBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +void CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { + ; +} + +bool CCursorBuffer::isSynchronous() { + return true; +} + +bool CCursorBuffer::good() { + return true; +} + +Aquamarine::SSHMAttrs CCursorBuffer::shm() { + Aquamarine::SSHMAttrs attrs; + attrs.success = true; + attrs.format = DRM_FORMAT_ARGB8888; + attrs.size = size; + attrs.stride = stride; + return attrs; +} + +std::tuple CCursorBuffer::beginDataPtr(uint32_t flags) { + return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; +} + +void CCursorBuffer::endDataPtr() { + ; +} + +CCursorManager::CCursorManager() { + m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); + m_pXcursor = std::make_unique(); + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + + if (m_pHyprcursor->valid() && *PUSEHYPRCURSOR) { // find default size. First, HYPRCURSOR_SIZE then default to 24 auto const* SIZE = getenv("HYPRCURSOR_SIZE"); if (SIZE) { @@ -48,10 +98,12 @@ CCursorManager::CCursorManager() { Debug::log(WARN, "XCURSOR_SIZE size not set, defaulting to size 24"); m_iSize = 24; } - - m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); } + // since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config + // and then later is disabled. + m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); + m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this); g_pEventLoopManager->addTimer(m_pAnimationTimer); @@ -65,63 +117,9 @@ CCursorManager::~CCursorManager() { g_pEventLoopManager->removeTimer(m_pAnimationTimer); m_pAnimationTimer.reset(); } -} -void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) { - std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; }); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { - surface = surf; - size = size_; - stride = cairo_image_surface_get_stride(surf); -} - -CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) { - pixelData = pixelData_; - size = size_; - stride = 4 * size_.x; -} - -CCursorManager::CCursorBuffer::~CCursorBuffer() { - ; -} - -Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() { - return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; -} - -Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() { - return Aquamarine::eBufferType::BUFFER_TYPE_SHM; -} - -void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) { - ; -} - -bool CCursorManager::CCursorBuffer::isSynchronous() { - return true; -} - -bool CCursorManager::CCursorBuffer::good() { - return true; -} - -Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() { - Aquamarine::SSHMAttrs attrs; - attrs.success = true; - attrs.format = DRM_FORMAT_ARGB8888; - attrs.size = size; - attrs.stride = stride; - return attrs; -} - -std::tuple CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) { - return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride}; -} - -void CCursorManager::CCursorBuffer::endDataPtr() { - ; + if (m_pHyprcursor->valid() && m_sCurrentStyleInfo.size > 0) + m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); } SP CCursorManager::getCursorBuffer() { @@ -137,91 +135,101 @@ void CCursorManager::setCursorSurface(SP surf, const Vector2D& hotsp m_bOurBufferConnected = false; } -void CCursorManager::setXCursor(const std::string& name) { - float scale = std::ceil(m_fCursorScale); - - auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); - auto& icon = xcursor->images.front(); - - m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); - - g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); +void CCursorManager::setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale) { + m_vCursorBuffers.emplace_back(buf); + g_pPointerManager->setCursorBuffer(getCursorBuffer(), hotspot, scale); if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); + std::erase_if(m_vCursorBuffers, [this](const auto& buf) { return buf.get() == m_vCursorBuffers.front().get(); }); - m_currentXcursor = xcursor; m_bOurBufferConnected = true; +} - if (m_currentXcursor->images.size() > 1) { - // animated - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[0].delay)); - m_iCurrentAnimationFrame = 0; +void CCursorManager::setAnimationTimer(const int& frame, const int& delay) { + if (delay > 0) { + // arm + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(delay)); } else { // disarm m_pAnimationTimer->updateTimeout(std::nullopt); } + + m_iCurrentAnimationFrame = frame; } void CCursorManager::setCursorFromName(const std::string& name) { static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); - if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) { - setXCursor(name); - return; - } + auto setXCursor = [this](auto const& name) { + float scale = std::ceil(m_fCursorScale); - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo); + auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto& icon = xcursor->images.front(); + auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); + setCursorBuffer(buf, icon.hotspot / scale, scale); - if (m_sCurrentCursorShapeData.images.size() < 1) { - // try with '_' first (old hc, etc) - std::string newName = name; - std::replace(newName.begin(), newName.end(), '-', '_'); + m_currentXcursor = xcursor; - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo); - } + int delay = 0; + int frame = 0; + if (m_currentXcursor->images.size() > 1) + delay = m_currentXcursor->images[frame].delay; - if (m_sCurrentCursorShapeData.images.size() < 1) { - // fallback to a default if available - constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; + setAnimationTimer(frame, delay); + }; - for (auto& s : fallbackShapes) { - m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); + auto setHyprCursor = [this](auto const& name) { + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(name.c_str(), m_sCurrentStyleInfo); - if (m_sCurrentCursorShapeData.images.size() > 0) - break; + if (m_sCurrentCursorShapeData.images.size() < 1) { + // try with '_' first (old hc, etc) + std::string newName = name; + std::replace(newName.begin(), newName.end(), '-', '_'); + + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(newName.c_str(), m_sCurrentStyleInfo); } if (m_sCurrentCursorShapeData.images.size() < 1) { - Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); - setXCursor(name); - return; + // fallback to a default if available + constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; + + for (auto& s : fallbackShapes) { + m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); + + if (m_sCurrentCursorShapeData.images.size() > 0) + break; + } + + if (m_sCurrentCursorShapeData.images.size() < 1) { + Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); + return false; + } } - } - m_vCursorBuffers.emplace_back(makeShared(m_sCurrentCursorShapeData.images[0].surface, - Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, - Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY})); + auto buf = + makeShared(m_sCurrentCursorShapeData.images[0].surface, Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size}, + Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}); + auto hotspot = Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale; + setCursorBuffer(buf, hotspot, m_fCursorScale); - g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale, - m_fCursorScale); - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); + int delay = 0; + int frame = 0; + if (m_sCurrentCursorShapeData.images.size() > 1) + delay = m_sCurrentCursorShapeData.images[frame].delay; - m_bOurBufferConnected = true; + setAnimationTimer(frame, delay); + return true; + }; - if (m_sCurrentCursorShapeData.images.size() > 1) { - // animated - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[0].delay)); - m_iCurrentAnimationFrame = 0; - } else { - // disarm - m_pAnimationTimer->updateTimeout(std::nullopt); - } + if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR || !setHyprCursor(name)) + setXCursor(name); } void CCursorManager::tickAnimatedCursor() { - if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1 && m_bOurBufferConnected) { + if (!m_bOurBufferConnected) + return; + + if (!m_pHyprcursor->valid() && m_currentXcursor->images.size() > 1) { m_iCurrentAnimationFrame++; if ((size_t)m_iCurrentAnimationFrame >= m_currentXcursor->images.size()) @@ -229,39 +237,24 @@ void CCursorManager::tickAnimatedCursor() { float scale = std::ceil(m_fCursorScale); auto& icon = m_currentXcursor->images.at(m_iCurrentAnimationFrame); - m_vCursorBuffers.emplace_back(makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot)); + auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); + setCursorBuffer(buf, icon.hotspot / scale, scale); + setAnimationTimer(m_iCurrentAnimationFrame, m_currentXcursor->images[m_iCurrentAnimationFrame].delay); + } else if (m_sCurrentCursorShapeData.images.size() > 1) { + m_iCurrentAnimationFrame++; - g_pPointerManager->setCursorBuffer(getCursorBuffer(), icon.hotspot / scale, scale); + if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) + m_iCurrentAnimationFrame = 0; - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_currentXcursor->images[m_iCurrentAnimationFrame].delay)); - - return; + auto hotspot = + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale; + auto buf = makeShared( + m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, + Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}); + setCursorBuffer(buf, hotspot, m_fCursorScale); + setAnimationTimer(m_iCurrentAnimationFrame, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay); } - - if (m_sCurrentCursorShapeData.images.size() < 2 || !m_bOurBufferConnected) - return; - - m_iCurrentAnimationFrame++; - if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size()) - m_iCurrentAnimationFrame = 0; - - m_vCursorBuffers.emplace_back(makeShared( - m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface, - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size}, - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY})); - - g_pPointerManager->setCursorBuffer( - getCursorBuffer(), - Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale, - m_fCursorScale); - - if (m_vCursorBuffers.size() > 1) - dropBufferRef(m_vCursorBuffers.at(0).get()); - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay)); } SCursorImageData CCursorManager::dataFor(const std::string& name) { @@ -278,11 +271,12 @@ SCursorImageData CCursorManager::dataFor(const std::string& name) { } void CCursorManager::setXWaylandCursor() { - const auto CURSOR = dataFor("left_ptr"); - if (CURSOR.surface) { + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + const auto CURSOR = dataFor("left_ptr"); + if (CURSOR.surface && *PUSEHYPRCURSOR) g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); - } else { + else { auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale)); auto& icon = xcursor->images.front(); @@ -291,21 +285,25 @@ void CCursorManager::setXWaylandCursor() { } void CCursorManager::updateTheme() { - float highestScale = 1.0; + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + float highestScale = 1.0; for (auto& m : g_pCompositor->m_vMonitors) { if (m->scale > highestScale) highestScale = m->scale; } - if (m_sCurrentStyleInfo.size && m_pHyprcursor->valid()) - m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); + m_fCursorScale = highestScale; - m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale); - m_fCursorScale = highestScale; + if (*PUSEHYPRCURSOR) { + if (m_sCurrentStyleInfo.size > 0 && m_pHyprcursor->valid()) + m_pHyprcursor->cursorSurfaceStyleDone(m_sCurrentStyleInfo); - if (m_pHyprcursor->valid()) - m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo); + m_sCurrentStyleInfo.size = std::round(m_iSize * highestScale); + + if (m_pHyprcursor->valid()) + m_pHyprcursor->loadThemeStyle(m_sCurrentStyleInfo); + } setCursorFromName("left_ptr"); @@ -316,24 +314,27 @@ void CCursorManager::updateTheme() { } bool CCursorManager::changeTheme(const std::string& name, const int size) { - auto options = Hyprcursor::SManagerOptions(); - options.logFn = hcLogger; - options.allowDefaultFallback = false; + static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); + m_szTheme = name.empty() ? "" : name; + m_iSize = size <= 0 ? 24 : size; + auto xcursor_theme = getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default"; - m_pHyprcursor = std::make_unique(name.empty() ? "" : name.c_str(), options); - if (m_pHyprcursor->valid()) { - m_szTheme = name; - m_iSize = size; - updateTheme(); - return true; - } + if (*PUSEHYPRCURSOR) { + auto options = Hyprcursor::SManagerOptions(); + options.logFn = hcLogger; + options.allowDefaultFallback = false; + m_szTheme = name.empty() ? "" : name; + m_iSize = size; - Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", name); + m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); + if (!m_pHyprcursor->valid()) { + Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + } + } else + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); - m_pXcursor->loadTheme(name, size); - - m_szTheme = name; - m_iSize = size; updateTheme(); + return true; } \ No newline at end of file diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index a114b6c2..ceb4816b 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -15,6 +15,28 @@ class CWLSurface; AQUAMARINE_FORWARD(IBuffer); +class CCursorBuffer : public Aquamarine::IBuffer { + public: + CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); + CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); + ~CCursorBuffer() = default; + + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual void update(const Hyprutils::Math::CRegion& damage); + virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good(); + virtual Aquamarine::SSHMAttrs shm(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + + private: + Vector2D hotspot; + cairo_surface_t* surface = nullptr; + uint8_t* pixelData = nullptr; + size_t stride = 0; +}; + class CCursorManager { public: CCursorManager(); @@ -24,7 +46,8 @@ class CCursorManager { void setCursorFromName(const std::string& name); void setCursorSurface(SP surf, const Vector2D& hotspot); - void setXCursor(const std::string& name); + void setCursorBuffer(SP buf, const Vector2D& hotspot, const float& scale); + void setAnimationTimer(const int& frame, const int& delay); bool changeTheme(const std::string& name, const int size); void updateTheme(); @@ -33,35 +56,8 @@ class CCursorManager { void tickAnimatedCursor(); - class CCursorBuffer : public Aquamarine::IBuffer { - public: - CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot); - CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot); - ~CCursorBuffer(); - - virtual Aquamarine::eBufferCapability caps(); - virtual Aquamarine::eBufferType type(); - virtual void update(const Hyprutils::Math::CRegion& damage); - virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu - virtual bool good(); - virtual Aquamarine::SSHMAttrs shm(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - - private: - Vector2D hotspot; - cairo_surface_t* surface = nullptr; - uint8_t* pixelData = nullptr; - size_t stride = 0; - - friend class CCursorManager; - }; - - void dropBufferRef(CCursorBuffer* ref); - - bool m_bOurBufferConnected = false; - private: + bool m_bOurBufferConnected = false; std::vector> m_vCursorBuffers; std::unique_ptr m_pHyprcursor; diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index b3f33086..76c908db 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -135,6 +135,11 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { continue; } + if (std::any_of(cursors.begin(), cursors.end(), [&shape](auto const& dp) { return dp->shape == shape; })) { + Debug::log(LOG, "XCursor already has a shape {} loaded, skipping", shape); + continue; + } + auto cursor = makeShared(); cursor->images = it->get()->images; cursor->shape = shape; @@ -180,11 +185,10 @@ SP CXCursorManager::createCursor(std::string const& shape, XcursorIma return xcursor; } -std::vector CXCursorManager::themePaths(std::string const& theme) { - auto const* path = XcursorLibraryPath(); - std::vector paths; +std::unordered_set CXCursorManager::themePaths(std::string const& theme) { + auto const* path = XcursorLibraryPath(); - auto expandTilde = [](std::string const& path) { + auto expandTilde = [](std::string const& path) { if (!path.empty() && path[0] == '~') { const char* home = std::getenv("HOME"); if (home) @@ -193,15 +197,76 @@ std::vector CXCursorManager::themePaths(std::string const& theme) { return path; }; - if (path) { + auto getInheritThemes = [](std::string const& indexTheme) { + std::ifstream infile(indexTheme); + std::string line; + std::vector themes; + + Debug::log(LOG, "XCursor parsing index.theme {}", indexTheme); + + while (std::getline(infile, line)) { + // Trim leading and trailing whitespace + line.erase(0, line.find_first_not_of(" \t\n\r")); + line.erase(line.find_last_not_of(" \t\n\r") + 1); + + if (line.rfind("Inherits", 0) == 0) { // Check if line starts with "Inherits" + std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" + // Remove leading whitespace from inheritThemes and = + inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + inheritThemes.erase(0, 1); + inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + + std::stringstream inheritStream(inheritThemes); + std::string inheritTheme; + while (std::getline(inheritStream, inheritTheme, ',')) { + // Trim leading and trailing whitespace from each theme + inheritTheme.erase(0, inheritTheme.find_first_not_of(" \t\n\r")); + inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + themes.push_back(inheritTheme); + } + } + } + infile.close(); + + return themes; + }; + + std::unordered_set paths; + std::unordered_set inherits; + + auto scanTheme = [&path, &paths, &expandTilde, &inherits, &getInheritThemes](auto const& t) { std::stringstream ss(path); - std::string item; + std::string line; - while (std::getline(ss, item, ':')) { - auto p = expandTilde(item + "/" + theme + "/cursors"); + Debug::log(LOG, "XCursor scanning theme {}", t); - if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) - paths.push_back(p); + while (std::getline(ss, line, ':')) { + auto p = expandTilde(line + "/" + t + "/cursors"); + if (std::filesystem::exists(p) && std::filesystem::is_directory(p)) { + Debug::log(LOG, "XCursor using theme path {}", p); + paths.insert(p); + } + + auto inherit = expandTilde(line + "/" + t + "/index.theme"); + if (std::filesystem::exists(inherit) && std::filesystem::is_regular_file(inherit)) { + auto inheritThemes = getInheritThemes(inherit); + for (auto const& i : inheritThemes) { + Debug::log(LOG, "XCursor theme {} inherits {}", t, i); + inherits.insert(i); + } + } + } + }; + + if (path) { + scanTheme(theme); + while (!inherits.empty()) { + auto oldInherits = inherits; + for (auto& i : oldInherits) + scanTheme(i); + + if (oldInherits.size() == inherits.size()) + break; } } @@ -402,14 +467,13 @@ std::vector> CXCursorManager::loadStandardCursors(std::string cons std::vector> CXCursorManager::loadAllFromDir(std::string const& path, int size) { std::vector> newCursors; - std::string full; if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { for (const auto& entry : std::filesystem::directory_iterator(path)) { if (!entry.is_regular_file() && !entry.is_symlink()) continue; - std::string full = entry.path().string(); + auto const& full = entry.path().string(); using PcloseType = int (*)(FILE*); const std::unique_ptr f(fopen(full.c_str(), "r"), static_cast(fclose)); @@ -428,7 +492,7 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa } } - std::string shape = entry.path().filename().string(); + auto const& shape = entry.path().filename().string(); auto cursor = createCursor(shape, xImages); newCursors.emplace_back(cursor); diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 9ced076f..20637055 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -32,15 +33,15 @@ class CXCursorManager { SP getShape(std::string const& shape, int size); private: - SP createCursor(std::string const& shape, XcursorImages* xImages); - std::vector themePaths(std::string const& theme); - std::string getLegacyShapeName(std::string const& shape); - std::vector> loadStandardCursors(std::string const& name, int size); - std::vector> loadAllFromDir(std::string const& path, int size); + SP createCursor(std::string const& shape, XcursorImages* xImages); + std::unordered_set themePaths(std::string const& theme); + std::string getLegacyShapeName(std::string const& shape); + std::vector> loadStandardCursors(std::string const& name, int size); + std::vector> loadAllFromDir(std::string const& path, int size); - int lastLoadSize = 0; - std::string themeName = ""; - SP defaultCursor; - SP hyprCursor; - std::vector> cursors; + int lastLoadSize = 0; + std::string themeName = ""; + SP defaultCursor; + SP hyprCursor; + std::vector> cursors; }; \ No newline at end of file From b2717cf7fd86774b450b58f6263291e277553e63 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Wed, 7 Aug 2024 04:26:09 -0700 Subject: [PATCH 0454/2393] xdg-shell: make xdg-positioner flip target greatest available space (#7209) When both flip directions use more space than is available, pick the direction that has more space available instead of just the opposite of what was initially requested. --- src/protocols/XDGShell.cpp | 93 +++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 4aa5d373..aea23329 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -531,29 +531,66 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo auto anchorRect = state.anchorRect.copy().translate(parentCoord); - auto width = state.requestedSize.x; - auto height = state.requestedSize.y; + auto width = state.requestedSize.x; + auto height = state.requestedSize.y; + auto gravity = state.gravity; auto anchorX = state.anchor.left() ? anchorRect.x : state.anchor.right() ? anchorRect.extent().x : anchorRect.middle().x; auto anchorY = state.anchor.top() ? anchorRect.y : state.anchor.bottom() ? anchorRect.extent().y : anchorRect.middle().y; - auto calcEffectiveX = [&]() { return state.gravity.left() ? anchorX - width : state.gravity.right() ? anchorX : anchorX - width / 2; }; - auto calcEffectiveY = [&]() { return state.gravity.top() ? anchorY - height : state.gravity.bottom() ? anchorY : anchorY - height / 2; }; + auto calcEffectiveX = [&](CEdges anchorGravity, double anchorX) { return anchorGravity.left() ? anchorX - width : anchorGravity.right() ? anchorX : anchorX - width / 2; }; + auto calcEffectiveY = [&](CEdges anchorGravity, double anchorY) { return anchorGravity.top() ? anchorY - height : anchorGravity.bottom() ? anchorY : anchorY - height / 2; }; - auto effectiveX = calcEffectiveX(); - auto effectiveY = calcEffectiveY(); + auto calcRemainingWidth = [&](double effectiveX) { + auto width = state.requestedSize.x; + if (effectiveX < constraint.x) { + auto diff = constraint.x - effectiveX; + effectiveX = constraint.x; + width -= diff; + } + + auto effectiveX2 = effectiveX + width; + if (effectiveX2 > constraint.extent().x) + width -= effectiveX2 - constraint.extent().x; + + return std::make_pair(effectiveX, width); + }; + + auto calcRemainingHeight = [&](double effectiveY) { + auto height = state.requestedSize.y; + if (effectiveY < constraint.y) { + auto diff = constraint.y - effectiveY; + effectiveY = constraint.y; + height -= diff; + } + + auto effectiveY2 = effectiveY + height; + if (effectiveY2 > constraint.extent().y) + height -= effectiveY2 - constraint.extent().y; + + return std::make_pair(effectiveY, height); + }; + + auto effectiveX = calcEffectiveX(gravity, anchorX); + auto effectiveY = calcEffectiveY(gravity, anchorY); // Note: the usage of offset is a guess which maintains compatibility with other compositors that were tested. // It considers the offset when deciding whether or not to flip but does not actually flip the offset, instead // applying it after the flip step. if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) { - auto flip = (state.gravity.left() && effectiveX + state.offset.x < constraint.x) || (state.gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x); + auto flip = (gravity.left() && effectiveX + state.offset.x < constraint.x) || (gravity.right() && effectiveX + state.offset.x + width > constraint.extent().x); if (flip) { - state.gravity ^= CEdges::LEFT | CEdges::RIGHT; - anchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX; - effectiveX = calcEffectiveX(); + auto newGravity = gravity ^ (CEdges::LEFT | CEdges::RIGHT); + auto newAnchorX = state.anchor.left() ? anchorRect.extent().x : state.anchor.right() ? anchorRect.x : anchorX; + auto newEffectiveX = calcEffectiveX(newGravity, newAnchorX); + + if (calcRemainingWidth(newEffectiveX).second > calcRemainingWidth(effectiveX).second) { + gravity = newGravity; + anchorX = newAnchorX; + effectiveX = newEffectiveX; + } } } @@ -561,9 +598,15 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo auto flip = (state.gravity.top() && effectiveY + state.offset.y < constraint.y) || (state.gravity.bottom() && effectiveY + state.offset.y + height > constraint.extent().y); if (flip) { - state.gravity ^= CEdges::TOP | CEdges::BOTTOM; - anchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; - effectiveY = calcEffectiveY(); + auto newGravity = gravity ^ (CEdges::TOP | CEdges::BOTTOM); + auto newAnchorY = state.anchor.top() ? anchorRect.extent().y : state.anchor.bottom() ? anchorRect.y : anchorY; + auto newEffectiveY = calcEffectiveY(newGravity, newAnchorY); + + if (calcRemainingHeight(newEffectiveY).second > calcRemainingHeight(effectiveY).second) { + gravity = newGravity; + anchorY = newAnchorY; + effectiveY = newEffectiveY; + } } } @@ -589,27 +632,15 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo } if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) { - if (effectiveX < constraint.x) { - auto diff = constraint.x - effectiveX; - effectiveX = constraint.x; - width -= diff; - } - - auto effectiveX2 = effectiveX + width; - if (effectiveX2 > constraint.extent().x) - width -= effectiveX2 - constraint.extent().x; + auto [newX, newWidth] = calcRemainingWidth(effectiveX); + effectiveX = newX; + width = newWidth; } if (state.constraintAdjustment & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) { - if (effectiveY < constraint.y) { - auto diff = constraint.y - effectiveY; - effectiveY = constraint.y; - height -= diff; - } - - auto effectiveY2 = effectiveY + height; - if (effectiveY2 > constraint.extent().y) - height -= effectiveY2 - constraint.extent().y; + auto [newY, newHeight] = calcRemainingHeight(effectiveY); + effectiveY = newY; + height = newHeight; } return {effectiveX - parentCoord.x, effectiveY - parentCoord.y, width, height}; From 2e3dc17a7e56c609659514af13ce911481334be3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 13:31:27 +0200 Subject: [PATCH 0455/2393] renderer: guard layer in renderLayer ref #7181 --- src/render/Renderer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7794d476..8c29bef4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -716,6 +716,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time, bool popups) { + if (!pLayer) + return; + static auto PDIMAROUND = CConfigValue("decoration:dim_around"); if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) { From f36c625e37f8913d8da38365a4783948f2217f02 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 13:35:02 +0200 Subject: [PATCH 0456/2393] compositor: minor cleanups for fading out layers --- src/Compositor.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 299a16c6..9b8fd3d7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1425,12 +1425,16 @@ void CCompositor::cleanupFadingOut(const int& monid) { } } + bool layersDirty = false; + for (auto& lsr : m_vSurfacesFadingOut) { auto ls = lsr.lock(); - if (!ls) + if (!ls) { + layersDirty = true; continue; + } if (ls->monitorID != monid) continue; @@ -1443,7 +1447,7 @@ void CCompositor::cleanupFadingOut(const int& monid) { for (auto& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { - std::erase_if(lsl, [&](auto& other) { return other == ls; }); + std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); } } } @@ -1459,6 +1463,9 @@ void CCompositor::cleanupFadingOut(const int& monid) { return; } } + + if (layersDirty) + std::erase_if(m_vSurfacesFadingOut, [](const auto& el) { return el.expired(); }); } void CCompositor::addToFadingOutSafe(PHLLS pLS) { From 99e9cb510777c62f56c94137b302186d4d9506d8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 16:08:50 +0200 Subject: [PATCH 0457/2393] drm-syncobj: fixup fd leak with timelines --- src/protocols/DRMSyncobj.cpp | 5 +++++ src/protocols/DRMSyncobj.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 8b0330de..37e6d0f1 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -114,6 +114,11 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) + close(fd); +} + SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 25dc10c1..bc89a3d3 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -34,6 +34,7 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: CDRMSyncobjTimelineResource(SP resource_, int fd_); + ~CDRMSyncobjTimelineResource(); static SP fromResource(wl_resource*); bool good(); From d5bc3eb1fa0e11e9e77ffef8c8449a9c022a13a5 Mon Sep 17 00:00:00 2001 From: Sami Liedes Date: Wed, 7 Aug 2024 16:28:02 +0200 Subject: [PATCH 0458/2393] hyprctl: link to much less libraries (#7212) This makes hyprctl start significantly faster. $ time for ((i=0; i<1000; i++)); do hyprctl/hyprctl -j activewindow >/dev/null; done Before: 12.269 s (about 12.3 ms/execution) After: 2.142 s (about 2.1 ms/execution) --- CMakeLists.txt | 6 ++++++ hyprctl/CMakeLists.txt | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa58b63d..fc8eafd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,12 @@ else() endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) +pkg_check_modules( + hyprctl_deps + REQUIRED + IMPORTED_TARGET + hyprutils>=0.2.1) + pkg_check_modules( deps REQUIRED diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt index 64b983e6..aaffe411 100644 --- a/hyprctl/CMakeLists.txt +++ b/hyprctl/CMakeLists.txt @@ -9,7 +9,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1) add_executable(hyprctl "main.cpp") -target_link_libraries(hyprctl PUBLIC PkgConfig::deps) +target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps) # binary install(TARGETS hyprctl) From 3e00d7dde774a44b5738d339ce58a4903897942b Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:36:20 -0400 Subject: [PATCH 0459/2393] compositor: fix general:extend_border_grab_area (#7214) Co-authored-by: Agent_00Ming --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9b8fd3d7..49408597 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -777,7 +777,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) @@ -807,7 +807,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = BB.copy().expand(w->m_iX11Type == 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent From a399f98c68d017152883fbf81d67624ac3254073 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 7 Aug 2024 16:37:09 +0200 Subject: [PATCH 0460/2393] cursormgr: avoid scanning ill formed inherit (#7211) avoid adding ill formed Inherit lines to inherit vector and later scanning them, it wont change anything in practice but makes the inherit theme parsing more in line with what its supposed todo. also check for return values of the various string functions so we dont end up erasing the wrong thing. --- src/managers/XCursorManager.cpp | 53 ++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 76c908db..f2a7ab53 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -205,23 +205,56 @@ std::unordered_set CXCursorManager::themePaths(std::string const& t Debug::log(LOG, "XCursor parsing index.theme {}", indexTheme); while (std::getline(infile, line)) { - // Trim leading and trailing whitespace - line.erase(0, line.find_first_not_of(" \t\n\r")); - line.erase(line.find_last_not_of(" \t\n\r") + 1); + if (line.empty()) + continue; + + // Trim leading and trailing whitespace + auto pos = line.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + line.erase(0, pos); + + pos = line.find_last_not_of(" \t\n\r"); + if (pos != std::string::npos && pos < line.length()) { + line.erase(pos + 1); + } + + if (line.rfind("Inherits", 8) != std::string::npos) { // Check if line starts with "Inherits" + std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" + if (inheritThemes.empty()) + continue; - if (line.rfind("Inherits", 0) == 0) { // Check if line starts with "Inherits" - std::string inheritThemes = line.substr(8); // Extract the part after "Inherits" // Remove leading whitespace from inheritThemes and = - inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); - inheritThemes.erase(0, 1); - inheritThemes.erase(0, inheritThemes.find_first_not_of(" \t\n\r")); + pos = inheritThemes.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritThemes.erase(0, pos); + + if (inheritThemes.empty()) + continue; + + if (inheritThemes.at(0) == '=') + inheritThemes.erase(0, 1); + else + continue; // not correct formatted index.theme + + pos = inheritThemes.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritThemes.erase(0, pos); std::stringstream inheritStream(inheritThemes); std::string inheritTheme; while (std::getline(inheritStream, inheritTheme, ',')) { + if (inheritTheme.empty()) + continue; + // Trim leading and trailing whitespace from each theme - inheritTheme.erase(0, inheritTheme.find_first_not_of(" \t\n\r")); - inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + pos = inheritTheme.find_first_not_of(" \t\n\r"); + if (pos != std::string::npos) + inheritTheme.erase(0, pos); + + pos = inheritTheme.find_last_not_of(" \t\n\r"); + if (pos != std::string::npos && pos < inheritTheme.length()) + inheritTheme.erase(inheritTheme.find_last_not_of(" \t\n\r") + 1); + themes.push_back(inheritTheme); } } From ea728315410e220d73a993f17c83ae9dc9be9015 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 17:04:43 +0200 Subject: [PATCH 0461/2393] wayland/compositor: introduce client commit events --- src/protocols/DRMSyncobj.cpp | 2 +- src/protocols/core/Compositor.cpp | 2 ++ src/protocols/core/Compositor.hpp | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 37e6d0f1..9a48b99a 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -75,7 +75,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); }); - listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) { + listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { // apply timelines if new ones have been attached, otherwise don't touch // the current ones if (pending.releaseTimeline) { diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 656433d3..a767dd52 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -432,6 +432,8 @@ void CWLSurfaceResource::commitPendingState() { pending.bufferDamage.clear(); pending.newBuffer = false; + events.roleCommit.emit(); + if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer) current.buffer->releaser = makeShared(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint); diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index af0dfa58..a3245399 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -75,8 +75,9 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { - CSignal precommit; - CSignal commit; + CSignal precommit; // before commit + CSignal roleCommit; // commit for role objects, before regular commit + CSignal commit; // after commit CSignal map; CSignal unmap; CSignal newSubsurface; From 2d552fbaa25f1457c3819521a2750dd30820271b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 18:54:45 +0200 Subject: [PATCH 0462/2393] renderer: fixup nvidia driver version checks --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8c29bef4..7b29eb77 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2737,7 +2737,7 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { // check nvidia version. Explicit KMS is supported in >=560 // in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled - int driverMajor = 0; + static int driverMajor = 0; static bool once = true; if (once) { From 9a09eac79b85c846e3a865a9078a3f8ff65a9259 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 7 Aug 2024 21:17:10 +0200 Subject: [PATCH 0463/2393] props: bump version to 0.42.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6599454d..787ffc30 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.41.2 +0.42.0 From 83a334f97df4389ca30cb63e50317a66a82562b9 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 8 Aug 2024 10:54:41 +0100 Subject: [PATCH 0464/2393] core: Move to C++26 and use native_handle to CLOEXEC the debug fd (#7219) Requires GCC >= 14 / Clang >= 18 --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- flake.nix | 2 +- meson.build | 2 +- nix/default.nix | 5 +++++ nix/overlays.nix | 2 +- nix/stdcxx.patch | 12 ++++++++++++ src/debug/Log.cpp | 3 +++ 7 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 nix/stdcxx.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index fc8eafd5..cfbd431f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ else() endif() include_directories(. "src/" "subprojects/udis86/" "protocols/") -set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD 26) add_compile_options( -Wall -Wextra diff --git a/flake.nix b/flake.nix index 9c20b3f5..9e1e3ab4 100644 --- a/flake.nix +++ b/flake.nix @@ -95,7 +95,7 @@ devShells = eachSystem (system: { default = pkgsFor.${system}.mkShell.override { - stdenv = pkgsFor.${system}.gcc13Stdenv; + stdenv = pkgsFor.${system}.gcc14Stdenv; } { name = "hyprland-shell"; nativeBuildInputs = with pkgsFor.${system}; [ diff --git a/meson.build b/meson.build index 886f4f9c..e8cd25b4 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project('Hyprland', 'cpp', 'c', 'optimization=3', 'buildtype=release', 'debug=false', - 'cpp_std=c++23', + 'cpp_std=c++26', ]) datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' diff --git a/nix/default.nix b/nix/default.nix index e4e12f43..9bae9d83 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -71,6 +71,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov src = lib.cleanSource ../.; }; + patches = [ + # forces GCC to use -std=c++26 + ./stdcxx.patch + ]; + postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp diff --git a/nix/overlays.nix b/nix/overlays.nix index d8979b45..36206f46 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -31,7 +31,7 @@ in { date = mkDate (self.lastModifiedDate or "19700101"); in { hyprland = final.callPackage ./default.nix { - stdenv = final.gcc13Stdenv; + stdenv = final.gcc14Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; inherit date; diff --git a/nix/stdcxx.patch b/nix/stdcxx.patch new file mode 100644 index 00000000..032e494d --- /dev/null +++ b/nix/stdcxx.patch @@ -0,0 +1,12 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index cfbd431f..73e8e0c2 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -64,6 +64,7 @@ endif() + include_directories(. "src/" "subprojects/udis86/" "protocols/") + set(CMAKE_CXX_STANDARD 26) + add_compile_options( ++ -std=c++26 + -Wall + -Wextra + -Wno-unused-parameter diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 0def77c0..a4c5b08e 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -5,10 +5,13 @@ #include #include +#include void Debug::init(const std::string& IS) { logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); logOfs.open(logFile, std::ios::out | std::ios::app); + auto handle = logOfs.native_handle(); + fcntl(handle, F_SETFD, FD_CLOEXEC); } void Debug::close() { From 4b4971c06fb02df00a2bd20b6b47b5d0e7d799a7 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 8 Aug 2024 21:01:50 +0200 Subject: [PATCH 0465/2393] internal: introduce new types to avoid unsigned int rollover and signed int overflow (#7216) * framebuffer: avoid gluint overflow GLuint was being initialized to -1 and rolling over to unsigned int max, its defined behaviour but very unnecessery. add a bool and use it for checking if allocated or not. * opengl: avoid gluint rollover -1 rolls over to unsigned int max, use 0xFF instead. * core: big uint64_t to int type conversion there were a few uint64_t to int implicit conversions overflowing int and causing UB, make all monitor/workspaces/windows use the new typedefs. also fix the various related 64 to 32 implicit conversions going around found with -Wshorten-64-to-32 --- hyprctl/main.cpp | 2 +- src/Compositor.cpp | 74 ++++++------- src/Compositor.hpp | 115 ++++++++++---------- src/SharedDefs.hpp | 4 + src/config/ConfigManager.cpp | 2 +- src/config/ConfigManager.hpp | 2 +- src/debug/HyprCtl.cpp | 4 +- src/desktop/LayerSurface.cpp | 4 +- src/desktop/LayerSurface.hpp | 4 +- src/desktop/Window.cpp | 2 +- src/desktop/Window.hpp | 14 +-- src/desktop/Workspace.cpp | 14 +-- src/desktop/Workspace.hpp | 10 +- src/events/Windows.cpp | 2 +- src/helpers/MiscFunctions.cpp | 78 ++++++------- src/helpers/MiscFunctions.hpp | 4 +- src/helpers/Monitor.cpp | 14 +-- src/helpers/Monitor.hpp | 52 ++++----- src/helpers/Timer.cpp | 2 +- src/helpers/Timer.hpp | 2 +- src/layout/DwindleLayout.cpp | 12 +- src/layout/DwindleLayout.hpp | 12 +- src/layout/IHyprLayout.hpp | 2 +- src/layout/MasterLayout.cpp | 10 +- src/layout/MasterLayout.hpp | 14 +-- src/macros.hpp | 2 + src/managers/KeybindManager.cpp | 6 +- src/managers/eventLoop/EventLoopManager.cpp | 4 +- src/managers/input/InputMethodPopup.hpp | 2 +- src/managers/input/Swipe.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 2 +- src/protocols/ForeignToplevelWlr.hpp | 2 +- src/render/Framebuffer.cpp | 11 +- src/render/Framebuffer.hpp | 3 +- src/render/OpenGL.cpp | 16 +-- src/render/Renderer.cpp | 2 +- src/render/Renderer.hpp | 2 +- src/signal-safe.cpp | 2 +- src/signal-safe.hpp | 4 +- 39 files changed, 263 insertions(+), 252 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 336d479e..c86406fc 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -113,7 +113,7 @@ int rollingRead(const int socket) { constexpr size_t BUFFER_SIZE = 8192; std::array buffer = {0}; - int sizeWritten = 0; + long sizeWritten = 0; std::cout << "[hyprctl] reading from socket following up log:" << std::endl; while (!sigintReceived) { sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 49408597..e3a347fd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -683,9 +683,9 @@ void CCompositor::startCompositor() { g_pEventLoopManager->enterLoop(); } -CMonitor* CCompositor::getMonitorFromID(const int& id) { +CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { for (auto& m : m_vMonitors) { - if (m->ID == (uint64_t)id) { + if (m->ID == id) { return m.get(); } } @@ -845,8 +845,8 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & FLOATING_ONLY) return floating(false); - const int64_t WORKSPACEID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); - const auto PWORKSPACE = getWorkspaceByID(WORKSPACEID); + const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); + const auto PWORKSPACE = getWorkspaceByID(WSPID); if (PWORKSPACE->m_bHasFullscreenWindow) return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); @@ -860,7 +860,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special != w->onSpecialWorkspace()) continue; - if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && + if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (w->hasPopupAt(pos)) return w; @@ -872,7 +872,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; - if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WORKSPACEID && !w->isHidden() && !w->m_bX11ShouldntFocus && + if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) return w; } @@ -1207,7 +1207,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } -PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const int& ID) { +PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) { for (auto& w : m_vWindows) { if (w->workspaceID() == ID && w->isFullscreen()) return w; @@ -1231,7 +1231,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { return PMONITOR->activeWorkspace->m_iID == w->m_iID; } -PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) { +PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { for (auto& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) return w; @@ -1255,7 +1255,7 @@ void CCompositor::sanityCheckWorkspaces() { } } -int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) { +int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; for (auto& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) @@ -1270,7 +1270,7 @@ int CCompositor::getWindowsOnWorkspace(const int& id, std::optional onlyTi return no; } -int CCompositor::getGroupsOnWorkspace(const int& id, std::optional onlyTiled, std::optional onlyVisible) { +int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; for (auto& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) @@ -1295,7 +1295,7 @@ PHLWINDOW CCompositor::getUrgentWindow() { return nullptr; } -bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { +bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) return true; @@ -1304,7 +1304,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const int& id) { return false; } -PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) { +PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) return w; @@ -1313,7 +1313,7 @@ PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const int& id) { return nullptr; } -PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const int& id) { +PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); if (!PWORKSPACE) @@ -1401,12 +1401,12 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { } } -void CCompositor::cleanupFadingOut(const int& monid) { +void CCompositor::cleanupFadingOut(const MONITORID& monid) { for (auto& ww : m_vWindowsFadingOut) { auto w = ww.lock(); - if (w->m_iMonitorID != (long unsigned int)monid) + if (w->m_iMonitorID != monid) continue; if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { @@ -1702,8 +1702,8 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return nullptr; } -int CCompositor::getNextAvailableNamedWorkspace() { - int lowest = -1337 + 1; +WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { + WORKSPACEID lowest = -1337 + 1; for (auto& w : m_vWorkspaces) { if (w->m_iID < -1 && w->m_iID < lowest) lowest = w->m_iID; @@ -1927,18 +1927,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->updateWindowDecos(); } -int CCompositor::getNextAvailableMonitorID(std::string const& name) { +MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) return m_mMonitorIDMap[name]; // otherwise, find minimum available ID that is not in the map - std::unordered_set usedIDs; + std::unordered_set usedIDs; for (auto const& monitor : m_vRealMonitors) { usedIDs.insert(monitor->ID); } - uint64_t nextID = 0; + MONITORID nextID = 0; while (usedIDs.count(nextID) > 0) { nextID++; } @@ -2078,7 +2078,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return m_vMonitors[currentPlace].get(); } else if (isNumber(name)) { // change by ID - int monID = -1; + MONITORID monID = MONITOR_INVALID; try { monID = std::stoi(name); } catch (std::exception& e) { @@ -2087,7 +2087,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return nullptr; } - if (monID > -1 && monID < (int)m_vMonitors.size()) { + if (monID > -1 && monID < (MONITORID)m_vMonitors.size()) { return getMonitorFromID(monID); } else { Debug::log(ERR, "Error in getMonitorFromString: invalid arg 1"); @@ -2121,7 +2121,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false; // fix old mon - int nextWorkspaceOnMonitorID = -1; + WORKSPACEID nextWorkspaceOnMonitorID = WORKSPACE_INVALID; if (!SWITCHINGISACTIVE) nextWorkspaceOnMonitorID = pWorkspace->m_iID; else { @@ -2132,7 +2132,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon } } - if (nextWorkspaceOnMonitorID == -1) { + if (nextWorkspaceOnMonitorID == WORKSPACE_INVALID) { nextWorkspaceOnMonitorID = 1; while (getWorkspaceByID(nextWorkspaceOnMonitorID) || [&]() -> bool { @@ -2219,9 +2219,9 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon EMIT_HOOK_EVENT("moveWorkspace", (std::vector{pWorkspace, pMonitor})); } -bool CCompositor::workspaceIDOutOfBounds(const int64_t& id) { - int64_t lowestID = INT64_MAX; - int64_t highestID = INT64_MIN; +bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { + WORKSPACEID lowestID = INT64_MAX; + WORKSPACEID highestID = INT64_MIN; for (auto& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) @@ -2370,7 +2370,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { return nullptr; } -void CCompositor::updateWorkspaceWindowDecos(const int& id) { +void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) { for (auto& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2379,7 +2379,7 @@ void CCompositor::updateWorkspaceWindowDecos(const int& id) { } } -void CCompositor::updateWorkspaceWindowData(const int& id) { +void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; @@ -2599,7 +2599,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con return Vector2D(X, Y); } -void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { +void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { for (auto& w : m_vWindows) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); @@ -2607,7 +2607,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const int& wid) { } } -PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, const std::string& name, bool isEmtpy) { +PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2625,7 +2625,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const int& id, const int& monid, co return PWORKSPACE; } -void CCompositor::renameWorkspace(const int& id, const std::string& name) { +void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) { const auto PWORKSPACE = getWorkspaceByID(id); if (!PWORKSPACE) @@ -2656,12 +2656,12 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) { m_pLastMonitor = pMonitor->self; } -bool CCompositor::isWorkspaceSpecial(const int& id) { +bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) { return id >= SPECIAL_WORKSPACE_START && id <= -2; } -int CCompositor::getNewSpecialID() { - int highest = SPECIAL_WORKSPACE_START; +WORKSPACEID CCompositor::getNewSpecialID() { + WORKSPACEID highest = SPECIAL_WORKSPACE_START; for (auto& ws : m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) { highest = ws->m_iID; @@ -2965,7 +2965,7 @@ void CCompositor::onNewMonitor(SP output) { PNEWMONITOR->output = output; PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; - PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(output->name); + PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name); PNEWMONITOR->isUnsafeFallback = FALLBACK; EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR); @@ -2990,7 +2990,7 @@ void CCompositor::onNewMonitor(SP output) { for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { - w->m_iLastSurfaceMonitorID = -1; + w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->updateSurfaceScaleTransformDetails(); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 295935c4..5e9e3266 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -46,55 +46,55 @@ class CCompositor { CCompositor(); ~CCompositor(); - wl_display* m_sWLDisplay; - wl_event_loop* m_sWLEventLoop; - int m_iDRMFD = -1; - bool m_bInitialized = false; - SP m_pAqBackend; + wl_display* m_sWLDisplay; + wl_event_loop* m_sWLEventLoop; + int m_iDRMFD = -1; + bool m_bInitialized = false; + SP m_pAqBackend; - std::string m_szHyprTempDataRoot = ""; + std::string m_szHyprTempDataRoot = ""; - std::string m_szWLDisplaySocket = ""; - std::string m_szInstanceSignature = ""; - std::string m_szInstancePath = ""; - std::string m_szCurrentSplash = "error"; + std::string m_szWLDisplaySocket = ""; + std::string m_szInstanceSignature = ""; + std::string m_szInstancePath = ""; + std::string m_szCurrentSplash = "error"; - std::vector> m_vMonitors; - std::vector> m_vRealMonitors; // for all monitors, even those turned off - std::vector m_vWindows; - std::vector m_vLayers; - std::vector m_vWorkspaces; - std::vector m_vWindowsFadingOut; - std::vector m_vSurfacesFadingOut; + std::vector> m_vMonitors; + std::vector> m_vRealMonitors; // for all monitors, even those turned off + std::vector m_vWindows; + std::vector m_vLayers; + std::vector m_vWorkspaces; + std::vector m_vWindowsFadingOut; + std::vector m_vSurfacesFadingOut; - std::unordered_map m_mMonitorIDMap; + std::unordered_map m_mMonitorIDMap; - void initServer(std::string socketName, int socketFd); - void startCompositor(); - void stopCompositor(); - void cleanup(); - void createLockFile(); - void removeLockFile(); - void bumpNofile(); - void restoreNofile(); + void initServer(std::string socketName, int socketFd); + void startCompositor(); + void stopCompositor(); + void cleanup(); + void createLockFile(); + void removeLockFile(); + void bumpNofile(); + void restoreNofile(); - WP m_pLastFocus; - PHLWINDOWREF m_pLastWindow; - WP m_pLastMonitor; + WP m_pLastFocus; + PHLWINDOWREF m_pLastWindow; + WP m_pLastMonitor; - std::vector m_vWindowFocusHistory; // first element is the most recently focused. + std::vector m_vWindowFocusHistory; // first element is the most recently focused. - bool m_bReadyToProcess = false; - bool m_bSessionActive = true; - bool m_bDPMSStateON = true; - bool m_bUnsafeState = false; // unsafe state is when there is no monitors. - bool m_bNextIsUnsafe = false; - CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state - bool m_bIsShuttingDown = false; + bool m_bReadyToProcess = false; + bool m_bSessionActive = true; + bool m_bDPMSStateON = true; + bool m_bUnsafeState = false; // unsafe state is when there is no monitors. + bool m_bNextIsUnsafe = false; + CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state + bool m_bIsShuttingDown = false; // ------------------------------------------------- // - CMonitor* getMonitorFromID(const int&); + CMonitor* getMonitorFromID(const MONITORID&); CMonitor* getMonitorFromName(const std::string&); CMonitor* getMonitorFromDesc(const std::string&); CMonitor* getMonitorFromCursor(); @@ -114,38 +114,38 @@ class CCompositor { PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); - PHLWORKSPACE getWorkspaceByID(const int&); + PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&); void sanityCheckWorkspaces(); - void updateWorkspaceWindowDecos(const int&); - void updateWorkspaceWindowData(const int&); - int getWindowsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroupsOnWorkspace(const int& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + void updateWorkspaceWindowDecos(const WORKSPACEID&); + void updateWorkspaceWindowData(const WORKSPACEID&); + int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); PHLWINDOW getUrgentWindow(); - bool hasUrgentWindowOnWorkspace(const int&); - PHLWINDOW getFirstWindowOnWorkspace(const int&); - PHLWINDOW getTopLeftWindowOnWorkspace(const int&); - PHLWINDOW getFullscreenWindowOnWorkspace(const int&); + bool hasUrgentWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&); + PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&); bool isWindowActive(PHLWINDOW); void changeWindowZOrder(PHLWINDOW, bool); - void cleanupFadingOut(const int& monid); + void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); - int getNextAvailableNamedWorkspace(); + WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); CMonitor* getMonitorInDirection(const char&); CMonitor* getMonitorInDirection(CMonitor*, const char&); void updateAllWindowsAnimatedDecorationValues(); - void updateWorkspaceWindows(const int64_t& id); + void updateWorkspaceWindows(const WORKSPACEID& id); void updateWindowAnimatedDecorationValues(PHLWINDOW); - int getNextAvailableMonitorID(std::string const& name); + MONITORID getNextAvailableMonitorID(std::string const& name); void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); void swapActiveWorkspaces(CMonitor*, CMonitor*); CMonitor* getMonitorFromString(const std::string&); - bool workspaceIDOutOfBounds(const int64_t&); + bool workspaceIDOutOfBounds(const WORKSPACEID&); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenState(const PHLWINDOW PWINDOW, const sFullscreenState state); @@ -162,12 +162,13 @@ class CCompositor { PHLLS getLayerSurfaceFromSurface(SP); void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - void forceReportSizesToWindowsOnWorkspace(const int&); - PHLWORKSPACE createNewWorkspace(const int&, const int&, const std::string& name = "", bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! - void renameWorkspace(const int&, const std::string& name = ""); + void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&); + PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", + bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void setActiveMonitor(CMonitor*); - bool isWorkspaceSpecial(const int&); - int getNewSpecialID(); + bool isWorkspaceSpecial(const WORKSPACEID&); + WORKSPACEID getNewSpecialID(); void performUserChecks(); void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace); PHLWINDOW getForceFocus(); diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index 2a1546c6..9bee7150 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -52,4 +52,8 @@ struct SHyprCtlCommand { std::function fn; }; +typedef int64_t WINDOWID; +typedef int64_t MONITORID; +typedef int64_t WORKSPACEID; + typedef std::function HOOK_CALLBACK_FN; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index be6433fa..1a823f3e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2425,7 +2425,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin // } const static std::string ruleOnCreatedEmpty = "on-created-empty:"; - const static int ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); + const static auto ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); auto assignRule = [&](std::string rule) -> std::optional { size_t delim = std::string::npos; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 75dea9ef..38dd0872 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -33,7 +33,7 @@ struct SWorkspaceRule { std::string monitor = ""; std::string workspaceString = ""; std::string workspaceName = ""; - int workspaceId = -1; + WORKSPACEID workspaceId = -1; bool isDefault = false; bool isPersistent = false; std::optional gapsIn; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d91a1cec..3ab0fa7a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -71,7 +71,7 @@ static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFor std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m, eHyprCtlOutputFormat format) { std::string result; - if (!m->output || m->ID == -1ull) + if (!m->output || m->ID == -1) return ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { @@ -155,7 +155,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { - if (!m->output || m->ID == -1ull) + if (!m->output || m->ID == -1) continue; result += diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8fd448ef..c352fa74 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -432,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) { PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, }; - float closest = std::numeric_limits::max(); - int leader = force; + float closest = std::numeric_limits::max(); + size_t leader = force; if (leader == -1) { for (size_t i = 0; i < 4; ++i) { float dist = MIDDLE.distance(edgePoints[i]); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 056f66a8..84935b34 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -42,7 +42,7 @@ class CLayerSurface { bool mapped = false; uint32_t layer = 0; - int monitorID = -1; + MONITORID monitorID = -1; bool fadingOut = false; bool readyToDelete = false; @@ -51,7 +51,7 @@ class CLayerSurface { bool forceBlur = false; bool forceBlurPopups = false; - int xray = -1; + int64_t xray = -1; bool ignoreAlpha = false; float ignoreAlphaValue = 0.f; bool dimAround = false; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 93c208cf..dcdcb573 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1243,7 +1243,7 @@ bool CWindow::isEffectiveInternalFSMode(const eFullscreenMode MODE) { return (eFullscreenMode)std::bit_floor((uint8_t)m_sFullscreenState.internal) == MODE; } -int CWindow::workspaceID() { +WORKSPACEID CWindow::workspaceID() { return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 11bf662a..2e5b54b1 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -270,7 +270,7 @@ class CWindow { bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bWasMaximized = false; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; - uint64_t m_iMonitorID = -1; + MONITORID m_iMonitorID = -1; std::string m_szTitle = ""; std::string m_szClass = ""; std::string m_szInitialTitle = ""; @@ -358,8 +358,8 @@ class CWindow { bool m_bStayFocused = false; // for toplevel monitor events - uint64_t m_iLastToplevelMonitorID = -1; - uint64_t m_iLastSurfaceMonitorID = -1; + MONITORID m_iLastToplevelMonitorID = -1; + MONITORID m_iLastSurfaceMonitorID = -1; // for idle inhibiting windows eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; @@ -421,7 +421,7 @@ class CWindow { bool canBeTorn(); void setSuspended(bool suspend); bool visibleOnMonitor(CMonitor* pMonitor); - int workspaceID(); + WORKSPACEID workspaceID(); bool onSpecialWorkspace(); void activate(bool force = false); int surfacesCount(); @@ -490,9 +490,9 @@ class CWindow { private: // For hidden windows and stuff - bool m_bHidden = false; - bool m_bSuspended = false; - int m_iLastWorkspace = WORKSPACE_INVALID; + bool m_bHidden = false; + bool m_bSuspended = false; + WORKSPACEID m_iLastWorkspace = WORKSPACE_INVALID; }; inline bool valid(PHLWINDOW w) { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index a08f1804..d9ac7927 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -5,13 +5,13 @@ #include using namespace Hyprutils::String; -PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { +PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(int id, int monitorID, std::string name, bool special, bool isEmtpy) { +CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { m_iMonitorID = monitorID; m_iID = id; m_szName = name; @@ -190,7 +190,7 @@ void CWorkspace::setActive(bool on) { ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 } -void CWorkspace::moveToMonitor(const int& id) { +void CWorkspace::moveToMonitor(const MONITORID& id) { ; // empty until https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/40 } @@ -275,7 +275,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { i = std::min(NEXTSPACE, std::string::npos - 1); if (cur == 'r') { - int from = 0, to = 0; + WORKSPACEID from = 0, to = 0; if (!prop.starts_with("r[") || !prop.ends_with("]")) { Debug::log(LOG, "Invalid selector {}", selector); return false; @@ -365,7 +365,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { } if (cur == 'w') { - int from = 0, to = 0; + WORKSPACEID from = 0, to = 0; if (!prop.starts_with("w[") || !prop.ends_with("]")) { Debug::log(LOG, "Invalid selector {}", selector); return false; @@ -446,7 +446,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { return false; } - int count; + WORKSPACEID count; if (wantsCountGroup) count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); @@ -506,7 +506,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { void CWorkspace::markInert() { m_bInert = true; m_iID = WORKSPACE_INVALID; - m_iMonitorID = -1; + m_iMonitorID = MONITOR_INVALID; m_bVisible = false; } diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 3e9ac8a8..9cacb0cc 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -17,16 +17,16 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(int id, int monitorID, std::string name, bool special = false, bool isEmtpy = true); + static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true); // use create() don't use this - CWorkspace(int id, int monitorID, std::string name, bool special = false, bool isEmpty = true); + CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); // Workspaces ID-based have IDs > 0 // and workspaces name-based have IDs starting with -1337 - int m_iID = -1; + WORKSPACEID m_iID = WORKSPACE_INVALID; std::string m_szName = ""; - uint64_t m_iMonitorID = -1; + MONITORID m_iMonitorID = MONITOR_INVALID; // Previous workspace ID and name is stored during a workspace change, allowing travel // to the previous workspace. SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; @@ -67,7 +67,7 @@ class CWorkspace { void startAnim(bool in, bool left, bool instant = false); void setActive(bool on); - void moveToMonitor(const int&); + void moveToMonitor(const MONITORID&); PHLWINDOW getLastFocusedWindow(); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 5d29a3b7..2eb7038f 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -148,7 +148,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_iMonitorID = PMONITOR->ID; } else { if (isNumber(MONITORSTR)) { - const long int MONITOR = std::stoi(MONITORSTR); + const MONITORID MONITOR = std::stoi(MONITORSTR); if (!g_pCompositor->getMonitorFromID(MONITOR)) PWINDOW->m_iMonitorID = 0; else diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 53c0dc13..a81aa7d1 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -249,7 +249,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { return {WORKSPACE_INVALID}; } - std::set invalidWSes; + std::set invalidWSes; if (same_mon) { for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); @@ -258,8 +258,8 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } } - int id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; - while (++id < INT_MAX) { + WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; + while (++id < LONG_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) { result.id = id; @@ -296,9 +296,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = (int)PLUSMINUSRESULT.value(); - int remains = (int)result.id; + WORKSPACEID remains = result.id; - std::set invalidWSes; + std::set invalidWSes; // Collect all the workspaces we can't jump to. for (auto& ws : g_pCompositor->m_vWorkspaces) { @@ -318,7 +318,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } // Prepare all named workspaces in case when we need them - std::vector namedWSes; + std::vector namedWSes; for (auto& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) continue; @@ -347,18 +347,18 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } else { // Just take a blind guess at where we'll probably end up - int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; - int predictedWSID = activeWSID + remains; - int remainingWSes = 0; - char walkDir = in[1]; + WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; + WORKSPACEID predictedWSID = activeWSID + remains; + int remainingWSes = 0; + char walkDir = in[1]; // sanitize. 0 means invalid oob in - - predictedWSID = std::max(predictedWSID, 0); + predictedWSID = std::max(predictedWSID, 0L); // Count how many invalidWSes are in between (how bad the prediction was) - int beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; - int endID = in[1] == '+' ? predictedWSID : activeWSID; - auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= + WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; + WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID; + auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { remainingWSes++; } @@ -367,7 +367,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (activeWSID < 0) { // Behaviour similar to 'm' // Find current - int currentItem = -1; + size_t currentItem = -1; for (size_t i = 0; i < namedWSes.size(); i++) { if (namedWSes[i] == activeWSID) { currentItem = i; @@ -376,14 +376,14 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } currentItem += remains; - currentItem = std::max(currentItem, 0); - if (currentItem >= (int)namedWSes.size()) { + currentItem = std::max(currentItem, 0UL); + if (currentItem >= namedWSes.size()) { // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0 - int diff = currentItem - (namedWSes.size() - 1); - predictedWSID = diff; - int beginID = 1; - int endID = predictedWSID; - auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= + size_t diff = currentItem - (namedWSes.size() - 1); + predictedWSID = diff; + WORKSPACEID beginID = 1; + WORKSPACEID endID = predictedWSID; + auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { remainingWSes++; } @@ -397,10 +397,10 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Go in the search direction for remainingWSes // The performance impact is directly proportional to the number of open and bound workspaces - int finalWSID = predictedWSID; + WORKSPACEID finalWSID = predictedWSID; if (walkDir == '-') { - int beginID = finalWSID; - int curID = finalWSID; + WORKSPACEID beginID = finalWSID; + WORKSPACEID curID = finalWSID; while (--curID > 0 && remainingWSes > 0) { if (!invalidWSes.contains(curID)) { remainingWSes--; @@ -411,9 +411,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (namedWSes.size()) { // Go to the named workspaces // Need remainingWSes more - int namedWSIdx = namedWSes.size() - remainingWSes; + auto namedWSIdx = namedWSes.size() - remainingWSes; // Sanitze - namedWSIdx = std::clamp(namedWSIdx, 0, (int)namedWSes.size() - 1); + namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1); finalWSID = namedWSes[namedWSIdx]; } else { // Couldn't find valid workspace in negative direction, search last first one back up positive direction @@ -425,7 +425,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } } if (walkDir == '+') { - int curID = finalWSID; + WORKSPACEID curID = finalWSID; while (++curID < INT32_MAX && remainingWSes > 0) { if (!invalidWSes.contains(curID)) { remainingWSes--; @@ -460,9 +460,9 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { result.id = (int)PLUSMINUSRESULT.value(); // result now has +/- what we should move on mon - int remains = (int)result.id; + int remains = (int)result.id; - std::vector validWSes; + std::vector validWSes; for (auto& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) continue; @@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::sort(validWSes.begin(), validWSes.end()); - int currentItem = -1; + size_t currentItem = -1; if (absolute) { // 1-index @@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // clamp if (currentItem < 0) { currentItem = 0; - } else if (currentItem >= (int)validWSes.size()) { + } else if (currentItem >= validWSes.size()) { currentItem = validWSes.size() - 1; } } else { @@ -489,7 +489,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { remains = remains < 0 ? -((-remains) % validWSes.size()) : remains % validWSes.size(); // get the current item - int activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; + WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; for (size_t i = 0; i < validWSes.size(); i++) { if (validWSes[i] == activeWSID) { currentItem = i; @@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { currentItem += remains; // sanitize - if (currentItem >= (int)validWSes.size()) { + if (currentItem >= validWSes.size()) { currentItem = currentItem % validWSes.size(); } else if (currentItem < 0) { currentItem = validWSes.size() + currentItem; @@ -547,9 +547,9 @@ std::optional cleanCmdForWorkspace(const std::string& inWorkspaceNa const std::string workspaceRule = "workspace " + inWorkspaceName; if (cmd[0] == '[') { - const int closingBracketIdx = cmd.find_last_of(']'); - auto tmpRules = cmd.substr(1, closingBracketIdx - 1); - cmd = cmd.substr(closingBracketIdx + 1); + const auto closingBracketIdx = cmd.find_last_of(']'); + auto tmpRules = cmd.substr(1, closingBracketIdx - 1); + cmd = cmd.substr(closingBracketIdx + 1); auto rulesList = CVarList(tmpRules, 0, ';'); @@ -785,13 +785,13 @@ std::vector getBacktrace() { #ifdef HAS_EXECINFO void* bt[1024]; - size_t btSize; + int btSize; char** btSymbols; btSize = backtrace(bt, 1024); btSymbols = backtrace_symbols(bt, btSize); - for (size_t i = 0; i < btSize; ++i) { + for (auto i = 0; i < btSize; ++i) { callstack.emplace_back(SCallstackFrameInfo{bt[i], std::string{btSymbols[i]}}); } #else diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 49e3bced..7eb2a1ed 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -6,6 +6,8 @@ #include "math/Math.hpp" #include #include +#include "SharedDefs.hpp" +#include "macros.hpp" struct SCallstackFrameInfo { void* adr = nullptr; @@ -13,7 +15,7 @@ struct SCallstackFrameInfo { }; struct SWorkspaceIDName { - int id = -1; + WORKSPACEID id = WORKSPACE_INVALID; std::string name; }; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8f23c462..f6b61d57 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -389,8 +389,8 @@ bool CMonitor::matchesStaticSelector(const std::string& selector) const { } } -int CMonitor::findAvailableDefaultWS() { - for (size_t i = 1; i < INT32_MAX; ++i) { +WORKSPACEID CMonitor::findAvailableDefaultWS() { + for (WORKSPACEID i = 1; i < LONG_MAX; ++i) { if (g_pCompositor->getWorkspaceByID(i)) continue; @@ -400,7 +400,7 @@ int CMonitor::findAvailableDefaultWS() { return i; } - return INT32_MAX; // shouldn't be reachable + return LONG_MAX; // shouldn't be reachable } void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { @@ -638,7 +638,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo g_pCompositor->updateFullscreenFadeOnWorkspace(activeSpecialWorkspace); } -void CMonitor::changeWorkspace(const int& id, bool internal, bool noMouseMove, bool noFocus) { +void CMonitor::changeWorkspace(const WORKSPACEID& id, bool internal, bool noMouseMove, bool noFocus) { changeWorkspace(g_pCompositor->getWorkspaceByID(id), internal, noMouseMove, noFocus); } @@ -745,7 +745,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pCompositor->updateSuspendedStates(); } -void CMonitor::setSpecialWorkspace(const int& id) { +void CMonitor::setSpecialWorkspace(const WORKSPACEID& id) { setSpecialWorkspace(g_pCompositor->getWorkspaceByID(id)); } @@ -766,11 +766,11 @@ void CMonitor::updateMatrix() { } } -int64_t CMonitor::activeWorkspaceID() { +WORKSPACEID CMonitor::activeWorkspaceID() { return activeWorkspace ? activeWorkspace->m_iID : 0; } -int64_t CMonitor::activeSpecialWorkspaceID() { +WORKSPACEID CMonitor::activeSpecialWorkspaceID() { return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index fbe26f67..7429ecf1 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -70,7 +70,7 @@ class CMonitor { bool primary = false; - uint64_t ID = -1; + MONITORID ID = MONITOR_INVALID; PHLWORKSPACE activeWorkspace = nullptr; PHLWORKSPACE activeSpecialWorkspace = nullptr; float setScale = 1; // scale set by cfg @@ -155,31 +155,31 @@ class CMonitor { std::array, 4> m_aLayerSurfaceLayers; // methods - void onConnect(bool noRule); - void onDisconnect(bool destroy = false); - void addDamage(const pixman_region32_t* rg); - void addDamage(const CRegion* rg); - void addDamage(const CBox* box); - bool shouldSkipScheduleFrameOnMouseEvent(); - void setMirror(const std::string&); - bool isMirror(); - bool matchesStaticSelector(const std::string& selector) const; - float getDefaultScale(); - void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); - void changeWorkspace(const int& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); - void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace); - void setSpecialWorkspace(const int& id); - void moveTo(const Vector2D& pos); - Vector2D middle(); - void updateMatrix(); - int64_t activeWorkspaceID(); - int64_t activeSpecialWorkspaceID(); - CBox logicalBox(); - void scheduleDone(); - bool attemptDirectScanout(); + void onConnect(bool noRule); + void onDisconnect(bool destroy = false); + void addDamage(const pixman_region32_t* rg); + void addDamage(const CRegion* rg); + void addDamage(const CBox* box); + bool shouldSkipScheduleFrameOnMouseEvent(); + void setMirror(const std::string&); + bool isMirror(); + bool matchesStaticSelector(const std::string& selector) const; + float getDefaultScale(); + void changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal = false, bool noMouseMove = false, bool noFocus = false); + void changeWorkspace(const WORKSPACEID& id, bool internal = false, bool noMouseMove = false, bool noFocus = false); + void setSpecialWorkspace(const PHLWORKSPACE& pWorkspace); + void setSpecialWorkspace(const WORKSPACEID& id); + void moveTo(const Vector2D& pos); + Vector2D middle(); + void updateMatrix(); + WORKSPACEID activeWorkspaceID(); + WORKSPACEID activeSpecialWorkspaceID(); + CBox logicalBox(); + void scheduleDone(); + bool attemptDirectScanout(); - bool m_bEnabled = false; - bool m_bRenderingInitPassed = false; + bool m_bEnabled = false; + bool m_bRenderingInitPassed = false; // For the list lookup @@ -189,7 +189,7 @@ class CMonitor { private: void setupDefaultWS(const SMonitorRule&); - int findAvailableDefaultWS(); + WORKSPACEID findAvailableDefaultWS(); wl_event_source* doneSource = nullptr; diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp index ec530df4..7b1726df 100644 --- a/src/helpers/Timer.cpp +++ b/src/helpers/Timer.cpp @@ -8,7 +8,7 @@ std::chrono::steady_clock::duration CTimer::getDuration() { return std::chrono::steady_clock::now() - m_tpLastReset; } -int CTimer::getMillis() { +long CTimer::getMillis() { return std::chrono::duration_cast(getDuration()).count(); } diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp index a6d1aeed..827e7625 100644 --- a/src/helpers/Timer.hpp +++ b/src/helpers/Timer.hpp @@ -6,7 +6,7 @@ class CTimer { public: void reset(); float getSeconds(); - int getMillis(); + long getMillis(); const std::chrono::steady_clock::time_point& chrono() const; private: diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index f287056f..acdc3de2 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -47,7 +47,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD } } -int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { +int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) { int no = 0; for (auto& n : m_lDwindleNodesData) { if (n.workspaceID == id && n.valid) @@ -56,7 +56,7 @@ int CHyprDwindleLayout::getNodesOnWorkspace(const int& id) { return no; } -SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) { +SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const WORKSPACEID& id) { for (auto& n : m_lDwindleNodesData) { if (n.workspaceID == id && validMapped(n.pWindow)) return &n; @@ -64,7 +64,7 @@ SDwindleNodeData* CHyprDwindleLayout::getFirstNodeOnWorkspace(const int& id) { return nullptr; } -SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const int& id, const Vector2D& point) { +SDwindleNodeData* CHyprDwindleLayout::getClosestNodeOnWorkspace(const WORKSPACEID& id, const Vector2D& point) { SDwindleNodeData* res = nullptr; double distClosest = -1; for (auto& n : m_lDwindleNodesData) { @@ -88,7 +88,7 @@ SDwindleNodeData* CHyprDwindleLayout::getNodeFromWindow(PHLWINDOW pWindow) { return nullptr; } -SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const int& id) { +SDwindleNodeData* CHyprDwindleLayout::getMasterNodeOnWorkspace(const WORKSPACEID& id) { for (auto& n : m_lDwindleNodesData) { if (!n.pParent && n.workspaceID == id) return &n; @@ -535,7 +535,7 @@ void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { m_lDwindleNodesData.remove(*PNODE); } -void CHyprDwindleLayout::recalculateMonitor(const int& monid) { +void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); if (!PMONITOR || !PMONITOR->activeWorkspace) @@ -872,7 +872,7 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, return; const auto PNODE = getNodeFromWindow(pWindow); - const int originalWorkspaceID = pWindow->workspaceID(); + const auto originalWorkspaceID = pWindow->workspaceID(); const Vector2D originalPos = pWindow->middle(); if (!PNODE) diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index f638f6a2..bbd511c2 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -24,7 +24,7 @@ struct SDwindleNodeData { CBox box = {0}; - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; float splitRatio = 1.f; @@ -48,7 +48,7 @@ class CHyprDwindleLayout : public IHyprLayout { virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowRemovedTiling(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW); - virtual void recalculateMonitor(const int&); + virtual void recalculateMonitor(const MONITORID&); virtual void recalculateWindow(PHLWINDOW); virtual void onBeginDragWindow(); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); @@ -77,13 +77,13 @@ class CHyprDwindleLayout : public IHyprLayout { std::optional m_vOverrideFocalPoint; // for onWindowCreatedTiling. - int getNodesOnWorkspace(const int&); + int getNodesOnWorkspace(const WORKSPACEID&); void applyNodeDataToWindow(SDwindleNodeData*, bool force = false); void calculateWorkspace(const PHLWORKSPACE& pWorkspace); SDwindleNodeData* getNodeFromWindow(PHLWINDOW); - SDwindleNodeData* getFirstNodeOnWorkspace(const int&); - SDwindleNodeData* getClosestNodeOnWorkspace(const int&, const Vector2D&); - SDwindleNodeData* getMasterNodeOnWorkspace(const int&); + SDwindleNodeData* getFirstNodeOnWorkspace(const WORKSPACEID&); + SDwindleNodeData* getClosestNodeOnWorkspace(const WORKSPACEID&, const Vector2D&); + SDwindleNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&); void toggleSplit(PHLWINDOW); void swapSplit(PHLWINDOW); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 4b1b59e3..7e0d5704 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -63,7 +63,7 @@ class IHyprLayout { Called when the monitor requires a layout recalculation this usually means reserved area changes */ - virtual void recalculateMonitor(const int&) = 0; + virtual void recalculateMonitor(const MONITORID&) = 0; /* Called when the compositor requests a window diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index be00168f..aa1c0adf 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -14,7 +14,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) { return nullptr; } -int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) { +int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int no = 0; for (auto& n : m_lMasterNodesData) { if (n.workspaceID == ws) @@ -24,7 +24,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const int& ws) { return no; } -int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) { +int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) { int no = 0; for (auto& n : m_lMasterNodesData) { if (n.workspaceID == ws && n.isMaster) @@ -34,7 +34,7 @@ int CHyprMasterLayout::getMastersOnWorkspace(const int& ws) { return no; } -SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const int& ws) { +SMasterWorkspaceData* CHyprMasterLayout::getMasterWorkspaceData(const WORKSPACEID& ws) { for (auto& n : m_lMasterWorkspacesData) { if (n.workspaceID == ws) return &n; @@ -63,7 +63,7 @@ std::string CHyprMasterLayout::getLayoutName() { return "Master"; } -SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const int& ws) { +SMasterNodeData* CHyprMasterLayout::getMasterNodeOnWorkspace(const WORKSPACEID& ws) { for (auto& n : m_lMasterNodesData) { if (n.isMaster && n.workspaceID == ws) return &n; @@ -304,7 +304,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { recalculateMonitor(pWindow->m_iMonitorID); } -void CHyprMasterLayout::recalculateMonitor(const int& monid) { +void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) { const auto PMONITOR = g_pCompositor->getMonitorFromID(monid); if (!PMONITOR || !PMONITOR->activeWorkspace) diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index fdb916e5..b72be74f 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -30,7 +30,7 @@ struct SMasterNodeData { float percSize = 1.f; // size multiplier for resizing children - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; bool ignoreFullscreenChecks = false; @@ -41,7 +41,7 @@ struct SMasterNodeData { }; struct SMasterWorkspaceData { - int workspaceID = -1; + WORKSPACEID workspaceID = WORKSPACE_INVALID; eOrientation orientation = ORIENTATION_LEFT; // @@ -55,7 +55,7 @@ class CHyprMasterLayout : public IHyprLayout { virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowRemovedTiling(PHLWINDOW); virtual bool isWindowTiled(PHLWINDOW); - virtual void recalculateMonitor(const int&); + virtual void recalculateMonitor(const MONITORID&); virtual void recalculateWindow(PHLWINDOW); virtual void resizeActiveWindow(const Vector2D&, eRectCorner corner = CORNER_NONE, PHLWINDOW pWindow = nullptr); virtual void fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE); @@ -81,14 +81,14 @@ class CHyprMasterLayout : public IHyprLayout { void buildOrientationCycleVectorFromEOperation(std::vector& cycle); void runOrientationCycle(SLayoutMessageHeader& header, CVarList* vars, int next); eOrientation getDynamicOrientation(PHLWORKSPACE); - int getNodesOnWorkspace(const int&); + int getNodesOnWorkspace(const WORKSPACEID&); void applyNodeDataToWindow(SMasterNodeData*); SMasterNodeData* getNodeFromWindow(PHLWINDOW); - SMasterNodeData* getMasterNodeOnWorkspace(const int&); - SMasterWorkspaceData* getMasterWorkspaceData(const int&); + SMasterNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&); + SMasterWorkspaceData* getMasterWorkspaceData(const WORKSPACEID&); void calculateWorkspace(PHLWORKSPACE); PHLWINDOW getNextWindow(PHLWINDOW, bool); - int getMastersOnWorkspace(const int&); + int getMastersOnWorkspace(const WORKSPACEID&); friend struct SMasterNodeData; friend struct SMasterWorkspaceData; diff --git a/src/macros.hpp b/src/macros.hpp index b2adb036..44014085 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -27,6 +27,8 @@ #define WORKSPACE_INVALID -1L #define WORKSPACE_NOT_CHANGED -101 +#define MONITOR_INVALID -1L + #define LISTENER(name) \ void listener_##name(wl_listener*, void*); \ inline wl_listener listen_##name = {.notify = listener_##name} diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c7b93730..d4bac507 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1738,7 +1738,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { return; } - const int WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; + const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); @@ -1756,7 +1756,7 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { } void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { - int workspaceID = getWorkspaceIDNameFromString(args).id; + auto workspaceID = getWorkspaceIDNameFromString(args).id; if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); return; @@ -1816,7 +1816,7 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { bool requestedWorkspaceIsAlreadyOpen = false; const auto PMONITOR = g_pCompositor->m_pLastMonitor; - int specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); + auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); for (auto& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == workspaceID) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index c2c088f8..041e7101 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -76,8 +76,8 @@ void CEventLoopManager::removeTimer(SP timer) { } static void timespecAddNs(timespec* pTimespec, int64_t delta) { - int delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC; - int delta_s_high = delta / TIMESPEC_NSEC_PER_SEC; + auto delta_ns_low = delta % TIMESPEC_NSEC_PER_SEC; + auto delta_s_high = delta / TIMESPEC_NSEC_PER_SEC; pTimespec->tv_sec += delta_s_high; diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index f6e5c8be..f8e4b962 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -33,7 +33,7 @@ class CInputPopup { WP popup; SP surface; CBox lastBoxLocal; - uint64_t lastMonitor = -1; + MONITORID lastMonitor = MONITOR_INVALID; struct { CHyprSignalListener map; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index c0e6c4f0..6ee690cd 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -77,7 +77,7 @@ void CInputManager::endWorkspaceSwipe() { // left of where we started. Instead, it's one more than the greatest // workspace ID that currently exists. if (workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID && *PSWIPENEW) { - int maxWorkspace = 0; + WORKSPACEID maxWorkspace = 0; for (const auto& ws : g_pCompositor->m_vWorkspaces) { maxWorkspace = std::max(maxWorkspace, ws->m_iID); } diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 295834ea..b31a4083 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -119,7 +119,7 @@ wl_resource* CForeignToplevelHandleWlr::res() { } void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { - if (lastMonitorID == (int64_t)pMonitor->ID) + if (lastMonitorID == pMonitor->ID) return; const auto CLIENT = resource->client(); diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp index e3b6f3f3..99f63b47 100644 --- a/src/protocols/ForeignToplevelWlr.hpp +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -20,7 +20,7 @@ class CForeignToplevelHandleWlr { SP resource; PHLWINDOWREF pWindow; bool closed = false; - int64_t lastMonitorID = -1; + MONITORID lastMonitorID = MONITOR_INVALID; void sendMonitor(CMonitor* pMonitor); void sendState(); diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 67629e23..c48ff6f3 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -12,9 +12,10 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); uint32_t glType = FormatUtils::glFormatToType(glFormat); - if (m_iFb == (uint32_t)-1) { + if (!m_iFbAllocated) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); + m_iFbAllocated = true; } if (m_cTex->m_iTexID == 0) { @@ -88,12 +89,12 @@ void CFramebuffer::bind() { } void CFramebuffer::release() { - if (m_iFb != (uint32_t)-1 && m_iFb) + if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); m_cTex->destroyTexture(); - m_iFb = -1; - m_vSize = Vector2D(); + m_iFbAllocated = false; + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { @@ -101,5 +102,5 @@ CFramebuffer::~CFramebuffer() { } bool CFramebuffer::isAllocated() { - return m_iFb != (GLuint)-1; + return m_iFbAllocated; } \ No newline at end of file diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index a46a4859..ca7f9e8a 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -18,7 +18,8 @@ class CFramebuffer { Vector2D m_vSize; SP m_cTex; - GLuint m_iFb = -1; + GLuint m_iFb; + bool m_iFbAllocated{false}; SP m_pStencilTex; }; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index c355f4f9..0461662c 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1247,14 +1247,14 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, -1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); renderRect(box, CColor(0, 0, 0, 0), round); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, -1); + glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); scissor(box); @@ -1269,7 +1269,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); glDisable(GL_STENCIL_TEST); - glStencilMask(-1); + glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); @@ -1802,12 +1802,12 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o CRegion tempDamage{damage}; // and draw - for (int i = 1; i <= *PBLURPASSES; ++i) { + for (auto i = 1; i <= *PBLURPASSES; ++i) { tempDamage = damage.copy().scale(1.f / (1 << i)); drawPass(&m_RenderData.pCurrentMonData->m_shBLUR1, &tempDamage); // down } - for (int i = *PBLURPASSES - 1; i >= 0; --i) { + for (auto i = *PBLURPASSES - 1; i >= 0; --i) { tempDamage = damage.copy().scale(1.f / (1 << i)); // when upsampling we make the region twice as big drawPass(&m_RenderData.pCurrentMonData->m_shBLUR2, &tempDamage); // up } @@ -2091,7 +2091,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glEnable(GL_STENCIL_TEST); - glStencilFunc(GL_ALWAYS, 1, -1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); @@ -2101,7 +2101,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float renderTexture(tex, pBox, a, round, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, -1); + glStencilFunc(GL_EQUAL, 1, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // stencil done. Render everything. @@ -2124,7 +2124,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glDisable(GL_STENCIL_TEST); renderTextureInternalWithDamage(tex, pBox, a, &texDamage, round, false, false, true, true); - glStencilMask(-1); + glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7b29eb77..17aed940 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1658,7 +1658,7 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgetMonitorFromID(monitor); if (!PMONITOR) diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 84501821..0b16efea 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,7 +49,7 @@ class CHyprRenderer { ~CHyprRenderer(); void renderMonitor(CMonitor* pMonitor); - void arrangeLayersForMonitor(const int&); + void arrangeLayersForMonitor(const MONITORID&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*, bool skipFrameSchedule = false); diff --git a/src/signal-safe.cpp b/src/signal-safe.cpp index 05ca9c65..44d23f9b 100644 --- a/src/signal-safe.cpp +++ b/src/signal-safe.cpp @@ -10,7 +10,7 @@ extern char** environ; char const* sig_getenv(char const* name) { - int len = strlen(name); + size_t len = strlen(name); for (char** var = environ; *var != NULL; var++) { if (strncmp(*var, name, len) == 0 && (*var)[len] == '=') { return (*var) + len + 1; diff --git a/src/signal-safe.hpp b/src/signal-safe.hpp index 3a38f043..ef643097 100644 --- a/src/signal-safe.hpp +++ b/src/signal-safe.hpp @@ -139,7 +139,7 @@ class BufFileWriter { abort(); } else { close(pipefd[1]); - int len; + long len; char readbuf[256]; while ((len = read(pipefd[0], readbuf, 256)) > 0) { write(readbuf, len); @@ -155,7 +155,7 @@ class BufFileWriter { void flush() { size_t i = 0; while (i < m_writeBufPos) { - int written = ::write(m_fd, m_writeBuf + i, m_writeBufPos - i); + auto written = ::write(m_fd, m_writeBuf + i, m_writeBufPos - i); if (written <= 0) { return; } From fd1d4e288edd586a3d5273cda053a51f5b14cad7 Mon Sep 17 00:00:00 2001 From: "Mathis H." Date: Fri, 9 Aug 2024 14:51:21 +0000 Subject: [PATCH 0466/2393] headers: set correct paths to header files (#7245) --- src/helpers/MiscFunctions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 7eb2a1ed..8b2ea0d1 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -6,8 +6,8 @@ #include "math/Math.hpp" #include #include -#include "SharedDefs.hpp" -#include "macros.hpp" +#include "../SharedDefs.hpp" +#include "../macros.hpp" struct SCallstackFrameInfo { void* adr = nullptr; From 8b37e81374928856d8fd859b95a62c8bf4211901 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 9 Aug 2024 19:33:20 +0200 Subject: [PATCH 0467/2393] cursormgr: add a new setting to sync gsettings (#7253) cursor:sync_gsettings_theme is set to default true and if enabled it will now sync xcursor theme loading with gsettings if it can, meaning CSD clients will now also change to the appropiate theme upon start and hyprctl setcursor THEME SIZE . --- CMakeLists.txt | 1 + meson.build | 2 ++ src/config/ConfigManager.cpp | 1 + src/managers/XCursorManager.cpp | 59 +++++++++++++++++++++++++++++++++ src/managers/XCursorManager.hpp | 1 + src/meson.build | 1 + 6 files changed, 65 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfbd431f..d8c45bbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,6 +117,7 @@ pkg_check_modules( libliftoff libudev gbm + gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.2.1) diff --git a/meson.build b/meson.build index e8cd25b4..6a9b7ac5 100644 --- a/meson.build +++ b/meson.build @@ -34,6 +34,8 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) +gio_dep = dependency('gio-2.0', required:true) + cmake = import('cmake') udis = cmake.subproject('udis86') udis86 = udis.dependency('libudis86') diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1a823f3e..fb93032a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -539,6 +539,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:enable_hyprcursor", Hyprlang::INT{1}); + m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index f2a7ab53..1108bbb2 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include "config/ConfigValue.hpp" #include "helpers/CursorShapes.hpp" #include "debug/Log.hpp" #include "XCursorManager.hpp" @@ -146,6 +149,10 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { cursors.emplace_back(cursor); } + + static auto SYNCGSETTINGS = CConfigValue("cursor:sync_gsettings_theme"); + if (*SYNCGSETTINGS) + syncGsettings(); } SP CXCursorManager::getShape(std::string const& shape, int size) { @@ -542,3 +549,55 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa return newCursors; } + +void CXCursorManager::syncGsettings() { + auto checkParamExists = [](std::string const& paramName, std::string const& category) { + auto* gSettingsSchemaSource = g_settings_schema_source_get_default(); + + if (!gSettingsSchemaSource) { + Debug::log(WARN, "GSettings default schema source does not exist, cant sync GSettings"); + return false; + } + + auto* gSettingsSchema = g_settings_schema_source_lookup(gSettingsSchemaSource, category.c_str(), true); + bool hasParam = false; + + if (gSettingsSchema != NULL) { + hasParam = gSettingsSchema && g_settings_schema_has_key(gSettingsSchema, paramName.c_str()); + g_settings_schema_unref(gSettingsSchema); + } + + return hasParam; + }; + + using SettingValue = std::variant; + auto setValue = [&checkParamExists](std::string const& paramName, const SettingValue& paramValue, std::string const& category) { + if (!checkParamExists(paramName, category)) { + Debug::log(WARN, "GSettings parameter doesnt exist {} in {}", paramName, category); + return; + } + + auto* gsettings = g_settings_new(category.c_str()); + + if (!gsettings) { + Debug::log(WARN, "GSettings failed to allocate new settings with category {}", category); + return; + } + + std::visit( + [&](auto&& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) + g_settings_set_string(gsettings, paramName.c_str(), value.c_str()); + else if constexpr (std::is_same_v) + g_settings_set_int(gsettings, paramName.c_str(), value); + }, + paramValue); + + g_settings_sync(); + g_object_unref(gsettings); + }; + + setValue("cursor-theme", themeName, "org.gnome.desktop.interface"); + setValue("cursor-size", lastLoadSize, "org.gnome.desktop.interface"); +} diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 20637055..464c1ec3 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -38,6 +38,7 @@ class CXCursorManager { std::string getLegacyShapeName(std::string const& shape); std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); + void syncGsettings(); int lastLoadSize = 0; std::string themeName = ""; diff --git a/src/meson.build b/src/meson.build index 098d8298..475ecc24 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,6 +28,7 @@ executable('Hyprland', src, xcb_xfixes_dep, backtrace_dep, epoll_dep, + gio_dep, udis86, dependency('pixman-1'), From 4fdc0d55e4b44bb5300679025d2378fb6de0cae4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 10 Aug 2024 00:04:26 +0200 Subject: [PATCH 0468/2393] eventloop: don't dispatch in enterLoop ref #6842, BSD blocks in udev on no event apparently --- src/managers/eventLoop/EventLoopManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 041e7101..d1b85cf2 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -48,7 +48,6 @@ void CEventLoopManager::enterLoop() { aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); for (auto& fd : aqPollFDs) { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); - fd->onSignal(); // dispatch outstanding } wl_display_run(m_sWayland.display); From 0bf9ceb53b338c79ab65e631877efcf96f53b49a Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Sat, 10 Aug 2024 16:09:12 -0400 Subject: [PATCH 0469/2393] core: Include cstring whenever strncpy is used (#7267) Fixes ppc64le build in alpine --- hyprctl/main.cpp | 1 + src/helpers/SdDaemon.cpp | 1 + src/managers/EventManager.cpp | 1 + src/xwayland/Server.cpp | 1 + 4 files changed, 4 insertions(+) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index c86406fc..5d5113b8 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace Hyprutils::String; #include "Strings.hpp" diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 25e0ca3b..48c23e6b 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Systemd { int SdBooted(void) { diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index 75c98e2a..079a6b68 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include CEventManager::CEventManager() { m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index cec582f6..200bec70 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -19,6 +19,7 @@ #include #include #include +#include // TODO: cleanup static bool set_cloexec(int fd, bool cloexec) { From 01ff5fdf6a00a9231bd3b56400d8bcab378c4257 Mon Sep 17 00:00:00 2001 From: Walt Bringenberg <44916811+wwaltb@users.noreply.github.com> Date: Sat, 10 Aug 2024 13:42:45 -0700 Subject: [PATCH 0470/2393] cursor: make inactive_timeout setting a float (#7268) --- src/config/ConfigManager.cpp | 2 +- src/render/Renderer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fb93032a..edc1723d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -531,7 +531,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); - m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0}); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 17aed940..a2d5a95e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2299,7 +2299,7 @@ void CHyprRenderer::setCursorFromName(const std::string& name, bool force) { } void CHyprRenderer::ensureCursorRenderingMode() { - static auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); + static auto PCURSORTIMEOUT = CConfigValue("cursor:inactive_timeout"); static auto PHIDEONTOUCH = CConfigValue("cursor:hide_on_touch"); static auto PHIDEONKEY = CConfigValue("cursor:hide_on_key_press"); From 511eea71c60e10f3d3d757a376f1ca98b9034ae0 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 11 Aug 2024 20:42:18 +0200 Subject: [PATCH 0471/2393] pointermgr: fix initial cursorwarp (#7286) change the hook to monitorAdded instead of newMonitor so its finalized in the compositor and added to vMonitors, move the checkDefaultCursorWarp to PointerManager and check for it upon mode change. and also ensure it doesnt go out of bounds by replacing it in the middle again on resolution changes. --- src/Compositor.cpp | 35 ------------------------ src/managers/PointerManager.cpp | 48 ++++++++++++++++++++++++++++++--- src/managers/PointerManager.hpp | 1 + 3 files changed, 45 insertions(+), 39 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e3a347fd..c3f95961 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2918,39 +2918,6 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } -static void checkDefaultCursorWarp(SP PNEWMONITOR, std::string monitorName) { - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static auto firstMonitorAdded = std::chrono::system_clock::now(); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = PNEWMONITOR->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } - - if (cursorDefaultDone || *PCURSORMONITOR == STRVAL_EMPTY) - return; - - // after 10s, don't set cursor to default monitor - auto timePassedSec = std::chrono::duration_cast(std::chrono::system_clock::now() - firstMonitorAdded); - if (timePassedSec.count() > 10) { - cursorDefaultDone = true; - return; - } - - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - void CCompositor::onNewMonitor(SP output) { // add it to real auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); @@ -2986,8 +2953,6 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); - checkDefaultCursorWarp(PNEWMONITOR, output->name); - for (auto& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3ba34c11..72ff5ae7 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -11,13 +11,21 @@ #include CPointerManager::CPointerManager() { - hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) { - auto PMONITOR = std::any_cast>(data); + hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { + auto PMONITOR = std::any_cast(data)->self.lock(); onMonitorLayoutChange(); - PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); - PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.modeChanged.registerStaticListener( + [this, PMONITOR](void* owner, std::any data) { + g_pEventLoopManager->doLater([this, PMONITOR]() { + onMonitorLayoutChange(); + checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name); + }); + }, + nullptr); + PMONITOR->events.disconnect.registerStaticListener( + [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( [this](void* owner, std::any data) { if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) @@ -35,6 +43,38 @@ CPointerManager::CPointerManager() { }); } +void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string monitorName) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = monitor->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + + if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { + if (*PCURSORMONITOR == monitorName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + } + + // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. + if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + void CPointerManager::lockSoftwareAll() { for (auto& state : monitorStates) state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 4a4c4f61..082855b5 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -26,6 +26,7 @@ class CPointerManager { public: CPointerManager(); + void checkDefaultCursorWarp(SP monitor, std::string monitorName); void attachPointer(SP pointer); void attachTouch(SP touch); void attachTablet(SP tablet); From 118d4e1001d5847aa42d1e5d5fa9623954ae751d Mon Sep 17 00:00:00 2001 From: "Yang, Ying-chao" Date: Mon, 12 Aug 2024 03:38:16 +0800 Subject: [PATCH 0472/2393] install: Prepend ${DESTDIR} when creating hyprland symbolic link (fixes #7280). (#7281) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8c45bbe..f26a5c3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,7 +330,7 @@ install( CODE "execute_process( \ COMMAND ${CMAKE_COMMAND} -E create_symlink \ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ - ${CMAKE_INSTALL_FULL_BINDIR}/hyprland + \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \ )") # session file From df9d830117cbbf8a1b2a144a28261c28753cb022 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 12 Aug 2024 18:18:03 +0300 Subject: [PATCH 0473/2393] flake.lock: update --- flake.lock | 24 ++-- hyprpm/Makefile | 363 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 375 insertions(+), 12 deletions(-) create mode 100644 hyprpm/Makefile diff --git a/flake.lock b/flake.lock index 5c384d4d..8930d2e3 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1722347739, - "narHash": "sha256-rAoh+K6KG+b1DwSWtqRVocdojnH6nGk6q07mNltoUSM=", + "lastModified": 1723405438, + "narHash": "sha256-bpmC2m7OhlDvqgQZdZ2jBLyeIkq/Jld3X4bqRAxBSp8=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7c3565f9bedc7cb601cc0baa14792247e4dc1d5a", + "rev": "9312aa28271c91e5d67ecb9def527b2bbcff0e66", "type": "github" }, "original": { @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1721330371, - "narHash": "sha256-aYlHTWylczLt6ERJyg6E66Y/XSCbVL7leVcRuJmVbpI=", + "lastModified": 1722623071, + "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "4493a972b48f9c3014befbbf381ed5fff91a65dc", + "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1722098849, - "narHash": "sha256-D3wIZlBNh7LuZ0NaoCpY/Pvu+xHxIVtSN+KkWZYvvVs=", + "lastModified": 1722869141, + "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "5dcbbc1e3de40b2cecfd2007434d86e924468f1f", + "rev": "0252fd13e78e60fb0da512a212e56007515a49f7", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1722185531, - "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=", + "lastModified": 1723175592, + "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d", + "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", "type": "github" }, "original": { diff --git a/hyprpm/Makefile b/hyprpm/Makefile new file mode 100644 index 00000000..5249a14b --- /dev/null +++ b/hyprpm/Makefile @@ -0,0 +1,363 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.29 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Disable VCS-based implicit rules. +% : %,v + +# Disable VCS-based implicit rules. +% : RCS/% + +# Disable VCS-based implicit rules. +% : RCS/%,v + +# Disable VCS-based implicit rules. +% : SCCS/s.% + +# Disable VCS-based implicit rules. +% : s.% + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake + +# The command to remove a file. +RM = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/mihai/Documents/code/git/Hyprland + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/mihai/Documents/code/git/Hyprland + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target package +package: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool..." + cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackConfig.cmake +.PHONY : package + +# Special rule for the target package +package/fast: package +.PHONY : package/fast + +# Special rule for the target package_source +package_source: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool for source..." + cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackSourceConfig.cmake /home/mihai/Documents/code/git/Hyprland/CPackSourceConfig.cmake +.PHONY : package_source + +# Special rule for the target package_source +package_source/fast: package_source +.PHONY : package_source/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." + /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# The main all target +all: cmake_check_build_system + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles /home/mihai/Documents/code/git/Hyprland/hyprpm//CMakeFiles/progress.marks + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +hyprpm/CMakeFiles/hyprpm.dir/rule: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/CMakeFiles/hyprpm.dir/rule +.PHONY : hyprpm/CMakeFiles/hyprpm.dir/rule + +# Convenience name for target. +hyprpm: hyprpm/CMakeFiles/hyprpm.dir/rule +.PHONY : hyprpm + +# fast build rule for target. +hyprpm/fast: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/build +.PHONY : hyprpm/fast + +src/core/DataState.o: src/core/DataState.cpp.o +.PHONY : src/core/DataState.o + +# target to build an object file +src/core/DataState.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.o +.PHONY : src/core/DataState.cpp.o + +src/core/DataState.i: src/core/DataState.cpp.i +.PHONY : src/core/DataState.i + +# target to preprocess a source file +src/core/DataState.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.i +.PHONY : src/core/DataState.cpp.i + +src/core/DataState.s: src/core/DataState.cpp.s +.PHONY : src/core/DataState.s + +# target to generate assembly for a file +src/core/DataState.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.s +.PHONY : src/core/DataState.cpp.s + +src/core/Manifest.o: src/core/Manifest.cpp.o +.PHONY : src/core/Manifest.o + +# target to build an object file +src/core/Manifest.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.o +.PHONY : src/core/Manifest.cpp.o + +src/core/Manifest.i: src/core/Manifest.cpp.i +.PHONY : src/core/Manifest.i + +# target to preprocess a source file +src/core/Manifest.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.i +.PHONY : src/core/Manifest.cpp.i + +src/core/Manifest.s: src/core/Manifest.cpp.s +.PHONY : src/core/Manifest.s + +# target to generate assembly for a file +src/core/Manifest.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.s +.PHONY : src/core/Manifest.cpp.s + +src/core/PluginManager.o: src/core/PluginManager.cpp.o +.PHONY : src/core/PluginManager.o + +# target to build an object file +src/core/PluginManager.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.o +.PHONY : src/core/PluginManager.cpp.o + +src/core/PluginManager.i: src/core/PluginManager.cpp.i +.PHONY : src/core/PluginManager.i + +# target to preprocess a source file +src/core/PluginManager.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.i +.PHONY : src/core/PluginManager.cpp.i + +src/core/PluginManager.s: src/core/PluginManager.cpp.s +.PHONY : src/core/PluginManager.s + +# target to generate assembly for a file +src/core/PluginManager.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.s +.PHONY : src/core/PluginManager.cpp.s + +src/main.o: src/main.cpp.o +.PHONY : src/main.o + +# target to build an object file +src/main.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.o +.PHONY : src/main.cpp.o + +src/main.i: src/main.cpp.i +.PHONY : src/main.i + +# target to preprocess a source file +src/main.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.i +.PHONY : src/main.cpp.i + +src/main.s: src/main.cpp.s +.PHONY : src/main.s + +# target to generate assembly for a file +src/main.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.s +.PHONY : src/main.cpp.s + +src/progress/CProgressBar.o: src/progress/CProgressBar.cpp.o +.PHONY : src/progress/CProgressBar.o + +# target to build an object file +src/progress/CProgressBar.cpp.o: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.o +.PHONY : src/progress/CProgressBar.cpp.o + +src/progress/CProgressBar.i: src/progress/CProgressBar.cpp.i +.PHONY : src/progress/CProgressBar.i + +# target to preprocess a source file +src/progress/CProgressBar.cpp.i: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.i +.PHONY : src/progress/CProgressBar.cpp.i + +src/progress/CProgressBar.s: src/progress/CProgressBar.cpp.s +.PHONY : src/progress/CProgressBar.s + +# target to generate assembly for a file +src/progress/CProgressBar.cpp.s: + cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.s +.PHONY : src/progress/CProgressBar.cpp.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... package" + @echo "... package_source" + @echo "... rebuild_cache" + @echo "... hyprpm" + @echo "... src/core/DataState.o" + @echo "... src/core/DataState.i" + @echo "... src/core/DataState.s" + @echo "... src/core/Manifest.o" + @echo "... src/core/Manifest.i" + @echo "... src/core/Manifest.s" + @echo "... src/core/PluginManager.o" + @echo "... src/core/PluginManager.i" + @echo "... src/core/PluginManager.s" + @echo "... src/main.o" + @echo "... src/main.i" + @echo "... src/main.s" + @echo "... src/progress/CProgressBar.o" + @echo "... src/progress/CProgressBar.i" + @echo "... src/progress/CProgressBar.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake + cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + From d361fcbd85a92f0494c6d8ef0c63aad798df20a7 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 12 Aug 2024 11:16:00 -0500 Subject: [PATCH 0474/2393] config: fix explicit sync option warning (#7293) --- src/config/ConfigManager.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index edc1723d..41d3871c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -822,9 +822,6 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (!isFirstLaunch) g_pHyprOpenGL->m_bReloadScreenShader = true; - if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit) - g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); - // parseError will be displayed next frame if (result.error) @@ -837,6 +834,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); + else if (*PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); else g_pHyprError->destroy(); @@ -925,7 +924,10 @@ void CConfigManager::init() { } std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std::string& VALUE) { - const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str()); + static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static int prevEnabledExplicit = *PENABLEEXPLICIT; + + const auto RET = m_pConfig->parseDynamic(COMMAND.c_str(), VALUE.c_str()); // invalidate layouts if they changed if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) { @@ -933,6 +935,13 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } + if (COMMAND.contains("explicit")) { + if (*PENABLEEXPLICIT != prevEnabledExplicit) + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + else + g_pHyprError->destroy(); + } + // Update window border colors g_pCompositor->updateAllWindowsAnimatedDecorationValues(); From 3fa6db1e7a7f5596f449ae12d0b45ff364d7f6f1 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 12 Aug 2024 19:19:03 +0200 Subject: [PATCH 0475/2393] core: fix data race and a unsigned int rollover (#7278) * keybindmgr: avoid uint rollover on mouse keycode mouse keycode is 0, and the switch case checks for 0 - 8 and rolls over, just return early if keycode is 0. * watchdog: avoid data races in watchdog asan thread sanitizer reported data races in the watchdog from reading and setting the bool variables make them std::atomic bools. also add a atomic bool for the main thread to wait for to avoid data race when reading the config values. * hyprdebug: change non unicode character to name asan created false positives and didnt like this bit, so for the sake of easier debugging rename it to something unicode. --- src/Compositor.cpp | 4 ++++ src/debug/HyprDebugOverlay.cpp | 16 ++++++++-------- src/debug/HyprDebugOverlay.hpp | 8 ++++---- src/helpers/Watchdog.cpp | 13 ++++++------- src/helpers/Watchdog.hpp | 14 ++++++++------ src/managers/KeybindManager.cpp | 3 +++ src/render/Renderer.cpp | 10 +++++----- 7 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c3f95961..a2f7c52a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -552,6 +552,10 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pConfigManager->init(); g_pWatchdog = std::make_unique(); // requires config + // wait for watchdog to initialize to not hit data races in reading config values. + while (!g_pWatchdog->m_bWatchdogInitialized) { + std::this_thread::yield(); + } Debug::log(LOG, "Creating the PointerManager!"); g_pPointerManager = std::make_unique(); diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 889be8ea..fbd8cd71 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -7,8 +7,8 @@ CHyprDebugOverlay::CHyprDebugOverlay() { m_pTexture = makeShared(); } -void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { - m_dLastRenderTimes.push_back(µs / 1000.f); +void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { + m_dLastRenderTimes.push_back(durationUs / 1000.f); if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimes.pop_front(); @@ -17,8 +17,8 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float µs) { m_pMonitor = pMonitor; } -void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { - m_dLastRenderTimesNoOverlay.push_back(µs / 1000.f); +void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { + m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f); if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) m_dLastRenderTimesNoOverlay.pop_front(); @@ -188,12 +188,12 @@ int CHyprMonitorDebugOverlay::draw(int offset) { return posY - offset; } -void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float µs) { - m_mMonitorOverlays[pMonitor].renderData(pMonitor, µs); +void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { + m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); } -void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float µs) { - m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, µs); +void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { + m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); } void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index a6063ee9..e7742b35 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -13,8 +13,8 @@ class CHyprMonitorDebugOverlay { public: int draw(int offset); - void renderData(CMonitor* pMonitor, float µs); - void renderDataNoOverlay(CMonitor* pMonitor, float µs); + void renderData(CMonitor* pMonitor, float durationUs); + void renderDataNoOverlay(CMonitor* pMonitor, float durationUs); void frameData(CMonitor* pMonitor); private: @@ -33,8 +33,8 @@ class CHyprDebugOverlay { public: CHyprDebugOverlay(); void draw(); - void renderData(CMonitor*, float µs); - void renderDataNoOverlay(CMonitor*, float µs); + void renderData(CMonitor*, float durationUs); + void renderDataNoOverlay(CMonitor*, float durationUs); void frameData(CMonitor*); private: diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp index b9f654da..c7ff648b 100644 --- a/src/helpers/Watchdog.cpp +++ b/src/helpers/Watchdog.cpp @@ -18,15 +18,14 @@ CWatchdog::CWatchdog() { m_pWatchdog = std::make_unique([this] { static auto PTIMEOUT = CConfigValue("debug:watchdog_timeout"); - while (1337) { - std::unique_lock lk(m_mWatchdogMutex); + m_bWatchdogInitialized = true; + while (!m_bExitThread) { + std::unique_lock lk(m_mWatchdogMutex); if (!m_bWillWatch) - m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; }); - else { - if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false) - pthread_kill(m_iMainThreadPID, SIGUSR1); - } + m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified || m_bExitThread; }); + else if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified || m_bExitThread; }) == false) + pthread_kill(m_iMainThreadPID, SIGUSR1); if (m_bExitThread) break; diff --git a/src/helpers/Watchdog.hpp b/src/helpers/Watchdog.hpp index 7bb499d6..b16cb518 100644 --- a/src/helpers/Watchdog.hpp +++ b/src/helpers/Watchdog.hpp @@ -11,21 +11,23 @@ class CWatchdog { CWatchdog(); ~CWatchdog(); - void startWatching(); - void endWatching(); + void startWatching(); + void endWatching(); + + std::atomic m_bWatchdogInitialized{false}; private: std::chrono::high_resolution_clock::time_point m_tTriggered; pthread_t m_iMainThreadPID = 0; - bool m_bWatching = false; - bool m_bWillWatch = false; + std::atomic m_bWatching = false; + std::atomic m_bWillWatch = false; std::unique_ptr m_pWatchdog; std::mutex m_mWatchdogMutex; - bool m_bNotified = false; - bool m_bExitThread = false; + std::atomic m_bNotified = false; + std::atomic m_bExitThread = false; std::condition_variable m_cvWatchdogCondition; }; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d4bac507..dba34d70 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -180,6 +180,9 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) { } uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { + if (keycode == 0) + return 0; + switch (keycode - 8) { case KEY_LEFTMETA: return HL_MODIFIER_META; case KEY_RIGHTMETA: return HL_MODIFIER_META; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a2d5a95e..6bf6a761 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1395,15 +1395,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->pendingFrame = false; - const float µs = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000.f; - g_pDebugOverlay->renderData(pMonitor, µs); + const float durationUs = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - renderStart).count() / 1000.f; + g_pDebugOverlay->renderData(pMonitor, durationUs); if (*PDEBUGOVERLAY == 1) { if (pMonitor == g_pCompositor->m_vMonitors.front().get()) { - const float µsNoOverlay = µs - std::chrono::duration_cast(endRenderOverlay - renderStartOverlay).count() / 1000.f; - g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay); + const float noOverlayUs = durationUs - std::chrono::duration_cast(endRenderOverlay - renderStartOverlay).count() / 1000.f; + g_pDebugOverlay->renderDataNoOverlay(pMonitor, noOverlayUs); } else { - g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs); + g_pDebugOverlay->renderDataNoOverlay(pMonitor, durationUs); } } } From c7b72790bd63172f04ee86784d4cb2a400532927 Mon Sep 17 00:00:00 2001 From: Kyle <56144092+txkyel@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:41:26 -0400 Subject: [PATCH 0476/2393] keybinds: Fix fullscreenState toggling behaviour (#7288) * Update fullscreen state dispatcher behaviour * Change syncFullscreen default to false * Revert all changes * Modify fullscreenstate dispatcher toggle behaviour * Update syncFullscreen according to state * Update syncFullscreen before setting fullscreen state --- src/managers/KeybindManager.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index dba34d70..8fc025ec 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1166,6 +1166,8 @@ void CKeybindManager::fullscreenStateActive(std::string args) { if (!PWINDOW) return; + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); + int internalMode, clientMode; try { internalMode = std::stoi(ARGS[0]); @@ -1184,18 +1186,15 @@ void CKeybindManager::fullscreenStateActive(std::string args) { } if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) { - g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.client, .client = PWINDOW->m_sFullscreenState.client}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client}); return; } if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) { - g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = PWINDOW->m_sFullscreenState.internal}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); + g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE}); return; } - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); } From 77cf651825c2afac69e3a827ff910a62c73e1218 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 12 Aug 2024 20:49:52 +0200 Subject: [PATCH 0477/2393] protocols: avoid crashing in drmlease (#7290) instead of potentially causing wonky behaviour from destructing in the constructor add the unique_ptr reset to doLater and dont use the not done constructed protolog in the constructor, call Debug::log directly. see issue #7240 --- src/protocols/DRMLease.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 9f5b6312..3ab38ea1 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -1,5 +1,6 @@ #include "DRMLease.hpp" #include "../Compositor.hpp" +#include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -225,7 +226,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe auto fd = drm->getNonMasterFD(); if (fd < 0) { - LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); + Debug::log(ERR, "[DRMLease] Failed to dup fd for drm node {}", drm->gpuName); return; } @@ -247,10 +248,8 @@ CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, break; } - if (!primaryDevice || primaryDevice->success) { - PROTO::lease.reset(); - return; - } + if (!primaryDevice || !primaryDevice->success) + g_pEventLoopManager->doLater([]() { PROTO::lease.reset(); }); } void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { From 39df1f4dbfedf97a7f30f9de359f3b3415844380 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:27:00 -0500 Subject: [PATCH 0478/2393] cursormgr: fix cursor gsettings on session change (#7295) --- src/Compositor.cpp | 1 + src/managers/CursorManager.cpp | 6 +++++- src/managers/CursorManager.hpp | 3 ++- src/managers/XCursorManager.cpp | 1 + src/managers/XCursorManager.hpp | 4 ++-- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a2f7c52a..26a985ef 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -393,6 +393,7 @@ void CCompositor::initAllSignals() { } g_pConfigManager->m_bWantsMonitorReload = true; + g_pCursorManager->syncGsettings(); } else { Debug::log(LOG, "Session got deactivated!"); diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 3f3a25f6..e2dd5bb3 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -337,4 +337,8 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { updateTheme(); return true; -} \ No newline at end of file +} + +void CCursorManager::syncGsettings() { + m_pXcursor->syncGsettings(); +} diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index ceb4816b..796ab10e 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -53,6 +53,7 @@ class CCursorManager { void updateTheme(); SCursorImageData dataFor(const std::string& name); // for xwayland void setXWaylandCursor(); + void syncGsettings(); void tickAnimatedCursor(); @@ -75,4 +76,4 @@ class CCursorManager { Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; }; -inline std::unique_ptr g_pCursorManager; \ No newline at end of file +inline std::unique_ptr g_pCursorManager; diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 1108bbb2..3d36add5 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -5,6 +5,7 @@ #include #include "config/ConfigValue.hpp" #include "helpers/CursorShapes.hpp" +#include "../managers/CursorManager.hpp" #include "debug/Log.hpp" #include "XCursorManager.hpp" diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 464c1ec3..48fda5dd 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -31,6 +31,7 @@ class CXCursorManager { void loadTheme(const std::string& name, int size); SP getShape(std::string const& shape, int size); + void syncGsettings(); private: SP createCursor(std::string const& shape, XcursorImages* xImages); @@ -38,11 +39,10 @@ class CXCursorManager { std::string getLegacyShapeName(std::string const& shape); std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); - void syncGsettings(); int lastLoadSize = 0; std::string themeName = ""; SP defaultCursor; SP hyprCursor; std::vector> cursors; -}; \ No newline at end of file +}; From 4aec237ec0bfcb86be9c26926f5a87e036b7f668 Mon Sep 17 00:00:00 2001 From: Patrick Ulbricht <70023807+PaddeCraft@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:14:52 +0200 Subject: [PATCH 0479/2393] README: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland (#7315) * readme: Change image sources from vaxerski/Hyprland to hyprwm/Hyprland * readme: Remove unused image --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index fc2bd206..f271c29c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-banner +banner
@@ -125,7 +125,6 @@ easy IPC, much more QoL stuff than other compositors and more... -[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg [Preview A]: https://i.ibb.co/C1yTb0r/falf.png [Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png [Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png From c5ec079c6fa92fe89bd2b689dd49197675edbe58 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 13 Aug 2024 22:14:58 +0300 Subject: [PATCH 0480/2393] hyprpm, hyprctl: remove Makefiles --- .gitignore | 2 + hyprctl/Makefile | 4 - hyprpm/Makefile | 363 ----------------------------------------------- 3 files changed, 2 insertions(+), 367 deletions(-) delete mode 100644 hyprctl/Makefile delete mode 100644 hyprpm/Makefile diff --git a/.gitignore b/.gitignore index 78f794fc..2e158a4e 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ gmon.out PKGBUILD src/version.h +hyprpm/Makefile +hyprctl/Makefile diff --git a/hyprctl/Makefile b/hyprctl/Makefile deleted file mode 100644 index 9798320c..00000000 --- a/hyprctl/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: - $(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl -clean: - rm ./hyprctl diff --git a/hyprpm/Makefile b/hyprpm/Makefile deleted file mode 100644 index 5249a14b..00000000 --- a/hyprpm/Makefile +++ /dev/null @@ -1,363 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.29 - -# Default target executed when no arguments are given to make. -default_target: all -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - -# Disable VCS-based implicit rules. -% : %,v - -# Disable VCS-based implicit rules. -% : RCS/% - -# Disable VCS-based implicit rules. -% : RCS/%,v - -# Disable VCS-based implicit rules. -% : SCCS/s.% - -# Disable VCS-based implicit rules. -% : s.% - -.SUFFIXES: .hpux_make_needs_suffix_list - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -#Suppress display of executed commands. -$(VERBOSE).SILENT: - -# A target that is always out of date. -cmake_force: -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake - -# The command to remove a file. -RM = /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/mihai/Documents/code/git/Hyprland - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/mihai/Documents/code/git/Hyprland - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target package -package: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool..." - cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackConfig.cmake -.PHONY : package - -# Special rule for the target package -package/fast: package -.PHONY : package/fast - -# Special rule for the target package_source -package_source: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Run CPack packaging tool for source..." - cd /home/mihai/Documents/code/git/Hyprland && /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cpack --config ./CPackSourceConfig.cmake /home/mihai/Documents/code/git/Hyprland/CPackSourceConfig.cmake -.PHONY : package_source - -# Special rule for the target package_source -package_source/fast: package_source -.PHONY : package_source/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "No interactive CMake dialog available..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache -.PHONY : edit_cache/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Running CMake to regenerate build system..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache -.PHONY : rebuild_cache/fast - -# Special rule for the target list_install_components -list_install_components: - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Available install components are: \"Unspecified\"" -.PHONY : list_install_components - -# Special rule for the target list_install_components -list_install_components/fast: list_install_components -.PHONY : list_install_components/fast - -# Special rule for the target install -install: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake -.PHONY : install - -# Special rule for the target install -install/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Install the project..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -P cmake_install.cmake -.PHONY : install/fast - -# Special rule for the target install/local -install/local: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local - -# Special rule for the target install/local -install/local/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing only the local directory..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local/fast - -# Special rule for the target install/strip -install/strip: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip - -# Special rule for the target install/strip -install/strip/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color "--switch=$(COLOR)" --cyan "Installing the project stripped..." - /nix/store/aqckch626lg0vxh41dabyzrq0jx7gdk5-cmake-3.29.6/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip/fast - -# The main all target -all: cmake_check_build_system - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles /home/mihai/Documents/code/git/Hyprland/hyprpm//CMakeFiles/progress.marks - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/all - $(CMAKE_COMMAND) -E cmake_progress_start /home/mihai/Documents/code/git/Hyprland/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/clean -.PHONY : clean - -# The main clean target -clean/fast: clean -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -# Convenience name for target. -hyprpm/CMakeFiles/hyprpm.dir/rule: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 hyprpm/CMakeFiles/hyprpm.dir/rule -.PHONY : hyprpm/CMakeFiles/hyprpm.dir/rule - -# Convenience name for target. -hyprpm: hyprpm/CMakeFiles/hyprpm.dir/rule -.PHONY : hyprpm - -# fast build rule for target. -hyprpm/fast: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/build -.PHONY : hyprpm/fast - -src/core/DataState.o: src/core/DataState.cpp.o -.PHONY : src/core/DataState.o - -# target to build an object file -src/core/DataState.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.o -.PHONY : src/core/DataState.cpp.o - -src/core/DataState.i: src/core/DataState.cpp.i -.PHONY : src/core/DataState.i - -# target to preprocess a source file -src/core/DataState.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.i -.PHONY : src/core/DataState.cpp.i - -src/core/DataState.s: src/core/DataState.cpp.s -.PHONY : src/core/DataState.s - -# target to generate assembly for a file -src/core/DataState.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/DataState.cpp.s -.PHONY : src/core/DataState.cpp.s - -src/core/Manifest.o: src/core/Manifest.cpp.o -.PHONY : src/core/Manifest.o - -# target to build an object file -src/core/Manifest.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.o -.PHONY : src/core/Manifest.cpp.o - -src/core/Manifest.i: src/core/Manifest.cpp.i -.PHONY : src/core/Manifest.i - -# target to preprocess a source file -src/core/Manifest.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.i -.PHONY : src/core/Manifest.cpp.i - -src/core/Manifest.s: src/core/Manifest.cpp.s -.PHONY : src/core/Manifest.s - -# target to generate assembly for a file -src/core/Manifest.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/Manifest.cpp.s -.PHONY : src/core/Manifest.cpp.s - -src/core/PluginManager.o: src/core/PluginManager.cpp.o -.PHONY : src/core/PluginManager.o - -# target to build an object file -src/core/PluginManager.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.o -.PHONY : src/core/PluginManager.cpp.o - -src/core/PluginManager.i: src/core/PluginManager.cpp.i -.PHONY : src/core/PluginManager.i - -# target to preprocess a source file -src/core/PluginManager.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.i -.PHONY : src/core/PluginManager.cpp.i - -src/core/PluginManager.s: src/core/PluginManager.cpp.s -.PHONY : src/core/PluginManager.s - -# target to generate assembly for a file -src/core/PluginManager.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/core/PluginManager.cpp.s -.PHONY : src/core/PluginManager.cpp.s - -src/main.o: src/main.cpp.o -.PHONY : src/main.o - -# target to build an object file -src/main.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.o -.PHONY : src/main.cpp.o - -src/main.i: src/main.cpp.i -.PHONY : src/main.i - -# target to preprocess a source file -src/main.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.i -.PHONY : src/main.cpp.i - -src/main.s: src/main.cpp.s -.PHONY : src/main.s - -# target to generate assembly for a file -src/main.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/main.cpp.s -.PHONY : src/main.cpp.s - -src/progress/CProgressBar.o: src/progress/CProgressBar.cpp.o -.PHONY : src/progress/CProgressBar.o - -# target to build an object file -src/progress/CProgressBar.cpp.o: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.o -.PHONY : src/progress/CProgressBar.cpp.o - -src/progress/CProgressBar.i: src/progress/CProgressBar.cpp.i -.PHONY : src/progress/CProgressBar.i - -# target to preprocess a source file -src/progress/CProgressBar.cpp.i: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.i -.PHONY : src/progress/CProgressBar.cpp.i - -src/progress/CProgressBar.s: src/progress/CProgressBar.cpp.s -.PHONY : src/progress/CProgressBar.s - -# target to generate assembly for a file -src/progress/CProgressBar.cpp.s: - cd /home/mihai/Documents/code/git/Hyprland && $(MAKE) $(MAKESILENT) -f hyprpm/CMakeFiles/hyprpm.dir/build.make hyprpm/CMakeFiles/hyprpm.dir/src/progress/CProgressBar.cpp.s -.PHONY : src/progress/CProgressBar.cpp.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... edit_cache" - @echo "... install" - @echo "... install/local" - @echo "... install/strip" - @echo "... list_install_components" - @echo "... package" - @echo "... package_source" - @echo "... rebuild_cache" - @echo "... hyprpm" - @echo "... src/core/DataState.o" - @echo "... src/core/DataState.i" - @echo "... src/core/DataState.s" - @echo "... src/core/Manifest.o" - @echo "... src/core/Manifest.i" - @echo "... src/core/Manifest.s" - @echo "... src/core/PluginManager.o" - @echo "... src/core/PluginManager.i" - @echo "... src/core/PluginManager.s" - @echo "... src/main.o" - @echo "... src/main.i" - @echo "... src/main.s" - @echo "... src/progress/CProgressBar.o" - @echo "... src/progress/CProgressBar.i" - @echo "... src/progress/CProgressBar.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -P /home/mihai/Documents/code/git/Hyprland/CMakeFiles/VerifyGlobs.cmake - cd /home/mihai/Documents/code/git/Hyprland && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - From 3b4aabe04c7756fb0a70d78b6f0e701228f46345 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:00:31 +0000 Subject: [PATCH 0481/2393] decorations: fix manual resize not recalculating decos (#7323) modified: src/layout/DwindleLayout.cpp modified: src/layout/MasterLayout.cpp --- src/layout/DwindleLayout.cpp | 2 ++ src/layout/MasterLayout.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index acdc3de2..20085ff7 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -246,6 +246,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for g_pHyprRenderer->damageWindow(PWINDOW); } + + PWINDOW->updateWindowDecos(); } void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection direction) { diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index aa1c0adf..e0b48e98 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -732,6 +732,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { g_pHyprRenderer->damageWindow(PWINDOW); } + + PWINDOW->updateWindowDecos(); } bool CHyprMasterLayout::isWindowTiled(PHLWINDOW pWindow) { From 197f8807900afc81c1c92ad17e621d1998ee268b Mon Sep 17 00:00:00 2001 From: davc0n Date: Wed, 14 Aug 2024 19:35:07 +0200 Subject: [PATCH 0482/2393] logs: Add file path to asset ERR log (#7336) --- src/render/OpenGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 0461662c..63cc2203 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2690,7 +2690,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { // check if wallpapers exist std::error_code err; if (!std::filesystem::exists(texPath, err)) { - Debug::log(ERR, "createBGTextureForMonitor: failed, file doesn't exist or access denied, ec: {}", err.message()); + Debug::log(ERR, "createBGTextureForMonitor: failed, file \"{}\" doesn't exist or access denied, ec: {}", texPath, err.message()); return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } From d85ae306c5746c6ebeac74c2a7a520bb3f05a119 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Thu, 15 Aug 2024 06:37:56 -0500 Subject: [PATCH 0483/2393] xcursor: handle file errors when loading xcursor themes (#7326) --- src/managers/XCursorManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 3d36add5..0921bcd4 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -511,8 +511,11 @@ std::vector> CXCursorManager::loadAllFromDir(std::string const& pa if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) { for (const auto& entry : std::filesystem::directory_iterator(path)) { - if (!entry.is_regular_file() && !entry.is_symlink()) + std::error_code e1, e2; + if ((!entry.is_regular_file(e1) && !entry.is_symlink(e2)) || e1 || e2) { + Debug::log(WARN, "XCursor failed to load shape {}: {}", entry.path().stem().string(), e1 ? e1.message() : e2.message()); continue; + } auto const& full = entry.path().string(); using PcloseType = int (*)(FILE*); From c30dfe92eee017bc70e131fa30d3c87b56d0a143 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 15 Aug 2024 11:39:29 +0000 Subject: [PATCH 0484/2393] [gha] Nix: update inputs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 8930d2e3..b4868793 100644 --- a/flake.lock +++ b/flake.lock @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723175592, - "narHash": "sha256-M0xJ3FbDUc4fRZ84dPGx5VvgFsOzds77KiBMW/mMTnI=", + "lastModified": 1723637854, + "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5e0ca22929f3342b19569b21b2f3462f053e497b", + "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", "type": "github" }, "original": { From 069faa4027d016549ee72afcd7df3b2c1e7ee578 Mon Sep 17 00:00:00 2001 From: Mirkwood Date: Thu, 15 Aug 2024 14:03:23 +0200 Subject: [PATCH 0485/2393] helpers: fix: revert to signed arithmetic for cycling through workspaces (#7339) The code clearly expects signed types there. Fixes #7329 --- src/helpers/MiscFunctions.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index a81aa7d1..86f24e3a 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -472,7 +472,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::sort(validWSes.begin(), validWSes.end()); - size_t currentItem = -1; + ssize_t currentItem = -1; if (absolute) { // 1-index @@ -481,7 +481,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // clamp if (currentItem < 0) { currentItem = 0; - } else if (currentItem >= validWSes.size()) { + } else if (currentItem >= (ssize_t)validWSes.size()) { currentItem = validWSes.size() - 1; } } else { @@ -490,7 +490,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // get the current item WORKSPACEID activeWSID = g_pCompositor->m_pLastMonitor->activeWorkspace ? g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID : 1; - for (size_t i = 0; i < validWSes.size(); i++) { + for (ssize_t i = 0; i < (ssize_t)validWSes.size(); i++) { if (validWSes[i] == activeWSID) { currentItem = i; break; @@ -501,7 +501,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { currentItem += remains; // sanitize - if (currentItem >= validWSes.size()) { + if (currentItem >= (ssize_t)validWSes.size()) { currentItem = currentItem % validWSes.size(); } else if (currentItem < 0) { currentItem = validWSes.size() + currentItem; From 0c56be74a310e137f577a2b71fc2c72a8100eada Mon Sep 17 00:00:00 2001 From: Kyle <56144092+txkyel@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:04:24 -0400 Subject: [PATCH 0486/2393] keybinds: Fix syncFullscreen inconsistent with state when set by fullscreenState (#7343) * Set syncFullscreen to true on synced non -1 states * Fix syncFullscreen value in fullscreenState --- src/managers/KeybindManager.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8fc025ec..38593497 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1179,23 +1179,16 @@ void CKeybindManager::fullscreenStateActive(std::string args) { const sFullscreenState STATE = sFullscreenState{.internal = (internalMode != -1 ? (eFullscreenMode)internalMode : PWINDOW->m_sFullscreenState.internal), .client = (clientMode != -1 ? (eFullscreenMode)clientMode : PWINDOW->m_sFullscreenState.client)}; - if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) { + if (internalMode != -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal && PWINDOW->m_sFullscreenState.client == STATE.client) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = FSMODE_NONE}); - PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(true, PRIORITY_SET_PROP); - return; - } - - if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) { + else if (internalMode != -1 && clientMode == -1 && PWINDOW->m_sFullscreenState.internal == STATE.internal) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = FSMODE_NONE, .client = PWINDOW->m_sFullscreenState.client}); - return; - } - - if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) { + else if (internalMode == -1 && clientMode != -1 && PWINDOW->m_sFullscreenState.client == STATE.client) g_pCompositor->setWindowFullscreenState(PWINDOW, sFullscreenState{.internal = PWINDOW->m_sFullscreenState.internal, .client = FSMODE_NONE}); - return; - } + else + g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); - g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); + PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(PWINDOW->m_sFullscreenState.internal == PWINDOW->m_sFullscreenState.client, PRIORITY_SET_PROP); } void CKeybindManager::moveActiveToWorkspace(std::string args) { From 520e91238f0e6e6990e6a0845d73d85012485525 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:08:54 +0000 Subject: [PATCH 0487/2393] gamma-control: fix crash on monitor disconnect (#7353) --- src/protocols/GammaControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 494d9862..4febffbb 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -109,7 +109,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } CGammaControl::~CGammaControl() { - if (!gammaTableSet || !pMonitor) + if (!gammaTableSet || !pMonitor || !pMonitor->output) return; // reset the LUT if the client dies for whatever reason and doesn't unset the gamma From 15f942000ef53776852d6d9dfd303e691aed73e3 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Thu, 15 Aug 2024 19:14:48 +0300 Subject: [PATCH 0488/2393] core: Preserve existing XDG_CURRENT_DESKTOP (#7347) * Preserve existing XDG_CURRENT_DESKTOP * fix --------- Co-authored-by: vaxerski --- src/Compositor.cpp | 7 ++++++- src/Compositor.hpp | 1 + src/main.cpp | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 26a985ef..4024fadf 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -305,6 +305,10 @@ void CCompositor::initServer(std::string socketName, int socketFd) { setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); setenv("XDG_SESSION_TYPE", "wayland", 1); + if (!getenv("XDG_CURRENT_DESKTOP")) { + setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); + m_bDesktopEnvSet = true; + } initManagers(STAGE_BASICINIT); @@ -422,7 +426,8 @@ void CCompositor::cleanEnvironment() { // in main unsetenv("HYPRLAND_CMD"); unsetenv("XDG_BACKEND"); - unsetenv("XDG_CURRENT_DESKTOP"); + if (m_bDesktopEnvSet) + unsetenv("XDG_CURRENT_DESKTOP"); if (m_pAqBackend->hasSession()) { const auto CMD = diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 5e9e3266..a570a06e 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -91,6 +91,7 @@ class CCompositor { bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; + bool m_bDesktopEnvSet = false; // ------------------------------------------------- // diff --git a/src/main.cpp b/src/main.cpp index e85b0a22..820a248c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,6 @@ int main(int argc, char** argv) { setenv("XDG_BACKEND", "wayland", 1); setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); setenv("MOZ_ENABLE_WAYLAND", "1", 1); - setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); // parse some args std::string configPath; From 12d9901472c6f9128fa8b16c25b3a879d1859e60 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 15 Aug 2024 18:16:18 +0200 Subject: [PATCH 0489/2393] protocols: refactor protocol logging to a macro (#7324) this avoids the usage of the unique_ptr PROTO::protocol before it has been constructed incase one wants to log something inside the constructor itself, move the logging to macros and print file:linenumber on ERR,CRIT,WARN and classname on the rest of the levels. --- src/protocols/AlphaModifier.cpp | 2 -- src/protocols/CursorShape.cpp | 2 -- src/protocols/DRMLease.cpp | 4 +-- src/protocols/DRMSyncobj.cpp | 2 -- src/protocols/DataDeviceWlr.cpp | 2 -- src/protocols/FocusGrab.cpp | 2 -- src/protocols/ForeignToplevel.cpp | 2 -- src/protocols/ForeignToplevelWlr.cpp | 2 -- src/protocols/FractionalScale.cpp | 2 -- src/protocols/GammaControl.cpp | 2 -- src/protocols/GlobalShortcuts.cpp | 2 -- src/protocols/IdleNotify.cpp | 2 -- src/protocols/InputMethodV2.cpp | 2 -- src/protocols/LayerShell.cpp | 2 -- src/protocols/LinuxDMABUF.cpp | 10 +++---- src/protocols/MesaDRM.cpp | 8 ++---- src/protocols/OutputManagement.cpp | 2 -- src/protocols/OutputPower.cpp | 2 -- src/protocols/PointerConstraints.cpp | 2 -- src/protocols/PointerGestures.cpp | 2 -- src/protocols/PresentationTime.cpp | 2 -- src/protocols/PrimarySelection.cpp | 2 -- src/protocols/Screencopy.cpp | 2 -- src/protocols/ServerDecorationKDE.cpp | 2 -- src/protocols/SessionLock.cpp | 2 -- src/protocols/ShortcutsInhibit.cpp | 2 -- src/protocols/Tablet.cpp | 2 -- src/protocols/TextInputV1.cpp | 2 -- src/protocols/TextInputV3.cpp | 2 -- src/protocols/ToplevelExport.cpp | 2 -- src/protocols/Viewporter.cpp | 2 -- src/protocols/VirtualKeyboard.cpp | 2 -- src/protocols/VirtualPointer.cpp | 2 -- src/protocols/WaylandProtocol.cpp | 4 +-- src/protocols/WaylandProtocol.hpp | 40 +++++++++++++++++++++------ src/protocols/XDGActivation.cpp | 2 -- src/protocols/XDGDecoration.cpp | 2 -- src/protocols/XDGOutput.cpp | 2 -- src/protocols/XDGShell.cpp | 2 -- src/protocols/XWaylandShell.cpp | 2 -- src/protocols/core/Compositor.cpp | 2 -- src/protocols/core/DataDevice.cpp | 2 -- src/protocols/core/Seat.cpp | 2 -- src/protocols/core/Shm.cpp | 2 -- src/protocols/core/Subcompositor.cpp | 2 -- 45 files changed, 42 insertions(+), 104 deletions(-) diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index 38b8c800..13597fa9 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -4,8 +4,6 @@ #include "../render/Renderer.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::alphaModifier->protoLog - CAlphaModifier::CAlphaModifier(SP resource_, SP surface_) : resource(resource_), pSurface(surface_) { if (!resource->resource()) return; diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 812afe53..233a5df9 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -2,8 +2,6 @@ #include #include "../helpers/CursorShapes.hpp" -#define LOGM PROTO::cursorShape->protoLog - CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 3ab38ea1..bc0945f1 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,8 +4,6 @@ #include #include -#define LOGM PROTO::lease->protoLog - CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if (!good()) return; @@ -226,7 +224,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe auto fd = drm->getNonMasterFD(); if (fd < 0) { - Debug::log(ERR, "[DRMLease] Failed to dup fd for drm node {}", drm->gpuName); + LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 9a48b99a..4993f1a4 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -7,8 +7,6 @@ #include -#define LOGM PROTO::sync->protoLog - CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index c039d3b4..ad6ee89a 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -3,8 +3,6 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" -#define LOGM PROTO::dataWlr->protoLog - CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 40f9af44..2d6b2ee2 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -8,8 +8,6 @@ #include #include -#define LOGM PROTO::focusGrab->protoLog - CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP surface) { listeners.destroy = surface->events.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index f7b3886f..59888ce2 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -1,8 +1,6 @@ #include "ForeignToplevel.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::foreignToplevel->protoLog - CForeignToplevelHandle::CForeignToplevelHandle(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) return; diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index b31a4083..bd597a91 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -4,8 +4,6 @@ #include "protocols/core/Output.hpp" #include "render/Renderer.hpp" -#define LOGM PROTO::foreignToplevelWlr->protoLog - CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) return; diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 5bf56c5a..d39fa67c 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -2,8 +2,6 @@ #include #include "core/Compositor.hpp" -#define LOGM PROTO::fractional->protoLog - CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 4febffbb..c902d00e 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -5,8 +5,6 @@ #include "../Compositor.hpp" #include "../protocols/core/Output.hpp" -#define LOGM PROTO::gamma->protoLog - CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if (!resource_->resource()) return; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 860004c9..92bfbae4 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,8 +1,6 @@ #include "GlobalShortcuts.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::globalShortcuts->protoLog - CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 2ec7d2a1..8d915ac6 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -1,8 +1,6 @@ #include "IdleNotify.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" -#define LOGM PROTO::idle->protoLog - static int onTimer(SP self, void* data) { const auto NOTIF = (CExtIdleNotification*)data; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index fd306f09..a0820e0b 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -6,8 +6,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::ime->protoLog - CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP resource_, SP owner_) : resource(resource_), owner(owner_) { if (!resource->resource()) return; diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 17d3b22a..c02d23f3 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -4,8 +4,6 @@ #include "core/Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::layerShell->protoLog - void CLayerShellResource::SState::reset() { anchor = 0; exclusive = 0; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 0fbf832e..3cdb5b34 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,8 +14,6 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" -#define LOGM PROTO::linuxDma->protoLog - static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -425,7 +423,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { - protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to get drm dev, disabling linux dmabuf"); removeGlobal(); return; } @@ -477,7 +475,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { - protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to get drm dev, disabling linux dmabuf"); removeGlobal(); return; } @@ -487,12 +485,12 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); drmFreeDevice(&device); if (mainDeviceFD < 0) { - protoLog(ERR, "failed to open drm dev, disabling linux dmabuf"); + LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; } } else { - protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); + LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); removeGlobal(); } diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index ed412555..9fcd5f9b 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -4,8 +4,6 @@ #include "../Compositor.hpp" #include "types/WLBuffer.hpp" -#define LOGM PROTO::mesaDRM->protoLog - CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); for (int i = 0; i < attrs_.planes; ++i) { @@ -115,7 +113,7 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co drmDevice* dev = nullptr; int drmFD = g_pCompositor->m_iDRMFD; if (drmGetDevice2(drmFD, 0, &dev) != 0) { - protoLog(ERR, "Failed to get device, disabling MesaDRM"); + LOGM(ERR, "Failed to get device, disabling MesaDRM"); removeGlobal(); return; } @@ -126,13 +124,13 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); if (!dev->nodes[DRM_NODE_PRIMARY]) { - protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); + LOGM(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); drmFreeDevice(&dev); removeGlobal(); return; } - protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); nodeName = dev->nodes[DRM_NODE_PRIMARY]; } drmFreeDevice(&dev); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 66f4c5f0..cfe388fa 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -4,8 +4,6 @@ using namespace Aquamarine; -#define LOGM PROTO::outputManagement->protoLog - COutputManager::COutputManager(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index 597b9871..0c324bf0 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -2,8 +2,6 @@ #include "../Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::outputPower->protoLog - COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!resource->resource()) return; diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index fd15242d..0f2dd991 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -5,8 +5,6 @@ #include "../managers/SeatManager.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::constraints->protoLog - CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : resourceL(resource_), locked(true), lifetime(lifetime_) { if (!resource_->resource()) diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 86510779..c83e3887 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -4,8 +4,6 @@ #include "core/Seat.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::pointerGestures->protoLog - CPointerGestureSwipe::CPointerGestureSwipe(SP resource_) : resource(resource_) { if (!resource->resource()) return; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index a2fc270c..335cf557 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -6,8 +6,6 @@ #include "core/Output.hpp" #include -#define LOGM PROTO::presentation->protoLog - CQueuedPresentationData::CQueuedPresentationData(SP surf) : surface(surf) { ; } diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 78eb8d63..4fede706 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -4,8 +4,6 @@ #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" -#define LOGM PROTO::primarySelection->protoLog - CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index a8afba84..f246f6dd 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -9,8 +9,6 @@ #include -#define LOGM PROTO::screencopy->protoLog - CScreencopyFrame::~CScreencopyFrame() { if (buffer && buffer->locked()) buffer->unlock(); diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index 42da52a9..c7b98a9c 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -1,8 +1,6 @@ #include "ServerDecorationKDE.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::serverDecorationKDE->protoLog - CServerDecorationKDE::CServerDecorationKDE(SP resource_, SP surf) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index df97413c..7b0d8b3b 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -5,8 +5,6 @@ #include "core/Compositor.hpp" #include "core/Output.hpp" -#define LOGM PROTO::sessionLock->protoLog - CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { if (!resource->resource()) diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index 1a0433e6..e4424ed7 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -3,8 +3,6 @@ #include "../Compositor.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::shortcutsInhibit->protoLog - CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, SP surf) : resource(resource_), pSurface(surf) { if (!resource->resource()) return; diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 72c7cfde..b974152e 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -7,8 +7,6 @@ #include #include -#define LOGM PROTO::tablet->protoLog - CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 78e910cb..f25f5aca 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -3,8 +3,6 @@ #include "../Compositor.hpp" #include "core/Compositor.hpp" -#define LOGM PROTO::textInputV1->protoLog - CTextInputV1::~CTextInputV1() { events.destroy.emit(); } diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 1302a57f..99d799f3 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -2,8 +2,6 @@ #include #include "core/Compositor.hpp" -#define LOGM PROTO::textInputV3->protoLog - void CTextInputV3::SState::reset() { cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; surrounding.updated = false; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index fb3fde2b..05e991d6 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -8,8 +8,6 @@ #include -#define LOGM PROTO::toplevelExport->protoLog - CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 78f3039f..58cb851d 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -2,8 +2,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::viewport->protoLog - CViewportResource::CViewportResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 2642ec11..27a4f248 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -2,8 +2,6 @@ #include #include "../devices/IKeyboard.hpp" -#define LOGM PROTO::virtualKeyboard->protoLog - CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 8626241a..eb92a640 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -1,8 +1,6 @@ #include "VirtualPointer.hpp" #include "core/Output.hpp" -#define LOGM PROTO::virtualPointer->protoLog - CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, WP boundOutput_) : boundOutput(boundOutput_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 954f160d..0782d323 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -21,7 +21,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, iface, ver, this, &bindManagerInternal); if (!m_pGlobal) { - protoLog(ERR, "could not create a global"); + LOGM(ERR, "could not create a global [{}]", m_szName); return; } @@ -30,7 +30,7 @@ IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, co m_liDisplayDestroy.parent = this; wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy.listener); - protoLog(LOG, "Registered global"); + LOGM(LOG, "Registered global [{}]", m_szName); } IWaylandProtocol::~IWaylandProtocol() { diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 4d4e7925..0fa8daab 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -11,6 +11,35 @@ #define PROTO NProtocols +#define EXTRACT_CLASS_NAME() \ + []() constexpr -> std::string_view { \ + constexpr std::string_view prettyFunction = __PRETTY_FUNCTION__; \ + constexpr size_t colons = prettyFunction.find("::"); \ + if (colons != std::string_view::npos) { \ + constexpr size_t begin = prettyFunction.substr(0, colons).rfind(' ') + 1; \ + constexpr size_t end = colons - begin; \ + return prettyFunction.substr(begin, end); \ + } else { \ + return "Global"; \ + } \ + }() + +#define LOGM(level, ...) \ + do { \ + std::ostringstream oss; \ + if (level == WARN || level == ERR || level == CRIT) { \ + oss << "[" << __FILE__ << ":" << __LINE__ << "] "; \ + } else if (level == LOG || level == INFO || level == TRACE) { \ + oss << "[" << EXTRACT_CLASS_NAME() << "] "; \ + } \ + if constexpr (std::is_same_v) { \ + oss << __VA_ARGS__; \ + Debug::log(level, oss.str()); \ + } else { \ + Debug::log(level, std::format("{}{}", oss.str(), std::format(__VA_ARGS__))); \ + } \ + } while (0) + class IWaylandProtocol; struct IWaylandProtocolDestroyWrapper { wl_listener listener; @@ -22,15 +51,10 @@ class IWaylandProtocol { IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name); virtual ~IWaylandProtocol(); - virtual void onDisplayDestroy(); - virtual void removeGlobal(); + virtual void onDisplayDestroy(); + virtual void removeGlobal(); - virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; - - template - void protoLog(LogLevel level, std::format_string fmt, Args&&... args) { - Debug::log(level, std::format("[{}] ", m_szName) + std::vformat(fmt.get(), std::make_format_args(args...))); - }; + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; IWaylandProtocolDestroyWrapper m_liDisplayDestroy; diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 40f33f02..4a6c7bfe 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -4,8 +4,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::activation->protoLog - CXDGActivationToken::CXDGActivationToken(SP resource_) : resource(resource_) { if (!resource_->resource()) return; diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index 021a1141..07b1694c 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -1,8 +1,6 @@ #include "XDGDecoration.hpp" #include -#define LOGM PROTO::xdgDecoration->protoLog - CXDGDecoration::CXDGDecoration(SP resource_, wl_resource* toplevel) : resource(resource_), pToplevelResource(toplevel) { if (!resource->resource()) return; diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 073aa502..9c2c353c 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -12,8 +12,6 @@ // -#define LOGM PROTO::xdgOutput->protoLog - void CXDGOutputProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagerResources, [&](const auto& other) { return other->resource() == res; }); } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index aea23329..eaf5c333 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -6,8 +6,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::xdgShell->protoLog - void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) { anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT); anchor.setLeft(edges == XDG_POSITIONER_ANCHOR_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp index 6cc5256f..d6c3b1a8 100644 --- a/src/protocols/XWaylandShell.cpp +++ b/src/protocols/XWaylandShell.cpp @@ -2,8 +2,6 @@ #include "core/Compositor.hpp" #include -#define LOGM PROTO::xwaylandShell->protoLog - CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index a767dd52..8b6f46b1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -13,8 +13,6 @@ #include "../../render/Renderer.hpp" #include -#define LOGM PROTO::compositor->protoLog - class CDefaultSurfaceRole : public ISurfaceRole { public: virtual eSurfaceRole role() { diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index fe3905d0..4ed28f24 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -6,8 +6,6 @@ #include "Seat.hpp" #include "Compositor.hpp" -#define LOGM PROTO::data->protoLog - CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index bb6a9d4d..a111c12c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -9,8 +9,6 @@ #include -#define LOGM PROTO::seat->protoLog - CWLTouchResource::CWLTouchResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 75c2134a..99459d9a 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,8 +7,6 @@ #include "../../Compositor.hpp" #include "../../helpers/Format.hpp" -#define LOGM PROTO::shm->protoLog - CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if (!pool_->pool->data) return; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 2a7c06dc..e0679eff 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -2,8 +2,6 @@ #include "Compositor.hpp" #include -#define LOGM PROTO::subcompositor->protoLog - CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_) : surface(surface_), parent(parent_), resource(resource_) { if (!good()) From 682b30fba89c043e86d9c96bdb8df133c1683054 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Fri, 16 Aug 2024 10:19:08 +0300 Subject: [PATCH 0490/2393] env: Add HYPRLAND_NO_SD_VARS env condition (#7358) * Add HYPRLAND_NO_SD_VARS env condition wip #7083 * Formatting shuffle * Formatting --- src/Compositor.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 4024fadf..9d247a56 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -429,7 +429,7 @@ void CCompositor::cleanEnvironment() { if (m_bDesktopEnvSet) unsetenv("XDG_CURRENT_DESKTOP"); - if (m_pAqBackend->hasSession()) { + if (m_pAqBackend->hasSession() && !envEnabled("HYPRLAND_NO_SD_VARS")) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " @@ -659,7 +659,11 @@ void CCompositor::prepareFallbackOutput() { void CCompositor::startCompositor() { signal(SIGPIPE, SIG_IGN); - if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) { + if ( + /* Session-less Hyprland usually means a nest, don't update the env in that case */ + m_pAqBackend->hasSession() && + /* Activation environment management is not disabled */ + !envEnabled("HYPRLAND_NO_SD_VARS")) { const auto CMD = #ifdef USES_SYSTEMD "systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash " From 1840a907a8c6b1f59cfa6738a8f46b320e8df8b1 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 16 Aug 2024 11:09:01 +0200 Subject: [PATCH 0491/2393] renderbuffer: ensure framebuffer gets deleted (#7363) after commit 4b4971c it uses m_iFbAllocated and deletes if upon calling release() but Renderbuffer generates directly on m_iFb without calling alloc() meaning it wont be deleted on release(), set m_iFbAllocated to true after generating the buffer. --- src/render/Renderbuffer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 58ed88d6..c4425ce9 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -35,7 +35,8 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : glBindRenderbuffer(GL_RENDERBUFFER, 0); glGenFramebuffers(1, &m_sFramebuffer.m_iFb); - m_sFramebuffer.m_vSize = buffer->size; + m_sFramebuffer.m_iFbAllocated = true; + m_sFramebuffer.m_vSize = buffer->size; m_sFramebuffer.bind(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO); From c5feee1e357f3c3c59ebe406630601c627807963 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 16 Aug 2024 18:00:59 +0200 Subject: [PATCH 0492/2393] xcursormgr: dont apply scale on gsettings (#7316) gtk scales the cursor size itself since its CSD so if we scale the size its gonna get double scaled. incorporate the scale into xcursormanager to keep track of it. --- src/managers/CursorManager.cpp | 10 +++++----- src/managers/XCursorManager.cpp | 18 ++++++++++-------- src/managers/XCursorManager.hpp | 9 +++++---- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index e2dd5bb3..1c047f85 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -102,7 +102,7 @@ CCursorManager::CCursorManager() { // since we fallback to xcursor always load it on startup. otherwise we end up with a empty theme if hyprcursor is enabled in the config // and then later is disabled. - m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize * std::ceil(m_fCursorScale)); + m_pXcursor->loadTheme(getenv("XCURSOR_THEME") ? getenv("XCURSOR_THEME") : "default", m_iSize, m_fCursorScale); m_pAnimationTimer = makeShared(std::nullopt, cursorAnimTimer, this); g_pEventLoopManager->addTimer(m_pAnimationTimer); @@ -163,7 +163,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { auto setXCursor = [this](auto const& name) { float scale = std::ceil(m_fCursorScale); - auto xcursor = m_pXcursor->getShape(name, m_iSize * scale); + auto xcursor = m_pXcursor->getShape(name, m_iSize, m_fCursorScale); auto& icon = xcursor->images.front(); auto buf = makeShared((uint8_t*)icon.pixels.data(), icon.size, icon.hotspot); setCursorBuffer(buf, icon.hotspot / scale, scale); @@ -277,7 +277,7 @@ void CCursorManager::setXWaylandCursor() { g_pXWayland->setCursor(cairo_image_surface_get_data(CURSOR.surface), cairo_image_surface_get_stride(CURSOR.surface), {CURSOR.size, CURSOR.size}, {CURSOR.hotspotX, CURSOR.hotspotY}); else { - auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize * std::ceil(m_fCursorScale)); + auto xcursor = m_pXcursor->getShape("left_ptr", m_iSize, 1); auto& icon = xcursor->images.front(); g_pXWayland->setCursor((uint8_t*)icon.pixels.data(), icon.size.x * 4, icon.size, icon.hotspot); @@ -329,10 +329,10 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); if (!m_pHyprcursor->valid()) { Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme); - m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale); } } else - m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize); + m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale); updateTheme(); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 0921bcd4..6f000f9f 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -100,12 +100,13 @@ CXCursorManager::CXCursorManager() { defaultCursor = hyprCursor; } -void CXCursorManager::loadTheme(std::string const& name, int size) { - if (lastLoadSize == size && themeName == name) +void CXCursorManager::loadTheme(std::string const& name, int size, float scale) { + if (lastLoadSize == (size * std::ceil(scale)) && themeName == name && lastLoadScale == scale) return; - lastLoadSize = size; - themeName = name.empty() ? "default" : name; + lastLoadSize = size * std::ceil(scale); + lastLoadScale = scale; + themeName = name.empty() ? "default" : name; defaultCursor.reset(); cursors.clear(); @@ -156,10 +157,10 @@ void CXCursorManager::loadTheme(std::string const& name, int size) { syncGsettings(); } -SP CXCursorManager::getShape(std::string const& shape, int size) { +SP CXCursorManager::getShape(std::string const& shape, int size, float scale) { // monitor scaling changed etc, so reload theme with new size. - if (size != lastLoadSize) - loadTheme(themeName, size); + if ((size * std::ceil(scale)) != lastLoadSize || scale != lastLoadScale) + loadTheme(themeName, size, scale); // try to get an icon we know if we have one for (auto const& c : cursors) { @@ -602,6 +603,7 @@ void CXCursorManager::syncGsettings() { g_object_unref(gsettings); }; + int unscaledSize = lastLoadSize / std::ceil(lastLoadScale); setValue("cursor-theme", themeName, "org.gnome.desktop.interface"); - setValue("cursor-size", lastLoadSize, "org.gnome.desktop.interface"); + setValue("cursor-size", unscaledSize, "org.gnome.desktop.interface"); } diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 48fda5dd..1f3c24db 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -29,8 +29,8 @@ class CXCursorManager { CXCursorManager(); ~CXCursorManager() = default; - void loadTheme(const std::string& name, int size); - SP getShape(std::string const& shape, int size); + void loadTheme(const std::string& name, int size, float scale); + SP getShape(std::string const& shape, int size, float scale); void syncGsettings(); private: @@ -40,8 +40,9 @@ class CXCursorManager { std::vector> loadStandardCursors(std::string const& name, int size); std::vector> loadAllFromDir(std::string const& path, int size); - int lastLoadSize = 0; - std::string themeName = ""; + int lastLoadSize = 0; + float lastLoadScale = 0; + std::string themeName = ""; SP defaultCursor; SP hyprCursor; std::vector> cursors; From 92744b5b9aa386257bf243c957ab64f7f4171a19 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 17 Aug 2024 17:33:16 +0100 Subject: [PATCH 0493/2393] IPC: Add config descriptions (#7377) Thanks @gulafaran for the work --- Co-authored-by: @gulafaran --- src/config/ConfigDescriptions.hpp | 1344 +++++++++++++++++++++++++++ src/config/ConfigManager.cpp | 63 +- src/config/ConfigManager.hpp | 66 ++ src/debug/HyprCtl.cpp | 16 + src/helpers/Color.cpp | 2 +- src/helpers/Color.hpp | 2 +- src/managers/input/InputManager.cpp | 11 +- 7 files changed, 1491 insertions(+), 13 deletions(-) create mode 100644 src/config/ConfigDescriptions.hpp diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp new file mode 100644 index 00000000..3c830132 --- /dev/null +++ b/src/config/ConfigDescriptions.hpp @@ -0,0 +1,1344 @@ +#pragma once + +#include "ConfigManager.hpp" + +inline static const std::vector CONFIG_OPTIONS = { + + /* + * general: + */ + + SConfigOptionDescription{ + .value = "general:border_size", + .description = "size of the border around windows", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "general:no_border_on_floating", + .description = "disable borders for floating windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:gaps_in", + .description = "gaps between windows\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"5"}, + }, + SConfigOptionDescription{ + .value = "general:gaps_out", + .description = "gaps between windows and monitor edges\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"20"}, + }, + SConfigOptionDescription{ + .value = "general:gaps_workspaces", + .description = "gaps between workspaces. Stacks with gaps_out.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 100}, + }, + SConfigOptionDescription{ + .value = "general:col.inactive_border", + .description = "border color for inactive windows", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xff444444"}, + }, + SConfigOptionDescription{ + .value = "general:col.active_border", + .description = "border color for the active window", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffffffff"}, + }, + SConfigOptionDescription{ + .value = "general:col.nogroup_border", + .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffffaaff"}, + }, + SConfigOptionDescription{ + .value = "general:col.nogroup_border_active", + .description = "active border color for window that cannot be added to a group", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0xffff00ff"}, + }, + SConfigOptionDescription{ + .value = "general:layout", + .description = "which layout to use. [dwindle/master]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"dwindle"}, + }, + SConfigOptionDescription{ + .value = "general:no_focus_fallback", + .description = "if true, will not fall back to the next available window when moving focus in a direction where no window was found", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:resize_on_border", + .description = "enables resizing windows by clicking and dragging on borders and gaps", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:extend_border_grab_area", + .description = "extends the area around the border where you can click and drag on, only used when general:resize_on_border is on.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{15, 0, 100}, + }, + SConfigOptionDescription{ + .value = "general:hover_icon_on_border", + .description = "show a cursor icon when hovering over borders, only used when general:resize_on_border is on.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "general:allow_tearing", + .description = "master switch for allowing tearing to occur. See the Tearing page.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:resize_corner", + .description = "force floating windows to use a specific corner when being resized (1-4 going clockwise from top left, 0 to disable)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 4}, + }, + + /* + * decoration: + */ + + SConfigOptionDescription{ + .value = "decoration:rounding", + .description = "rounded corners' radius (in layout px)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 20}, + }, + SConfigOptionDescription{ + .value = "decoration:active_opacity", + .description = "opacity of active windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:inactive_opacity", + .description = "opacity of inactive windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:fullscreen_opacity", + .description = "opacity of fullscreen windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:drop_shadow", + .description = "enable drop shadows on windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_range", + .description = "Shadow range (size) in layout px", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{4, 0, 100}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_render_power", + .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 1, 4}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_ignore_window", + .description = "if true, the shadow will not be rendered behind the window itself, only around it.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "decoration:col.shadow", + .description = "shadow's color. Alpha dictates shadow's opacity.", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xee1a1a1a}, + }, + SConfigOptionDescription{ + .value = "decoration:col.shadow_inactive", + .description = "inactive shadow color. (if not set, will fall back to col.shadow)", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "decoration:shadow_offset", + .description = "shadow's rendering offset.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow_scale", + .description = "shadow's scale. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_inactive", + .description = "enables dimming of inactive windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_strength", + .description = "how much inactive windows should be dimmed [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_special", + .description = "how much to dim the rest of the screen by when a special workspace is open. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:dim_around", + .description = "how much the dimaround window rule should dim by. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.4, 0, 1}, + }, + SConfigOptionDescription{ + .value = "decoration:screen_shader", + .description = "screen_shader a path to a custom shader to be applied at the end of rendering. See examples/screenShader.frag for an example.", + .type = CONFIG_OPTION_STRING_LONG, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + + /* + * blur: + */ + + SConfigOptionDescription{ + .value = "blur:enabled", + .description = "enable kawase window background blur", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "blur:size", + .description = "blur size (distance)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{8, 0, 100}, + }, + SConfigOptionDescription{ + .value = "blur:passes", + .description = "the amount of passes to perform", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 10}, + }, + SConfigOptionDescription{ + .value = "blur:ignore_opacity", + .description = "make the blur layer ignore the opacity of the window", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:new_optimizations", + .description = "whether to enable further optimizations to the blur. Recommended to leave on, as it will massively improve performance.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "blur:xray", + .description = "if enabled, floating windows will ignore tiled windows in their blur. Only available if blur_new_optimizations is true. Will reduce overhead on floating " + "blur significantly.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:noise", + .description = "how much noise to apply. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.0117, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:contrast", + .description = "contrast modulation for blur. [0.0 - 2.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.8916, 0, 2}, + }, + SConfigOptionDescription{ + .value = "blur:brightness", + .description = "brightness modulation for blur. [0.0 - 2.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.8172, 0, 2}, + }, + SConfigOptionDescription{ + .value = "blur:vibrancy", + .description = "Increase saturation of blurred colors. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.1696, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:vibrancy_darkness", + .description = "How strong the effect of vibrancy is on dark areas . [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "blur:special", + .description = "whether to blur behind the special workspace (note: expensive)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:popups", + .description = "whether to blur popups (e.g. right-click menus)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:popups_ignorealpha", + .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, + }, + + /* + * animations: + */ + + SConfigOptionDescription{ + .value = "animations:enabled", + .description = "enable animations", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "animations:first_launch_animation", + .description = "enable first launch animation", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * input: + */ + + SConfigOptionDescription{ + .value = "input:kb_model", + .description = "Appropriate XKB keymap parameter. See the note below.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, + }, + SConfigOptionDescription{ + .value = "input:kb_layout", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"us"}, + }, + SConfigOptionDescription{ + .value = "input:kb_variant", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_options", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_rules", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, + }, + SConfigOptionDescription{ + .value = "input:kb_file", + .description = "Appropriate XKB keymap parameter", + .type = CONFIG_OPTION_STRING_LONG, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:numlock_by_default", + .description = "Engage numlock by default.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:resolve_binds_by_sym", + .description = "Determines how keybinds act when multiple layouts are used. If false, keybinds will always act as if the first specified layout is active. If true, " + "keybinds specified by symbols are activated when you type the respective symbol with the current layout.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:repeat_rate", + .description = "The repeat rate for held-down keys, in repeats per second.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{25, 0, 200}, + }, + SConfigOptionDescription{ + .value = "input:repeat_delay", + .description = "Delay before a held-down key is repeated, in milliseconds.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{600, 0, 2000}, + }, + SConfigOptionDescription{ + .value = "input:sensitivity", + .description = "Sets the mouse input sensitivity. Value is clamped to the range -1.0 to 1.0.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0, -1, 1}, + }, + SConfigOptionDescription{ + .value = "input:accel_profile", + .description = "Sets the cursor acceleration profile. Can be one of adaptive, flat. Can also be custom, see below. Leave empty to use libinput's default mode for your " + "input device. [adaptive/flat/custom]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:force_no_accel", + .description = "Force no cursor acceleration. This bypasses most of your pointer settings to get as raw of a signal as possible. Enabling this is not recommended due to " + "potential cursor desynchronization.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:left_handed", + .description = "Switches RMB and LMB", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:scroll_points", + .description = "Sets the scroll acceleration profile, when accel_profile is set to custom. Has to be in the form . Leave empty to have a flat scroll curve.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:scroll_method", + .description = "Sets the scroll method. Can be one of 2fg (2 fingers), edge, on_button_down, no_scroll. [2fg/edge/on_button_down/no_scroll]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:scroll_button", + .description = "Sets the scroll button. Has to be an int, cannot be a string. Check wev if you have any doubts regarding the ID. 0 means default.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 300}, + }, + SConfigOptionDescription{ + .value = "input:scroll_button_lock", + .description = "If the scroll button lock is enabled, the button does not need to be held down. Pressing and releasing the button toggles the button lock, which logically " + "holds the button down or releases it. While the button is logically held down, motion events are converted to scroll events.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:scroll_factor", + .description = "Multiplier added to scroll movement for external mice. Note that there is a separate setting for touchpad scroll_factor.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:natural_scroll", + .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:follow_mouse", + .description = "Specify if and how cursor movement should affect window focus. See the note below. [0/1/2/3]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 3}, + }, + SConfigOptionDescription{ + .value = "input:mouse_refocus", + .description = "if disabled, mouse focus won't switch to the hovered window unless the mouse crosses a window boundary when follow_mouse=1.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:float_switch_override_focus", + .description = "If enabled (1 or 2), focus will change to the window under the cursor when changing from tiled-to-floating and vice versa. If 2, focus will also follow " + "mouse on float-to-float switches.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:special_fallthrough", + .description = "if enabled, having only floating windows in the special workspace will not block focusing windows in the regular workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:off_window_axis_events", + .description = "Handles axis events around (gaps/border for tiled, dragarea/border for floated) a focused window. 0 ignores axis events 1 sends out-of-bound coordinates 2 " + "fakes pointer coordinates to the closest point inside the window 3 warps the cursor to the closest point inside the window", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 3}, + }, + SConfigOptionDescription{ + .value = "input:emulate_discrete_scroll", + .description = "Emulates discrete scrolling from high resolution scrolling events. 0 disables it, 1 enables handling of non-standard events only, and 2 force enables all " + "scroll wheel events to be handled", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + + /* + * input:touchpad: + */ + + SConfigOptionDescription{ + .value = "input:touchpad:disable_while_typing", + .description = "Disable the touchpad while typing.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:natural_scroll", + .description = "Inverts scrolling direction. When enabled, scrolling moves content directly, rather than manipulating a scrollbar.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:scroll_factor", + .description = "Multiplier applied to the amount of scroll movement.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:middle_button_emulation", + .description = + "Sending LMB and RMB simultaneously will be interpreted as a middle click. This disables any touchpad area that would normally send a middle click based on location.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap_button_map", + .description = "Sets the tap button mapping for touchpad button emulation. Can be one of lrm (default) or lmr (Left, Middle, Right Buttons). [lrm/lmr]", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:touchpad:clickfinger_behavior", + .description = + "Button presses with 1, 2, or 3 fingers will be mapped to LMB, RMB, and MMB respectively. This disables interpretation of clicks based on location on the touchpad.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap-to-click", + .description = "Tapping on the touchpad with 1, 2, or 3 fingers will send LMB, RMB, and MMB respectively.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:drag_lock", + .description = "When enabled, lifting the finger off for a short time while dragging will not drop the dragged item.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:touchpad:tap-and-drag", + .description = "Sets the tap and drag mode for the touchpad", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * input:touchdevice: + */ + + SConfigOptionDescription{ + .value = "input:touchdevice:transform", + .description = "Transform the input from touchdevices. The possible transformations are the same as those of the monitors", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "input:touchdevice:output", + .description = "The monitor to bind touch devices. The default is auto-detection. To stop auto-detection, use an empty string or the [[Empty]] value.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:touchdevice:enabled", + .description = "Whether input is enabled for touch devices.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * input:tablet: + */ + + SConfigOptionDescription{ + .value = "input:tablet:transform", + .description = "transform the input from tablets. The possible transformations are the same as those of the monitors", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 6}, // ##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "input:tablet:output", + .description = "the monitor to bind tablets. Empty means unbound..", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "input:tablet:region_position", + .description = "position of the mapped region in monitor layout.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:region_size", + .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {-100, -100}, {4000, 4000}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:relative_input", + .description = "whether the input should be relative", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:tablet:left_handed", + .description = "if enabled, the tablet will be rotated 180 degrees", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "input:tablet:active_area_size", + .description = "size of tablet's active area in mm", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}}, + }, + SConfigOptionDescription{ + .value = "input:tablet:active_area_position", + .description = "position of the active area in mm", + .type = CONFIG_OPTION_VECTOR, + .data = SConfigOptionDescription::SVectorData{{}, {}, {500, 500}}, + }, + + /* ##TODO + * + * PER DEVICE SETTINGS? + * + * */ + + /* + * gestures: + */ + + SConfigOptionDescription{ + .value = "gestures:workspace_swipe", + .description = "enable workspace swipe gesture on touchpad", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_fingers", + .description = "how many fingers for the touchpad gesture", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 0, 5}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_min_fingers", + .description = "if enabled, workspace_swipe_fingers is considered the minimum number of fingers to swipe", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_distance", + .description = "in px, the distance of the touchpad gesture", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{300, 0, 2000}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_touch", + .description = "enable workspace swiping from the edge of a touchscreen", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_invert", + .description = "invert the direction (touchpad only)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_touch_invert", + .description = "invert the direction (touchscreen only)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_min_speed_to_force", + .description = "minimum speed in px per timepoint to force the change ignoring cancel_ratio. Setting to 0 will disable this mechanic.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{30, 0, 200}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_cancel_ratio", + .description = "how much the swipe has to proceed in order to commence it. (0.7 -> if > 0.7 * distance, switch, if less, revert) [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.5, 0, 1}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_create_new", + .description = "whether a swipe right on the last workspace should create a new one.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_direction_lock", + .description = "if enabled, switching direction will be locked when you swipe past the direction_lock_threshold (touchpad only).", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_direction_lock_threshold", + .description = "in px, the distance to swipe before direction lock activates (touchpad only).", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{10, 0, 200}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_forever", + .description = "if enabled, swiping will not clamp at the neighboring workspaces but continue to the further ones.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "gestures:workspace_swipe_use_r", + .description = "if enabled, swiping will use the r prefix instead of the m prefix for finding workspaces.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * group: + */ + + SConfigOptionDescription{ + .value = "group:insert_after_current", + .description = "whether new windows in a group spawn after current or at group tail", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:focus_removed_window", + .description = "whether Hyprland should focus on the window that has just been moved out of the group", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "general:col.border_active", + .description = "border color for inactive windows", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66ffff00"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_inactive", + .description = "border color for the active window", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66777700"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_locked_active", + .description = "inactive border color for window that cannot be added to a group (see denywindowfromgroup dispatcher)", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66ff5500"}, + }, + SConfigOptionDescription{ + .value = "general:col.border_locked_inactive", + .description = "active border color for window that cannot be added to a group", + .type = CONFIG_OPTION_GRADIENT, + .data = SConfigOptionDescription::SGradientData{"0x66775500"}, + }, + + /* + * group:groupbar: + */ + + SConfigOptionDescription{ + .value = "group:groupbar:enabled", + .description = "enables groupbars", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:font_family", + .description = "font used to display groupbar titles, use misc:font_family if not specified", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "group:groupbar:font_size", + .description = "font size of groupbar title", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{8, 2, 64}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:gradients", + .description = "enables gradients", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:height", + .description = "height of the groupbar", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{14, 1, 64}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:stacked", + .description = "render the groupbar as a vertical stack", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:priority", + .description = "sets the decoration priority for groupbars", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 0, 6}, //##TODO RANGE? + }, + SConfigOptionDescription{ + .value = "group:groupbar:render_titles", + .description = "whether to render titles in the group bar decoration", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:scrolling", + .description = "whether scrolling in the groupbar changes group active window", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:text_color", + .description = "controls the group bar text color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xffffffff}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.active", + .description = "active group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66ffff00}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.inactive", + .description = "inactive (out of focus) group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66777700}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.locked_active", + .description = "active locked group border color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66ff5500}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:col.locked_inactive", + .description = "controls the group bar text color", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x66775500}, + }, + + /* + * misc: + */ + + SConfigOptionDescription{ + .value = "misc:disable_hyprland_logo", + .description = "disables the random Hyprland logo / anime girl background. :(", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:disable_splash_rendering", + .description = "disables the Hyprland splash rendering. (requires a monitor reload to take effect)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:col.splash", + .description = "Changes the color of the splash text (requires a monitor reload to take effect).", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0xffffffff}, + }, + SConfigOptionDescription{ + .value = "misc:font_family", + .description = "Set the global default font to render the text including debug fps/notification, config error messages and etc., selected from system fonts.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"Sans"}, + }, + SConfigOptionDescription{ + .value = "misc:splash_font_family", + .description = "Changes the font used to render the splash text, selected from system fonts (requires a monitor reload to take effect).", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{STRVAL_EMPTY}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:force_default_wallpaper", + .description = "Enforce any of the 3 default wallpapers. Setting this to 0 or 1 disables the anime background. -1 means “random”. [-1/0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{-1, -1, 2}, + }, + SConfigOptionDescription{ + .value = "misc:vfr", + .description = "controls the VFR status of Hyprland. Heavily recommended to leave enabled to conserve resources.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:vrr", + .description = " controls the VRR (Adaptive Sync) of your monitors. 0 - off, 1 - on, 2 - fullscreen only [0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:mouse_move_enables_dpms", + .description = "If DPMS is set to off, wake up the monitors if the mouse move", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:key_press_enables_dpms", + .description = "If DPMS is set to off, wake up the monitors if a key is pressed.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:always_follow_on_dnd", + .description = "Will make mouse focus follow the mouse when drag and dropping. Recommended to leave it enabled, especially for people using focus follows mouse at 0.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:layers_hog_keyboard_focus", + .description = "If true, will make keyboard-interactive layers keep their focus on mouse move (e.g. wofi, bemenu)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:animate_manual_resizes", + .description = "If true, will animate manual window resizes/moves", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:animate_mouse_windowdragging", + .description = "If true, will animate windows being dragged by mouse, note that this can cause weird behavior on some curves", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:disable_autoreload", + .description = "If true, the config will not reload automatically on save, and instead needs to be reloaded with hyprctl reload. Might save on battery.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:enable_swallow", + .description = "Enable window swallowing", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:swallow_regex", + .description = + "The class regex to be used for windows that should be swallowed (usually, a terminal). To know more about the list of regex which can be used use this cheatsheet.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:swallow_exception_regex", + .description = "The title regex to be used for windows that should not be swallowed by the windows specified in swallow_regex (e.g. wev). The regex is matched against the " + "parent (e.g. Kitty) window’s title on the assumption that it changes to whatever process it’s running.", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "misc:focus_on_activate", + .description = "Whether Hyprland should focus an app that requests to be focused (an activate request)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:mouse_move_focuses_monitor", + .description = "Whether mouse moving into a different monitor should focus it", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:render_ahead_of_time", + .description = "[Warning: buggy] starts rendering before your monitor displays a frame in order to lower latency", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:render_ahead_safezone", + .description = "how many ms of safezone to add to rendering ahead of time. Recommended 1-2.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 1, 10}, + }, + SConfigOptionDescription{ + .value = "misc:allow_session_lock_restore", + .description = "if true, will allow you to restart a lockscreen app in case it crashes (red screen of death)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:background_color", + .description = "change the background color. (requires enabled disable_hyprland_logo)", + .type = CONFIG_OPTION_COLOR, + .data = SConfigOptionDescription::SColorData{0x111111}, + }, + SConfigOptionDescription{ + .value = "misc:close_special_on_empty", + .description = "close the special workspace if the last window is removed", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "misc:new_window_takes_over_fullscreen", + .description = "if there is a fullscreen or maximized window, decide whether a new tiled window opened should replace it, stay behind or disable the fullscreen/maximized " + "state. 0 - behind, 1 - takes over, 2 - unfullscreen/unmaxize [0/1/2]", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:exit_window_retains_fullscreen", + .description = "if true, closing a fullscreen window makes the next focused window fullscreen", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "misc:initial_workspace_tracking", + .description = "if enabled, windows will open on the workspace they were invoked on. 0 - disabled, 1 - single-shot, 2 - persistent (all children too)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 2}, + }, + SConfigOptionDescription{ + .value = "misc:middle_click_paste", + .description = "whether to enable middle-click-paste (aka primary selection)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * binds: + */ + + SConfigOptionDescription{ + .value = "binds:pass_mouse_when_bound", + .description = "if disabled, will not pass the mouse events to apps / dragging windows around if a keybind has been triggered.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:scroll_event_delay", + .description = "in ms, how many ms to wait after a scroll event to allow passing another one for the binds.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{300, 0, 2000}, + }, + SConfigOptionDescription{ + .value = "binds:workspace_back_and_forth", + .description = "If enabled, an attempt to switch to the currently focused workspace will instead switch to the previous workspace. Akin to i3’s auto_back_and_forth.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:allow_workspace_cycles", + .description = "If enabled, workspaces don’t forget their previous workspace, so cycles can be created by switching to the first workspace in a sequence, then endlessly " + "going to the previous workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:workspace_center_on", + .description = "Whether switching workspaces should center the cursor on the workspace (0) or on the last active window for that workspace (1)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "binds:focus_preferred_method", + .description = "sets the preferred focus finding method when using focuswindow/movewindow/etc with a direction. 0 - history (recent have priority), 1 - length (longer " + "shared edges have priority)", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "binds:ignore_group_lock", + .description = "If enabled, dispatchers like moveintogroup, moveoutofgroup and movewindoworgroup will ignore lock per group.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:movefocus_cycles_fullscreen", + .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "binds:disable_keybind_grabbing", + .description = "If enabled, apps that request keybinds to be disabled (e.g. VMs) will not be able to do so.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "binds:window_direction_monitor_fallback", + .description = "If enabled, moving a window or focus over the edge of a monitor with a direction will move it to the next monitor in that direction.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + + /* + * xwayland: + */ + + SConfigOptionDescription{ + .value = "xwayland:use_nearest_neighbor", + .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "xwayland:force_zero_scaling", + .description = "forces a scale of 1 on xwayland windows on scaled displays.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * opengl: + */ + + SConfigOptionDescription{ + .value = "opengl:nvidia_anti_flicker", + .description = "reduces flickering on nvidia at the cost of possible frame drops on lower-end GPUs. On non-nvidia, this is ignored.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "opengl:force_introspection", + .description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - " + "nothing, 1 - force always on, 2 - force always on if nvidia", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + + /* + * render: + */ + + SConfigOptionDescription{ + .value = "render:explicit_sync", + .description = "Whether to enable explicit sync support. Requires a hyprland restart. 0 - no, 1 - yes, 2 - auto based on the gpu driver", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "render:explicit_sync_kms", + .description = "Whether to enable explicit sync support for the KMS layer. Requires explicit_sync to be enabled. 0 - no, 1 - yes, 2 - auto based on the gpu driver", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "render:direct_scanout", + .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " + "recommended to set this to false if the fullscreen application shows graphical glitches.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * cursor: + */ + + SConfigOptionDescription{ + .value = "cursor:use_nearest_neighbor", + .description = "sync xcursor theme with gsettings, it applies cursor-theme and cursor-size on theme load to gsettings making most CSD gtk based clients use same xcursor " + "theme and size.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:no_hardware_cursors", + .description = "disables hardware cursors", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:no_break_fs_vrr", + .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:min_refresh_rate", + .description = "minimum refresh rate for cursor movement when no_break_fs_vrr is active. Set to minimum supported refresh rate or higher", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{24, 10, 500}, + }, + SConfigOptionDescription{ + .value = "cursor:hotspot_padding", + .description = "the padding, in logical px, between screen edges and the cursor", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "cursor:inactive_timeout", + .description = "in seconds, after how many seconds of cursor’s inactivity to hide it. Set to 0 for never.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 20}, + }, + SConfigOptionDescription{ + .value = "cursor:no_warps", + .description = "if true, will not warp the cursor in many cases (focusing, keybinds, etc)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:persistent_warps", + .description = "When a window is refocused, the cursor returns to its last position relative to that window, rather than to the centre.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:warp_on_change_workspace", + .description = "If true, move the cursor to the last focused window after changing the workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:default_monitor", + .description = "the name of a default monitor for the cursor to be set to on startup (see hyprctl monitors for names)", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? + }, + SConfigOptionDescription{ + .value = "cursor:zoom_factor", + .description = "the factor to zoom by around the cursor. Like a magnifying glass. Minimum 1.0 (meaning no zoom)", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 1, 10}, + }, + SConfigOptionDescription{ + .value = "cursor:zoom_rigid", + .description = "whether the zoom should follow the cursor rigidly (cursor is always centered if it can be) or loosely", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:enable_hyprcursor", + .description = "whether to enable hyprcursor support", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:hide_on_key_press", + .description = "Hides the cursor when you press any key until the mouse is moved.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "cursor:hide_on_touch", + .description = "Hides the cursor when the last input was a touch input until a mouse input is done.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "cursor:allow_dumb_copy", + .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + + /* + * debug: + */ + + SConfigOptionDescription{ + .value = "debug:overlay", + .description = "print the debug performance overlay. Disable VFR for accurate results.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:damage_blink", + .description = "disable logging to a file", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:disable_logs", + .description = "disable logging to a file", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:disable_time", + .description = "disables time logging", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "debug:damage_tracking", + .description = "redraw only the needed bits of the display. Do not change. (default: full - 2) monitor - 1, none - 0", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{2, 0, 2}, + }, + SConfigOptionDescription{ + .value = "debug:enable_stdout_logs", + .description = "enables logging to stdout", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:manual_crash", + .description = "set to 1 and then back to 0 to crash Hyprland.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "debug:suppress_errors", + .description = "if true, do not display config file parsing errors.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:watchdog_timeout", + .description = "sets the timeout in seconds for watchdog to abort processing of a signal of the main thread. Set to 0 to disable.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{5, 0, 20}, + }, + SConfigOptionDescription{ + .value = "debug:disable_scale_checks", + .description = "disables verification of the scale factors. Will result in pixel alignment and rounding errors.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "debug:error_limit", + .description = "limits the number of displayed config file parsing errors.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{5, 0, 20}, + }, + SConfigOptionDescription{ + .value = "debug:error_position", + .description = "sets the position of the error bar. top - 0, bottom - 1", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{0, 0, 1}, + }, + SConfigOptionDescription{ + .value = "debug:colored_stdout_logs", + .description = "enables colors in the stdout logs.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, +}; \ No newline at end of file diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 41d3871c..1856bd49 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -28,7 +28,9 @@ #include using namespace Hyprutils::String; -extern "C" char** environ; +extern "C" char** environ; + +#include "ConfigDescriptions.hpp" static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** data) { std::string V = VALUE; @@ -312,8 +314,6 @@ CConfigManager::CConfigManager() { configPaths.emplace_back(getMainConfigPath()); m_pConfig = std::make_unique(configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); - m_pConfig->addConfigValue("general:sensitivity", {1.0f}); - m_pConfig->addConfigValue("general:apply_sens_to_raw", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:border_size", Hyprlang::INT{1}); m_pConfig->addConfigValue("general:no_border_on_floating", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:border_part_of_window", Hyprlang::INT{1}); @@ -2607,3 +2607,60 @@ std::optional CConfigManager::handlePlugin(const std::string& comma return {}; } + +const std::vector& CConfigManager::getAllDescriptions() { + return CONFIG_OPTIONS; +} + +std::string SConfigOptionDescription::jsonify() const { + auto parseData = [this]() -> std::string { + return std::visit( + [](auto&& val) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return std::format(R"#( "value": "{}")#", val.value); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {}, + "min": {}, + "max": {})#", + val.value, val.min, val.max); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {}, + "min": {}, + "max": {})#", + val.value, val.min, val.max); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.color.getAsHex()); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.value); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": {})#", val.choices); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "x": {}, + "y": {}, + "min_x": {}, + "min_y": {}, + "max_x": {}, + "max_y": {})#", + val.vec.x, val.vec.y, val.min.x, val.min.y, val.max.x, val.max.y); + } else if constexpr (std::is_same_v) { + return std::format(R"#( "value": "{}")#", val.gradient); + } + return std::string{""}; + }, + data); + }; + + std::string json = std::format(R"#({{ + "value": "{}", + "description": "{}", + "type": {}, + "flags": {}, + "data": {{ + {} + }} +}})#", + value, description, (uint16_t)type, (uint32_t)flags, parseData()); + + return json; +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 38dd0872..4241031b 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -83,6 +83,70 @@ struct SExecRequestedRule { uint64_t iPid = 0; }; +enum eConfigOptionType : uint16_t { + CONFIG_OPTION_BOOL = 0, + CONFIG_OPTION_INT = 1, /* e.g. 0/1/2*/ + CONFIG_OPTION_FLOAT = 2, + CONFIG_OPTION_STRING_SHORT = 3, /* e.g. "auto" */ + CONFIG_OPTION_STRING_LONG = 4, /* e.g. a command */ + CONFIG_OPTION_COLOR = 5, + CONFIG_OPTION_CHOICE = 6, /* e.g. "one", "two", "three" */ + CONFIG_OPTION_GRADIENT = 7, + CONFIG_OPTION_VECTOR = 8, +}; + +enum eConfigOptionFlags : uint32_t { + CONFIG_OPTION_FLAG_PERCENTAGE = (1 << 0), +}; + +struct SConfigOptionDescription { + + struct SBoolData { + bool value = false; + }; + + struct SRangeData { + int value = 0, min = 0, max = 2; + }; + + struct SFloatData { + float value = 0, min = 0, max = 100; + }; + + struct SStringData { + std::string value; + }; + + struct SColorData { + CColor color; + }; + + struct SChoiceData { + int firstIndex = 0; + std::string choices; // comma-separated + }; + + struct SGradientData { + std::string gradient; + }; + + struct SVectorData { + Vector2D vec, min, max; + }; + + std::string value; // e.g. general:gaps_in + std::string description; + std::string specialCategory; // if value is special (e.g. device:abc) value will be abc and special device + bool specialKey = false; + eConfigOptionType type = CONFIG_OPTION_BOOL; + uint32_t flags = 0; // eConfigOptionFlags + + std::string jsonify() const; + + // + std::variant data; +}; + class CConfigManager { public: CConfigManager(); @@ -115,6 +179,8 @@ class CConfigManager { std::vector getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); std::vector getMatchingRules(PHLLS); + const std::vector& getAllDescriptions(); + std::unordered_map m_mAdditionalReservedAreas; std::unordered_map getAnimationConfig(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3ab0fa7a..717fb5c0 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1561,6 +1561,21 @@ std::string getIsLocked(eHyprCtlOutputFormat format, std::string request) { return lockedStr; } +std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) { + std::string json = "{"; + const auto& DESCS = g_pConfigManager->getAllDescriptions(); + + for (const auto& d : DESCS) { + json += d.jsonify() + ",\n"; + } + + json.pop_back(); + json.pop_back(); + + json += "}\n"; + return json; +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1581,6 +1596,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"layouts", true, layoutsRequest}); registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); + registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); diff --git a/src/helpers/Color.cpp b/src/helpers/Color.cpp index 67526dc7..f9a207bb 100644 --- a/src/helpers/Color.cpp +++ b/src/helpers/Color.cpp @@ -21,6 +21,6 @@ CColor::CColor(uint64_t hex) { this->a = ALPHA(hex); } -uint32_t CColor::getAsHex() { +uint32_t CColor::getAsHex() const { return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1; } \ No newline at end of file diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 7ec55b0d..8abfe748 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -10,7 +10,7 @@ class CColor { float r = 0, g = 0, b = 0, a = 1.f; - uint32_t getAsHex(); + uint32_t getAsHex() const; CColor operator-(const CColor& c2) const { return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index c502cb0d..069cdddb 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -82,18 +82,13 @@ CInputManager::~CInputManager() { } void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { - static auto PSENS = CConfigValue("general:sensitivity"); - static auto PNOACCEL = CConfigValue("input:force_no_accel"); - static auto PSENSTORAW = CConfigValue("general:apply_sens_to_raw"); + static auto PNOACCEL = CConfigValue("input:force_no_accel"); const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; - if (*PSENSTORAW == 1) - PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS); - else - PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); - g_pPointerManager->move(DELTA * *PSENS); + g_pPointerManager->move(DELTA); mouseMoveUnified(e.timeMs); From 912e7ba82defdb10efc892a5db578598c972fe4a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 17 Aug 2024 19:27:11 +0200 Subject: [PATCH 0494/2393] render: fixup format mismatch after leaving DS fixes #7373 --- src/debug/HyprCtl.cpp | 20 ++++++++++---------- src/helpers/Monitor.cpp | 2 +- src/helpers/Monitor.hpp | 1 + src/render/Renderer.cpp | 4 ++++ 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 717fb5c0..78c8504a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -158,16 +158,16 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1) continue; - result += - std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), - m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, - (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + result += std::format( + "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" + "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" + "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n", + m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, + m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), + m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, + (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), + (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled, + formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); } } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f6b61d57..9542d2c4 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -946,7 +946,7 @@ bool CMonitorState::updateSwapchain() { Debug::log(WARN, "updateSwapchain: No mode?"); return true; } - options.format = STATE.drmFormat; + options.format = m_pOwner->drmFormat; options.scanout = true; options.length = 2; options.size = MODE->pixelSize; diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7429ecf1..dcfcb63b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -100,6 +100,7 @@ class CMonitor { std::optional forceSize; SP currentMode; SP cursorSwapchain; + uint32_t drmFormat = DRM_FORMAT_INVALID; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6bf6a761..b363c287 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1207,6 +1207,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } else if (!pMonitor->lastScanout.expired()) { Debug::log(LOG, "Left a direct scanout."); pMonitor->lastScanout.reset(); + + // reset DRM format, make sure it's the one we want. + pMonitor->output->state->setFormat(pMonitor->drmFormat); } } @@ -2155,6 +2158,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR for (auto& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); + pMonitor->drmFormat = fmt.second; if (!pMonitor->state.test()) { Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); From d21a6b12b8983bba8745a62fd595a1dbee882012 Mon Sep 17 00:00:00 2001 From: leiserfg Date: Sun, 18 Aug 2024 08:43:30 +0200 Subject: [PATCH 0495/2393] Update aquamarine input in flake --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index b4868793..c70d31d1 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1723405438, - "narHash": "sha256-bpmC2m7OhlDvqgQZdZ2jBLyeIkq/Jld3X4bqRAxBSp8=", + "lastModified": 1723920171, + "narHash": "sha256-dVCMrAe+D/5S91erhwQj2DSzHOVzAanWqoy+vPWB9DY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9312aa28271c91e5d67ecb9def527b2bbcff0e66", + "rev": "71d49670fe246cdaff4860b0effba0ab9f163b72", "type": "github" }, "original": { From b2a18aa80a29ecf400ae1e8c964d4313f7223bf5 Mon Sep 17 00:00:00 2001 From: Sami Liedes Date: Sun, 18 Aug 2024 10:14:42 +0300 Subject: [PATCH 0496/2393] input: Fix disabling tap-to-click (#7304) * Allow disabling tap-to-click * Style fix --- src/managers/input/InputManager.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 069cdddb..e5f921a2 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1107,8 +1107,9 @@ void CInputManager::setPointerConfigs() { libinput_device_config_tap_set_drag_lock_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED); if (libinput_device_config_tap_get_finger_count(LIBINPUTDEV)) // this is for tapping (like on a laptop) - if (g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1) - libinput_device_config_tap_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_ENABLED); + libinput_device_config_tap_set_enabled(LIBINPUTDEV, + g_pConfigManager->getDeviceInt(devname, "tap-to-click", "input:touchpad:tap-to-click") == 1 ? LIBINPUT_CONFIG_TAP_ENABLED : + LIBINPUT_CONFIG_TAP_DISABLED); if (libinput_device_config_scroll_has_natural_scroll(LIBINPUTDEV)) { From 1006663b6eaa55149e9a21aa8a34e41c85eb08ca Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 18 Aug 2024 10:23:27 +0200 Subject: [PATCH 0497/2393] shm: align size to stride (#7383) calculate the size to the stride we got to better align it. --- src/protocols/core/Shm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 99459d9a..9996a607 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -63,7 +63,7 @@ Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { } std::tuple CWLSHMBuffer::beginDataPtr(uint32_t flags) { - return {(uint8_t*)pool->data + offset, fmt, size.x * size.y * 4}; + return {(uint8_t*)pool->data + offset, fmt, stride * size.y}; } void CWLSHMBuffer::endDataPtr() { From 279ec1c291021479b050c83a0435ac7076c1aee0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 19:51:54 +0200 Subject: [PATCH 0498/2393] linux-dmabuf: allow on split-node systems ref #7364 --- src/protocols/LinuxDMABUF.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 3cdb5b34..32625792 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -490,9 +490,8 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const return; } } else { - LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); + LOGM(ERR, "DRM device {} has no render node, disabling linux dmabuf checks", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); - removeGlobal(); } }); } From 50348a3ddbb6bc3367300c9bba2ff682e4a356e3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 20:19:13 +0200 Subject: [PATCH 0499/2393] renderer: pass custom modelines to aq ref #7390 --- src/render/Renderer.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b363c287..c2ecbbf3 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1994,17 +1994,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) { Debug::log(ERR, "Tried to set custom modeline on non-DRM output"); fail = true; - } else { - // FIXME: - // auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode); - // if (mode) { - // wlr_output_state_set_mode(pMonitor->state.wlr(), mode); - // pMonitor->customDrmMode = RULE->drmMode; - // } else { - // Debug::log(ERR, "wlr_drm_connector_add_mode failed"); - // fail = true; - // } - } + } else + pMonitor->output->state->setCustomMode(makeShared( + Aquamarine::SOutputMode{.pixelSize = {RULE->drmMode.hdisplay, RULE->drmMode.vdisplay}, .refreshRate = RULE->drmMode.vrefresh, .modeInfo = RULE->drmMode})); } else pMonitor->output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE})); From 5afc4dc42e2409da62b7bcdf0ead90329e8d7a92 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 18 Aug 2024 21:02:46 +0200 Subject: [PATCH 0500/2393] compositor: update suspendstate on window move (#7396) hyprctl dispatch -- movetoworkspacesilent x,"^kitty$" where X is the current workspace makes kitty stops updating until current workspace is changed while it is on the screen. update the suspend state after it has been moved. --- src/Compositor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 9d247a56..1437a653 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2737,6 +2737,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID()); + g_pCompositor->updateSuspendedStates(); } PHLWINDOW CCompositor::getForceFocus() { From bf611fbbf3183e6f96529d79189be56189a46e1b Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:40:21 +0200 Subject: [PATCH 0501/2393] screencopy: nuke unused stuff --- src/protocols/Screencopy.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index f246f6dd..8a7fd567 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -38,17 +38,6 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t g_pHyprRenderer->makeEGLCurrent(); - if (g_pHyprOpenGL->m_mMonitorRenderResources.contains(pMonitor)) { - const auto& RDATA = g_pHyprOpenGL->m_mMonitorRenderResources.at(pMonitor); - // bind the fb for its format. Suppress gl errors. -#ifndef GLES2 - glBindFramebuffer(GL_READ_FRAMEBUFFER, RDATA.offloadFB.m_iFb); -#else - glBindFramebuffer(GL_FRAMEBUFFER, RDATA.offloadFB.m_iFb); -#endif - } else - LOGM(ERR, "No RDATA in screencopy???"); - shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor); if (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture output"); From fa12efdd2aae6851305245f16a801fb571fbe2c1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:54:47 +0200 Subject: [PATCH 0502/2393] protocol: fix logm template checks --- src/protocols/WaylandProtocol.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 0fa8daab..87c75ed8 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -32,7 +32,7 @@ } else if (level == LOG || level == INFO || level == TRACE) { \ oss << "[" << EXTRACT_CLASS_NAME() << "] "; \ } \ - if constexpr (std::is_same_v) { \ + if constexpr (std::tuple_size::value == 1 && std::is_same_v) { \ oss << __VA_ARGS__; \ Debug::log(level, oss.str()); \ } else { \ From f4045ab8d032186b7c5409cd9f05eeaa813320ba Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 18 Aug 2024 22:57:21 +0200 Subject: [PATCH 0503/2393] screencopy: fix 10b format r/b flip --- src/protocols/Screencopy.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8a7fd567..b25d9456 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -46,6 +46,10 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t return; } + // TODO: hack, we can't bit flip so we'll format flip heh, GL_BGRA_EXT wont work here + if (shmFormat == DRM_FORMAT_XRGB2101010 || shmFormat == DRM_FORMAT_ARGB2101010) + shmFormat = DRM_FORMAT_XBGR2101010; + const auto PSHMINFO = FormatUtils::getPixelFormatFromDRM(shmFormat); if (!PSHMINFO) { LOGM(ERR, "No pixel format supported by renderer in capture output"); From 11dfb8397becca85cad078dd31bf043d1c40ceac Mon Sep 17 00:00:00 2001 From: diniamo Date: Sun, 18 Aug 2024 20:43:04 +0200 Subject: [PATCH 0504/2393] flake: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index c70d31d1..97016819 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1723920171, - "narHash": "sha256-dVCMrAe+D/5S91erhwQj2DSzHOVzAanWqoy+vPWB9DY=", + "lastModified": 1724006173, + "narHash": "sha256-1ROh0buuxiMyc6eIb3CIbJsmYO7PhLqSYs55mOx1XTk=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "71d49670fe246cdaff4860b0effba0ab9f163b72", + "rev": "7f8df01d4297b9068a9592400f16044602844f86", "type": "github" }, "original": { From 83d88fa56467a2b749fb2320e1595281107bd326 Mon Sep 17 00:00:00 2001 From: loseardes77 Date: Sun, 18 Aug 2024 22:25:23 +0200 Subject: [PATCH 0505/2393] hyprpm, hyprctl: update shell completions --- hyprctl/hyprctl.bash | 89 ++++++------ hyprctl/hyprctl.fish | 305 ++++++++++++++++++++++-------------------- hyprctl/hyprctl.usage | 20 ++- hyprctl/hyprctl.zsh | 271 ++++++++++++++++++++----------------- hyprpm/hyprpm.bash | 58 ++++---- hyprpm/hyprpm.fish | 85 ++++++------ hyprpm/hyprpm.usage | 4 +- hyprpm/hyprpm.zsh | 46 ++++--- 8 files changed, 471 insertions(+), 407 deletions(-) diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash index c69cca21..e26e623e 100644 --- a/hyprctl/hyprctl.bash +++ b/hyprctl/hyprctl.bash @@ -1,17 +1,17 @@ -_hyprctl_cmd_2 () { +_hyprctl_cmd_1 () { hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' +} + +_hyprctl_cmd_2 () { + hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } _hyprctl_cmd_0 () { - hyprctl clients | awk '/class/{ print $2 }' -} - -_hyprctl_cmd_1 () { - hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' + hyprpm list | awk '/Plugin/{print $4}' } _hyprctl () { @@ -23,25 +23,25 @@ _hyprctl () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") - + declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize) declare -A literal_transitions - literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)" - literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)" - literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)" - literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)" - literal_transitions[9]="([117]=20 [114]=16)" - literal_transitions[11]="([103]=2)" - literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)" - literal_transitions[14]="([39]=2)" - literal_transitions[15]="([138]=2 [96]=2)" - literal_transitions[17]="([18]=2 [7]=2)" - literal_transitions[18]="([76]=19)" - literal_transitions[19]="([34]=4 [45]=4)" - literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)" - - declare -A match_anything_transitions - match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18) + literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)" + literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)" + literal_transitions[3]="([139]=2 [63]=16 [64]=16 [45]=16 [105]=16 [27]=2 [26]=2 [52]=4 [5]=16 [66]=2 [67]=16 [129]=16 [113]=16 [12]=2 [74]=4 [99]=2 [35]=16 [152]=16 [98]=16 [59]=16 [117]=16 [41]=16 [17]=2 [138]=16 [154]=2 [122]=16)" + literal_transitions[6]="([126]=2)" + literal_transitions[10]="([56]=2)" + literal_transitions[11]="([9]=2)" + literal_transitions[12]="([14]=19 [80]=22)" + literal_transitions[13]="([142]=2)" + literal_transitions[14]="([0]=2 [84]=2 [2]=2 [85]=2 [4]=2 [87]=2 [88]=2 [90]=2 [91]=2 [92]=2 [93]=2 [94]=2 [96]=2 [15]=2 [18]=2 [103]=2 [21]=2 [104]=2 [23]=2 [24]=2 [28]=2 [29]=2 [30]=2 [108]=2 [111]=2 [32]=2 [112]=2 [36]=2 [38]=2 [119]=2 [124]=2 [46]=2 [47]=2 [48]=2 [49]=2 [53]=2 [55]=2 [131]=2 [132]=2 [134]=2 [135]=2 [60]=2 [136]=20 [141]=2 [65]=2 [144]=2 [145]=2 [68]=2 [147]=2 [70]=2 [71]=2 [72]=2 [73]=2 [148]=2 [75]=2 [76]=2 [150]=2 [153]=2)" + literal_transitions[15]="([86]=4 [6]=4 [109]=4 [61]=4 [77]=4 [54]=4 [62]=4)" + literal_transitions[16]="([40]=2 [44]=2)" + literal_transitions[17]="([7]=23)" + literal_transitions[18]="([31]=2 [149]=2)" + literal_transitions[19]="([95]=2 [16]=2 [115]=2 [20]=2)" + literal_transitions[20]="([106]=2 [82]=2 [127]=2 [1]=2 [83]=2)" + literal_transitions[23]="([57]=21 [110]=21)" + declare -A match_anything_transitions=([6]=17 [7]=2 [0]=1 [22]=2 [5]=18 [4]=2 [2]=17 [18]=2 [11]=17 [8]=2 [9]=2 [13]=17 [10]=17 [1]=1) declare -A subword_transitions local state=0 @@ -79,21 +79,9 @@ _hyprctl () { done + local -a matches=() + local prefix="${words[$cword]}" - - local shortest_suffix="$word" - for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do - local char="${COMP_WORDBREAKS:$i:1}" - local candidate="${word##*$char}" - if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then - shortest_suffix=$candidate - fi - done - local superfluous_prefix="" - if [[ "$shortest_suffix" != "$word" ]]; then - local superfluous_prefix=${word%$shortest_suffix} - fi - if [[ -v "literal_transitions[$state]" ]]; then local state_transitions_initializer=${literal_transitions[$state]} declare -A state_transitions @@ -102,25 +90,38 @@ _hyprctl () { for literal_id in "${!state_transitions[@]}"; do local literal="${literals[$literal_id]}" if [[ $literal = "${prefix}"* ]]; then - local completion=${literal#"$superfluous_prefix"} - COMPREPLY+=("$completion ") + matches+=("$literal ") fi done fi declare -A commands - commands=([5]=1 [16]=2 [12]=3 [10]=0) + commands=([7]=0 [22]=1 [8]=3 [5]=2) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} local completions=() - mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1) + readarray -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1) for item in "${completions[@]}"; do if [[ $item = "${prefix}"* ]]; then - COMPREPLY+=("$item") + matches+=("$item") fi done fi + local shortest_suffix="$prefix" + for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do + local char="${COMP_WORDBREAKS:$i:1}" + local candidate=${prefix##*$char} + if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then + shortest_suffix=$candidate + fi + done + local superfluous_prefix="" + if [[ "$shortest_suffix" != "$prefix" ]]; then + local superfluous_prefix=${prefix%$shortest_suffix} + fi + COMPREPLY=("${matches[@]#$superfluous_prefix}") + return 0 } diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish index c5c03e49..11309416 100644 --- a/hyprctl/hyprctl.fish +++ b/hyprctl/hyprctl.fish @@ -1,21 +1,21 @@ -function _hyprctl_3 +function _hyprctl_2 set 1 $argv[1] hyprctl monitors | awk '/Monitor/{ print $2 }' end function _hyprctl_4 set 1 $argv[1] - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' +end + +function _hyprctl_3 + set 1 $argv[1] + hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' end function _hyprctl_1 set 1 $argv[1] - hyprctl clients | awk '/class/{ print $2 }' -end - -function _hyprctl_2 - set 1 $argv[1] - hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' + hyprpm list | awk '/Plugin/{print $4}' end function _hyprctl @@ -29,145 +29,160 @@ function _hyprctl set COMP_CWORD (count $COMP_WORDS) end - set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow" + set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" - set --local descriptions - set descriptions[1] "Focus the next window on a workspace" - set descriptions[3] "Get the current cursor pos in global layout coordinates" - set descriptions[5] "Rename a workspace" - set descriptions[7] "Focus the first window matching" - set descriptions[10] "Swap the focused window with the next window" - set descriptions[12] "Move the active window" - set descriptions[16] "List the layers" - set descriptions[18] "List active outputs with their properties" - set descriptions[20] "Get into a kill mode, where you can kill an app by clicking on it" - set descriptions[21] "Set the current window's floating state to false" - set descriptions[22] "ERROR" - set descriptions[23] "Focus a monitor" - set descriptions[24] "Swap the active window with another window" - set descriptions[25] "Move the active window out of a group" - set descriptions[26] "Send a notification using the built-in Hyprland notification system" - set descriptions[27] "Move the cursor to a specified position" - set descriptions[28] "Set the cursor theme and reloads the cursor manager" - set descriptions[29] "Set the hyprctl error string" - set descriptions[30] "Move the active workspace to a monitor" - set descriptions[31] "CONFUSED" - set descriptions[34] "Set a property of a window" - set descriptions[35] "Specify the Hyprland instance" - set descriptions[36] "Disable output" - set descriptions[37] "Toggle the current window's floating state" - set descriptions[38] "Get the list of defined workspace rules" - set descriptions[39] "Move the focused window to a workspace" - set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock" - set descriptions[42] "List all workspaces with their properties" - set descriptions[43] "Swap the active window with the next or previous in a group" - set descriptions[44] "Close a specified window" - set descriptions[45] "WARNING" - set descriptions[46] "Specify the Hyprland instance" - set descriptions[47] "List all registered binds" - set descriptions[48] "Move the active window in a direction or to a monitor" - set descriptions[49] "Change the split ratio" - set descriptions[51] "Prohibit the active window from becoming or being inserted into group" - set descriptions[52] "Change the workspace" - set descriptions[53] "List all current config parsing errors" - set descriptions[54] "Toggle the current active window into a group" - set descriptions[55] "Get the config option status (values)" - set descriptions[58] "Close the active window" - set descriptions[59] "Pass the key to a specified window" - set descriptions[60] "List all decorations and their info" - set descriptions[61] "List all connected keyboards and mice" - set descriptions[62] "Switch focus from current to previously focused window" - set descriptions[63] "Change the current mapping group" - set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal" - set descriptions[66] "Force the renderer to reload all resources and outputs" - set descriptions[67] "Move a selected window" - set descriptions[69] "Print the Hyprland version: flags, commit and branch of build" - set descriptions[70] "Set all monitors' DPMS status" - set descriptions[71] "Resize the active window" - set descriptions[72] "Move the active window into a group" - set descriptions[73] "OK" - set descriptions[75] "Set the current window's floating state to true" - set descriptions[76] "Print tail of the log" - set descriptions[79] "List all layouts available (including plugin ones)" - set descriptions[80] "Move a workspace to a monitor" - set descriptions[81] "Execute a shell command" - set descriptions[83] "Modify the window stack order of the active or specified window" - set descriptions[84] "Toggle the focused window's internal fullscreen state" - set descriptions[86] "Issue a keyword to call a config keyword dynamically" - set descriptions[89] "Disable output" - set descriptions[90] "Pin a window" - set descriptions[91] "Allows adding/removing fake outputs to a specific backend" - set descriptions[93] "Toggle a special workspace on/off" - set descriptions[94] "Toggle the focused window's fullscreen state" - set descriptions[95] "Toggle the current window to always be opaque" - set descriptions[96] "Focus the requested workspace" - set descriptions[98] "Switch to the next window in a group" - set descriptions[99] "Output in JSON format" - set descriptions[100] "List all running Hyprland instances and their info" - set descriptions[101] "Execute a raw shell command" - set descriptions[102] "Exit the compositor with no questions asked" - set descriptions[103] "List all windows with their properties" - set descriptions[105] "Execute a batch of commands separated by ;" - set descriptions[106] "Dismiss all or up to amount of notifications" - set descriptions[108] "Set the xkb layout index for a keyboard" - set descriptions[109] "Move window doesnt switch to the workspace" - set descriptions[110] "Apply a tag to the window" - set descriptions[111] "Behave as moveintogroup" - set descriptions[112] "Refresh state after issuing the command" - set descriptions[113] "Move the focus in a direction" - set descriptions[114] "Focus the urgent window or the last window" - set descriptions[116] "Get the active workspace name and its properties" - set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg" - set descriptions[119] "Center the active window" - set descriptions[120] "HINT" - set descriptions[121] "Interact with hyprpaper if present" - set descriptions[122] "No Icon" - set descriptions[123] "Force reload the config" - set descriptions[125] "Print system info" - set descriptions[126] "Interact with a plugin" - set descriptions[128] "Get the active window name and its properties" - set descriptions[129] "Swap the active workspaces between two monitors" - set descriptions[130] "Print the current random splash" - set descriptions[131] "On shortcut X sends shortcut Y to a specified window" - set descriptions[133] "Lock the focused group" - set descriptions[136] "Lock the groups" - set descriptions[137] "Move the cursor to the corner of the active window" - set descriptions[140] "INFO" - set descriptions[141] "Resize a selected window" + set descriptions + set descriptions[1] "Resize the active window" + set descriptions[2] "Fullscreen" + set descriptions[3] "Switch to the next window in a group" + set descriptions[4] "Refresh state after issuing the command" + set descriptions[5] "Move the active window into a group" + set descriptions[7] "CONFUSED" + set descriptions[9] "Print system info" + set descriptions[11] "List all layouts available (including plugin ones)" + set descriptions[12] "Set a property of a window" + set descriptions[14] "Set the xkb layout index for a keyboard" + set descriptions[16] "Prohibit the active window from becoming or being inserted into group" + set descriptions[19] "Execute a shell command" + set descriptions[20] "Set the cursor theme and reloads the cursor manager" + set descriptions[22] "Focus the urgent window or the last window" + set descriptions[23] "Get the list of defined workspace rules" + set descriptions[24] "Move the active workspace to a monitor" + set descriptions[25] "Move window doesnt switch to the workspace" + set descriptions[26] "Interact with hyprpaper if present" + set descriptions[29] "Swap the active window with the next or previous in a group" + set descriptions[30] "Move the cursor to the corner of the active window" + set descriptions[31] "Move a selected window" + set descriptions[33] "Move the active window in a direction or to a monitor" + set descriptions[34] "Lists all global shortcuts" + set descriptions[35] "List all windows with their properties" + set descriptions[37] "Temporarily enable or disable binds:ignore_group_lock" + set descriptions[38] "Print the current random splash" + set descriptions[39] "Execute a raw shell command" + set descriptions[40] "List active outputs with their properties" + set descriptions[43] "Disable output" + set descriptions[44] "Gets the current config info about animations and beziers" + set descriptions[47] "Change the split ratio" + set descriptions[48] "Move the active window" + set descriptions[49] "Pass the key to a specified window" + set descriptions[50] "Swap the focused window with the next window" + set descriptions[51] "List all connected keyboards and mice" + set descriptions[52] "List the layers" + set descriptions[54] "Lock the focused group" + set descriptions[55] "OK" + set descriptions[56] "Move a workspace to a monitor" + set descriptions[58] "Specify the Hyprland instance" + set descriptions[59] "Disable output" + set descriptions[61] "Pin a window" + set descriptions[62] "WARNING" + set descriptions[63] "INFO" + set descriptions[66] "Set the current window's floating state to true" + set descriptions[69] "On shortcut X sends shortcut Y to a specified window" + set descriptions[70] "List all workspaces with their properties" + set descriptions[71] "Focus the next window on a workspace" + set descriptions[72] "Modify the window stack order of the active or specified window" + set descriptions[73] "Toggle the current active window into a group" + set descriptions[74] "Lock the groups" + set descriptions[76] "Set all monitors' DPMS status" + set descriptions[77] "Switch focus from current to previously focused window" + set descriptions[78] "No Icon" + set descriptions[79] "Execute a batch of commands separated by ;" + set descriptions[80] "Send a notification using the built-in Hyprland notification system" + set descriptions[82] "List all running Hyprland instances and their info" + set descriptions[83] "Maximize no fullscreen" + set descriptions[84] "Maximize and fullscreen" + set descriptions[85] "Move the active window out of a group" + set descriptions[86] "Close the active window" + set descriptions[87] "HINT" + set descriptions[88] "Move the focused window to a workspace" + set descriptions[89] "Move the cursor to a specified position" + set descriptions[90] "List all current config parsing errors" + set descriptions[91] "Close a specified window" + set descriptions[92] "Swap the active window with another window" + set descriptions[93] "Apply a tag to the window" + set descriptions[94] "Force the renderer to reload all resources and outputs" + set descriptions[95] "Center the active window" + set descriptions[97] "Focus the first window matching" + set descriptions[98] "Set the hyprctl error string" + set descriptions[101] "List all registered binds" + set descriptions[102] "Print the Hyprland version: flags, commit and branch of build" + set descriptions[103] "Prints the help message" + set descriptions[104] "Toggle a special workspace on/off" + set descriptions[105] "Toggle the focused window's fullscreen state" + set descriptions[107] "None" + set descriptions[108] "Issue a keyword to call a config keyword dynamically" + set descriptions[109] "Toggle the current window to always be opaque" + set descriptions[110] "ERROR" + set descriptions[111] "Specify the Hyprland instance" + set descriptions[112] "Toggle the current window's floating state" + set descriptions[113] "Rename a workspace" + set descriptions[115] "Get the active workspace name and its properties" + set descriptions[117] "Get into a kill mode, where you can kill an app by clicking on it" + set descriptions[119] "Allows adding/removing fake outputs to a specific backend" + set descriptions[120] "Execute a Global Shortcut using the GlobalShortcuts portal" + set descriptions[121] "Issue a dispatch to call a keybind dispatcher with an arg" + set descriptions[122] "Force reload the config" + set descriptions[124] "Output in JSON format" + set descriptions[125] "Emits a custom event to socket2" + set descriptions[126] "Prints the help message" + set descriptions[128] "Current" + set descriptions[129] "Get the active window name and its properties" + set descriptions[131] "Dismiss all or up to amount of notifications" + set descriptions[132] "Focus a monitor" + set descriptions[133] "Move the focus in a direction" + set descriptions[134] "Interact with a plugin" + set descriptions[135] "Exit the compositor with no questions asked" + set descriptions[136] "Change the workspace" + set descriptions[137] "Sets the focused window’s fullscreen mode and the one sent to the client" + set descriptions[138] "Get the config option status (values)" + set descriptions[141] "List all decorations and their info" + set descriptions[142] "Set the current window's floating state to false" + set descriptions[144] "Return a parsable JSON with all the config options, descriptions, value types and ranges" + set descriptions[145] "Resize a selected window" + set descriptions[146] "Toggle the focused window's internal fullscreen state" + set descriptions[147] "Print tail of the log" + set descriptions[148] "Swap the active workspaces between two monitors" + set descriptions[149] "Change the current mapping group" + set descriptions[151] "Behave as moveintogroup" + set descriptions[152] "Get the current cursor pos in global layout coordinates" + set descriptions[154] "Focus the requested workspace" - set --local literal_transitions - set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5" - set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18" - set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3" - set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" - set literal_transitions[10] "set inputs 118 115; set tos 21 17" - set literal_transitions[12] "set inputs 104; set tos 3" - set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2" - set literal_transitions[15] "set inputs 40; set tos 3" - set literal_transitions[16] "set inputs 139 97; set tos 3 3" - set literal_transitions[18] "set inputs 19 8; set tos 3 3" - set literal_transitions[19] "set inputs 77; set tos 20" - set literal_transitions[20] "set inputs 35 46; set tos 5 5" - set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3" + set literal_transitions + set literal_transitions[1] "set inputs 121 44 126 82 4 52 51 129 90 59 9 11 12 131 14 98 102 103 134 101 138 23 20 141 26 144 108 147 70 34 35 79 115 38 152 117 122 124 40 43 80 119; set tos 15 3 22 3 22 3 3 3 3 22 3 3 4 5 6 7 3 22 8 3 3 3 3 9 3 3 10 11 3 3 3 22 3 3 3 3 14 22 12 22 16 13" + set literal_transitions[2] "set inputs 82 52 51 129 9 90 11 12 131 14 98 102 134 101 23 20 138 141 26 144 108 147 70 34 35 115 38 152 117 40 119 122 121 80 44; set tos 3 3 3 3 3 3 3 4 5 6 7 3 8 3 3 3 3 9 3 3 10 11 3 3 3 3 3 3 3 12 13 14 15 16 3" + set literal_transitions[4] "set inputs 140 64 65 46 106 28 27 53 6 67 68 130 114 13 75 100 36 153 99 60 118 42 18 139 155 123; set tos 3 17 17 17 17 3 3 5 17 3 17 17 17 3 5 3 17 17 17 17 17 17 3 17 3 17" + set literal_transitions[7] "set inputs 127; set tos 3" + set literal_transitions[11] "set inputs 57; set tos 3" + set literal_transitions[12] "set inputs 10; set tos 3" + set literal_transitions[13] "set inputs 15 81; set tos 20 23" + set literal_transitions[14] "set inputs 143; set tos 3" + set literal_transitions[15] "set inputs 1 85 3 86 5 88 89 91 92 93 94 95 97 16 19 104 22 105 24 25 29 30 31 109 112 33 113 37 39 120 125 47 48 49 50 54 56 132 133 135 136 61 137 142 66 145 146 69 148 71 72 73 74 149 76 77 151 154; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 21 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + set literal_transitions[16] "set inputs 87 7 110 62 78 55 63; set tos 5 5 5 5 5 5 5" + set literal_transitions[17] "set inputs 41 45; set tos 3 3" + set literal_transitions[18] "set inputs 8; set tos 24" + set literal_transitions[19] "set inputs 32 150; set tos 3 3" + set literal_transitions[20] "set inputs 96 17 116 21; set tos 3 3 3 3" + set literal_transitions[21] "set inputs 107 83 128 2 84; set tos 3 3 3 3 3" + set literal_transitions[24] "set inputs 58 111; set tos 22 22" - set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12 - set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19 + set match_anything_transitions_from 7 8 1 23 6 5 3 19 12 9 10 14 11 2 + set match_anything_transitions_to 18 3 2 3 19 3 18 3 18 3 3 18 18 2 - set --local state 1 - set --local word_index 2 + set state 1 + set word_index 2 while test $word_index -lt $COMP_CWORD - set --local -- word $COMP_WORDS[$word_index] + set -- word $COMP_WORDS[$word_index] if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] if contains -- $word $literals - set --local literal_matched 0 + set literal_matched 0 for literal_id in (seq 1 (count $literals)) if test $literals[$literal_id] = $word - set --local index (contains --index -- $literal_id $inputs) + set index (contains --index -- $literal_id $inputs) set state $tos[$index] set word_index (math $word_index + 1) set literal_matched 1 @@ -181,7 +196,7 @@ function _hyprctl end if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state] - set --local index (contains --index -- $state $match_anything_transitions_from) + set index (contains --index -- $state $match_anything_transitions_from) set state $match_anything_transitions_to[$index] set word_index (math $word_index + 1) continue @@ -191,8 +206,8 @@ function _hyprctl end if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] for literal_id in $inputs if test -n $descriptions[$literal_id] @@ -203,14 +218,14 @@ function _hyprctl end end - set command_states 6 17 13 11 - set command_ids 2 3 4 1 + set command_states 8 23 9 6 + set command_ids 1 2 4 3 if contains $state $command_states - set --local index (contains --index $state $command_states) - set --local function_id $command_ids[$index] - set --local function_name _hyprctl_$function_id - set --local --erase inputs - set --local --erase tos + set index (contains --index $state $command_states) + set function_id $command_ids[$index] + set function_name _hyprctl_$function_id + set --erase inputs + set --erase tos $function_name "$COMP_WORDS[$COMP_CWORD]" end diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage index 298d253e..b2c55682 100644 --- a/hyprctl/hyprctl.usage +++ b/hyprctl/hyprctl.usage @@ -2,13 +2,14 @@ # Repo: https://github.com/adaszko/complgen # Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage" -hyprctl []... +hyprctl []... ::= (-i | --instance) "Specify the Hyprland instance" | (-j) "Output in JSON format" | (-r) "Refresh state after issuing the command" | (--batch) "Execute a batch of commands separated by ;" | (-q | --quiet) "Disable output" + | (-h | --help) "Prints the help message" ; ::= {{{ hyprctl clients | awk '/class/{print $2}' }}}; @@ -59,16 +60,18 @@ hyprctl []... ::= (activewindow) "Get the active window name and its properties" | (activeworkspace) "Get the active workspace name and its properties" + | (animations) "Gets the current config info about animations and beziers" | (binds) "List all registered binds" | (clients) "List all windows with their properties" | (configerrors) "List all current config parsing errors" | (cursorpos) "Get the current cursor pos in global layout coordinates" | (decorations ) "List all decorations and their info" + | (descriptions) "Return a parsable JSON with all the config options, descriptions, value types and ranges" | (devices) "List all connected keyboards and mice" | (dismissnotify ) "Dismiss all or up to amount of notifications" | (dispatch ) "Issue a dispatch to call a keybind dispatcher with an arg" | (getoption) "Get the config option status (values)" - | (globalshortcuts) "" + | (globalshortcuts) "Lists all global shortcuts" | (hyprpaper) "Interact with hyprpaper if present" | (instances) "List all running Hyprland instances and their info" | (keyword ) "Issue a keyword to call a config keyword dynamically" @@ -79,8 +82,8 @@ hyprctl []... | (notify ) "Send a notification using the built-in Hyprland notification system" | (output (create (wayland | x11 | headless | auto) | remove )) "Allows adding/removing fake outputs to a specific backend" | (plugin ) "Interact with a plugin" - | (reload) "Force reload the config" - | (rollinglog) "Print tail of the log" + | (reload [config-only]) "Force reload the config" + | (rollinglog [-f]) "Print tail of the log" | (setcursor) "Set the cursor theme and reloads the cursor manager" | (seterror [disable]) "Set the hyprctl error string" | (setprop ) "Set a property of a window" @@ -92,6 +95,13 @@ hyprctl []... | (workspaces) "List all workspaces with their properties" ; + ::= (-1) "Current" + | (0) "None" + | (1) "Maximize no fullscreen" + | (2) "Fullscreen" + | (3) "Maximize and fullscreen" + ; + ::= (exec) "Execute a shell command" | (execr) "Execute a raw shell command" | (pass) "Pass the key to a specified window" @@ -106,6 +116,7 @@ hyprctl []... | (settiled) "Set the current window's floating state to false" | (fullscreen) "Toggle the focused window's fullscreen state" | (fakefullscreen) "Toggle the focused window's internal fullscreen state" + | (fullscreenstate ) "Sets the focused window’s fullscreen mode and the one sent to the client" | (dpms) "Set all monitors' DPMS status" | (pin) "Pin a window" | (movefocus) "Move the focus in a direction" @@ -148,4 +159,5 @@ hyprctl []... | (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock" | (global) "Execute a Global Shortcut using the GlobalShortcuts portal" | (submap) "Change the current mapping group" + | (event) "Emits a custom event to socket2" ; diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh index aeac9663..9a858100 100644 --- a/hyprctl/hyprctl.zsh +++ b/hyprctl/hyprctl.zsh @@ -1,145 +1,160 @@ #compdef hyprctl -_hyprctl_cmd_2 () { +_hyprctl_cmd_1 () { hyprctl monitors | awk '/Monitor/{ print $2 }' } _hyprctl_cmd_3 () { - hyprpm list | awk '/Plugin/{ print $4 }' + hyprctl clients | awk '/class/{print $2}' } -_hyprctl_cmd_0 () { - hyprctl clients | awk '/class/{ print $2 }' -} - -_hyprctl_cmd_1 () { +_hyprctl_cmd_2 () { hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' } +_hyprctl_cmd_0 () { + hyprpm list | awk '/Plugin/{print $4}' +} + _hyprctl () { - local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow") + local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize") local -A descriptions - descriptions[1]="Focus the next window on a workspace" - descriptions[3]="Get the current cursor pos in global layout coordinates" - descriptions[5]="Rename a workspace" - descriptions[7]="Focus the first window matching" - descriptions[10]="Swap the focused window with the next window" - descriptions[12]="Move the active window" - descriptions[16]="List the layers" - descriptions[18]="List active outputs with their properties" - descriptions[20]="Get into a kill mode, where you can kill an app by clicking on it" - descriptions[21]="Set the current window's floating state to false" - descriptions[22]="ERROR" - descriptions[23]="Focus a monitor" - descriptions[24]="Swap the active window with another window" - descriptions[25]="Move the active window out of a group" - descriptions[26]="Send a notification using the built-in Hyprland notification system" - descriptions[27]="Move the cursor to a specified position" - descriptions[28]="Set the cursor theme and reloads the cursor manager" - descriptions[29]="Set the hyprctl error string" - descriptions[30]="Move the active workspace to a monitor" - descriptions[31]="CONFUSED" - descriptions[34]="Set a property of a window" - descriptions[35]="Specify the Hyprland instance" - descriptions[36]="Disable output" - descriptions[37]="Toggle the current window's floating state" - descriptions[38]="Get the list of defined workspace rules" - descriptions[39]="Move the focused window to a workspace" - descriptions[41]="Temporarily enable or disable binds:ignore_group_lock" - descriptions[42]="List all workspaces with their properties" - descriptions[43]="Swap the active window with the next or previous in a group" - descriptions[44]="Close a specified window" - descriptions[45]="WARNING" - descriptions[46]="Specify the Hyprland instance" - descriptions[47]="List all registered binds" - descriptions[48]="Move the active window in a direction or to a monitor" - descriptions[49]="Change the split ratio" - descriptions[51]="Prohibit the active window from becoming or being inserted into group" - descriptions[52]="Change the workspace" - descriptions[53]="List all current config parsing errors" - descriptions[54]="Toggle the current active window into a group" - descriptions[55]="Get the config option status (values)" - descriptions[58]="Close the active window" - descriptions[59]="Pass the key to a specified window" - descriptions[60]="List all decorations and their info" - descriptions[61]="List all connected keyboards and mice" - descriptions[62]="Switch focus from current to previously focused window" - descriptions[63]="Change the current mapping group" - descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal" - descriptions[66]="Force the renderer to reload all resources and outputs" - descriptions[67]="Move a selected window" - descriptions[69]="Print the Hyprland version: flags, commit and branch of build" - descriptions[70]="Set all monitors' DPMS status" - descriptions[71]="Resize the active window" - descriptions[72]="Move the active window into a group" - descriptions[73]="OK" - descriptions[75]="Set the current window's floating state to true" - descriptions[76]="Print tail of the log" - descriptions[79]="List all layouts available (including plugin ones)" - descriptions[80]="Move a workspace to a monitor" - descriptions[81]="Execute a shell command" - descriptions[83]="Modify the window stack order of the active or specified window" - descriptions[84]="Toggle the focused window's internal fullscreen state" - descriptions[86]="Issue a keyword to call a config keyword dynamically" - descriptions[89]="Disable output" - descriptions[90]="Pin a window" - descriptions[91]="Allows adding/removing fake outputs to a specific backend" - descriptions[93]="Toggle a special workspace on/off" - descriptions[94]="Toggle the focused window's fullscreen state" - descriptions[95]="Toggle the current window to always be opaque" - descriptions[96]="Focus the requested workspace" - descriptions[98]="Switch to the next window in a group" - descriptions[99]="Output in JSON format" - descriptions[100]="List all running Hyprland instances and their info" - descriptions[101]="Execute a raw shell command" - descriptions[102]="Exit the compositor with no questions asked" - descriptions[103]="List all windows with their properties" - descriptions[105]="Execute a batch of commands separated by ;" - descriptions[106]="Dismiss all or up to amount of notifications" - descriptions[108]="Set the xkb layout index for a keyboard" - descriptions[109]="Move window doesnt switch to the workspace" - descriptions[110]="Apply a tag to the window" - descriptions[111]="Behave as moveintogroup" - descriptions[112]="Refresh state after issuing the command" - descriptions[113]="Move the focus in a direction" - descriptions[114]="Focus the urgent window or the last window" - descriptions[116]="Get the active workspace name and its properties" - descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg" - descriptions[119]="Center the active window" - descriptions[120]="HINT" - descriptions[121]="Interact with hyprpaper if present" - descriptions[122]="No Icon" - descriptions[123]="Force reload the config" - descriptions[125]="Print system info" - descriptions[126]="Interact with a plugin" - descriptions[128]="Get the active window name and its properties" - descriptions[129]="Swap the active workspaces between two monitors" - descriptions[130]="Print the current random splash" - descriptions[131]="On shortcut X sends shortcut Y to a specified window" - descriptions[133]="Lock the focused group" - descriptions[136]="Lock the groups" - descriptions[137]="Move the cursor to the corner of the active window" - descriptions[140]="INFO" - descriptions[141]="Resize a selected window" + descriptions[1]="Resize the active window" + descriptions[2]="Fullscreen" + descriptions[3]="Switch to the next window in a group" + descriptions[4]="Refresh state after issuing the command" + descriptions[5]="Move the active window into a group" + descriptions[7]="CONFUSED" + descriptions[9]="Print system info" + descriptions[11]="List all layouts available (including plugin ones)" + descriptions[12]="Set a property of a window" + descriptions[14]="Set the xkb layout index for a keyboard" + descriptions[16]="Prohibit the active window from becoming or being inserted into group" + descriptions[19]="Execute a shell command" + descriptions[20]="Set the cursor theme and reloads the cursor manager" + descriptions[22]="Focus the urgent window or the last window" + descriptions[23]="Get the list of defined workspace rules" + descriptions[24]="Move the active workspace to a monitor" + descriptions[25]="Move window doesnt switch to the workspace" + descriptions[26]="Interact with hyprpaper if present" + descriptions[29]="Swap the active window with the next or previous in a group" + descriptions[30]="Move the cursor to the corner of the active window" + descriptions[31]="Move a selected window" + descriptions[33]="Move the active window in a direction or to a monitor" + descriptions[34]="Lists all global shortcuts" + descriptions[35]="List all windows with their properties" + descriptions[37]="Temporarily enable or disable binds:ignore_group_lock" + descriptions[38]="Print the current random splash" + descriptions[39]="Execute a raw shell command" + descriptions[40]="List active outputs with their properties" + descriptions[43]="Disable output" + descriptions[44]="Gets the current config info about animations and beziers" + descriptions[47]="Change the split ratio" + descriptions[48]="Move the active window" + descriptions[49]="Pass the key to a specified window" + descriptions[50]="Swap the focused window with the next window" + descriptions[51]="List all connected keyboards and mice" + descriptions[52]="List the layers" + descriptions[54]="Lock the focused group" + descriptions[55]="OK" + descriptions[56]="Move a workspace to a monitor" + descriptions[58]="Specify the Hyprland instance" + descriptions[59]="Disable output" + descriptions[61]="Pin a window" + descriptions[62]="WARNING" + descriptions[63]="INFO" + descriptions[66]="Set the current window's floating state to true" + descriptions[69]="On shortcut X sends shortcut Y to a specified window" + descriptions[70]="List all workspaces with their properties" + descriptions[71]="Focus the next window on a workspace" + descriptions[72]="Modify the window stack order of the active or specified window" + descriptions[73]="Toggle the current active window into a group" + descriptions[74]="Lock the groups" + descriptions[76]="Set all monitors' DPMS status" + descriptions[77]="Switch focus from current to previously focused window" + descriptions[78]="No Icon" + descriptions[79]="Execute a batch of commands separated by ;" + descriptions[80]="Send a notification using the built-in Hyprland notification system" + descriptions[82]="List all running Hyprland instances and their info" + descriptions[83]="Maximize no fullscreen" + descriptions[84]="Maximize and fullscreen" + descriptions[85]="Move the active window out of a group" + descriptions[86]="Close the active window" + descriptions[87]="HINT" + descriptions[88]="Move the focused window to a workspace" + descriptions[89]="Move the cursor to a specified position" + descriptions[90]="List all current config parsing errors" + descriptions[91]="Close a specified window" + descriptions[92]="Swap the active window with another window" + descriptions[93]="Apply a tag to the window" + descriptions[94]="Force the renderer to reload all resources and outputs" + descriptions[95]="Center the active window" + descriptions[97]="Focus the first window matching" + descriptions[98]="Set the hyprctl error string" + descriptions[101]="List all registered binds" + descriptions[102]="Print the Hyprland version: flags, commit and branch of build" + descriptions[103]="Prints the help message" + descriptions[104]="Toggle a special workspace on/off" + descriptions[105]="Toggle the focused window's fullscreen state" + descriptions[107]="None" + descriptions[108]="Issue a keyword to call a config keyword dynamically" + descriptions[109]="Toggle the current window to always be opaque" + descriptions[110]="ERROR" + descriptions[111]="Specify the Hyprland instance" + descriptions[112]="Toggle the current window's floating state" + descriptions[113]="Rename a workspace" + descriptions[115]="Get the active workspace name and its properties" + descriptions[117]="Get into a kill mode, where you can kill an app by clicking on it" + descriptions[119]="Allows adding/removing fake outputs to a specific backend" + descriptions[120]="Execute a Global Shortcut using the GlobalShortcuts portal" + descriptions[121]="Issue a dispatch to call a keybind dispatcher with an arg" + descriptions[122]="Force reload the config" + descriptions[124]="Output in JSON format" + descriptions[125]="Emits a custom event to socket2" + descriptions[126]="Prints the help message" + descriptions[128]="Current" + descriptions[129]="Get the active window name and its properties" + descriptions[131]="Dismiss all or up to amount of notifications" + descriptions[132]="Focus a monitor" + descriptions[133]="Move the focus in a direction" + descriptions[134]="Interact with a plugin" + descriptions[135]="Exit the compositor with no questions asked" + descriptions[136]="Change the workspace" + descriptions[137]="Sets the focused window’s fullscreen mode and the one sent to the client" + descriptions[138]="Get the config option status (values)" + descriptions[141]="List all decorations and their info" + descriptions[142]="Set the current window's floating state to false" + descriptions[144]="Return a parsable JSON with all the config options, descriptions, value types and ranges" + descriptions[145]="Resize a selected window" + descriptions[146]="Toggle the focused window's internal fullscreen state" + descriptions[147]="Print tail of the log" + descriptions[148]="Swap the active workspaces between two monitors" + descriptions[149]="Change the current mapping group" + descriptions[151]="Behave as moveintogroup" + descriptions[152]="Get the current cursor pos in global layout coordinates" + descriptions[154]="Focus the requested workspace" local -A literal_transitions - literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)" - literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)" - literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)" - literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)" - literal_transitions[10]="([118]=21 [115]=17)" - literal_transitions[12]="([104]=3)" - literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)" - literal_transitions[15]="([40]=3)" - literal_transitions[16]="([139]=3 [97]=3)" - literal_transitions[18]="([19]=3 [8]=3)" - literal_transitions[19]="([77]=20)" - literal_transitions[20]="([35]=5 [46]=5)" - literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)" + literal_transitions[1]="([121]=15 [44]=3 [126]=22 [82]=3 [4]=22 [52]=3 [51]=3 [129]=3 [90]=3 [59]=22 [9]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [103]=22 [134]=8 [101]=3 [138]=3 [23]=3 [20]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [79]=22 [115]=3 [38]=3 [152]=3 [117]=3 [122]=14 [124]=22 [40]=12 [43]=22 [80]=16 [119]=13)" + literal_transitions[2]="([82]=3 [52]=3 [51]=3 [129]=3 [9]=3 [90]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [134]=8 [101]=3 [23]=3 [20]=3 [138]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [115]=3 [38]=3 [152]=3 [117]=3 [40]=12 [119]=13 [122]=14 [121]=15 [80]=16 [44]=3)" + literal_transitions[4]="([140]=3 [64]=17 [65]=17 [46]=17 [106]=17 [28]=3 [27]=3 [53]=5 [6]=17 [67]=3 [68]=17 [130]=17 [114]=17 [13]=3 [75]=5 [100]=3 [36]=17 [153]=17 [99]=17 [60]=17 [118]=17 [42]=17 [18]=3 [139]=17 [155]=3 [123]=17)" + literal_transitions[7]="([127]=3)" + literal_transitions[11]="([57]=3)" + literal_transitions[12]="([10]=3)" + literal_transitions[13]="([15]=20 [81]=23)" + literal_transitions[14]="([143]=3)" + literal_transitions[15]="([1]=3 [85]=3 [3]=3 [86]=3 [5]=3 [88]=3 [89]=3 [91]=3 [92]=3 [93]=3 [94]=3 [95]=3 [97]=3 [16]=3 [19]=3 [104]=3 [22]=3 [105]=3 [24]=3 [25]=3 [29]=3 [30]=3 [31]=3 [109]=3 [112]=3 [33]=3 [113]=3 [37]=3 [39]=3 [120]=3 [125]=3 [47]=3 [48]=3 [49]=3 [50]=3 [54]=3 [56]=3 [132]=3 [133]=3 [135]=3 [136]=3 [61]=3 [137]=21 [142]=3 [66]=3 [145]=3 [146]=3 [69]=3 [148]=3 [71]=3 [72]=3 [73]=3 [74]=3 [149]=3 [76]=3 [77]=3 [151]=3 [154]=3)" + literal_transitions[16]="([87]=5 [7]=5 [110]=5 [62]=5 [78]=5 [55]=5 [63]=5)" + literal_transitions[17]="([41]=3 [45]=3)" + literal_transitions[18]="([8]=24)" + literal_transitions[19]="([32]=3 [150]=3)" + literal_transitions[20]="([96]=3 [17]=3 [116]=3 [21]=3)" + literal_transitions[21]="([107]=3 [83]=3 [128]=3 [2]=3 [84]=3)" + literal_transitions[24]="([58]=22 [111]=22)" local -A match_anything_transitions - match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19) + match_anything_transitions=([7]=18 [8]=3 [1]=2 [23]=3 [6]=19 [5]=3 [3]=18 [19]=3 [12]=18 [9]=3 [10]=3 [14]=18 [11]=18 [2]=2) declare -A subword_transitions @@ -199,7 +214,7 @@ _hyprctl () { fi done fi - local -A commands=([6]=1 [17]=2 [13]=3 [11]=0) + local -A commands=([8]=0 [23]=1 [9]=3 [6]=2) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} @@ -252,4 +267,8 @@ _hyprctl () { return 0 } -compdef _hyprctl hyprctl +if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then + compdef _hyprctl hyprctl +else + _hyprctl +fi diff --git a/hyprpm/hyprpm.bash b/hyprpm/hyprpm.bash index ffc33e19..3c2bc90b 100644 --- a/hyprpm/hyprpm.bash +++ b/hyprpm/hyprpm.bash @@ -2,6 +2,10 @@ _hyprpm_cmd_0 () { hyprpm list | awk '/Plugin/{print $4}' } +_hyprpm_cmd_1 () { + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +} + _hyprpm () { if [[ $(type -t _get_comp_words_by_ref) != function ]]; then echo _get_comp_words_by_ref: function not defined. Make sure the bash-completions system package is installed @@ -11,16 +15,13 @@ _hyprpm () { local words cword _get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword - local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f") - + declare -a literals=(--no-shallow -n ::= disable list --help update add --verbose -v --force -s remove enable --notify -h reload -f) declare -A literal_transitions - literal_transitions[0]="([9]=6 [2]=2 [7]=6 [8]=6 [4]=6 [10]=2 [11]=3 [5]=2 [13]=6 [3]=3 [14]=2 [15]=6 [6]=2)" - literal_transitions[1]="([10]=2 [11]=3 [3]=3 [2]=2 [14]=2 [5]=2 [6]=2)" - literal_transitions[4]="([1]=5)" - literal_transitions[5]="([0]=6 [12]=6)" - - declare -A match_anything_transitions - match_anything_transitions=([3]=2 [2]=4 [0]=1 [1]=1) + literal_transitions[0]="([0]=7 [3]=3 [4]=4 [8]=7 [9]=7 [6]=4 [7]=4 [11]=7 [5]=7 [10]=7 [12]=2 [13]=3 [15]=7 [16]=4 [17]=7)" + literal_transitions[1]="([12]=2 [13]=3 [3]=3 [4]=4 [16]=4 [6]=4 [7]=4)" + literal_transitions[5]="([2]=6)" + literal_transitions[6]="([1]=7 [14]=7)" + declare -A match_anything_transitions=([1]=1 [4]=5 [3]=4 [2]=4 [0]=1) declare -A subword_transitions local state=0 @@ -58,21 +59,9 @@ _hyprpm () { done + local -a matches=() + local prefix="${words[$cword]}" - - local shortest_suffix="$word" - for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do - local char="${COMP_WORDBREAKS:$i:1}" - local candidate="${word##*$char}" - if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then - shortest_suffix=$candidate - fi - done - local superfluous_prefix="" - if [[ "$shortest_suffix" != "$word" ]]; then - local superfluous_prefix=${word%$shortest_suffix} - fi - if [[ -v "literal_transitions[$state]" ]]; then local state_transitions_initializer=${literal_transitions[$state]} declare -A state_transitions @@ -81,25 +70,38 @@ _hyprpm () { for literal_id in "${!state_transitions[@]}"; do local literal="${literals[$literal_id]}" if [[ $literal = "${prefix}"* ]]; then - local completion=${literal#"$superfluous_prefix"} - COMPREPLY+=("$completion ") + matches+=("$literal ") fi done fi declare -A commands - commands=([3]=0) + commands=([3]=0 [2]=1) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} local completions=() - mapfile -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1) + readarray -t completions < <(_hyprpm_cmd_${command_id} "$prefix" | cut -f1) for item in "${completions[@]}"; do if [[ $item = "${prefix}"* ]]; then - COMPREPLY+=("$item") + matches+=("$item") fi done fi + local shortest_suffix="$prefix" + for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do + local char="${COMP_WORDBREAKS:$i:1}" + local candidate=${prefix##*$char} + if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then + shortest_suffix=$candidate + fi + done + local superfluous_prefix="" + if [[ "$shortest_suffix" != "$prefix" ]]; then + local superfluous_prefix=${prefix%$shortest_suffix} + fi + COMPREPLY=("${matches[@]#$superfluous_prefix}") + return 0 } diff --git a/hyprpm/hyprpm.fish b/hyprpm/hyprpm.fish index 7be4f224..82561bd8 100644 --- a/hyprpm/hyprpm.fish +++ b/hyprpm/hyprpm.fish @@ -3,6 +3,11 @@ function _hyprpm_1 hyprpm list | awk '/Plugin/{print $4}' end +function _hyprpm_2 + set 1 $argv[1] + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +end + function _hyprpm set COMP_LINE (commandline --cut-at-cursor) @@ -14,49 +19,51 @@ function _hyprpm set COMP_CWORD (count $COMP_WORDS) end - set --local literals "-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f" + set literals "--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f" - set --local descriptions - set descriptions[1] "Send a hyprland notification for important events (e.g. load fail)" - set descriptions[3] "List all installed plugins" + set descriptions + set descriptions[1] "Disable shallow cloning of Hyprland sources" + set descriptions[2] "Send a hyprland notification for important events (e.g. load fail)" set descriptions[4] "Unload a plugin" - set descriptions[5] "Show help menu" - set descriptions[6] "Check and update all plugins if needed" - set descriptions[7] "Install a new plugin repository from git" - set descriptions[8] "Enable too much loggin" + set descriptions[5] "List all installed plugins" + set descriptions[6] "Show help menu" + set descriptions[7] "Check and update all plugins if needed" + set descriptions[8] "Install a new plugin repository from git" set descriptions[9] "Enable too much loggin" - set descriptions[10] "Force an operation ignoring checks (e.g. update -f)" - set descriptions[11] "Remove a plugin repository" - set descriptions[12] "Load a plugin" - set descriptions[13] "Send a hyprland notification for important events (e.g. load fail)" - set descriptions[14] "Show help menu" - set descriptions[15] "Reload all plugins" - set descriptions[16] "Force an operation ignoring checks (e.g. update -f)" + set descriptions[10] "Enable too much loggin" + set descriptions[11] "Force an operation ignoring checks (e.g. update -f)" + set descriptions[12] "Disable shallow cloning of Hyprland sources" + set descriptions[13] "Remove a plugin repository" + set descriptions[14] "Load a plugin" + set descriptions[15] "Send a hyprland notification for important events (e.g. load fail)" + set descriptions[16] "Show help menu" + set descriptions[17] "Reload all plugins" + set descriptions[18] "Force an operation ignoring checks (e.g. update -f)" - set --local literal_transitions - set literal_transitions[1] "set inputs 10 3 8 9 5 11 12 6 14 4 15 16 7; set tos 7 3 7 7 7 3 4 3 7 4 3 7 3" - set literal_transitions[2] "set inputs 11 12 4 3 15 6 7; set tos 3 4 4 3 3 3 3" - set literal_transitions[5] "set inputs 2; set tos 6" - set literal_transitions[6] "set inputs 1 13; set tos 7 7" + set literal_transitions + set literal_transitions[1] "set inputs 1 4 5 9 10 7 8 12 6 11 13 14 16 17 18; set tos 8 4 5 8 8 5 5 8 8 8 3 4 8 5 8" + set literal_transitions[2] "set inputs 13 14 4 5 17 7 8; set tos 3 4 4 5 5 5 5" + set literal_transitions[6] "set inputs 3; set tos 7" + set literal_transitions[7] "set inputs 2 15; set tos 8 8" - set --local match_anything_transitions_from 4 3 1 2 - set --local match_anything_transitions_to 3 5 2 2 + set match_anything_transitions_from 2 5 4 3 1 + set match_anything_transitions_to 2 6 5 5 2 - set --local state 1 - set --local word_index 2 + set state 1 + set word_index 2 while test $word_index -lt $COMP_CWORD - set --local -- word $COMP_WORDS[$word_index] + set -- word $COMP_WORDS[$word_index] if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] if contains -- $word $literals - set --local literal_matched 0 + set literal_matched 0 for literal_id in (seq 1 (count $literals)) if test $literals[$literal_id] = $word - set --local index (contains --index -- $literal_id $inputs) + set index (contains --index -- $literal_id $inputs) set state $tos[$index] set word_index (math $word_index + 1) set literal_matched 1 @@ -70,7 +77,7 @@ function _hyprpm end if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state] - set --local index (contains --index -- $state $match_anything_transitions_from) + set index (contains --index -- $state $match_anything_transitions_from) set state $match_anything_transitions_to[$index] set word_index (math $word_index + 1) continue @@ -80,8 +87,8 @@ function _hyprpm end if set --query literal_transitions[$state] && test -n $literal_transitions[$state] - set --local --erase inputs - set --local --erase tos + set --erase inputs + set --erase tos eval $literal_transitions[$state] for literal_id in $inputs if test -n $descriptions[$literal_id] @@ -92,14 +99,14 @@ function _hyprpm end end - set command_states 4 - set command_ids 1 + set command_states 4 3 + set command_ids 1 2 if contains $state $command_states - set --local index (contains --index $state $command_states) - set --local function_id $command_ids[$index] - set --local function_name _hyprpm_$function_id - set --local --erase inputs - set --local --erase tos + set index (contains --index $state $command_states) + set function_id $command_ids[$index] + set function_name _hyprpm_$function_id + set --erase inputs + set --erase tos $function_name "$COMP_WORDS[$COMP_CWORD]" end diff --git a/hyprpm/hyprpm.usage b/hyprpm/hyprpm.usage index 369c9d2b..24e631c5 100644 --- a/hyprpm/hyprpm.usage +++ b/hyprpm/hyprpm.usage @@ -5,10 +5,11 @@ hyprpm []... | (--help | -h) "Show help menu" | (--verbose | -v) "Enable too much loggin" | (--force | -f) "Force an operation ignoring checks (e.g. update -f)" + | (--no-shallow | -s) "Disable shallow cloning of Hyprland sources" ; ::= (add) "Install a new plugin repository from git" - | (remove) "Remove a plugin repository" + | (remove ) "Remove a plugin repository" | (update) "Check and update all plugins if needed" | (list) "List all installed plugins" | (enable ) "Load a plugin" @@ -17,3 +18,4 @@ hyprpm []... ; ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}}; + ::= {{{ hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' }}}; diff --git a/hyprpm/hyprpm.zsh b/hyprpm/hyprpm.zsh index 854e8426..859c5313 100644 --- a/hyprpm/hyprpm.zsh +++ b/hyprpm/hyprpm.zsh @@ -4,34 +4,40 @@ _hyprpm_cmd_0 () { hyprpm list | awk '/Plugin/{print $4}' } +_hyprpm_cmd_1 () { + hyprpm list | awk '/Repository/{print $4}' | sed 's/:$//' +} + _hyprpm () { - local -a literals=("-n" "::=" "list" "disable" "--help" "update" "add" "--verbose" "-v" "--force" "remove" "enable" "--notify" "-h" "reload" "-f") + local -a literals=("--no-shallow" "-n" "::=" "disable" "list" "--help" "update" "add" "--verbose" "-v" "--force" "-s" "remove" "enable" "--notify" "-h" "reload" "-f") local -A descriptions - descriptions[1]="Send a hyprland notification for important events (e.g. load fail)" - descriptions[3]="List all installed plugins" + descriptions[1]="Disable shallow cloning of Hyprland sources" + descriptions[2]="Send a hyprland notification for important events (e.g. load fail)" descriptions[4]="Unload a plugin" - descriptions[5]="Show help menu" - descriptions[6]="Check and update all plugins if needed" - descriptions[7]="Install a new plugin repository from git" - descriptions[8]="Enable too much loggin" + descriptions[5]="List all installed plugins" + descriptions[6]="Show help menu" + descriptions[7]="Check and update all plugins if needed" + descriptions[8]="Install a new plugin repository from git" descriptions[9]="Enable too much loggin" - descriptions[10]="Force an operation ignoring checks (e.g. update -f)" - descriptions[11]="Remove a plugin repository" - descriptions[12]="Load a plugin" - descriptions[13]="Send a hyprland notification for important events (e.g. load fail)" - descriptions[14]="Show help menu" - descriptions[15]="Reload all plugins" - descriptions[16]="Force an operation ignoring checks (e.g. update -f)" + descriptions[10]="Enable too much loggin" + descriptions[11]="Force an operation ignoring checks (e.g. update -f)" + descriptions[12]="Disable shallow cloning of Hyprland sources" + descriptions[13]="Remove a plugin repository" + descriptions[14]="Load a plugin" + descriptions[15]="Send a hyprland notification for important events (e.g. load fail)" + descriptions[16]="Show help menu" + descriptions[17]="Reload all plugins" + descriptions[18]="Force an operation ignoring checks (e.g. update -f)" local -A literal_transitions - literal_transitions[1]="([10]=7 [3]=3 [8]=7 [9]=7 [5]=7 [11]=3 [12]=4 [6]=3 [14]=7 [4]=4 [15]=3 [16]=7 [7]=3)" - literal_transitions[2]="([11]=3 [12]=4 [4]=4 [3]=3 [15]=3 [6]=3 [7]=3)" - literal_transitions[5]="([2]=6)" - literal_transitions[6]="([1]=7 [13]=7)" + literal_transitions[1]="([1]=8 [4]=4 [5]=5 [9]=8 [10]=8 [7]=5 [8]=5 [12]=8 [6]=8 [11]=8 [13]=3 [14]=4 [16]=8 [17]=5 [18]=8)" + literal_transitions[2]="([13]=3 [14]=4 [4]=4 [5]=5 [17]=5 [7]=5 [8]=5)" + literal_transitions[6]="([3]=7)" + literal_transitions[7]="([2]=8 [15]=8)" local -A match_anything_transitions - match_anything_transitions=([4]=3 [3]=5 [1]=2 [2]=2) + match_anything_transitions=([2]=2 [5]=6 [4]=5 [3]=5 [1]=2) declare -A subword_transitions @@ -91,7 +97,7 @@ _hyprpm () { fi done fi - local -A commands=([4]=0) + local -A commands=([4]=0 [3]=1) if [[ -v "commands[$state]" ]]; then local command_id=${commands[$state]} From 33015546c62a7b73793d62983a84b097362cec1a Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 19 Aug 2024 12:46:36 +0000 Subject: [PATCH 0506/2393] config: add missing header for libc++ after 92744b5b9aa3 (#7403) In file included from src/pch/pch.hpp:1: In file included from src/Compositor.hpp:11: src/config/ConfigManager.hpp:147:10: error: no template named 'variant' in namespace 'std' 147 | std::variant data; | ~~~~~^ --- src/config/ConfigManager.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 4241031b..4d087753 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -6,6 +6,7 @@ #include "../debug/Log.hpp" #include #include "../defines.hpp" +#include #include #include #include From 01e3da4d51927427860368c88a523f47c479b710 Mon Sep 17 00:00:00 2001 From: JL2210 Date: Mon, 19 Aug 2024 09:02:09 -0400 Subject: [PATCH 0507/2393] examples: more systemd examples (#7409) These allow launching hyprland with a systemd service. They provide graphical-session.target which allows enabling services such as the ones for Waybar and Mako. --- example/hyprland-session.service | 14 ++++++++++++++ example/hyprland-systemd.desktop | 5 +++++ 2 files changed, 19 insertions(+) create mode 100644 example/hyprland-session.service create mode 100644 example/hyprland-systemd.desktop diff --git a/example/hyprland-session.service b/example/hyprland-session.service new file mode 100644 index 00000000..7d33f5b3 --- /dev/null +++ b/example/hyprland-session.service @@ -0,0 +1,14 @@ +[Unit] +Description=Hyprland - Tiling compositor with the looks +Documentation=man:Hyprland(1) +BindsTo=graphical-session.target +Before=graphical-session.target +Wants=graphical-session-pre.target +After=graphical-session-pre.target + +[Service] +Type=notify +ExecStart=/usr/bin/Hyprland +ExecStop=/usr/bin/hyprctl dispatch exit +Restart=on-failure +Slice=session.slice diff --git a/example/hyprland-systemd.desktop b/example/hyprland-systemd.desktop new file mode 100644 index 00000000..b36a87b2 --- /dev/null +++ b/example/hyprland-systemd.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Name=Hyprland +Comment=An intelligent dynamic tiling Wayland compositor +Exec=systemctl --user start --wait hyprland-session +Type=Application From 272d9048706379201b761c3159c24a20cd62fad1 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 19 Aug 2024 18:36:06 +0200 Subject: [PATCH 0508/2393] monitors: avoid crash on wayland output removal --- src/events/Monitors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index b2778062..60fb5bef 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -98,7 +98,7 @@ void Events::listener_monitorDestroy(void* owner, void* data) { if (!pMonitor) return; - Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); + Debug::log(LOG, "Destroy called for monitor {}", pMonitor->szName); pMonitor->onDisconnect(true); From c86db7bbb0cf14d4955ee3a4d13c0ed9f8a0e0ae Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 19 Aug 2024 18:44:22 +0200 Subject: [PATCH 0509/2393] monitor: avoid dangling references to old monitors being undestroyed ref #7414 --- src/Compositor.cpp | 3 +-- src/events/Events.hpp | 1 - src/events/Monitors.cpp | 25 ------------------------- src/helpers/Monitor.cpp | 21 +++++++++++++++++---- src/helpers/Monitor.hpp | 2 +- 5 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 1437a653..75c22743 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2935,7 +2935,7 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { void CCompositor::onNewMonitor(SP output) { // add it to real - auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared()); + auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared(output)); if (std::string("HEADLESS-1") == output->name) { g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); output->name = "FALLBACK"; // we are allowed to do this :) @@ -2944,7 +2944,6 @@ void CCompositor::onNewMonitor(SP output) { Debug::log(LOG, "New output with name {}", output->name); PNEWMONITOR->szName = output->name; - PNEWMONITOR->output = output; PNEWMONITOR->self = PNEWMONITOR; const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? output == g_pCompositor->m_pUnsafeOutput->output : false; PNEWMONITOR->ID = FALLBACK ? MONITOR_INVALID : g_pCompositor->getNextAvailableMonitorID(output->name); diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 8e73f54a..0af16f64 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -27,7 +27,6 @@ namespace Events { // Monitor part 2 the sequel DYNLISTENFUNC(monitorFrame); - DYNLISTENFUNC(monitorDestroy); DYNLISTENFUNC(monitorStateRequest); DYNLISTENFUNC(monitorDamage); DYNLISTENFUNC(monitorNeedsFrame); diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index 60fb5bef..9d2210f6 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -85,31 +85,6 @@ void Events::listener_monitorFrame(void* owner, void* data) { } } -void Events::listener_monitorDestroy(void* owner, void* data) { - CMonitor* pMonitor = (CMonitor*)owner; - - for (auto& m : g_pCompositor->m_vRealMonitors) { - if (m->output == pMonitor->output) { - pMonitor = m.get(); - break; - } - } - - if (!pMonitor) - return; - - Debug::log(LOG, "Destroy called for monitor {}", pMonitor->szName); - - pMonitor->onDisconnect(true); - - pMonitor->output = nullptr; - pMonitor->m_bRenderingInitPassed = false; - - Debug::log(LOG, "Removing monitor {} from realMonitors", pMonitor->szName); - - std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == pMonitor; }); -} - void Events::listener_monitorNeedsFrame(void* owner, void* data) { const auto PMONITOR = (CMonitor*)owner; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9542d2c4..2c6282e1 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -25,7 +25,7 @@ int ratHandler(void* data) { return 1; } -CMonitor::CMonitor() : state(this) { +CMonitor::CMonitor(SP output_) : state(this), output(output_) { ; } @@ -40,16 +40,29 @@ void CMonitor::onConnect(bool noRule) { outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); } - listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); - listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); }); - listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); + listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); + listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); listeners.needsFrame = output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); + listeners.presented = output->events.present.registerListener([this](std::any d) { auto E = std::any_cast(d); PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); }); + listeners.destroy = output->events.destroy.registerListener([this](std::any d) { + Debug::log(LOG, "Destroy called for monitor {}", szName); + + onDisconnect(true); + + output = nullptr; + m_bRenderingInitPassed = false; + + Debug::log(LOG, "Removing monitor {} from realMonitors", szName); + + std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == this; }); + }); + listeners.state = output->events.state.registerListener([this](std::any d) { auto E = std::any_cast(d); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index dcfcb63b..01a5d28d 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -59,7 +59,7 @@ class CMonitorState { class CMonitor { public: - CMonitor(); + CMonitor(SP output); ~CMonitor(); Vector2D vecPosition = Vector2D(-1, -1); // means unset From 4eff224a7f6f4baa5600f687d6f2ef4ad8340ad3 Mon Sep 17 00:00:00 2001 From: Ali Atashrooz Date: Wed, 21 Aug 2024 13:54:02 +0330 Subject: [PATCH 0510/2393] example/config: fix typo in default config (#7446) * Update hyprland.conf * Update defaultConfig.hpp --- example/hyprland.conf | 6 +++--- src/config/defaultConfig.hpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index f69309c2..d55d25fd 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -169,9 +169,9 @@ device { } -#################### -### KEYBINDINGSS ### -#################### +################### +### KEYBINDINGS ### +################### # See https://wiki.hyprland.org/Configuring/Keywords/ $mainMod = SUPER # Sets "Windows" key as main modifier diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 98b617d0..59265fee 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -182,9 +182,9 @@ device { } -#################### -### KEYBINDINGSS ### -#################### +################### +### KEYBINDINGS ### +################### # See https://wiki.hyprland.org/Configuring/Keywords/ $mainMod = SUPER # Sets "Windows" key as main modifier From 946ed1f32ae8e3840d1b3bb04c6e048ca7501fba Mon Sep 17 00:00:00 2001 From: ParaN3xus <136563585+ParaN3xus@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:24:42 +0800 Subject: [PATCH 0511/2393] core: add option to control which window to focus on close (#7368) --- src/config/ConfigDescriptions.hpp | 9 ++++++++- src/config/ConfigManager.cpp | 1 + src/events/Windows.cpp | 7 ++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 3c830132..73b995ae 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -453,6 +453,13 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1, 0, 3}, }, + SConfigOptionDescription{ + .value = "input:focus_on_close", + .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " + "to the window under the cursor.", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "next,cursor"}, + }, SConfigOptionDescription{ .value = "input:mouse_refocus", .description = "if disabled, mouse focus won't switch to the hovered window unless the mouse crosses a window boundary when follow_mouse=1.", @@ -1341,4 +1348,4 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, -}; \ No newline at end of file +}; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1856bd49..155b75d3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -449,6 +449,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("animations:first_launch_animation", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1}); + m_pConfig->addConfigValue("input:focus_on_close", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:off_window_axis_events", Hyprlang::INT{1}); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 2eb7038f..e4e3900b 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -648,7 +648,12 @@ void Events::listener_unmapWindow(void* owner, void* data) { // refocus on a new window if needed if (wasLastWindow) { - const auto PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW); + static auto FOCUSONCLOSE = CConfigValue("input:focus_on_close"); + PHLWINDOW PWINDOWCANDIDATE = nullptr; + if (*FOCUSONCLOSE) + PWINDOWCANDIDATE = (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING)); + else + PWINDOWCANDIDATE = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(PWINDOW); Debug::log(LOG, "On closed window, new focused candidate is {}", PWINDOWCANDIDATE); From 3e7325af57c4670ebea65d2669f49526819c2260 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 21 Aug 2024 12:52:40 +0200 Subject: [PATCH 0512/2393] output: dont cast enum out of range (#7448) avoid casting non typed enum out of range, looks like WL_OUTPUT_MODE_CURRENT was the intention here. --- src/protocols/core/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 878d1484..8d0b0121 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -55,7 +55,7 @@ void CWLOutputResource::updateState() { if (resource->version() >= 2) resource->sendScale(std::ceil(monitor->scale)); - resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); + resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); if (resource->version() >= 2) resource->sendDone(); From 883463f9dd7f1cdc68c3e32017c0a71ccbe39b26 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 21 Aug 2024 14:37:50 +0200 Subject: [PATCH 0513/2393] animations: add workspace in/out configs --- src/config/ConfigManager.cpp | 10 +++++++++- src/desktop/Workspace.cpp | 12 ++++++++++-- src/managers/AnimationManager.cpp | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 155b75d3..e2ae2c47 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -724,7 +724,6 @@ void CConfigManager::setDefaultAnimationVars() { INITANIMCFG("fade"); INITANIMCFG("border"); INITANIMCFG("borderangle"); - INITANIMCFG("workspaces"); // windows INITANIMCFG("windowsIn"); @@ -745,7 +744,12 @@ void CConfigManager::setDefaultAnimationVars() { // border // workspaces + INITANIMCFG("workspaces"); + INITANIMCFG("workspacesIn"); + INITANIMCFG("workspacesOut"); INITANIMCFG("specialWorkspace"); + INITANIMCFG("specialWorkspaceIn"); + INITANIMCFG("specialWorkspaceOut"); } // init the values @@ -774,7 +778,11 @@ void CConfigManager::setDefaultAnimationVars() { CREATEANIMCFG("fadeLayersIn", "fadeLayers"); CREATEANIMCFG("fadeLayersOut", "fadeLayers"); + CREATEANIMCFG("workspacesIn", "workspaces"); + CREATEANIMCFG("workspacesOut", "workspaces"); CREATEANIMCFG("specialWorkspace", "workspaces"); + CREATEANIMCFG("specialWorkspaceIn", "specialWorkspace"); + CREATEANIMCFG("specialWorkspaceOut", "specialWorkspace"); } std::optional CConfigManager::resetHLConfig() { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index d9ac7927..a9412e6d 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -22,10 +22,11 @@ CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bo void CWorkspace::init(PHLWORKSPACE self) { m_pSelf = self; - m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), + m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : + g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, AVARDAMAGE_ENTIRE); m_fAlpha.create(AVARTYPE_FLOAT, - m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspace") : g_pConfigManager->getAnimationPropertyConfig("workspaces"), self, + m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, AVARDAMAGE_ENTIRE); m_fAlpha.setValueAndWarp(1.f); @@ -81,6 +82,13 @@ CWorkspace::~CWorkspace() { } void CWorkspace::startAnim(bool in, bool left, bool instant) { + if (!instant) { + const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); + + m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + } + const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index dcc7a45f..beb880be 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -471,7 +471,7 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config, } return "unknown style"; - } else if (config == "workspaces" || config == "specialWorkspace") { + } else if (config.starts_with("workspaces") || config.starts_with("specialWorkspace")) { if (style == "slide" || style == "slidevert" || style == "fade") return ""; else if (style.starts_with("slidefade")) { From 1b1ecf77e0c195460eb5335652d65de6fd83cf7b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 21 Aug 2024 22:37:28 +0300 Subject: [PATCH 0514/2393] Nix: include xcursor regardless of xwayland --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index 9bae9d83..c8eaf731 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -136,11 +136,11 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov tomlplusplus wayland wayland-protocols + xorg.libXcursor ] (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) (lib.optionals enableXWayland [ xorg.libxcb - xorg.libXcursor xorg.libXdmcp xorg.xcbutil xorg.xcbutilerrors From c5786be695224c2d2771854436844b88a6b48fc5 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Tue, 20 Aug 2024 13:36:41 -0400 Subject: [PATCH 0515/2393] Fix static asan patch --- scripts/hyprlandStaticAsan.diff | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/hyprlandStaticAsan.diff b/scripts/hyprlandStaticAsan.diff index e74eb6ab..b352d65d 100644 --- a/scripts/hyprlandStaticAsan.diff +++ b/scripts/hyprlandStaticAsan.diff @@ -1,13 +1,13 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index f54cdf5d..ad7c3e73 100755 +index f26a5c3c..3dfef333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -130,6 +130,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) - message(STATUS "Enabling ASan") +@@ -143,6 +143,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) + message(STATUS "Enabling ASan") - target_link_libraries(Hyprland asan) -+ pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) -+ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) - target_compile_options(Hyprland PUBLIC -fsanitize=address) - endif() + target_link_libraries(Hyprland asan) ++ pkg_check_modules(ffidep REQUIRED IMPORTED_TARGET libffi) ++ target_link_libraries(Hyprland ${CMAKE_SOURCE_DIR}/libwayland-server.a PkgConfig::ffidep) + target_compile_options(Hyprland PUBLIC -fsanitize=address) + endif() From 8162fae37728b3ae2b1a82a32663e76c59c4ce61 Mon Sep 17 00:00:00 2001 From: James R Larrowe Date: Tue, 20 Aug 2024 13:54:51 -0400 Subject: [PATCH 0516/2393] Fix Makefile too ... did this ever work? --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index adf6fbe8..bc7b750b 100644 --- a/Makefile +++ b/Makefile @@ -87,8 +87,8 @@ asan: #git reset --hard @echo -en "If you want to apply a patch, input its path (leave empty for none):\n" - @read patchvar - @if [-n "$patchvar"]; then patch -p1 < $patchvar || echo ""; else echo "No patch specified"; fi + @read patchvar; \ + if [ -n "$$patchvar" ]; then patch -p1 < "$$patchvar" || echo ""; else echo "No patch specified"; fi git clone --recursive https://gitlab.freedesktop.org/wayland/wayland cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd .. From cae937c51bd220d6676c6027d05ea51fc3c821bb Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Wed, 21 Aug 2024 23:05:03 +0200 Subject: [PATCH 0517/2393] layersurface: dont rollover on size_t (#7451) unneded rollover on size_t if force equals -1 --- src/desktop/LayerSurface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index c352fa74..8fd448ef 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -432,8 +432,8 @@ void CLayerSurface::startAnimation(bool in, bool instant) { PMONITOR->vecPosition + Vector2D{PMONITOR->vecSize.x, PMONITOR->vecSize.y / 2}, }; - float closest = std::numeric_limits::max(); - size_t leader = force; + float closest = std::numeric_limits::max(); + int leader = force; if (leader == -1) { for (size_t i = 0; i < 4; ++i) { float dist = MIDDLE.distance(edgePoints[i]); From a437e44a6af8e8f42966ffe3a26c1d562fce6b33 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Thu, 22 Aug 2024 13:04:13 +0300 Subject: [PATCH 0518/2393] CMakeLists: wayland.xml is in wayland-scanner pkgdatadir See https://gitlab.freedesktop.org/wayland/wayland/-/blob/6c4a695045155583a99f3fbce7bb745f79c2e726/meson.build#L129-136 Similar fix as https://github.com/hyprwm/aquamarine/pull/55. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f26a5c3c..b1373e07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ find_package(PkgConfig REQUIRED) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") -pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir) +pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake") @@ -259,7 +259,7 @@ function(protocolWayland) OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp COMMAND hyprwayland-scanner --wayland-enums - ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(generate-protocol-headers From 4fa63104c94ca5e2d2e3baaf3b3926db246b964c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 22 Aug 2024 14:30:10 +0300 Subject: [PATCH 0519/2393] Nix: exclude wayland-scanner until next staging merge --- CMakeLists.txt | 13 ++++++------- nix/default.nix | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1373e07..e8ea4797 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,8 @@ find_package(PkgConfig REQUIRED) pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) +message( + STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}") if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Configuring Hyprland in Debug with CMake") @@ -87,11 +89,7 @@ else() endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules( - hyprctl_deps - REQUIRED - IMPORTED_TARGET - hyprutils>=0.2.1) +pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) pkg_check_modules( deps @@ -258,8 +256,9 @@ function(protocolWayland) add_custom_command( OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp - COMMAND hyprwayland-scanner --wayland-enums - ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ + COMMAND + hyprwayland-scanner --wayland-enums + ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) target_sources(generate-protocol-headers diff --git a/nix/default.nix b/nix/default.nix index c8eaf731..64796a90 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -97,7 +97,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov ninja pkg-config python3 # for udis86 - wayland-scanner + # re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable + # wayland-scanner ]; outputs = [ From bdb296a83c595f3814f8159d2cffd25c3edfb842 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 22 Aug 2024 14:30:17 +0300 Subject: [PATCH 0520/2393] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 97016819..fd06ac7d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724006173, - "narHash": "sha256-1ROh0buuxiMyc6eIb3CIbJsmYO7PhLqSYs55mOx1XTk=", + "lastModified": 1724273991, + "narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7f8df01d4297b9068a9592400f16044602844f86", + "rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1721324361, - "narHash": "sha256-BiJKO0IIdnSwHQBSrEJlKlFr753urkLE48wtt0UhNG4=", + "lastModified": 1724174162, + "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "adbefbf49664a6c2c8bf36b6487fd31e3eb68086", + "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1723637854, - "narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=", + "lastModified": 1724224976, + "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9", + "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1722365976, - "narHash": "sha256-Khdm+mDzYA//XaU0M+hftod+rKr5q9SSHSEuiQ0/9ow=", + "lastModified": 1724073926, + "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "7f2a77ddf60390248e2a3de2261d7102a13e5341", + "rev": "a08ecbbf33598924e93542f737fc6169a26b481e", "type": "github" }, "original": { From f634b9e61af7dae0ca70379bd207eea45bb417d1 Mon Sep 17 00:00:00 2001 From: Red <21181998+Redender64@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:36:12 +0000 Subject: [PATCH 0521/2393] Fix crash reports having execute permission --- src/debug/CrashReporter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index c31975b8..000d8c5d 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -86,7 +86,7 @@ void CrashReporter::createAndSaveCrash(int sig) { stderr.flush(); } - reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRWXU); + reportFd = open(reportPath.get_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (reportFd < 0) { exit_with_error("Failed to open crash report path for writing"); } From 3b663f4afcecb1abc93a61d6448183c5978f5cd2 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 23 Aug 2024 14:13:43 +0200 Subject: [PATCH 0522/2393] screencopy: fixup 10-bit sharing via shm on nvidia --- src/protocols/Screencopy.cpp | 2 +- src/protocols/ToplevelExport.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index b25d9456..1559476b 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -238,7 +238,7 @@ bool CScreencopyFrame::copyShm() { g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(box.w, box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : pMonitor->output->state->state().drmFormat); + fb.alloc(box.w, box.h, pMonitor->output->state->state().drmFormat); if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { LOGM(ERR, "Can't copy: failed to begin rendering"); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 05e991d6..916f7395 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -245,7 +245,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pHyprRenderer->makeEGLCurrent(); CFramebuffer outFB; - outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); + outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); if (overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); From df4f222482a7c2a1116ef5c91ba6e4b55d94ad6c Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 23 Aug 2024 15:06:52 +0200 Subject: [PATCH 0523/2393] layersurface: remove layer on destroy from monitor (#7457) remove destroyed layer weakptrs on destroy, we can hit multiple null ptr derefs in renderering on mirroring and unmirroring displays otherwise. --- src/desktop/LayerSurface.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8fd448ef..46aea86c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -107,6 +107,12 @@ void CLayerSurface::onDestroy() { g_pHyprRenderer->damageBox(&geomFixed); } + for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto& lsl : mon->m_aLayerSurfaceLayers) { + std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); + } + } + readyToDelete = true; layerSurface.reset(); if (surface) From a3b75559b35880a85149ab0b644cc0c26cdfdae1 Mon Sep 17 00:00:00 2001 From: MahouShoujoMivutilde <14999778+MahouShoujoMivutilde@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:35:52 +0300 Subject: [PATCH 0524/2393] input: Fix modifier keys getting stuck if depressed during config reload (#7486) The problem: If `input:numlock_by_default = true`, depressed mods will get stuck on config reload; this takes effect after some other mod is pressed. This restores 0.41.2 behavior, with the exception that selected keyboard layout is preserved. https://github.com/hyprwm/Hyprland/blob/918d8340afd652b011b937d29d5eea0be08467f5/src/managers/input/InputManager.cpp#L993-L1002 --- src/devices/IKeyboard.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index e05cbd04..13440169 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -119,7 +119,8 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { if (IDX != XKB_MOD_INVALID) modifiersState.locked |= (uint32_t)1 << IDX; - updateModifiers(modifiersState.depressed, modifiersState.latched, modifiersState.locked, modifiersState.group); + // 0 to avoid mods getting stuck if depressed during reload + updateModifiers(0, 0, modifiersState.locked, modifiersState.group); } for (size_t i = 0; i < LEDNAMES.size(); ++i) { From 688fe5c14781c63a1db23d4d02bf239283068ff6 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Sat, 24 Aug 2024 04:42:14 +0900 Subject: [PATCH 0525/2393] windowrules: add fullscreenstate field (#7466) * windowrules: add fullscreenstate field * fix typo --- src/Compositor.cpp | 7 ++-- src/config/ConfigManager.cpp | 62 ++++++++++++++++++++++++++++-------- src/desktop/Window.hpp | 15 +++++---- 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 75c22743..c9a698ce 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2326,8 +2326,12 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS PWINDOW->m_sFullscreenState.client = state.client; g_pXWaylandManager->setWindowFullscreen(PWINDOW, state.client & FSMODE_FULLSCREEN); - if (!CHANGEINTERNAL) + if (!CHANGEINTERNAL) { + PWINDOW->updateDynamicRules(); + updateWindowAnimatedDecorationValues(PWINDOW); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); return; + } g_pLayoutManager->getCurrentLayout()->fullscreenRequestForWindow(PWINDOW, CURRENT_EFFECTIVE_MODE, EFFECTIVE_MODE); @@ -2339,7 +2343,6 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS EMIT_HOOK_EVENT("fullscreen", PWINDOW); PWINDOW->updateDynamicRules(); - PWINDOW->updateWindowDecos(); updateWindowAnimatedDecorationValues(PWINDOW); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e2ae2c47..51b1e1d2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1212,6 +1212,32 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo continue; } + if (!rule.szFullscreenState.empty()) { + const auto ARGS = CVarList(rule.szFullscreenState, 2, ' '); + // + std::optional internalMode, clientMode; + + if (ARGS[0] == "*") + internalMode = {}; + else if (isNumber(ARGS[0])) + internalMode = (eFullscreenMode)std::stoi(ARGS[0]); + else + throw std::runtime_error("szFullscreenState internal mode not valid"); + + if (ARGS[1] == "*") + clientMode = {}; + else if (isNumber(ARGS[1])) + clientMode = (eFullscreenMode)std::stoi(ARGS[1]); + else + throw std::runtime_error("szFullscreenState client mode not valid"); + + if (internalMode.has_value() && pWindow->m_sFullscreenState.internal != internalMode) + continue; + + if (clientMode.has_value() && pWindow->m_sFullscreenState.client != clientMode) + continue; + } + if (!rule.szOnWorkspace.empty()) { const auto PWORKSPACE = pWindow->m_pWorkspace; if (!PWORKSPACE || !PWORKSPACE->matchesStaticSelector(rule.szOnWorkspace)) @@ -2219,17 +2245,18 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& rule.szRule = RULE; rule.szValue = VALUE; - const auto TAGPOS = VALUE.find("tag:"); - const auto TITLEPOS = VALUE.find("title:"); - const auto CLASSPOS = VALUE.find("class:"); - const auto INITIALTITLEPOS = VALUE.find("initialTitle:"); - const auto INITIALCLASSPOS = VALUE.find("initialClass:"); - const auto X11POS = VALUE.find("xwayland:"); - const auto FLOATPOS = VALUE.find("floating:"); - const auto FULLSCREENPOS = VALUE.find("fullscreen:"); - const auto PINNEDPOS = VALUE.find("pinned:"); - const auto FOCUSPOS = VALUE.find("focus:"); - const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); + const auto TAGPOS = VALUE.find("tag:"); + const auto TITLEPOS = VALUE.find("title:"); + const auto CLASSPOS = VALUE.find("class:"); + const auto INITIALTITLEPOS = VALUE.find("initialTitle:"); + const auto INITIALCLASSPOS = VALUE.find("initialClass:"); + const auto X11POS = VALUE.find("xwayland:"); + const auto FLOATPOS = VALUE.find("floating:"); + const auto FULLSCREENPOS = VALUE.find("fullscreen:"); + const auto PINNEDPOS = VALUE.find("pinned:"); + const auto FOCUSPOS = VALUE.find("focus:"); + const auto FULLSCREENSTATEPOS = VALUE.find("fullscreenstate:"); + const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); // find workspacepos that isn't onworkspacepos size_t WORKSPACEPOS = std::string::npos; @@ -2242,9 +2269,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& currentPos = VALUE.find("workspace:", currentPos + 1); } - const auto checkPos = std::unordered_set{ - TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, PINNEDPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, - }; + const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, + FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS}; if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; @@ -2273,6 +2299,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& min = FULLSCREENPOS; if (PINNEDPOS > pos && PINNEDPOS < min) min = PINNEDPOS; + if (FULLSCREENSTATEPOS > pos && FULLSCREENSTATEPOS < min) + min = FULLSCREENSTATEPOS; if (ONWORKSPACEPOS > pos && ONWORKSPACEPOS < min) min = ONWORKSPACEPOS; if (WORKSPACEPOS > pos && WORKSPACEPOS < min) @@ -2317,6 +2345,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (PINNEDPOS != std::string::npos) rule.bPinned = extract(PINNEDPOS + 7) == "1" ? 1 : 0; + if (FULLSCREENSTATEPOS != std::string::npos) + rule.szFullscreenState = extract(FULLSCREENSTATEPOS + 16); + if (WORKSPACEPOS != std::string::npos) rule.szWorkspace = extract(WORKSPACEPOS + 10); @@ -2358,6 +2389,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (rule.bPinned != -1 && rule.bPinned != other.bPinned) return false; + if (!rule.szFullscreenState.empty() && rule.szFullscreenState != other.szFullscreenState) + return false; + if (!rule.szWorkspace.empty() && rule.szWorkspace != other.szWorkspace) return false; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 2e5b54b1..e1850fb3 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -196,13 +196,14 @@ struct SWindowRule { std::string szInitialTitle; std::string szInitialClass; std::string szTag; - int bX11 = -1; // -1 means "ANY" - int bFloating = -1; - int bFullscreen = -1; - int bPinned = -1; - int bFocus = -1; - std::string szOnWorkspace = ""; // empty means any - std::string szWorkspace = ""; // empty means any + int bX11 = -1; // -1 means "ANY" + int bFloating = -1; + int bFullscreen = -1; + int bPinned = -1; + int bFocus = -1; + std::string szFullscreenState = ""; // empty means any + std::string szOnWorkspace = ""; // empty means any + std::string szWorkspace = ""; // empty means any }; struct SInitialWorkspaceToken { From e45e606fbd7f7e805eb5a1c81482ea44b66e88d2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 24 Aug 2024 15:22:10 +0200 Subject: [PATCH 0526/2393] layersurface: don't unref from monitor until dtor reee --- src/desktop/LayerSurface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 46aea86c..8d13bf19 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -71,6 +71,12 @@ CLayerSurface::~CLayerSurface() { surface->unassign(); g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); + + for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto& lsl : mon->m_aLayerSurfaceLayers) { + std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); + } + } } void CLayerSurface::onDestroy() { @@ -107,12 +113,6 @@ void CLayerSurface::onDestroy() { g_pHyprRenderer->damageBox(&geomFixed); } - for (auto& mon : g_pCompositor->m_vRealMonitors) { - for (auto& lsl : mon->m_aLayerSurfaceLayers) { - std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); - } - } - readyToDelete = true; layerSurface.reset(); if (surface) From 82c67e61a96b23c7b962ab8e3ed9079f671942e1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 24 Aug 2024 15:24:55 +0200 Subject: [PATCH 0527/2393] config: fix uninitialized values with mode parsing --- src/config/ConfigManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 51b1e1d2..0390b9d9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1218,14 +1218,14 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo std::optional internalMode, clientMode; if (ARGS[0] == "*") - internalMode = {}; + internalMode = std::nullopt; else if (isNumber(ARGS[0])) internalMode = (eFullscreenMode)std::stoi(ARGS[0]); else throw std::runtime_error("szFullscreenState internal mode not valid"); if (ARGS[1] == "*") - clientMode = {}; + clientMode = std::nullopt; else if (isNumber(ARGS[1])) clientMode = (eFullscreenMode)std::stoi(ARGS[1]); else From 66586c38f53f16bcf762f019359a3c9042546a72 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 24 Aug 2024 11:45:53 -0500 Subject: [PATCH 0528/2393] keybinds: refactor dispatchers to be better (#7331) --- src/debug/HyprCtl.cpp | 6 +- src/managers/KeybindManager.cpp | 578 ++++++++++++++++++++------------ src/managers/KeybindManager.hpp | 171 +++++----- src/plugins/PluginAPI.cpp | 7 +- 4 files changed, 457 insertions(+), 305 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 78c8504a..a92c3a53 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -962,11 +962,11 @@ std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) { if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) return "Invalid dispatcher"; - DISPATCHER->second(DISPATCHARG); + SDispatchResult res = DISPATCHER->second(DISPATCHARG); - Debug::log(LOG, "Hyprctl: dispatcher {} : {}", DISPATCHSTR, DISPATCHARG); + Debug::log(LOG, "Hyprctl: dispatcher {} : {}{}", DISPATCHSTR, DISPATCHARG, res.success ? "" : " -> " + res.error); - return "ok"; + return res.success ? "ok" : res.error; } std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 38593497..8bf7152e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -405,7 +405,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { m_dPressedKeys.push_back(KEY); - suppressEvent = handleKeybinds(MODS, KEY, true); + suppressEvent = !handleKeybinds(MODS, KEY, true).passEvent; if (suppressEvent) shadowKeybinds(keysym, KEYCODE); @@ -427,7 +427,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { if (!foundInPressedKeys) { Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys"); // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy - suppressEvent = handleKeybinds(MODS, KEY, false); + suppressEvent = !handleKeybinds(MODS, KEY, false).passEvent; } shadowKeybinds(); @@ -457,14 +457,14 @@ bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { bool found = false; if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { if (e.delta < 0) - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true).passEvent; else - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true).passEvent; } else if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { if (e.delta < 0) - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true).passEvent; else - found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true); + found = !handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true).passEvent; } if (found) @@ -500,7 +500,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_dPressedKeys.push_back(KEY); - suppressEvent = handleKeybinds(MODS, KEY, true); + suppressEvent = !handleKeybinds(MODS, KEY, true).passEvent; if (suppressEvent) shadowKeybinds(); @@ -510,7 +510,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { bool foundInPressedKeys = false; for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { if (it->keyName == KEY_NAME) { - suppressEvent = handleKeybinds(MODS, *it, false); + suppressEvent = !handleKeybinds(MODS, *it, false).passEvent; foundInPressedKeys = true; suppressEvent = !it->sent; it = m_dPressedKeys.erase(it); @@ -521,7 +521,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { if (!foundInPressedKeys) { Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)"); // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy - suppressEvent = handleKeybinds(MODS, KEY, false); + suppressEvent = !handleKeybinds(MODS, KEY, false).passEvent; } shadowKeybinds(); @@ -590,8 +590,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); } -bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { - bool found = false; +SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { + static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); + bool found = false; + SDispatchResult res; if (pressed) { if (keycodeToModifier(key.keycode)) @@ -605,11 +607,6 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi m_sMkKeys.erase(key.keysym); } - static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); - - if (!*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) - Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); - for (auto& k : m_lKeybinds) { const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; const bool SPECIALTRIGGERED = @@ -711,10 +708,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi m_iPassPressed = (int)pressed; + // if the dispatchers says to pass event then we will if (k.handler == "mouse") - DISPATCHER->second((pressed ? "1" : "0") + k.arg); + res = DISPATCHER->second((pressed ? "1" : "0") + k.arg); else - DISPATCHER->second(k.arg); + res = DISPATCHER->second(k.arg); m_iPassPressed = -1; @@ -737,7 +735,18 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi found = true; } - return found; + // if keybind wasn't found (or dispatcher said to) then pass event + res.passEvent |= !found; + + if (!found && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) { + Debug::log(LOG, "Keybind handling is disabled due to an inhibitor"); + + res.success = false; + if (res.error.empty()) + res.error = "Keybind handling is disabled due to an inhibitor"; + } + + return res; } void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) { @@ -838,7 +847,7 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { // Dispatchers -void CKeybindManager::spawn(std::string args) { +SDispatchResult CKeybindManager::spawn(std::string args) { args = trim(args); @@ -850,7 +859,7 @@ void CKeybindManager::spawn(std::string args) { args = args.substr(args.find_first_of(']') + 1); } - const uint64_t PROC = spawnRaw(args); + const uint64_t PROC = spawnRawProc(args); if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); @@ -861,9 +870,16 @@ void CKeybindManager::spawn(std::string args) { Debug::log(LOG, "Applied {} rule arguments for exec.", RULESLIST.size()); } + + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; } -uint64_t CKeybindManager::spawnRaw(std::string args) { +SDispatchResult CKeybindManager::spawnRaw(std::string args) { + const uint64_t PROC = spawnRawProc(args); + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; +} + +uint64_t CKeybindManager::spawnRawProc(std::string args) { Debug::log(LOG, "Executing {}", args); const auto HLENV = getHyprlandLaunchEnv(); @@ -924,26 +940,30 @@ uint64_t CKeybindManager::spawnRaw(std::string args) { return grandchild; } -void CKeybindManager::killActive(std::string args) { +SDispatchResult CKeybindManager::killActive(std::string args) { g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow.lock()); + + return {}; } -void CKeybindManager::kill(std::string args) { +SDispatchResult CKeybindManager::kill(std::string args) { const auto PWINDOW = g_pCompositor->getWindowByRegex(args); if (!PWINDOW) { Debug::log(ERR, "kill: no window found"); - return; + return {.success = false, .error = "kill: no window found"}; } g_pCompositor->closeWindow(PWINDOW); + + return {}; } void CKeybindManager::clearKeybinds() { m_lKeybinds.clear(); } -static void toggleActiveFloatingCore(std::string args, std::optional floatState) { +static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional floatState) { PHLWINDOW PWINDOW = nullptr; if (args != "active" && args.length() > 1) @@ -952,10 +972,10 @@ static void toggleActiveFloatingCore(std::string args, std::optional float PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (floatState.has_value() && floatState == PWINDOW->m_bIsFloating) - return; + return {}; // remove drag status if (!g_pInputManager->currentlyDraggedWindow.expired()) @@ -981,25 +1001,27 @@ static void toggleActiveFloatingCore(std::string args, std::optional float g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + return {}; } -void CKeybindManager::toggleActiveFloating(std::string args) { +SDispatchResult CKeybindManager::toggleActiveFloating(std::string args) { return toggleActiveFloatingCore(args, std::nullopt); } -void CKeybindManager::setActiveFloating(std::string args) { +SDispatchResult CKeybindManager::setActiveFloating(std::string args) { return toggleActiveFloatingCore(args, true); } -void CKeybindManager::setActiveTiled(std::string args) { +SDispatchResult CKeybindManager::setActiveTiled(std::string args) { return toggleActiveFloatingCore(args, false); } -void CKeybindManager::centerWindow(std::string args) { +SDispatchResult CKeybindManager::centerWindow(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return; + return {.success = false, .error = "No floating window found"}; const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); @@ -1009,9 +1031,11 @@ void CKeybindManager::centerWindow(std::string args) { PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); + + return {}; } -void CKeybindManager::toggleActivePseudo(std::string args) { +SDispatchResult CKeybindManager::toggleActivePseudo(std::string args) { PHLWINDOW PWINDOW = nullptr; if (args != "active" && args.length() > 1) @@ -1020,12 +1044,14 @@ void CKeybindManager::toggleActivePseudo(std::string args) { PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; PWINDOW->m_bIsPseudotiled = !PWINDOW->m_bIsPseudotiled; if (!PWINDOW->isFullscreen()) g_pLayoutManager->getCurrentLayout()->recalculateWindow(PWINDOW); + + return {}; } SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCURRENTWORKSPACE) { @@ -1051,7 +1077,7 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; } -void CKeybindManager::changeworkspace(std::string args) { +SDispatchResult CKeybindManager::changeworkspace(std::string args) { // Workspace_back_and_forth being enabled means that an attempt to switch to // the current workspace will instead switch to the previous. static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); @@ -1061,7 +1087,7 @@ void CKeybindManager::changeworkspace(std::string args) { const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PMONITOR) - return; + return {.success = false, .error = "Last monitor not found"}; const auto PCURRENTWORKSPACE = PMONITOR->activeWorkspace; const bool EXPLICITPREVIOUS = args.contains("previous"); @@ -1069,18 +1095,17 @@ void CKeybindManager::changeworkspace(std::string args) { const auto& [workspaceToChangeTo, workspaceName] = getWorkspaceToChangeFromArgs(args, PCURRENTWORKSPACE); if (workspaceToChangeTo == WORKSPACE_INVALID) { Debug::log(ERR, "Error in changeworkspace, invalid value"); - return; + return {.success = false, .error = "Error in changeworkspace, invalid value"}; } - if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) { - return; - } + if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) + return {}; const auto PREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PREVWS.id == -1)) - return; + return {.success = false, .error = "Previous workspace doesn't exist"}; g_pInputManager->unconstrainMouse(); g_pInputManager->m_bEmptyFocusCursorSet = false; @@ -1093,7 +1118,7 @@ void CKeybindManager::changeworkspace(std::string args) { if (!BISWORKSPACECURRENT && pWorkspaceToChangeTo->m_bIsSpecialWorkspace) { PMONITOR->setSpecialWorkspace(pWorkspaceToChangeTo); g_pInputManager->simulateMouseMovement(); - return; + return {}; } g_pInputManager->releaseAllMouseButtons(); @@ -1101,7 +1126,7 @@ void CKeybindManager::changeworkspace(std::string args) { const auto PMONITORWORKSPACEOWNER = PMONITOR->ID == pWorkspaceToChangeTo->m_iMonitorID ? PMONITOR : g_pCompositor->getMonitorFromID(pWorkspaceToChangeTo->m_iMonitorID); if (!PMONITORWORKSPACEOWNER) - return; + return {.success = false, .error = "Workspace to switch to has no monitor"}; updateRelativeCursorCoords(); @@ -1143,13 +1168,15 @@ void CKeybindManager::changeworkspace(std::string args) { if (PLAST && (!HLSurface || HLSurface->getWindow())) PLAST->warpCursor(); } + + return {}; } -void CKeybindManager::fullscreenActive(std::string args) { +SDispatchResult CKeybindManager::fullscreenActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const eFullscreenMode MODE = args == "1" ? FSMODE_MAXIMIZED : FSMODE_FULLSCREEN; @@ -1157,14 +1184,16 @@ void CKeybindManager::fullscreenActive(std::string args) { g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); else g_pCompositor->setWindowFullscreenInternal(PWINDOW, MODE); + + return {}; } -void CKeybindManager::fullscreenStateActive(std::string args) { +SDispatchResult CKeybindManager::fullscreenStateActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); const auto ARGS = CVarList(args, 2, ' '); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_SET_PROP); @@ -1189,9 +1218,11 @@ void CKeybindManager::fullscreenStateActive(std::string args) { g_pCompositor->setWindowFullscreenState(PWINDOW, STATE); PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(PWINDOW->m_sFullscreenState.internal == PWINDOW->m_sFullscreenState.client, PRIORITY_SET_PROP); + + return {}; } -void CKeybindManager::moveActiveToWorkspace(std::string args) { +SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { PHLWINDOW PWINDOW = nullptr; @@ -1203,17 +1234,17 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { } if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(LOG, "Invalid workspace in moveActiveToWorkspace"); - return; + return {.success = false, .error = "Invalid workspace in moveActiveToWorkspace"}; } if (WORKSPACEID == PWINDOW->workspaceID()) { Debug::log(LOG, "Not moving to workspace because it didn't change."); - return; + return {.success = false, .error = "Not moving to workspace because it didn't change."}; } auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID); @@ -1249,9 +1280,11 @@ void CKeybindManager::moveActiveToWorkspace(std::string args) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { +SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { PHLWINDOW PWINDOW = nullptr; const auto ORIGINALARGS = args; @@ -1264,16 +1297,16 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { } if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; const auto& [WORKSPACEID, workspaceName] = getWorkspaceIDNameFromString(args); if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "Error in moveActiveToWorkspaceSilent, invalid value"); - return; + return {.success = false, .error = "Error in moveActiveToWorkspaceSilent, invalid value"}; } if (WORKSPACEID == PWINDOW->workspaceID()) - return; + return {}; g_pHyprRenderer->damageWindow(PWINDOW); @@ -1293,16 +1326,18 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { else g_pInputManager->refocus(); } + + return {}; } -void CKeybindManager::moveFocusTo(std::string args) { +SDispatchResult CKeybindManager::moveFocusTo(std::string args) { static auto PFULLCYCLE = CConfigValue("binds:movefocus_cycles_fullscreen"); static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move focus in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); @@ -1310,7 +1345,7 @@ void CKeybindManager::moveFocusTo(std::string args) { if (*PMONITORFALLBACK) tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg)); - return; + return {}; } const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? @@ -1320,69 +1355,81 @@ void CKeybindManager::moveFocusTo(std::string args) { // Found window in direction, switch to it if (PWINDOWTOCHANGETO) { switchToWindow(PWINDOWTOCHANGETO); - return; + return {}; } Debug::log(LOG, "No window found in direction {}, looking for a monitor", arg); if (*PMONITORFALLBACK && tryMoveFocusToMonitor(g_pCompositor->getMonitorInDirection(arg))) - return; + return {}; static auto PNOFALLBACK = CConfigValue("general:no_focus_fallback"); if (*PNOFALLBACK) - return; + return {.success = false, .error = std::format("Nothing to focus to in direction {}", arg)}; Debug::log(LOG, "No monitor found in direction {}, falling back to next window on current workspace", arg); const auto PWINDOWNEXT = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); if (PWINDOWNEXT) switchToWindow(PWINDOWNEXT); + + return {}; } -void CKeybindManager::focusUrgentOrLast(std::string args) { +SDispatchResult CKeybindManager::focusUrgentOrLast(std::string args) { const auto PWINDOWURGENT = g_pCompositor->getUrgentWindow(); const auto PWINDOWPREV = g_pCompositor->m_pLastWindow.lock() ? (g_pCompositor->m_vWindowFocusHistory.size() < 2 ? nullptr : g_pCompositor->m_vWindowFocusHistory[1].lock()) : (g_pCompositor->m_vWindowFocusHistory.empty() ? nullptr : g_pCompositor->m_vWindowFocusHistory[0].lock()); if (!PWINDOWURGENT && !PWINDOWPREV) - return; + return {.success = false, .error = "Window not found"}; switchToWindow(PWINDOWURGENT ? PWINDOWURGENT : PWINDOWPREV); + + return {}; } -void CKeybindManager::focusCurrentOrLast(std::string args) { +SDispatchResult CKeybindManager::focusCurrentOrLast(std::string args) { const auto PWINDOWPREV = g_pCompositor->m_pLastWindow.lock() ? (g_pCompositor->m_vWindowFocusHistory.size() < 2 ? nullptr : g_pCompositor->m_vWindowFocusHistory[1].lock()) : (g_pCompositor->m_vWindowFocusHistory.empty() ? nullptr : g_pCompositor->m_vWindowFocusHistory[0].lock()); if (!PWINDOWPREV) - return; + return {.success = false, .error = "Window not found"}; switchToWindow(PWINDOWPREV); + + return {}; } -void CKeybindManager::swapActive(std::string args) { +SDispatchResult CKeybindManager::swapActive(std::string args) { char arg = args[0]; if (!isDirection(args)) { Debug::log(ERR, "Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } Debug::log(LOG, "Swapping active window in direction {}", arg); const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + + if (!PLASTWINDOW) + return {.success = false, .error = "Window to swap with not found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Can't swap fullscreen window"}; const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); if (!PWINDOWTOCHANGETO) - return; + return {.success = false, .error = "Window to swap with not found"}; updateRelativeCursorCoords(); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, PWINDOWTOCHANGETO); PLASTWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::moveActiveTo(std::string args) { +SDispatchResult CKeybindManager::moveActiveTo(std::string args) { char arg = args[0]; bool silent = args.ends_with(" silent"); if (silent) @@ -1391,25 +1438,28 @@ void CKeybindManager::moveActiveTo(std::string args) { if (args.starts_with("mon:")) { const auto PNEWMONITOR = g_pCompositor->getMonitorFromString(args.substr(4)); if (!PNEWMONITOR) - return; + return {.success = false, .error = std::format("Monitor {} not found", args.substr(4))}; if (silent) moveActiveToWorkspaceSilent(PNEWMONITOR->activeWorkspace->getConfigName()); else moveActiveToWorkspace(PNEWMONITOR->activeWorkspace->getConfigName()); - return; + return {}; } if (!isDirection(args)) { Debug::log(ERR, "Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move window in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + if (!PLASTWINDOW) + return {.success = false, .error = "Window to move not found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Can't move fullscreen window"}; if (PLASTWINDOW->m_bIsFloating) { std::optional vPosx, vPosy; @@ -1427,7 +1477,7 @@ void CKeybindManager::moveActiveTo(std::string args) { PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition.goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition.goal().y)); - return; + return {}; } // If the window to change to is on the same workspace, switch them @@ -1438,30 +1488,32 @@ void CKeybindManager::moveActiveTo(std::string args) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PLASTWINDOW, args, silent); if (!silent) PLASTWINDOW->warpCursor(); - return; + return {}; } static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); if (!*PMONITORFALLBACK) - return; + return {}; // Otherwise, we always want to move to the next monitor in that direction const auto PMONITORTOCHANGETO = g_pCompositor->getMonitorInDirection(arg); if (!PMONITORTOCHANGETO) - return; + return {.success = false, .error = "Nowhere to move active window to"}; const auto PWORKSPACE = PMONITORTOCHANGETO->activeWorkspace; if (silent) moveActiveToWorkspaceSilent(PWORKSPACE->getConfigName()); else moveActiveToWorkspace(PWORKSPACE->getConfigName()); + + return {}; } -void CKeybindManager::toggleGroup(std::string args) { +SDispatchResult CKeybindManager::toggleGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (PWINDOW->isFullscreen()) g_pCompositor->setWindowFullscreenInternal(PWINDOW, FSMODE_NONE); @@ -1470,30 +1522,32 @@ void CKeybindManager::toggleGroup(std::string args) { PWINDOW->createGroup(); else PWINDOW->destroyGroup(); + + return {}; } -void CKeybindManager::changeGroupActive(std::string args) { +SDispatchResult CKeybindManager::changeGroupActive(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; if (PWINDOW->m_sGroupData.pNextWindow.expired()) - return; + return {.success = false, .error = "No next window in group"}; if (PWINDOW->m_sGroupData.pNextWindow.lock() == PWINDOW) - return; + return {.success = false, .error = "Only one window in group"}; if (isNumber(args, false)) { // index starts from '1'; '0' means last window const int INDEX = std::stoi(args); if (INDEX > PWINDOW->getGroupSize()) - return; + return {}; if (INDEX == 0) PWINDOW->setGroupCurrent(PWINDOW->getGroupTail()); else PWINDOW->setGroupCurrent(PWINDOW->getGroupWindowByIndex(INDEX - 1)); - return; + return {}; } if (args != "b" && args != "prev") { @@ -1501,39 +1555,45 @@ void CKeybindManager::changeGroupActive(std::string args) { } else { PWINDOW->setGroupCurrent(PWINDOW->getGroupPrevious()); } + + return {}; } -void CKeybindManager::toggleSplit(std::string args) { +SDispatchResult CKeybindManager::toggleSplit(std::string args) { SLayoutMessageHeader header; header.pWindow = g_pCompositor->m_pLastWindow.lock(); if (!header.pWindow) - return; + return {.success = false, .error = "Window not found"}; const auto PWORKSPACE = header.pWindow->m_pWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - return; + return {.success = false, .error = "Can't split windows that already split"}; g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "togglesplit"); + + return {}; } -void CKeybindManager::swapSplit(std::string args) { +SDispatchResult CKeybindManager::swapSplit(std::string args) { SLayoutMessageHeader header; header.pWindow = g_pCompositor->m_pLastWindow.lock(); if (!header.pWindow) - return; + return {.success = false, .error = "Window not found"}; const auto PWORKSPACE = header.pWindow->m_pWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - return; + return {.success = false, .error = "Can't split windows that already split"}; g_pLayoutManager->getCurrentLayout()->layoutMessage(header, "swapsplit"); + + return {}; } -void CKeybindManager::alterSplitRatio(std::string args) { +SDispatchResult CKeybindManager::alterSplitRatio(std::string args) { std::optional splitResult; bool exact = false; @@ -1545,39 +1605,43 @@ void CKeybindManager::alterSplitRatio(std::string args) { if (!splitResult.has_value()) { Debug::log(ERR, "Splitratio invalid in alterSplitRatio!"); - return; + return {.success = false, .error = "Splitratio invalid in alterSplitRatio!"}; } const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW) - return; + return {.success = false, .error = "Window not found"}; g_pLayoutManager->getCurrentLayout()->alterSplitRatio(PLASTWINDOW, splitResult.value(), exact); + + return {}; } -void CKeybindManager::focusMonitor(std::string arg) { +SDispatchResult CKeybindManager::focusMonitor(std::string arg) { const auto PMONITOR = g_pCompositor->getMonitorFromString(arg); tryMoveFocusToMonitor(PMONITOR); + + return {}; } -void CKeybindManager::moveCursorToCorner(std::string arg) { +SDispatchResult CKeybindManager::moveCursorToCorner(std::string arg) { if (!isNumber(arg)) { Debug::log(ERR, "moveCursorToCorner, arg has to be a number."); - return; + return {.success = false, .error = "moveCursorToCorner, arg has to be a number."}; } const auto CORNER = std::stoi(arg); if (CORNER < 0 || CORNER > 3) { Debug::log(ERR, "moveCursorToCorner, corner not 0 - 3."); - return; + return {.success = false, .error = "moveCursorToCorner, corner not 0 - 3."}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW) - return; + return {.success = false, .error = "Window not found"}; switch (CORNER) { case 0: @@ -1598,16 +1662,18 @@ void CKeybindManager::moveCursorToCorner(std::string arg) { g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); break; } + + return {}; } -void CKeybindManager::moveCursor(std::string args) { +SDispatchResult CKeybindManager::moveCursor(std::string args) { std::string x_str, y_str; int x, y; size_t i = args.find_first_of(' '); if (i == std::string::npos) { Debug::log(ERR, "moveCursor, takes 2 arguments."); - return; + return {.success = false, .error = "moveCursor, takes 2 arguments"}; } x_str = args.substr(0, i); @@ -1615,26 +1681,28 @@ void CKeybindManager::moveCursor(std::string args) { if (!isNumber(x_str)) { Debug::log(ERR, "moveCursor, x argument has to be a number."); - return; + return {.success = false, .error = "moveCursor, x argument has to be a number."}; } if (!isNumber(y_str)) { Debug::log(ERR, "moveCursor, y argument has to be a number."); - return; + return {.success = false, .error = "moveCursor, y argument has to be a number."}; } x = std::stoi(x_str); y = std::stoi(y_str); g_pCompositor->warpCursorTo({x, y}, true); + + return {}; } -void CKeybindManager::workspaceOpt(std::string args) { +SDispatchResult CKeybindManager::workspaceOpt(std::string args) { // current workspace const auto PWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; if (!PWORKSPACE) - return; // ???? + return {.success = false, .error = "Workspace not found"}; // ???? if (args == "allpseudo") { PWORKSPACE->m_bDefaultPseudo = !PWORKSPACE->m_bDefaultPseudo; @@ -1677,14 +1745,16 @@ void CKeybindManager::workspaceOpt(std::string args) { } } else { Debug::log(ERR, "Invalid arg in workspaceOpt, opt \"{}\" doesn't exist.", args); - return; + return {.success = false, .error = std::format("Invalid arg in workspaceOpt, opt \"{}\" doesn't exist.", args)}; } // recalc mon g_pLayoutManager->getCurrentLayout()->recalculateMonitor(g_pCompositor->m_pLastMonitor->ID); + + return {}; } -void CKeybindManager::renameWorkspace(std::string args) { +SDispatchResult CKeybindManager::renameWorkspace(std::string args) { try { const auto FIRSTSPACEPOS = args.find_first_of(' '); if (FIRSTSPACEPOS != std::string::npos) { @@ -1694,34 +1764,42 @@ void CKeybindManager::renameWorkspace(std::string args) { } else { g_pCompositor->renameWorkspace(std::stoi(args), ""); } - } catch (std::exception& e) { Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what()); } + } catch (std::exception& e) { + Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what()); + return {.success = false, .error = std::format("Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what())}; + } + + return {}; } -void CKeybindManager::exitHyprland(std::string argz) { +SDispatchResult CKeybindManager::exitHyprland(std::string argz) { g_pCompositor->stopCompositor(); + return {}; } -void CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { +SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { CMonitor* PMONITOR = g_pCompositor->getMonitorFromString(args); if (!PMONITOR) { Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"); - return; + return {.success = false, .error = "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"}; } // get the current workspace const auto PCURRENTWORKSPACE = g_pCompositor->m_pLastMonitor->activeWorkspace; if (!PCURRENTWORKSPACE) { Debug::log(ERR, "moveCurrentWorkspaceToMonitor invalid workspace!"); - return; + return {.success = false, .error = "moveCurrentWorkspaceToMonitor invalid workspace!"}; } g_pCompositor->moveWorkspaceToMonitor(PCURRENTWORKSPACE, PMONITOR); + + return {}; } -void CKeybindManager::moveWorkspaceToMonitor(std::string args) { +SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!args.contains(' ')) - return; + return {}; std::string workspace = args.substr(0, args.find_first_of(' ')); std::string monitor = args.substr(args.find_first_of(' ') + 1); @@ -1730,38 +1808,40 @@ void CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!PMONITOR) { Debug::log(ERR, "Ignoring moveWorkspaceToMonitor: monitor doesnt exist"); - return; + return {.success = false, .error = "Ignoring moveWorkspaceToMonitor: monitor doesnt exist"}; } const auto WORKSPACEID = getWorkspaceIDNameFromString(workspace).id; if (WORKSPACEID == WORKSPACE_INVALID) { Debug::log(ERR, "moveWorkspaceToMonitor invalid workspace!"); - return; + return {.success = false, .error = "moveWorkspaceToMonitor invalid workspace!"}; } const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(WORKSPACEID); if (!PWORKSPACE) { Debug::log(ERR, "moveWorkspaceToMonitor workspace doesn't exist!"); - return; + return {.success = false, .error = "moveWorkspaceToMonitor workspace doesn't exist!"}; } g_pCompositor->moveWorkspaceToMonitor(PWORKSPACE, PMONITOR); + + return {}; } -void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { +SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { auto workspaceID = getWorkspaceIDNameFromString(args).id; if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"}; } const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); if (!PCURRMONITOR) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"}; } auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID); @@ -1770,7 +1850,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID); // we can skip the moving, since it's already on the current monitor changeworkspace(pWorkspace->getConfigName()); - return; + return {}; } static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); @@ -1789,24 +1869,26 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { const auto POLDMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); if (!POLDMONITOR) { // wat Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"); - return; + return {.success = false, .error = "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"}; } if (POLDMONITOR->activeWorkspaceID() == workspaceID) { g_pCompositor->swapActiveWorkspaces(POLDMONITOR, PCURRMONITOR); - return; + return {}; } else { g_pCompositor->moveWorkspaceToMonitor(pWorkspace, PCURRMONITOR, true); } } changeworkspace(pWorkspace->getConfigName()); + + return {}; } -void CKeybindManager::toggleSpecialWorkspace(std::string args) { +SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { const auto& [workspaceID, workspaceName] = getWorkspaceIDNameFromString("special:" + args); if (workspaceID == WORKSPACE_INVALID || !g_pCompositor->isWorkspaceSpecial(workspaceID)) { Debug::log(ERR, "Invalid workspace passed to special"); - return; + return {.success = false, .error = "Invalid workspace passed to special"}; } bool requestedWorkspaceIsAlreadyOpen = false; @@ -1833,9 +1915,11 @@ void CKeybindManager::toggleSpecialWorkspace(std::string args) { PMONITOR->setSpecialWorkspace(PSPECIALWORKSPACE); } + + return {}; } -void CKeybindManager::forceRendererReload(std::string args) { +SDispatchResult CKeybindManager::forceRendererReload(std::string args) { bool overAgain = false; for (auto& m : g_pCompositor->m_vMonitors) { @@ -1851,37 +1935,43 @@ void CKeybindManager::forceRendererReload(std::string args) { if (overAgain) forceRendererReload(args); + + return {}; } -void CKeybindManager::resizeActive(std::string args) { +SDispatchResult CKeybindManager::resizeActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + return {}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); if (SIZ.x < 1 || SIZ.y < 1) - return; + return {}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize.goal()); if (PLASTWINDOW->m_vRealSize.goal().x > 1 && PLASTWINDOW->m_vRealSize.goal().y > 1) PLASTWINDOW->setHidden(false); + + return {}; } -void CKeybindManager::moveActive(std::string args) { +SDispatchResult CKeybindManager::moveActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return; + return {}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition.goal()); + + return {}; } -void CKeybindManager::moveWindow(std::string args) { +SDispatchResult CKeybindManager::moveWindow(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto MOVECMD = args.substr(0, args.find_first_of(',')); @@ -1890,18 +1980,20 @@ void CKeybindManager::moveWindow(std::string args) { if (!PWINDOW) { Debug::log(ERR, "moveWindow: no window"); - return; + return {.success = false, .error = "moveWindow: no window"}; } if (PWINDOW->isFullscreen()) - return; + return {}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goal(), PWINDOW); + + return {}; } -void CKeybindManager::resizeWindow(std::string args) { +SDispatchResult CKeybindManager::resizeWindow(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto MOVECMD = args.substr(0, args.find_first_of(',')); @@ -1910,24 +2002,26 @@ void CKeybindManager::resizeWindow(std::string args) { if (!PWINDOW) { Debug::log(ERR, "resizeWindow: no window"); - return; + return {.success = false, .error = "resizeWindow: no window"}; } if (PWINDOW->isFullscreen()) - return; + return {}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); if (SIZ.x < 1 || SIZ.y < 1) - return; + return {}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goal(), CORNER_NONE, PWINDOW); if (PWINDOW->m_vRealSize.goal().x > 1 && PWINDOW->m_vRealSize.goal().y > 1) PWINDOW->setHidden(false); + + return {}; } -void CKeybindManager::circleNext(std::string arg) { +SDispatchResult CKeybindManager::circleNext(std::string arg) { if (g_pCompositor->m_pLastWindow.expired()) { // if we have a clear focus, find the first window and get the next focusable. @@ -1937,7 +2031,7 @@ void CKeybindManager::circleNext(std::string arg) { switchToWindow(PWINDOW); } - return; + return {}; } CVarList args{arg, 0, 's', true}; @@ -1952,20 +2046,22 @@ void CKeybindManager::circleNext(std::string arg) { switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); else switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); + + return {}; } -void CKeybindManager::focusWindow(std::string regexp) { +SDispatchResult CKeybindManager::focusWindow(std::string regexp) { const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) - return; + return {}; Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); const auto PWORKSPACE = PWINDOW->m_pWorkspace; if (!PWORKSPACE) { Debug::log(ERR, "BUG THIS: null workspace in focusWindow"); - return; + return {.success = false, .error = "BUG THIS: null workspace in focusWindow"}; } updateRelativeCursorCoords(); @@ -2001,9 +2097,11 @@ void CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->warpCursor(); + + return {}; } -void CKeybindManager::tagWindow(std::string args) { +SDispatchResult CKeybindManager::tagWindow(std::string args) { PHLWINDOW PWINDOW = nullptr; CVarList vars{args, 0, 's', true}; @@ -2012,21 +2110,23 @@ void CKeybindManager::tagWindow(std::string args) { else if (vars.size() == 2) PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); else - return; + return {}; if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { PWINDOW->updateDynamicRules(); g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW->m_pSelf.lock()); } + + return {}; } -void CKeybindManager::setSubmap(std::string submap) { +SDispatchResult CKeybindManager::setSubmap(std::string submap) { if (submap == "reset" || submap == "") { m_szCurrentSelectedSubmap = ""; Debug::log(LOG, "Reset active submap to the default one."); g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""}); EMIT_HOOK_EVENT("submap", m_szCurrentSelectedSubmap); - return; + return {}; } for (auto& k : g_pKeybindManager->m_lKeybinds) { @@ -2035,26 +2135,27 @@ void CKeybindManager::setSubmap(std::string submap) { Debug::log(LOG, "Changed keybind submap to {}", submap); g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap}); EMIT_HOOK_EVENT("submap", m_szCurrentSelectedSubmap); - return; + return {}; } } Debug::log(ERR, "Cannot set submap {}, submap doesn't exist (wasn't registered!)", submap); + return {.success = false, .error = std::format("Cannot set submap {}, submap doesn't exist (wasn't registered!)", submap)}; } -void CKeybindManager::pass(std::string regexp) { +SDispatchResult CKeybindManager::pass(std::string regexp) { // find the first window passing the regex const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) { Debug::log(ERR, "pass: window not found"); - return; + return {.success = false, .error = "pass: window not found"}; } if (!g_pSeatManager->keyboard) { Debug::log(ERR, "No kb in pass?"); - return; + return {.success = false, .error = "No kb in pass?"}; } const auto XWTOXW = PWINDOW->m_bIsX11 && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsX11; @@ -2093,7 +2194,7 @@ void CKeybindManager::pass(std::string regexp) { } if (XWTOXW) - return; + return {}; // Massive hack: // this will make g_pSeatManager NOT send the leave event to XWayland apps, provided we are not on an XWayland window already. @@ -2114,14 +2215,16 @@ void CKeybindManager::pass(std::string regexp) { g_pSeatManager->setKeyboardFocus(LASTKBSURF); else g_pSeatManager->setPointerFocus(LASTMOUSESURF, SL); + + return {}; } -void CKeybindManager::sendshortcut(std::string args) { +SDispatchResult CKeybindManager::sendshortcut(std::string args) { // args=[,WINDOW_RULES] const auto ARGS = CVarList(args, 3); if (ARGS.size() != 3) { Debug::log(ERR, "sendshortcut: invalid args"); - return; + return {.success = false, .error = "sendshortcut: invalid args"}; } const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); @@ -2139,7 +2242,7 @@ void CKeybindManager::sendshortcut(std::string args) { isMouse = 1; if (keycode < 272) { Debug::log(ERR, "sendshortcut: invalid mouse button"); - return; + return {.success = false, .error = "sendshortcut: invalid mouse button"}; } } else { @@ -2154,7 +2257,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!KB) { Debug::log(ERR, "sendshortcut: no kb"); - return; + return {.success = false, .error = "sendshortcut: no kb"}; } const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY); @@ -2178,7 +2281,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!keycode) { Debug::log(ERR, "sendshortcut: key not found"); - return; + return {.success = false, .error = "sendshortcut: key not found"}; } } else @@ -2187,7 +2290,7 @@ void CKeybindManager::sendshortcut(std::string args) { if (!keycode) { Debug::log(ERR, "sendshortcut: invalid key"); - return; + return {.success = false, .error = "sendshortcut: invalid key"}; } const std::string regexp = ARGS[2]; @@ -2201,12 +2304,12 @@ void CKeybindManager::sendshortcut(std::string args) { if (!PWINDOW) { Debug::log(ERR, "sendshortcut: window not found"); - return; + return {.success = false, .error = "sendshortcut: window not found"}; } if (!g_pSeatManager->keyboard) { Debug::log(ERR, "No kb in sendshortcut?"); - return; + return {.success = false, .error = "No kb in sendshortcut?"}; } if (!isMouse) @@ -2247,7 +2350,7 @@ void CKeybindManager::sendshortcut(std::string args) { } if (!PWINDOW) - return; + return {}; if (PWINDOW->m_bIsX11) { //xwayland hack, see pass if (!isMouse) { @@ -2265,16 +2368,21 @@ void CKeybindManager::sendshortcut(std::string args) { g_pSeatManager->setKeyboardFocus(LASTSURFACE); else g_pSeatManager->setPointerFocus(LASTSURFACE, SL); + + return {}; } -void CKeybindManager::layoutmsg(std::string msg) { +SDispatchResult CKeybindManager::layoutmsg(std::string msg) { SLayoutMessageHeader hd = {g_pCompositor->m_pLastWindow.lock()}; g_pLayoutManager->getCurrentLayout()->layoutMessage(hd, msg); + + return {}; } -void CKeybindManager::dpms(std::string arg) { - bool enable = arg.starts_with("on"); - std::string port = ""; +SDispatchResult CKeybindManager::dpms(std::string arg) { + SDispatchResult res; + bool enable = arg.starts_with("on"); + std::string port = ""; if (arg.starts_with("toggle")) enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off @@ -2294,6 +2402,8 @@ void CKeybindManager::dpms(std::string arg) { if (!m->state.commit()) { Debug::log(ERR, "Couldn't commit output {}", m->szName); + res.success = false; + res.error = "Couldn't commit output {}"; } if (enable) @@ -2305,14 +2415,16 @@ void CKeybindManager::dpms(std::string arg) { g_pCompositor->m_bDPMSStateON = enable; g_pPointerManager->recheckEnteredOutputs(); + + return res; } -void CKeybindManager::swapnext(std::string arg) { +SDispatchResult CKeybindManager::swapnext(std::string arg) { PHLWINDOW toSwap = nullptr; if (g_pCompositor->m_pLastWindow.expired()) - return; + return {}; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); @@ -2339,9 +2451,11 @@ void CKeybindManager::swapnext(std::string arg) { PLASTWINDOW->m_pLastCycledWindow = toSwap; g_pCompositor->focusWindow(PLASTWINDOW); + + return {}; } -void CKeybindManager::swapActiveWorkspaces(std::string args) { +SDispatchResult CKeybindManager::swapActiveWorkspaces(std::string args) { const auto MON1 = args.substr(0, args.find_first_of(' ')); const auto MON2 = args.substr(args.find_first_of(' ') + 1); @@ -2349,12 +2463,14 @@ void CKeybindManager::swapActiveWorkspaces(std::string args) { const auto PMON2 = g_pCompositor->getMonitorFromString(MON2); if (!PMON1 || !PMON2 || PMON1 == PMON2) - return; + return {}; g_pCompositor->swapActiveWorkspaces(PMON1, PMON2); + + return {}; } -void CKeybindManager::pinActive(std::string args) { +SDispatchResult CKeybindManager::pinActive(std::string args) { PHLWINDOW PWINDOW = nullptr; @@ -2365,11 +2481,11 @@ void CKeybindManager::pinActive(std::string args) { if (!PWINDOW) { Debug::log(ERR, "pin: window not found"); - return; + return {.success = false, .error = "pin: window not found"}; } if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return; + return {}; PWINDOW->m_bPinned = !PWINDOW->m_bPinned; @@ -2377,7 +2493,7 @@ void CKeybindManager::pinActive(std::string args) { if (!PMONITOR) { Debug::log(ERR, "pin: monitor not found"); - return; + return {.success = false, .error = "pin: window not found"}; } PWINDOW->m_pWorkspace = PMONITOR->activeWorkspace; @@ -2391,40 +2507,41 @@ void CKeybindManager::pinActive(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"pin", std::format("{:x},{}", (uintptr_t)PWINDOW.get(), (int)PWINDOW->m_bPinned)}); EMIT_HOOK_EVENT("pin", PWINDOW); + + return {}; } -void CKeybindManager::mouse(std::string args) { +SDispatchResult CKeybindManager::mouse(std::string args) { const auto ARGS = CVarList(args.substr(1), 2, ' '); const auto PRESSED = args[0] == '1'; if (!PRESSED) { - changeMouseBindMode(MBIND_INVALID); - return; + return changeMouseBindMode(MBIND_INVALID); } if (ARGS[0] == "movewindow") { - changeMouseBindMode(MBIND_MOVE); + return changeMouseBindMode(MBIND_MOVE); } else { try { switch (std::stoi(ARGS[1])) { - case 1: changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break; - case 2: changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break; - default: changeMouseBindMode(MBIND_RESIZE); + case 1: return changeMouseBindMode(MBIND_RESIZE_FORCE_RATIO); break; + case 2: return changeMouseBindMode(MBIND_RESIZE_BLOCK_RATIO); break; + default: return changeMouseBindMode(MBIND_RESIZE); } - } catch (std::exception& e) { changeMouseBindMode(MBIND_RESIZE); } + } catch (std::exception& e) { return changeMouseBindMode(MBIND_RESIZE); } } } -void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { +SDispatchResult CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { if (MODE != MBIND_INVALID) { if (!g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode != MBIND_INVALID) - return; + return {}; const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const PHLWINDOW PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!PWINDOW) - return; + return SDispatchResult{.passEvent = true}; if (!PWINDOW->isFullscreen() && MODE == MBIND_MOVE) PWINDOW->checkInputOnDecos(INPUT_TYPE_DRAG_START, MOUSECOORDS); @@ -2437,19 +2554,23 @@ void CKeybindManager::changeMouseBindMode(const eMouseBindMode MODE) { g_pLayoutManager->getCurrentLayout()->onBeginDragWindow(); } else { if (g_pInputManager->currentlyDraggedWindow.expired() || g_pInputManager->dragMode == MBIND_INVALID) - return; + return {}; g_pLayoutManager->getCurrentLayout()->onEndDragWindow(); g_pInputManager->dragMode = MODE; } + + return {}; } -void CKeybindManager::bringActiveToTop(std::string args) { +SDispatchResult CKeybindManager::bringActiveToTop(std::string args) { if (g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bIsFloating) g_pCompositor->changeWindowZOrder(g_pCompositor->m_pLastWindow.lock(), true); + + return {}; } -void CKeybindManager::alterZOrder(std::string args) { +SDispatchResult CKeybindManager::alterZOrder(std::string args) { const auto WINDOWREGEX = args.substr(args.find_first_of(',') + 1); const auto POSITION = args.substr(0, args.find_first_of(',')); auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX); @@ -2459,7 +2580,7 @@ void CKeybindManager::alterZOrder(std::string args) { if (!PWINDOW) { Debug::log(ERR, "alterZOrder: no window"); - return; + return {.success = false, .error = "alterZOrder: no window"}; } if (POSITION == "top") @@ -2468,13 +2589,15 @@ void CKeybindManager::alterZOrder(std::string args) { g_pCompositor->changeWindowZOrder(PWINDOW, 0); else { Debug::log(ERR, "alterZOrder: bad position: {}", POSITION); - return; + return {.success = false, .error = "alterZOrder: bad position: {}"}; } g_pInputManager->simulateMouseMovement(); + + return {}; } -void CKeybindManager::lockGroups(std::string args) { +SDispatchResult CKeybindManager::lockGroups(std::string args) { if (args == "lock" || args.empty() || args == "lockgroups") g_pKeybindManager->m_bGroupsLocked = true; else if (args == "toggle") @@ -2483,13 +2606,15 @@ void CKeybindManager::lockGroups(std::string args) { g_pKeybindManager->m_bGroupsLocked = false; g_pEventManager->postEvent(SHyprIPCEvent{"lockgroups", g_pKeybindManager->m_bGroupsLocked ? "1" : "0"}); + + return {}; } -void CKeybindManager::lockActiveGroup(std::string args) { +SDispatchResult CKeybindManager::lockActiveGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; const auto PHEAD = PWINDOW->getGroupHead(); @@ -2501,6 +2626,8 @@ void CKeybindManager::lockActiveGroup(std::string args) { PHEAD->m_sGroupData.locked = false; g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection) { @@ -2573,41 +2700,43 @@ void CKeybindManager::moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& g_pEventManager->postEvent(SHyprIPCEvent{"moveoutofgroup", std::format("{:x}", (uintptr_t)pWindow.get())}); } -void CKeybindManager::moveIntoGroup(std::string args) { +SDispatchResult CKeybindManager::moveIntoGroup(std::string args) { char arg = args[0]; static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return; + return {}; if (!isDirection(args)) { Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) - return; + return {}; auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); if (!PWINDOWINDIR || !PWINDOWINDIR->m_sGroupData.pNextWindow.lock()) - return; + return {}; // Do not move window into locked group if binds:ignore_group_lock is false if (!*PIGNOREGROUPLOCK && (PWINDOWINDIR->getGroupHead()->m_sGroupData.locked || (PWINDOW->m_sGroupData.pNextWindow.lock() && PWINDOW->getGroupHead()->m_sGroupData.locked))) - return; + return {}; moveWindowIntoGroup(PWINDOW, PWINDOWINDIR); + + return {}; } -void CKeybindManager::moveOutOfGroup(std::string args) { +SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return; + return {}; PHLWINDOW PWINDOW = nullptr; @@ -2617,28 +2746,30 @@ void CKeybindManager::moveOutOfGroup(std::string args) { PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; moveWindowOutOfGroup(PWINDOW); + + return {}; } -void CKeybindManager::moveWindowOrGroup(std::string args) { +SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) { char arg = args[0]; static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!isDirection(args)) { Debug::log(ERR, "Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg); - return; + return {.success = false, .error = std::format("Cannot move into group in direction {}, unsupported direction. Supported: l,r,u/t,d/b", arg)}; } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || PWINDOW->isFullscreen()) - return; + return {}; if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { g_pLayoutManager->getCurrentLayout()->moveWindowTo(PWINDOW, args); - return; + return {}; } const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); @@ -2670,9 +2801,11 @@ void CKeybindManager::moveWindowOrGroup(std::string args) { } g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } -void CKeybindManager::setIgnoreGroupLock(std::string args) { +SDispatchResult CKeybindManager::setIgnoreGroupLock(std::string args) { static auto PIGNOREGROUPLOCK = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("binds:ignore_group_lock"); if (args == "toggle") @@ -2681,12 +2814,14 @@ void CKeybindManager::setIgnoreGroupLock(std::string args) { **PIGNOREGROUPLOCK = args == "on"; g_pEventManager->postEvent(SHyprIPCEvent{"ignoregrouplock", std::to_string(**PIGNOREGROUPLOCK)}); + + return {}; } -void CKeybindManager::denyWindowFromGroup(std::string args) { +SDispatchResult CKeybindManager::denyWindowFromGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PWINDOW || (PWINDOW && PWINDOW->m_sGroupData.pNextWindow.lock())) - return; + return {}; if (args == "toggle") PWINDOW->m_sGroupData.deny = !PWINDOW->m_sGroupData.deny; @@ -2694,28 +2829,32 @@ void CKeybindManager::denyWindowFromGroup(std::string args) { PWINDOW->m_sGroupData.deny = args == "on"; g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); + + return {}; } -void CKeybindManager::global(std::string args) { +SDispatchResult CKeybindManager::global(std::string args) { const auto APPID = args.substr(0, args.find_first_of(':')); const auto NAME = args.substr(args.find_first_of(':') + 1); if (NAME.empty()) - return; + return {}; if (!PROTO::globalShortcuts->isTaken(APPID, NAME)) - return; + return {}; PROTO::globalShortcuts->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed); + + return {}; } -void CKeybindManager::moveGroupWindow(std::string args) { +SDispatchResult CKeybindManager::moveGroupWindow(std::string args) { const auto BACK = args == "b" || args == "prev"; const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock()) - return; + return {}; if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); @@ -2724,8 +2863,11 @@ void CKeybindManager::moveGroupWindow(std::string args) { PLASTWINDOW->switchWithWindowInGroup(BACK ? PLASTWINDOW->getGroupPrevious() : PLASTWINDOW->m_sGroupData.pNextWindow.lock()); PLASTWINDOW->updateWindowDecos(); + + return {}; } -void CKeybindManager::event(std::string args) { +SDispatchResult CKeybindManager::event(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); + return {}; } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 26b42b00..d1f26c2c 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -71,33 +71,39 @@ enum eMultiKeyCase { MK_FULL_MATCH }; +struct SDispatchResult { + bool passEvent = false; + bool success = true; + std::string error; +}; + class CKeybindManager { public: CKeybindManager(); ~CKeybindManager(); - bool onKeyEvent(std::any, SP); - bool onAxisEvent(const IPointer::SAxisEvent&); - bool onMouseEvent(const IPointer::SButtonEvent&); - void resizeWithBorder(const IPointer::SButtonEvent&); - void onSwitchEvent(const std::string&); - void onSwitchOnEvent(const std::string&); - void onSwitchOffEvent(const std::string&); + bool onKeyEvent(std::any, SP); + bool onAxisEvent(const IPointer::SAxisEvent&); + bool onMouseEvent(const IPointer::SButtonEvent&); + void resizeWithBorder(const IPointer::SButtonEvent&); + void onSwitchEvent(const std::string&); + void onSwitchOnEvent(const std::string&); + void onSwitchOffEvent(const std::string&); - void addKeybind(SKeybind); - void removeKeybind(uint32_t, const SParsedKey&); - uint32_t stringToModMask(std::string); - uint32_t keycodeToModifier(xkb_keycode_t); - void clearKeybinds(); - void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); + void addKeybind(SKeybind); + void removeKeybind(uint32_t, const SParsedKey&); + uint32_t stringToModMask(std::string); + uint32_t keycodeToModifier(xkb_keycode_t); + void clearKeybinds(); + void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); - std::unordered_map> m_mDispatchers; + std::unordered_map> m_mDispatchers; - wl_event_source* m_pActiveKeybindEventSource = nullptr; + wl_event_source* m_pActiveKeybindEventSource = nullptr; - bool m_bGroupsLocked = false; + bool m_bGroupsLocked = false; - std::list m_lKeybinds; + std::list m_lKeybinds; //since we cant find keycode through keyname in xkb: //on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42) @@ -105,7 +111,7 @@ class CKeybindManager { //we also store the keyboard pointer (in the string) to differentiate between different keyboard (layouts) std::unordered_map m_mKeyToCodeCache; - static void changeMouseBindMode(const eMouseBindMode mode); + static SDispatchResult changeMouseBindMode(const eMouseBindMode mode); private: std::deque m_dPressedKeys; @@ -124,7 +130,7 @@ class CKeybindManager { CTimer m_tScrollTimer; - bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); + SDispatchResult handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); std::set m_sMkKeys = {}; std::set m_sMkMods = {}; @@ -143,71 +149,72 @@ class CKeybindManager { static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); + static uint64_t spawnRawProc(std::string); // -------------- Dispatchers -------------- // - static void killActive(std::string); - static void kill(std::string); - static void spawn(std::string); - static uint64_t spawnRaw(std::string); - static void toggleActiveFloating(std::string); - static void toggleActivePseudo(std::string); - static void setActiveFloating(std::string); - static void setActiveTiled(std::string); - static void changeworkspace(std::string); - static void fullscreenActive(std::string); - static void fullscreenStateActive(std::string args); - static void moveActiveToWorkspace(std::string); - static void moveActiveToWorkspaceSilent(std::string); - static void moveFocusTo(std::string); - static void focusUrgentOrLast(std::string); - static void focusCurrentOrLast(std::string); - static void centerWindow(std::string); - static void moveActiveTo(std::string); - static void swapActive(std::string); - static void toggleGroup(std::string); - static void changeGroupActive(std::string); - static void alterSplitRatio(std::string); - static void focusMonitor(std::string); - static void toggleSplit(std::string); - static void swapSplit(std::string); - static void moveCursorToCorner(std::string); - static void moveCursor(std::string); - static void workspaceOpt(std::string); - static void renameWorkspace(std::string); - static void exitHyprland(std::string); - static void moveCurrentWorkspaceToMonitor(std::string); - static void moveWorkspaceToMonitor(std::string); - static void focusWorkspaceOnCurrentMonitor(std::string); - static void toggleSpecialWorkspace(std::string); - static void forceRendererReload(std::string); - static void resizeActive(std::string); - static void moveActive(std::string); - static void moveWindow(std::string); - static void resizeWindow(std::string); - static void circleNext(std::string); - static void focusWindow(std::string); - static void tagWindow(std::string); - static void setSubmap(std::string); - static void pass(std::string); - static void sendshortcut(std::string); - static void layoutmsg(std::string); - static void dpms(std::string); - static void swapnext(std::string); - static void swapActiveWorkspaces(std::string); - static void pinActive(std::string); - static void mouse(std::string); - static void bringActiveToTop(std::string); - static void alterZOrder(std::string); - static void lockGroups(std::string); - static void lockActiveGroup(std::string); - static void moveIntoGroup(std::string); - static void moveOutOfGroup(std::string); - static void moveGroupWindow(std::string); - static void moveWindowOrGroup(std::string); - static void setIgnoreGroupLock(std::string); - static void denyWindowFromGroup(std::string); - static void global(std::string); - static void event(std::string); + static SDispatchResult killActive(std::string); + static SDispatchResult kill(std::string); + static SDispatchResult spawn(std::string); + static SDispatchResult spawnRaw(std::string); + static SDispatchResult toggleActiveFloating(std::string); + static SDispatchResult toggleActivePseudo(std::string); + static SDispatchResult setActiveFloating(std::string); + static SDispatchResult setActiveTiled(std::string); + static SDispatchResult changeworkspace(std::string); + static SDispatchResult fullscreenActive(std::string); + static SDispatchResult fullscreenStateActive(std::string args); + static SDispatchResult moveActiveToWorkspace(std::string); + static SDispatchResult moveActiveToWorkspaceSilent(std::string); + static SDispatchResult moveFocusTo(std::string); + static SDispatchResult focusUrgentOrLast(std::string); + static SDispatchResult focusCurrentOrLast(std::string); + static SDispatchResult centerWindow(std::string); + static SDispatchResult moveActiveTo(std::string); + static SDispatchResult swapActive(std::string); + static SDispatchResult toggleGroup(std::string); + static SDispatchResult changeGroupActive(std::string); + static SDispatchResult alterSplitRatio(std::string); + static SDispatchResult focusMonitor(std::string); + static SDispatchResult toggleSplit(std::string); + static SDispatchResult swapSplit(std::string); + static SDispatchResult moveCursorToCorner(std::string); + static SDispatchResult moveCursor(std::string); + static SDispatchResult workspaceOpt(std::string); + static SDispatchResult renameWorkspace(std::string); + static SDispatchResult exitHyprland(std::string); + static SDispatchResult moveCurrentWorkspaceToMonitor(std::string); + static SDispatchResult moveWorkspaceToMonitor(std::string); + static SDispatchResult focusWorkspaceOnCurrentMonitor(std::string); + static SDispatchResult toggleSpecialWorkspace(std::string); + static SDispatchResult forceRendererReload(std::string); + static SDispatchResult resizeActive(std::string); + static SDispatchResult moveActive(std::string); + static SDispatchResult moveWindow(std::string); + static SDispatchResult resizeWindow(std::string); + static SDispatchResult circleNext(std::string); + static SDispatchResult focusWindow(std::string); + static SDispatchResult tagWindow(std::string); + static SDispatchResult setSubmap(std::string); + static SDispatchResult pass(std::string); + static SDispatchResult sendshortcut(std::string); + static SDispatchResult layoutmsg(std::string); + static SDispatchResult dpms(std::string); + static SDispatchResult swapnext(std::string); + static SDispatchResult swapActiveWorkspaces(std::string); + static SDispatchResult pinActive(std::string); + static SDispatchResult mouse(std::string); + static SDispatchResult bringActiveToTop(std::string); + static SDispatchResult alterZOrder(std::string); + static SDispatchResult lockGroups(std::string); + static SDispatchResult lockActiveGroup(std::string); + static SDispatchResult moveIntoGroup(std::string); + static SDispatchResult moveOutOfGroup(std::string); + static SDispatchResult moveGroupWindow(std::string); + static SDispatchResult moveWindowOrGroup(std::string); + static SDispatchResult setIgnoreGroupLock(std::string); + static SDispatchResult denyWindowFromGroup(std::string); + static SDispatchResult global(std::string); + static SDispatchResult event(std::string); friend class CCompositor; friend class CInputManager; diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 098e3f12..398d4ce1 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -194,7 +194,10 @@ APICALL bool HyprlandAPI::addDispatcher(HANDLE handle, const std::string& name, PLUGIN->registeredDispatchers.push_back(name); - g_pKeybindManager->m_mDispatchers[name] = handler; + g_pKeybindManager->m_mDispatchers[name] = [handler](std::string arg1) -> SDispatchResult { + handler(arg1); + return {}; + }; return true; } @@ -378,4 +381,4 @@ APICALL bool HyprlandAPI::unregisterHyprCtlCommand(HANDLE handle, SPunregisterCommand(cmd); return true; -} \ No newline at end of file +} From aac90d92797825a65b9faab038586a3b88448667 Mon Sep 17 00:00:00 2001 From: "Nelo-T. Wallus" Date: Sun, 25 Aug 2024 13:13:48 +0200 Subject: [PATCH 0529/2393] hyprpm: Fix checking dependencies (#7504) * hyprpm: Fix checking dependencies * hyprpm: Check for dependency "pkg-config" --------- Co-authored-by: Nelo-T. Wallus --- hyprpm/src/core/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 6988547c..ab457ca6 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -904,9 +904,9 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { } bool CPluginManager::hasDeps() { - std::vector deps = {"meson", "cpio", "cmake"}; + std::vector deps = {"meson", "cpio", "cmake", "pkg-config"}; for (auto& d : deps) { - if (!execAndGet("which " + d + " 2>&1").contains("/")) + if (!execAndGet("command -v " + d).contains("/")) return false; } From b672118f9238a48a18efd741cbcda387c5552238 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sun, 25 Aug 2024 09:37:03 -0500 Subject: [PATCH 0530/2393] xwayland: deactivate xwayland focus if wayland is focused (#7458) * xwayland: deactivate xwayland focus if wayland is focused * xwayland: deactivate last xwayland surface after focusing wayland --- src/managers/XWaylandManager.cpp | 5 ++++- src/xwayland/XWM.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index f329dbe1..2f0632e0 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -43,8 +43,11 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool w->m_pXWaylandSurface->restackToTop(); } w->m_pXWaylandSurface->activate(activate); - } else + } else { w->m_pXDGSurface->toplevel->setActive(activate); + if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow->m_bIsX11) + activateSurface(g_pCompositor->m_pLastFocus.lock(), false); + } } } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index f6b6864c..a409b440 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -897,7 +897,7 @@ void CXWM::activateSurface(SP surf, bool activate) { if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - if (!surf) { + if (!surf || (!activate && g_pCompositor->m_pLastWindow && !g_pCompositor->m_pLastWindow->m_bIsX11)) { setActiveWindow((uint32_t)XCB_WINDOW_NONE); focusWindow(nullptr); } else { From 83ab3ae0afeafe25ca2038888478740d0a80396a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 26 Aug 2024 10:24:45 +0200 Subject: [PATCH 0531/2393] xwaylandmgr: minor refactor to activateSurface Make it more efficient now that we can + fix possible nullptr deref fixes #7514 --- src/managers/XWaylandManager.cpp | 36 +++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 2f0632e0..a6fd97f5 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -28,26 +28,28 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool if (!pSurface) return; - // TODO: - // this cannot be nicely done until we rewrite wlr_surface - for (auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped) - continue; + auto HLSurface = CWLSurface::fromResource(pSurface); + if (!HLSurface) { + Debug::log(TRACE, "CHyprXWaylandManager::activateSurface on non-desktop surface, ignoring"); + return; + } - if (w->m_pWLSurface->resource() != pSurface) - continue; + const auto PWINDOW = HLSurface->getWindow(); + if (!PWINDOW) { + Debug::log(TRACE, "CHyprXWaylandManager::activateSurface on non-window surface, ignoring"); + return; + } - if (w->m_bIsX11) { - if (activate) { - w->m_pXWaylandSurface->setMinimized(false); - w->m_pXWaylandSurface->restackToTop(); - } - w->m_pXWaylandSurface->activate(activate); - } else { - w->m_pXDGSurface->toplevel->setActive(activate); - if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow->m_bIsX11) - activateSurface(g_pCompositor->m_pLastFocus.lock(), false); + if (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface) { + if (activate) { + PWINDOW->m_pXWaylandSurface->setMinimized(false); + PWINDOW->m_pXWaylandSurface->restackToTop(); } + PWINDOW->m_pXWaylandSurface->activate(activate); + } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) { + PWINDOW->m_pXDGSurface->toplevel->setActive(activate); + if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) + activateSurface(g_pCompositor->m_pLastFocus.lock(), false); } } From 28f6c2df5923bfe514d238399f934fc80bb1449d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:27:34 +0000 Subject: [PATCH 0532/2393] sessionLock: fix misc:allow_session_lock_restore (#7511) * Revert "sessionLock: fix the check for locking a locked session (#6843)" This reverts commit 9ff83f4aa97269bf26381a84501d0b19f1926961. * sessionLock: remove early check for session beeing locked It is checked in the `onNewSessionLock` handler, which also respects the `misc:allow_session_lock_restore` option. --- src/protocols/SessionLock.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 7b0d8b3b..fe44face 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -175,13 +175,6 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { return; } - if (locked) { - LOGM(ERR, "Tried to lock a locked session"); - RESOURCE->inert = true; - RESOURCE->resource->sendFinished(); - return; - } - events.newLock.emit(RESOURCE); locked = true; From ca85455a8ed5dbe920a47c1a48de1dd993446481 Mon Sep 17 00:00:00 2001 From: Adithya Ajith <50308085+adharmic@users.noreply.github.com> Date: Mon, 26 Aug 2024 05:25:52 -0500 Subject: [PATCH 0533/2393] misc: Rename all instances of "emtpy" to "empty" (#7522) --- src/Compositor.cpp | 4 ++-- src/Compositor.hpp | 2 +- src/desktop/Workspace.cpp | 10 +++++----- src/desktop/Workspace.hpp | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c9a698ce..a419e741 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2624,7 +2624,7 @@ void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { } } -PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmtpy) { +PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2635,7 +2635,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; - const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmtpy)); + const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmpty)); PWORKSPACE->m_fAlpha.setValueAndWarp(0); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a570a06e..bb986f5e 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -165,7 +165,7 @@ class CCompositor { Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&); PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", - bool isEmtpy = true); // will be deleted next frame if left empty and unfocused! + bool isEmpty = true); // will be deleted next frame if left empty and unfocused! void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void setActiveMonitor(CMonitor*); bool isWorkspaceSpecial(const WORKSPACEID&); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index a9412e6d..72d9705e 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -5,18 +5,18 @@ #include using namespace Hyprutils::String; -PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { - PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); +PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { + PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmpty); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmtpy) { +CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { m_iMonitorID = monitorID; m_iID = id; m_szName = name; m_bIsSpecialWorkspace = special; - m_bWasCreatedEmtpy = isEmtpy; + m_bWasCreatedEmpty = isEmpty; } void CWorkspace::init(PHLWORKSPACE self) { @@ -49,7 +49,7 @@ void CWorkspace::init(PHLWORKSPACE self) { const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self); m_bPersistent = WORKSPACERULE.isPersistent; - if (self->m_bWasCreatedEmtpy) + if (self->m_bWasCreatedEmpty) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) g_pKeybindManager->spawn(*cmd); diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 9cacb0cc..7a32459c 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -17,7 +17,7 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmtpy = true); + static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); // use create() don't use this CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); @@ -57,7 +57,7 @@ class CWorkspace { // last monitor (used on reconnect) std::string m_szLastMonitor = ""; - bool m_bWasCreatedEmtpy = true; + bool m_bWasCreatedEmpty = true; bool m_bPersistent = false; From 9c5a37a797ea1f1829859ab5b07016b2f27f739c Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 14:08:30 +0200 Subject: [PATCH 0534/2393] build: fix 32bit builds (#7510) ensure the correct type is passed to std::clamp and std::max int64_t is different on 64bit compared to 32bit, also in presentationtime tv_sec is __time_t and on 32bit its a 32bit type so right shift count >= width of type. so only bit shift on 64bit. and avoid potential nullptr deref in the for loops, check for .end() before *it <= endID. --- src/helpers/MiscFunctions.cpp | 10 +++++----- src/protocols/PresentationTime.cpp | 6 +++++- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 86f24e3a..ef319946 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -353,13 +353,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { char walkDir = in[1]; // sanitize. 0 means invalid oob in - - predictedWSID = std::max(predictedWSID, 0L); + predictedWSID = std::max(predictedWSID, static_cast(0)); // Count how many invalidWSes are in between (how bad the prediction was) WORKSPACEID beginID = in[1] == '+' ? activeWSID + 1 : predictedWSID; WORKSPACEID endID = in[1] == '+' ? predictedWSID : activeWSID; auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= - for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { + for (auto it = begin; it != invalidWSes.end() && *it <= endID; it++) { remainingWSes++; } @@ -376,7 +376,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { } currentItem += remains; - currentItem = std::max(currentItem, 0UL); + currentItem = std::max(currentItem, static_cast(0)); if (currentItem >= namedWSes.size()) { // At the seam between namedWSes and normal WSes. Behave like r+[diff] at imaginary ws 0 size_t diff = currentItem - (namedWSes.size() - 1); @@ -384,7 +384,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { WORKSPACEID beginID = 1; WORKSPACEID endID = predictedWSID; auto begin = invalidWSes.upper_bound(beginID - 1); // upper_bound is >, we want >= - for (auto it = begin; *it <= endID && it != invalidWSes.end(); it++) { + for (auto it = begin; it != invalidWSes.end() && *it <= endID; it++) { remainingWSes++; } walkDir = '+'; @@ -413,7 +413,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Need remainingWSes more auto namedWSIdx = namedWSes.size() - remainingWSes; // Sanitze - namedWSIdx = std::clamp(namedWSIdx, 0UL, namedWSes.size() - 1); + namedWSIdx = std::clamp(namedWSIdx, static_cast(0), namedWSes.size() - static_cast(1)); finalWSID = namedWSes[namedWSIdx]; } else { // Couldn't find valid workspace in negative direction, search last first one back up positive direction diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 335cf557..638435c7 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -58,8 +58,12 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; + __time_t tv_sec = 0; + if (sizeof(__time_t) > 4) + tv_sec = when->tv_sec >> 32; + if (data->wasPresented) - resource->sendPresented((uint32_t)(when->tv_sec >> 32), (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), + resource->sendPresented((uint32_t)tv_sec, (uint32_t)(when->tv_sec & 0xFFFFFFFF), (uint32_t)(when->tv_nsec), untilRefreshNs, (uint32_t)(seq >> 32), (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else resource->sendDiscarded(); From 8d6c18076f3268a6c85c6085d29f898267028101 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 17:25:39 +0200 Subject: [PATCH 0535/2393] core: make most for loops use const references (#7527) why not let the compiler optimise things for us at hyprspeeds when we can. --- src/Compositor.cpp | 32 ++++++------- src/config/ConfigManager.cpp | 36 +++++++------- src/debug/HyprCtl.cpp | 26 +++++------ src/debug/HyprDebugOverlay.cpp | 8 ++-- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Window.cpp | 16 +++---- src/helpers/Monitor.cpp | 4 +- src/layout/DwindleLayout.cpp | 2 +- src/layout/IHyprLayout.cpp | 2 +- src/layout/MasterLayout.cpp | 8 ++-- src/managers/AnimationManager.cpp | 2 +- src/managers/KeybindManager.cpp | 8 ++-- src/managers/PointerManager.cpp | 14 +++--- src/managers/SeatManager.cpp | 70 ++++++++++++++-------------- src/managers/SessionLockManager.cpp | 4 +- src/managers/XWaylandManager.cpp | 4 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 6 +-- src/managers/input/Swipe.cpp | 6 +-- src/managers/input/Tablets.cpp | 4 +- src/plugins/HookSystem.cpp | 2 +- src/protocols/DRMLease.cpp | 4 +- src/protocols/DataDeviceWlr.cpp | 6 +-- src/protocols/core/Compositor.cpp | 8 ++-- src/protocols/core/DataDevice.cpp | 8 ++-- src/protocols/core/Output.cpp | 2 +- src/protocols/core/Seat.cpp | 2 +- src/render/OpenGL.cpp | 8 ++-- src/render/Renderer.cpp | 24 +++++----- src/xwayland/XSurface.cpp | 4 +- src/xwayland/XWM.cpp | 14 +++--- 31 files changed, 169 insertions(+), 169 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a419e741..0aa7f213 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -314,7 +314,7 @@ void CCompositor::initServer(std::string socketName, int socketFd) { initManagers(STAGE_LATE); - for (auto& o : pendingOutputs) { + for (auto const& o : pendingOutputs) { onNewMonitor(o); } pendingOutputs.clear(); @@ -403,7 +403,7 @@ void CCompositor::initAllSignals() { m_bSessionActive = false; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { m->noFrameSchedule = true; m->framesToSkip = 1; } @@ -741,7 +741,7 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { float bestDistance = 0.f; SP pBestMon; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); if (dist < bestDistance || !pBestMon) { @@ -1164,8 +1164,8 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo } SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { - for (auto& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { - for (auto& ls : lsl | std::views::reverse) { + for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { + for (auto const& ls : lsl | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1183,7 +1183,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po } SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { - for (auto& ls : *layerSurfaces | std::views::reverse) { + for (auto const& ls : *layerSurfaces | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; @@ -1458,7 +1458,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { g_pHyprOpenGL->markBlurDirtyForMonitor(getMonitorFromID(monid)); if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); @@ -1718,7 +1718,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { WORKSPACEID lowest = -1337 + 1; - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iID < -1 && w->m_iID < lowest) lowest = w->m_iID; } @@ -1748,7 +1748,7 @@ PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) { } bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (VECINRECT(point, m->vecPosition.x, m->vecPosition.y, m->vecSize.x + m->vecPosition.x, m->vecSize.y + m->vecPosition.y)) return true; } @@ -1834,7 +1834,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha } void CCompositor::updateAllWindowsAnimatedDecorationValues() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped) continue; @@ -2139,7 +2139,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon if (!SWITCHINGISACTIVE) nextWorkspaceOnMonitorID = pWorkspace->m_iID; else { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iMonitorID == POLDMON->ID && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) { nextWorkspaceOnMonitorID = w->m_iID; break; @@ -2237,7 +2237,7 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { WORKSPACEID lowestID = INT64_MAX; WORKSPACEID highestID = INT64_MIN; - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) continue; @@ -2271,7 +2271,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID); if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { - for (auto& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (!ls->fadingOut) ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } @@ -2376,7 +2376,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { if (!pWindow->m_bIsX11) return nullptr; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsX11) continue; @@ -2543,7 +2543,7 @@ void CCompositor::closeWindow(PHLWINDOW pWindow) { PHLLS CCompositor::getLayerSurfaceFromSurface(SP pSurface) { std::pair, bool> result = {pSurface, false}; - for (auto& ls : m_vLayers) { + for (auto const& ls : m_vLayers) { if (ls->layerSurface && ls->layerSurface->surface == pSurface) return ls; @@ -2679,7 +2679,7 @@ bool CCompositor::isWorkspaceSpecial(const WORKSPACEID& id) { WORKSPACEID CCompositor::getNewSpecialID() { WORKSPACEID highest = SPECIAL_WORKSPACE_START; - for (auto& ws : m_vWorkspaces) { + for (auto const& ws : m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace && ws->m_iID > highest) { highest = ws->m_iID; } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 0390b9d9..007869ee 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -813,11 +813,11 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static int prevEnabledExplicit = *PENABLEEXPLICIT; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); } - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); // Update the keyboard layout to the cfg'd one if this is not the first launch @@ -901,7 +901,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { m->forceFullFrames = 2; // also force mirrors, as the aspect ratio could've changed - for (auto& mirror : m->mirrors) + for (auto const& mirror : m->mirrors) mirror->forceFullFrames = 3; } @@ -940,7 +940,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: // invalidate layouts if they changed if (COMMAND == "monitor" || COMMAND.contains("gaps_") || COMMAND.starts_with("dwindle:") || COMMAND.starts_with("master:")) { - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } @@ -1034,7 +1034,7 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s } SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { - for (auto& r : m_dMonitorRules | std::views::reverse) { + for (auto const& r : m_dMonitorRules | std::views::reverse) { if (PMONITOR.matchesStaticSelector(r.name)) { return r; } @@ -1042,7 +1042,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); - for (auto& r : m_dMonitorRules) { + for (auto const& r : m_dMonitorRules) { if (r.name.empty()) { return r; } @@ -1354,7 +1354,7 @@ void CConfigManager::dispatchExecOnce() { firstExecDispatched = true; isLaunchingExecOnce = true; - for (auto& c : firstExecRequests) { + for (auto const& c : firstExecRequests) { handleRawExec("", c); } @@ -1438,7 +1438,7 @@ bool CConfigManager::deviceConfigExists(const std::string& dev) { } bool CConfigManager::shouldBlurLS(const std::string& ns) { - for (auto& bls : m_dBlurLSNamespaces) { + for (auto const& bls : m_dBlurLSNamespaces) { if (bls == ns) { return true; } @@ -1553,7 +1553,7 @@ CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) { } std::string CConfigManager::getBoundMonitorStringForWS(const std::string& wsname) { - for (auto& wr : m_dWorkspaceRules) { + for (auto const& wr : m_dWorkspaceRules) { const auto WSNAME = wr.workspaceName.starts_with("name:") ? wr.workspaceName.substr(5) : wr.workspaceName; if (WSNAME == wsname) @@ -1624,7 +1624,7 @@ void CConfigManager::addPluginKeyword(HANDLE handle, const std::string& name, Hy } void CConfigManager::removePluginConfig(HANDLE handle) { - for (auto& k : pluginKeywords) { + for (auto const& k : pluginKeywords) { if (k.handle != handle) continue; @@ -1647,7 +1647,7 @@ std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) { if (other->monitor == name) return other->workspaceString; if (other->monitor.substr(0, 5) == "desc:") { - auto monitor = g_pCompositor->getMonitorFromDesc(other->monitor.substr(5)); + auto const monitor = g_pCompositor->getMonitorFromDesc(other->monitor.substr(5)); if (monitor && monitor->szName == name) return other->workspaceString; } @@ -2044,7 +2044,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool dontInhibit = false; const auto BINDARGS = command.substr(4); - for (auto& arg : BINDARGS) { + for (auto const& arg : BINDARGS) { if (arg == 'l') { locked = true; } else if (arg == 'r') { @@ -2222,9 +2222,9 @@ std::optional CConfigManager::handleLayerRule(const std::string& co m_dLayerRules.push_back({VALUE, RULE}); - for (auto& m : g_pCompositor->m_vMonitors) - for (auto& lsl : m->m_aLayerSurfaceLayers) - for (auto& ls : lsl) + for (auto const& m : g_pCompositor->m_vMonitors) + for (auto const& lsl : m->m_aLayerSurfaceLayers) + for (auto const& ls : lsl) ls->applyRules(); return {}; @@ -2423,9 +2423,9 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl matchName = matchName.substr(8); } - for (auto& m : g_pCompositor->m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& m : g_pCompositor->m_vMonitors) { + for (auto const& lsl : m->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (BYADDRESS) { if (std::format("0x{:x}", (uintptr_t)ls.get()) == matchName) ls->forceBlur = forceBlur; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a92c3a53..2fc5cc7d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -146,7 +146,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { + for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { result += CHyprCtl::getMonitorData(m, format); } @@ -154,7 +154,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { - for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { + for (auto const& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) { if (!m->output || m->ID == -1) continue; @@ -272,7 +272,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; @@ -283,7 +283,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { result += "]"; } else { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped && !g_pHyprCtl->m_sCurrentRequestParams.all) continue; @@ -381,7 +381,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { result += CHyprCtl::getWorkspaceData(w, format); result += ","; } @@ -389,7 +389,7 @@ std::string workspacesRequest(eHyprCtlOutputFormat format, std::string request) trimTrailingComma(result); result += "]"; } else { - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { result += CHyprCtl::getWorkspaceData(w, format); } } @@ -401,7 +401,7 @@ std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string reque std::string result = ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& r : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& r : g_pConfigManager->getAllWorkspaceRules()) { result += getWorkspaceRuleData(r, format); result += ","; } @@ -409,7 +409,7 @@ std::string workspaceRulesRequest(eHyprCtlOutputFormat format, std::string reque trimTrailingComma(result); result += "]"; } else { - for (auto& r : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& r : g_pConfigManager->getAllWorkspaceRules()) { result += getWorkspaceRuleData(r, format); } } @@ -437,7 +437,7 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "{\n"; - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { result += std::format( R"#("{}": {{ "levels": {{ @@ -744,7 +744,7 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) ret += ",\n["; - for (auto& bz : g_pAnimationManager->getAllBeziers()) { + for (auto const& bz : g_pAnimationManager->getAllBeziers()) { ret += std::format(R"#( {{ "name": "{}" @@ -782,7 +782,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); } else { ret += "["; - for (auto& sh : SHORTCUTS) { + for (auto const& sh : SHORTCUTS) { ret += std::format(R"#( {{ "name": "{}", @@ -1286,7 +1286,7 @@ std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { g_pCompositor->focusWindow(PLASTWINDOW); } - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); return "ok"; @@ -1386,7 +1386,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { bool added = false; if (!vars[3].empty()) { - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (m->szName == vars[3]) return "Name already taken"; } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index fbd8cd71..22c741a6 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -57,7 +57,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgFrametime = 0; float maxFrametime = 0; float minFrametime = 9999; - for (auto& ft : m_dLastFrametimes) { + for (auto const& ft : m_dLastFrametimes) { if (ft > maxFrametime) maxFrametime = ft; if (ft < minFrametime) @@ -70,7 +70,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgRenderTime = 0; float maxRenderTime = 0; float minRenderTime = 9999; - for (auto& rt : m_dLastRenderTimes) { + for (auto const& rt : m_dLastRenderTimes) { if (rt > maxRenderTime) maxRenderTime = rt; if (rt < minRenderTime) @@ -83,7 +83,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0; float minRenderTimeNoOverlay = 9999; - for (auto& rt : m_dLastRenderTimesNoOverlay) { + for (auto const& rt : m_dLastRenderTimesNoOverlay) { if (rt > maxRenderTimeNoOverlay) maxRenderTimeNoOverlay = rt; if (rt < minRenderTimeNoOverlay) @@ -96,7 +96,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { float avgAnimMgrTick = 0; float maxAnimMgrTick = 0; float minAnimMgrTick = 9999; - for (auto& at : m_dLastAnimationTicks) { + for (auto const& at : m_dLastAnimationTicks) { if (at > maxAnimMgrTick) maxAnimMgrTick = at; if (at < minAnimMgrTick) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 8d13bf19..331dba9c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -72,7 +72,7 @@ CLayerSurface::~CLayerSurface() { g_pHyprRenderer->makeEGLCurrent(); std::erase_if(g_pHyprOpenGL->m_mLayerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == self.lock(); }); - for (auto& mon : g_pCompositor->m_vRealMonitors) { + for (auto const& mon : g_pCompositor->m_vRealMonitors) { for (auto& lsl : mon->m_aLayerSurfaceLayers) { std::erase_if(lsl, [this](auto& ls) { return ls.expired() || ls.get() == this; }); } diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index dcdcb573..64337097 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -252,7 +252,7 @@ void CWindow::updateWindowDecos() { if (!m_bIsMapped || isHidden()) return; - for (auto& wd : m_vDecosToRemove) { + for (auto const& wd : m_vDecosToRemove) { for (auto it = m_dWindowDecorations.begin(); it != m_dWindowDecorations.end(); it++) { if (it->get() == wd) { g_pDecorationPositioner->uncacheDecoration(it->get()); @@ -270,11 +270,11 @@ void CWindow::updateWindowDecos() { // make a copy because updateWindow can remove decos. std::vector decos; - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { decos.push_back(wd.get()); } - for (auto& wd : decos) { + for (auto const& wd : decos) { if (std::find_if(m_dWindowDecorations.begin(), m_dWindowDecorations.end(), [wd](const auto& other) { return other.get() == wd; }) == m_dWindowDecorations.end()) continue; wd->updateWindow(m_pSelf.lock()); @@ -454,7 +454,7 @@ PHLWINDOW CWindow::X11TransientFor() { s = s->parent; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pXWaylandSurface != s) continue; return w; @@ -464,7 +464,7 @@ PHLWINDOW CWindow::X11TransientFor() { } void CWindow::removeDecorationByType(eDecorationType type) { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (wd->getDecorationType() == type) m_vDecosToRemove.push_back(wd.get()); } @@ -617,7 +617,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { int opacityIDX = 0; - for (auto& r : vars) { + for (auto const& r : vars) { if (r == "opacity") continue; @@ -770,7 +770,7 @@ void CWindow::updateDynamicRules() { m_tags.removeDynamicTags(); m_vMatchedRules = g_pConfigManager->getMatchingRules(m_pSelf.lock()); - for (auto& r : m_vMatchedRules) { + for (auto const& r : m_vMatchedRules) { applyDynamicRule(r); } @@ -881,7 +881,7 @@ void CWindow::destroyGroup() { addresses += std::format("{:x},", (uintptr_t)curr.get()); } while (curr.get() != this); - for (auto& w : members) { + for (auto const& w : members) { if (w->m_sGroupData.head) g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr); w->m_sGroupData.head = false; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 2c6282e1..8b533d8a 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -207,7 +207,7 @@ void CMonitor::onConnect(bool noRule) { // verify last mon valid bool found = false; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m == g_pCompositor->m_pLastMonitor) { found = true; break; @@ -272,7 +272,7 @@ void CMonitor::onDisconnect(bool destroy) { listeners.commit.reset(); for (size_t i = 0; i < 4; ++i) { - for (auto& ls : m_aLayerSurfaceLayers[i]) { + for (auto const& ls : m_aLayerSurfaceLayers[i]) { if (ls->layerSurface && !ls->fadingOut) ls->layerSurface->sendClosed(); } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 20085ff7..db69cc04 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -49,7 +49,7 @@ void SDwindleNodeData::getAllChildrenRecursive(std::deque* pD int CHyprDwindleLayout::getNodesOnWorkspace(const WORKSPACEID& id) { int no = 0; - for (auto& n : m_lDwindleNodesData) { + for (auto const& n : m_lDwindleNodesData) { if (n.workspaceID == id && n.valid) ++no; } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 233933d4..9b3d02b4 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -691,7 +691,7 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) { bool shouldBeFloated = g_pXWaylandManager->shouldBeFloated(pWindow, true); if (!shouldBeFloated) { - for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { + for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { if (r.szRule.starts_with("float")) { shouldBeFloated = true; break; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index e0b48e98..d234d300 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -16,7 +16,7 @@ SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) { int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int no = 0; - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == ws) no++; } @@ -26,7 +26,7 @@ int CHyprMasterLayout::getNodesOnWorkspace(const WORKSPACEID& ws) { int CHyprMasterLayout::getMastersOnWorkspace(const WORKSPACEID& ws) { int no = 0; - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == ws && n.isMaster) no++; } @@ -381,7 +381,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (*PSMARTRESIZING) { // check the total width and height so that later // if larger/smaller than screen size them down/up - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID == pWorkspace->m_iID) { if (nd.isMaster) masterAccumulatedSize += totalSize / MASTERS * nd.percSize; @@ -552,7 +552,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { float slaveAccumulatedHeightL = 0; float slaveAccumulatedHeightR = 0; if (*PSMARTRESIZING) { - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster) continue; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index beb880be..e2e98735 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -131,7 +131,7 @@ void CAnimationManager::tick() { } // damage any workspace window that is on any monitor - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) continue; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8bf7152e..7eb96730 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -765,7 +765,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - for (auto& pk : m_dPressedKeys) { + for (auto const& pk : m_dPressedKeys) { if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { shadow = true; @@ -864,7 +864,7 @@ SDispatchResult CKeybindManager::spawn(std::string args) { if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); - for (auto& r : RULESLIST) { + for (auto const& r : RULESLIST) { g_pConfigManager->addExecRule({r, (unsigned long)PROC}); } @@ -1708,7 +1708,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { PWORKSPACE->m_bDefaultPseudo = !PWORKSPACE->m_bDefaultPseudo; // apply - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE) continue; @@ -2129,7 +2129,7 @@ SDispatchResult CKeybindManager::setSubmap(std::string submap) { return {}; } - for (auto& k : g_pKeybindManager->m_lKeybinds) { + for (auto const& k : g_pKeybindManager->m_lKeybinds) { if (k.submap == submap) { m_szCurrentSelectedSubmap = submap; Debug::log(LOG, "Changed keybind submap to {}", submap); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 72ff5ae7..80f1ab4f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -90,7 +90,7 @@ void CPointerManager::unlockSoftwareAll() { } void CPointerManager::lockSoftwareForMonitor(CMonitor* Monitor) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->ID == Monitor->ID) { lockSoftwareForMonitor(m); return; @@ -107,7 +107,7 @@ void CPointerManager::lockSoftwareForMonitor(SP mon) { } void CPointerManager::unlockSoftwareForMonitor(CMonitor* Monitor) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->ID == Monitor->ID) { unlockSoftwareForMonitor(m); return; @@ -225,7 +225,7 @@ void CPointerManager::recheckEnteredOutputs() { auto box = getCursorBoxGlobal(); - for (auto& s : monitorStates) { + for (auto const& s : monitorStates) { if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) continue; @@ -279,7 +279,7 @@ void CPointerManager::resetCursorImage(bool apply) { currentCursorImage.scale = 1.F; currentCursorImage.hotspot = {0, 0}; - for (auto& s : monitorStates) { + for (auto const& s : monitorStates) { if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled) continue; @@ -289,7 +289,7 @@ void CPointerManager::resetCursorImage(bool apply) { if (!apply) return; - for (auto& ms : monitorStates) { + for (auto const& ms : monitorStates) { if (!ms->monitor || !ms->monitor->m_bEnabled || !ms->monitor->dpmsStatus) { Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); continue; @@ -334,7 +334,7 @@ void CPointerManager::onCursorMoved() { if (!hasCursor()) return; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); @@ -1006,7 +1006,7 @@ void CPointerManager::detachTablet(SP tablet) { } void CPointerManager::damageCursor(SP pMonitor) { - for (auto& mw : monitorStates) { + for (auto const& mw : monitorStates) { if (mw->monitor != pMonitor) continue; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 801ae55a..e296dcc8 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -24,7 +24,7 @@ void CSeatManager::onNewSeatResource(SP resource) { } SP CSeatManager::containerForResource(SP seatResource) { - for (auto& c : seatResources) { + for (auto const& c : seatResources) { if (c->resource == seatResource) return c; } @@ -112,11 +112,11 @@ void CSeatManager::setKeyboardFocus(SP surf) { if (state.keyboardFocusResource) { auto client = state.keyboardFocusResource->client(); - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != client) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -134,12 +134,12 @@ void CSeatManager::setKeyboardFocus(SP surf) { } auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.keyboardFocusResource = r->resource; - for (auto& k : r->resource->keyboards) { + for (auto const& k : r->resource->keyboards) { if (!k) continue; @@ -157,11 +157,11 @@ void CSeatManager::sendKeyboardKey(uint32_t timeMs, uint32_t key, wl_keyboard_ke if (!state.keyboardFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.keyboardFocusResource->client()) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -174,11 +174,11 @@ void CSeatManager::sendKeyboardMods(uint32_t depressed, uint32_t latched, uint32 if (!state.keyboardFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.keyboardFocusResource->client()) continue; - for (auto& k : s->resource->keyboards) { + for (auto const& k : s->resource->keyboards) { if (!k) continue; @@ -205,11 +205,11 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocusResource) { auto client = state.pointerFocusResource->client(); - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != client) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -230,12 +230,12 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& } auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.pointerFocusResource = r->resource; - for (auto& p : r->resource->pointers) { + for (auto const& p : r->resource->pointers) { if (!p) continue; @@ -257,11 +257,11 @@ void CSeatManager::sendPointerMotion(uint32_t timeMs, const Vector2D& local) { if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -276,11 +276,11 @@ void CSeatManager::sendPointerButton(uint32_t timeMs, uint32_t key, wl_pointer_b if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -300,11 +300,11 @@ void CSeatManager::sendPointerFrame(WP pResource) { if (!pResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != pResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -318,11 +318,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double if (!state.pointerFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.pointerFocusResource->client()) continue; - for (auto& p : s->resource->pointers) { + for (auto const& p : s->resource->pointers) { if (!p) continue; @@ -346,12 +346,12 @@ void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, i state.touchFocus = surf; auto client = surf->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.touchFocusResource = r->resource; - for (auto& t : r->resource->touches) { + for (auto const& t : r->resource->touches) { if (!t) continue; @@ -372,12 +372,12 @@ void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) { return; auto client = state.touchFocusResource->client(); - for (auto& r : seatResources | std::views::reverse) { + for (auto const& r : seatResources | std::views::reverse) { if (r->resource->client() != client) continue; state.touchFocusResource = r->resource; - for (auto& t : r->resource->touches) { + for (auto const& t : r->resource->touches) { if (!t) continue; @@ -395,11 +395,11 @@ void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -412,11 +412,11 @@ void CSeatManager::sendTouchFrame() { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -429,11 +429,11 @@ void CSeatManager::sendTouchCancel() { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -446,11 +446,11 @@ void CSeatManager::sendTouchShape(int32_t id, const Vector2D& shape) { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; @@ -463,11 +463,11 @@ void CSeatManager::sendTouchOrientation(int32_t id, double angle) { if (!state.touchFocusResource) return; - for (auto& s : seatResources) { + for (auto const& s : seatResources) { if (s->resource->client() != state.touchFocusResource->client()) continue; - for (auto& t : s->resource->touches) { + for (auto const& t : s->resource->touches) { if (!t) continue; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index a82432a8..86108cac 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -137,7 +137,7 @@ bool CSessionLockManager::isSurfaceSessionLock(SP pSurface) if (!m_pSessionLock) return false; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->surface->surface() == pSurface) return true; } @@ -154,7 +154,7 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { if (g_pCompositor->m_pLastFocus) return; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (!sls->mapped) continue; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index a6fd97f5..4654eeb7 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -147,7 +147,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { - for (auto& a : pWindow->m_pXWaylandSurface->atoms) + for (auto const& a : pWindow->m_pXWaylandSurface->atoms) if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || @@ -193,7 +193,7 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { if (!pWindow->m_bIsX11) return; - for (auto& a : pWindow->m_pXWaylandSurface->atoms) { + for (auto const& a : pWindow->m_pXWaylandSurface->atoms) { if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_NOTIFICATION"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_COMBO"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"]) { diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 2c335a7e..4bcb4df3 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -31,7 +31,7 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) { void CInputManager::recheckIdleInhibitorStatus() { - for (auto& ii : m_vIdleInhibitors) { + for (auto const& ii : m_vIdleInhibitors) { if (ii->nonDesktop) { PROTO::idle->setInhibit(true); return; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index e5f921a2..a4a63a84 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -919,7 +919,7 @@ void CInputManager::setupKeyboard(SP keeb) { } void CInputManager::setKeyboardLayout() { - for (auto& k : m_vKeyboards) + for (auto const& k : m_vKeyboards) applyConfigToKeyboard(k); g_pKeybindManager->updateXKBTranslationState(); @@ -1197,7 +1197,7 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { if (m_vKeyboards.size() > 0) { bool found = false; - for (auto& k : m_vKeyboards | std::views::reverse) { + for (auto const& k : m_vKeyboards | std::views::reverse) { if (!k) continue; @@ -1673,7 +1673,7 @@ void CInputManager::releaseAllMouseButtons() { if (PROTO::data->dndActive()) return; - for (auto& mb : buttonsCopy) { + for (auto const& mb : buttonsCopy) { g_pSeatManager->sendPointerButton(0, mb, WL_POINTER_BUTTON_STATE_RELEASED); } diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 6ee690cd..aa1d3274 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -14,7 +14,7 @@ void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { return; int onMonitor = 0; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) { onMonitor++; } @@ -38,7 +38,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.speedPoints = 0; if (PWORKSPACE->m_bHasFullscreenWindow) { - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { + for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = 1.f; } } @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { g_pInputManager->refocus(); // apply alpha - for (auto& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { + for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 5e50e851..23d328bc 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -14,7 +14,7 @@ static void unfocusTool(SP tool) { tool->setSurface(nullptr); if (tool->isDown) PROTO::tablet->up(tool); - for (auto& b : tool->buttonsDown) { + for (auto const& b : tool->buttonsDown) { PROTO::tablet->buttonTool(tool, b, false); } PROTO::tablet->proximityOut(tool); @@ -31,7 +31,7 @@ static void focusTool(SP tool, SP tablet, SPproximityIn(tool, tablet, surf); if (tool->isDown) PROTO::tablet->down(tool); - for (auto& b : tool->buttonsDown) { + for (auto const& b : tool->buttonsDown) { PROTO::tablet->buttonTool(tool, b, true); } } diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 9118456b..745b2593 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -81,7 +81,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr std::vector finalBytes; finalBytes.resize(probe.len); - for (auto& len : probe.insSizes) { + for (auto const& len : probe.insSizes) { // copy original bytes to our finalBytes for (size_t i = 0; i < len; ++i) { diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index bc0945f1..f906740c 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -50,12 +50,12 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPmonitor->isBeingLeased = true; } listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) { - for (auto& m : requested) { + for (auto const& m : requested) { if (m && m->monitor) m->monitor->isBeingLeased = false; } diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index ad6ee89a..dce64508 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -291,7 +291,7 @@ void CDataDeviceWLRProtocol::sendSelectionToDevice(SP dev, SP source, bool primary) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; if (o->primary != primary) @@ -302,7 +302,7 @@ void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) if (!source) { LOGM(LOG, "resetting {}selection", primary ? "primary " : " "); - for (auto& d : m_vDevices) { + for (auto const& d : m_vDevices) { sendSelectionToDevice(d, nullptr, primary); } @@ -311,7 +311,7 @@ void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) LOGM(LOG, "New {}selection for data source {:x}", primary ? "primary" : "", (uintptr_t)source.get()); - for (auto& d : m_vDevices) { + for (auto const& d : m_vDevices) { sendSelectionToDevice(d, source, primary); } } diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 8b6f46b1..75f1e646 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -260,7 +260,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std for (auto& n : nodes) { std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); // subsurfaces is sorted lowest -> highest - for (auto& c : n->subsurfaces) { + for (auto const& c : n->subsurfaces) { if (c->zIndex >= 0) break; if (c->surface.expired()) @@ -274,7 +274,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std nodes2.clear(); - for (auto& n : nodes) { + for (auto const& n : nodes) { Vector2D offset = {}; if (n->role->role() == SURFACE_ROLE_SUBSURFACE) { auto subsurface = ((CSubsurfaceRole*)n->role.get())->subsurface.lock(); @@ -284,8 +284,8 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std fn(n, offset, data); } - for (auto& n : nodes) { - for (auto& c : n->subsurfaces) { + for (auto const& n : nodes) { + for (auto const& c : n->subsurfaces) { if (c->zIndex < 0) continue; if (c->surface.expired()) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 4ed28f24..943c790f 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -306,7 +306,7 @@ CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SPself = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; @@ -390,7 +390,7 @@ void CWLDataDeviceProtocol::onDestroyDataSource(WP source } void CWLDataDeviceProtocol::setSelection(SP source) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; o->dead = true; @@ -439,7 +439,7 @@ void CWLDataDeviceProtocol::updateSelection() { } void CWLDataDeviceProtocol::onKeyboardFocus() { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { o->dead = true; } @@ -606,7 +606,7 @@ bool CWLDataDeviceProtocol::wasDragSuccessful() { if (!dnd.focusedDevice || !dnd.currentSource) return false; - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->dead || !o->source || !o->source->hasDnd()) continue; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 8d0b0121..bcf62fae 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -118,7 +118,7 @@ bool CWLOutputProtocol::isDefunct() { } void CWLOutputProtocol::sendDone() { - for (auto& r : m_vOutputs) { + for (auto const& r : m_vOutputs) { r->resource->sendDone(); } } diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index a111c12c..f7764389 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -172,7 +172,7 @@ void CWLPointerResource::sendLeave() { if (!PROTO::data->dndActive()) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - for (auto& b : pressedButtons) { + for (auto const& b : pressedButtons) { sendButton(now.tv_sec * 1000 + now.tv_nsec / 1000000, b, WL_POINTER_BUTTON_STATE_RELEASED); } } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 63cc2203..2aeda8be 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -690,7 +690,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { } if (*PBLURSPECIAL) { - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (!ws->m_bIsSpecialWorkspace || ws->m_iMonitorID != pMonitor->ID) continue; @@ -1936,9 +1936,9 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { } } - for (auto& m : g_pCompositor->m_vMonitors) { - for (auto& lsl : m->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& m : g_pCompositor->m_vMonitors) { + for (auto const& lsl : m->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (!ls->layerSurface || ls->xray != 1) continue; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c2ecbbf3..2ef7e208 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -331,7 +331,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) return true; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) return true; @@ -915,7 +915,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->m_RenderData.damage = preOccludedDamage; // and then special - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_iMonitorID == pMonitor->ID && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { const auto SPECIALANIMPROGRS = ws->m_vRenderOffset.isBeingAnimated() ? ws->m_vRenderOffset.getCurveValue() : ws->m_fAlpha.getCurveValue(); const bool ANIMOUT = !pMonitor->activeSpecialWorkspace; @@ -935,7 +935,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } // special - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { if (ws->m_bHasFullscreenWindow) renderWorkspaceWindowsFullscreen(pMonitor, ws, time); @@ -1489,7 +1489,7 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, } void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; @@ -1499,8 +1499,8 @@ void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE w->m_pWLSurface->resource()->breadthfirst([now](SP r, const Vector2D& offset, void* d) { r->frame(now); }, nullptr); } - for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& lsl : pMonitor->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { if (ls->fadingOut || !ls->surface->resource()) continue; @@ -1673,10 +1673,10 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; - for (auto& la : PMONITOR->m_aLayerSurfaceLayers) + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, true, &usableArea); - for (auto& la : PMONITOR->m_aLayerSurfaceLayers) + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, false, &usableArea); PMONITOR->vecReservedTopLeft = Vector2D(usableArea.x, usableArea.y) - PMONITOR->vecPosition; @@ -1808,7 +1808,7 @@ void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const in } void CHyprRenderer::damageRegion(const CRegion& rg) { - for (auto& RECT : rg.getRects()) { + for (auto const& RECT : rg.getRects()) { damageBox(RECT.x1, RECT.y1, RECT.x2 - RECT.x1, RECT.y2 - RECT.y1); } } @@ -2370,7 +2370,7 @@ std::tuple CHyprRenderer::getRenderTimes(CMonitor* pMonitor float avgRenderTime = 0; float maxRenderTime = 0; float minRenderTime = 9999; - for (auto& rt : POVERLAY->m_dLastRenderTimes) { + for (auto const& rt : POVERLAY->m_dLastRenderTimes) { if (rt > maxRenderTime) maxRenderTime = rt; if (rt < minRenderTime) @@ -2528,12 +2528,12 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty()) return; - for (auto& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (topls->alpha.value() != 0.f) return; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w == PCANDIDATE || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isHidden()) continue; diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 30ffbc68..02fe2b3b 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -151,8 +151,8 @@ bool CXWaylandSurface::wantsFocus() { HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"], }; - for (auto& searched : search) { - for (auto& a : atoms) { + for (auto const& searched : search) { + for (auto const& a : atoms) { if (a == searched) return false; } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index a409b440..995ec7f2 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -24,7 +24,7 @@ static int onX11Event(int fd, uint32_t mask, void* data) { } SP CXWM::windowForXID(xcb_window_t wid) { - for (auto& s : surfaces) { + for (auto const& s : surfaces) { if (s->xID == wid) return s; } @@ -156,7 +156,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ std::string propName; if (Debug::trace) { propName = std::format("{}?", atom); - for (auto& ha : HYPRATOMS) { + for (auto const& ha : HYPRATOMS) { if (ha.second != atom) continue; @@ -285,7 +285,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { return; std::string propName = "?"; - for (auto& ha : HYPRATOMS) { + for (auto const& ha : HYPRATOMS) { if (ha.second != e->type) continue; @@ -317,7 +317,7 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { Debug::log(LOG, "[xwm] surface {:x} requests serial {:x}", (uintptr_t)XSURF.get(), XSURF->wlSerial); - for (auto& res : shellResources) { + for (auto const& res : shellResources) { if (!res) continue; @@ -579,7 +579,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { atoms.push_back(HYPRATOMS["TIMESTAMP"]); atoms.push_back(HYPRATOMS["TARGETS"]); - for (auto& m : mimes) { + for (auto const& m : mimes) { atoms.push_back(mimeToAtom(m)); } @@ -944,7 +944,7 @@ void CXWM::onNewSurface(SP surf) { const auto WLID = surf->id(); - for (auto& sr : surfaces) { + for (auto const& sr : surfaces) { if (sr->surface || sr->wlID != WLID) continue; @@ -961,7 +961,7 @@ void CXWM::onNewResource(SP resource) { std::erase_if(shellResources, [](const auto& e) { return e.expired(); }); shellResources.push_back(resource); - for (auto& surf : surfaces) { + for (auto const& surf : surfaces) { if (surf->resource || surf->wlSerial != resource->serial) continue; From 1ea47950f4262ec1215087948c7275f8e0115af2 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 18:02:44 +0200 Subject: [PATCH 0536/2393] misc: fix some minor typos (#7530) * keybindmgr: fix typo in swap prev seems a suspicious extra ) got added, remove it. * configmgr: dont dereference invalid iterator i think the idea here was to print the key and not the iterator at or past .end() --- src/config/ConfigManager.cpp | 2 +- src/managers/KeybindManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 007869ee..5ce380a0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1720,7 +1720,7 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { if (it != flagsmap.end()) mode.flags |= it->second; else - Debug::log(ERR, "invalid flag {} in modeline", it->first); + Debug::log(ERR, "invalid flag {} in modeline", key); } snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7eb96730..9fac656c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2441,7 +2441,7 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) { // sometimes we may come back to ourselves. if (toSwap == PLASTWINDOW) { if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW), true; + toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true); else toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); } From 72c7818ae66a18d126e2b4245d649fe3a93d3b8e Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 26 Aug 2024 20:24:30 +0200 Subject: [PATCH 0537/2393] misc: constify the remaining for loops (#7534) now we roll loops at blazing constified speed. --- hyprctl/main.cpp | 4 +- hyprpm/src/core/DataState.cpp | 2 +- hyprpm/src/core/Manifest.cpp | 4 +- hyprpm/src/core/PluginManager.cpp | 38 +++--- src/Compositor.cpp | 112 +++++++++--------- src/config/ConfigManager.cpp | 26 ++-- src/debug/HyprCtl.cpp | 74 ++++++------ src/debug/HyprDebugOverlay.cpp | 2 +- src/debug/HyprNotificationOverlay.cpp | 4 +- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Popup.cpp | 10 +- src/desktop/Subsurface.cpp | 6 +- src/desktop/Window.cpp | 16 +-- src/desktop/Workspace.cpp | 4 +- src/events/Windows.cpp | 4 +- src/helpers/BezierCurve.cpp | 2 +- src/helpers/Format.cpp | 4 +- src/helpers/MiscFunctions.cpp | 12 +- src/helpers/Monitor.cpp | 22 ++-- src/layout/DwindleLayout.cpp | 4 +- src/layout/IHyprLayout.cpp | 6 +- src/layout/MasterLayout.cpp | 10 +- src/managers/AnimationManager.cpp | 10 +- src/managers/CursorManager.cpp | 6 +- src/managers/HookSystemManager.cpp | 4 +- src/managers/KeybindManager.cpp | 12 +- src/managers/PointerManager.cpp | 20 ++-- src/managers/ProtocolManager.cpp | 2 +- src/managers/SeatManager.cpp | 2 +- src/managers/SessionLockManager.cpp | 6 +- src/managers/XCursorManager.cpp | 2 +- src/managers/XWaylandManager.cpp | 2 +- src/managers/eventLoop/EventLoopManager.cpp | 10 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 20 ++-- src/managers/input/InputMethodRelay.cpp | 14 +-- src/managers/input/Tablets.cpp | 2 +- src/plugins/PluginAPI.cpp | 4 +- src/plugins/PluginSystem.cpp | 20 ++-- src/protocols/DRMLease.cpp | 12 +- src/protocols/DataDeviceWlr.cpp | 4 +- src/protocols/FocusGrab.cpp | 2 +- src/protocols/ForeignToplevel.cpp | 8 +- src/protocols/ForeignToplevelWlr.cpp | 16 +-- src/protocols/FractionalScale.cpp | 2 +- src/protocols/GammaControl.cpp | 4 +- src/protocols/GlobalShortcuts.cpp | 12 +- src/protocols/IdleNotify.cpp | 4 +- src/protocols/InputMethodV2.cpp | 10 +- src/protocols/LinuxDMABUF.cpp | 20 ++-- src/protocols/MesaDRM.cpp | 6 +- src/protocols/OutputManagement.cpp | 24 ++-- src/protocols/PointerGestures.cpp | 16 +-- src/protocols/PresentationTime.cpp | 4 +- src/protocols/PrimarySelection.cpp | 8 +- src/protocols/RelativePointer.cpp | 2 +- src/protocols/Screencopy.cpp | 8 +- src/protocols/SessionLock.cpp | 2 +- src/protocols/ShortcutsInhibit.cpp | 4 +- src/protocols/Tablet.cpp | 58 ++++----- src/protocols/TearingControl.cpp | 4 +- src/protocols/ToplevelExport.cpp | 6 +- src/protocols/VirtualKeyboard.cpp | 2 +- src/protocols/XDGOutput.cpp | 4 +- src/protocols/XDGShell.cpp | 6 +- src/protocols/core/Compositor.cpp | 6 +- src/protocols/core/DataDevice.cpp | 2 +- src/protocols/core/Output.cpp | 4 +- src/protocols/core/Seat.cpp | 8 +- src/protocols/core/Shm.cpp | 4 +- src/protocols/core/Subcompositor.cpp | 4 +- src/render/OpenGL.cpp | 54 ++++----- src/render/Renderer.cpp | 88 +++++++------- src/render/Texture.cpp | 2 +- .../decorations/CHyprBorderDecoration.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- .../decorations/DecorationPositioner.cpp | 6 +- src/xwayland/XWM.cpp | 6 +- 79 files changed, 472 insertions(+), 472 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 5d5113b8..1ad189b7 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -287,12 +287,12 @@ void instancesRequest(bool json) { std::vector inst = instances(); if (!json) { - for (auto& el : inst) { + for (auto const& el : inst) { result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket); } } else { result += '['; - for (auto& el : inst) { + for (auto const& el : inst) { result += std::format(R"#( {{ "instance": "{}", diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 61ad336f..05c63f4e 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -49,7 +49,7 @@ void DataState::addNewPluginRepo(const SPluginRepository& repo) { {"rev", repo.rev} }} }; - for (auto& p : repo.plugins) { + for (auto const& p : repo.plugins) { // copy .so to the good place if (std::filesystem::exists(p.filename)) std::filesystem::copy_file(p.filename, PATH + "/" + p.name + ".so"); diff --git a/hyprpm/src/core/Manifest.cpp b/hyprpm/src/core/Manifest.cpp index 42a8357c..754d9d69 100644 --- a/hyprpm/src/core/Manifest.cpp +++ b/hyprpm/src/core/Manifest.cpp @@ -6,7 +6,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { auto manifest = toml::parse_file(path); if (type == MANIFEST_HYPRLOAD) { - for (auto& [key, val] : manifest) { + for (auto const& [key, val] : manifest) { if (key.str().ends_with(".build")) continue; @@ -63,7 +63,7 @@ CManifest::CManifest(const eManifestType type, const std::string& path) { } } - for (auto& [key, val] : manifest) { + for (auto const& [key, val] : manifest) { if (key.str() == "repository") continue; diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index ab457ca6..669789b4 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -204,9 +204,9 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.m_iSteps = 2; progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"); - for (auto& pl : pManifest->m_vPlugins) { + for (auto const& pl : pManifest->m_vPlugins) { std::string message = std::string{Colors::RESET} + " → " + pl.name + " by "; - for (auto& a : pl.authors) { + for (auto const& a : pl.authors) { message += a + ", "; } if (pl.authors.size() > 0) { @@ -222,7 +222,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); - for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; @@ -264,7 +264,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); - for (auto& bs : p.buildSteps) { + for (auto const& bs : p.buildSteps) { std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } @@ -299,7 +299,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& repo.url = url; repo.rev = rev; repo.hash = repohash; - for (auto& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_vPlugins) { repo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, false, p.failed}); } DataState::addNewPluginRepo(repo); @@ -579,7 +579,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { const std::string USERNAME = getpwuid(getuid())->pw_name; m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; - for (auto& repo : REPOS) { + for (auto const& repo : REPOS) { bool update = forceUpdateAll; progress.m_iSteps++; @@ -658,7 +658,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); - for (auto& [hl, plugin] : pManifest->m_sRepository.commitPins) { + for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; @@ -679,7 +679,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); - for (auto& bs : p.buildSteps) { + for (auto const& bs : p.buildSteps) { std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } @@ -709,7 +709,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (repohash.length() > 0) repohash.pop_back(); newrepo.hash = repohash; - for (auto& p : pManifest->m_vPlugins) { + for (auto const& p : pManifest->m_vPlugins) { const auto OLDPLUGINIT = std::find_if(repo.plugins.begin(), repo.plugins.end(), [&](const auto& other) { return other.name == p.name; }); newrepo.plugins.push_back(SPlugin{p.name, m_szWorkingPluginDirectory + "/" + p.output, OLDPLUGINIT != repo.plugins.end() ? OLDPLUGINIT->enabled : false}); } @@ -794,8 +794,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { const auto REPOS = DataState::getAllRepositories(); auto enabled = [REPOS](const std::string& plugin) -> bool { - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (p.name == plugin && p.enabled) return true; } @@ -805,8 +805,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { }; auto repoForName = [REPOS](const std::string& name) -> std::string { - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (p.name == name) return r.name; } @@ -816,7 +816,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { }; // unload disabled plugins - for (auto& p : loadedPlugins) { + for (auto const& p : loadedPlugins) { if (!enabled(p)) { // unload loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false); @@ -825,8 +825,8 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { } // load enabled plugins - for (auto& r : REPOS) { - for (auto& p : r.plugins) { + for (auto const& r : REPOS) { + for (auto const& p : r.plugins) { if (!p.enabled) continue; @@ -855,10 +855,10 @@ bool CPluginManager::loadUnloadPlugin(const std::string& path, bool load) { void CPluginManager::listAllPlugins() { const auto REPOS = DataState::getAllRepositories(); - for (auto& r : REPOS) { + for (auto const& r : REPOS) { std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n"; - for (auto& p : r.plugins) { + for (auto const& p : r.plugins) { std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name; @@ -905,7 +905,7 @@ std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { bool CPluginManager::hasDeps() { std::vector deps = {"meson", "cpio", "cmake", "pkg-config"}; - for (auto& d : deps) { + for (auto const& d : deps) { if (!execAndGet("command -v " + d).contains("/")) return false; } diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0aa7f213..cacbeece 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -391,7 +391,7 @@ void CCompositor::initAllSignals() { m_bSessionActive = true; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { scheduleFrameForMonitor(m.get()); g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); } @@ -477,7 +477,7 @@ void CCompositor::cleanup() { m_vWorkspaces.clear(); m_vWindows.clear(); - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { g_pHyprOpenGL->destroyMonitorResources(m.get()); m->output->state->setEnabled(false); @@ -641,7 +641,7 @@ void CCompositor::removeLockFile() { void CCompositor::prepareFallbackOutput() { // create a backup monitor SP headless; - for (auto& impl : m_pAqBackend->getImplementations()) { + for (auto const& impl : m_pAqBackend->getImplementations()) { if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) { headless = impl; break; @@ -698,7 +698,7 @@ void CCompositor::startCompositor() { } CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->ID == id) { return m.get(); } @@ -708,7 +708,7 @@ CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { } CMonitor* CCompositor::getMonitorFromName(const std::string& name) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->szName == name) { return m.get(); } @@ -717,7 +717,7 @@ CMonitor* CCompositor::getMonitorFromName(const std::string& name) { } CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->szDescription.starts_with(desc)) return m.get(); } @@ -730,7 +730,7 @@ CMonitor* CCompositor::getMonitorFromCursor() { CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { SP mon; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { mon = m; break; @@ -771,7 +771,7 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { } bool CCompositor::monitorExists(CMonitor* pMonitor) { - for (auto& m : m_vRealMonitors) { + for (auto const& m : m_vRealMonitors) { if (m.get() == pMonitor) return true; } @@ -789,7 +789,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && @@ -807,7 +807,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper auto windowForWorkspace = [&](bool special) -> PHLWINDOW { auto floating = [&](bool aboveFullscreen) -> PHLWINDOW { - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular continue; @@ -870,7 +870,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper return found; // for windows, we need to check their extensions too, first. - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (special != w->onSpecialWorkspace()) continue; @@ -881,7 +881,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper } } - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (special != w->onSpecialWorkspace()) continue; @@ -963,7 +963,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo } CMonitor* CCompositor::getMonitorFromOutput(SP out) { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m->output == out) { return m.get(); } @@ -973,7 +973,7 @@ CMonitor* CCompositor::getMonitorFromOutput(SP out) { } CMonitor* CCompositor::getRealMonitorFromOutput(SP out) { - for (auto& m : m_vRealMonitors) { + for (auto const& m : m_vRealMonitors) { if (m->output == out) { return m.get(); } @@ -1212,7 +1212,7 @@ PHLWINDOW CCompositor::getWindowFromSurface(SP pSurface) { } PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if ((uint32_t)(((uint64_t)w.get()) & 0xFFFFFFFF) == handle) { return w; } @@ -1222,7 +1222,7 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { } PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == ID && w->isFullscreen()) return w; } @@ -1246,7 +1246,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { } PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) return w; } @@ -1271,7 +1271,7 @@ void CCompositor::sanityCheckWorkspaces() { int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) @@ -1286,7 +1286,7 @@ int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { int no = 0; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped) continue; if (!w->m_sGroupData.head) @@ -1301,7 +1301,7 @@ int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional } PHLWINDOW CCompositor::getUrgentWindow() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_bIsMapped && w->m_bIsUrgent) return w; } @@ -1310,7 +1310,7 @@ PHLWINDOW CCompositor::getUrgentWindow() { } bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) return true; } @@ -1319,7 +1319,7 @@ bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { } PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) return w; } @@ -1335,7 +1335,7 @@ PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden()) continue; @@ -1400,7 +1400,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { else toMove.emplace_front(pw); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->X11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) { x11Stack(w, top, x11Stack); } @@ -1416,7 +1416,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { } void CCompositor::cleanupFadingOut(const MONITORID& monid) { - for (auto& ww : m_vWindowsFadingOut) { + for (auto const& ww : m_vWindowsFadingOut) { auto w = ww.lock(); @@ -1441,7 +1441,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { bool layersDirty = false; - for (auto& lsr : m_vSurfacesFadingOut) { + for (auto const& lsr : m_vSurfacesFadingOut) { auto ls = lsr.lock(); @@ -1530,7 +1530,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (!pWindow->m_bIsFloating) { // for tiled windows, we calc edges - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -1622,7 +1622,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { float bestAngleAbs = 2.0 * M_PI; constexpr float THRESHOLD = 0.3 * M_PI; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -1660,7 +1660,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { bool gotToWindow = false; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w != pWindow && !gotToWindow) continue; @@ -1676,7 +1676,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return w; } - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; @@ -1689,7 +1689,7 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { bool gotToWindow = false; - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (w != pWindow && !gotToWindow) continue; @@ -1705,7 +1705,7 @@ PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl return w; } - for (auto& w : m_vWindows | std::views::reverse) { + for (auto const& w : m_vWindows | std::views::reverse) { if (floating.has_value() && w->m_bIsFloating != floating.value()) continue; @@ -1727,7 +1727,7 @@ WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { } PHLWORKSPACE CCompositor::getWorkspaceByName(const std::string& name) { - for (auto& w : m_vWorkspaces) { + for (auto const& w : m_vWorkspaces) { if (w->m_szName == name && !w->inert()) return w; } @@ -1779,7 +1779,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha auto longestIntersect = -1; CMonitor* longestIntersectMonitor = nullptr; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (m == m_pLastMonitor) continue; @@ -1843,7 +1843,7 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() { } void CCompositor::updateWorkspaceWindows(const int64_t& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->workspaceID() != id) continue; @@ -1968,7 +1968,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) PWORKSPACEA->m_iMonitorID = pMonitorB->ID; PWORKSPACEA->moveToMonitor(pMonitorB->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACEA) { if (w->m_bPinned) { w->m_pWorkspace = PWORKSPACEB; @@ -1993,7 +1993,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) PWORKSPACEB->m_iMonitorID = pMonitorA->ID; PWORKSPACEB->moveToMonitor(pMonitorA->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACEB) { if (w->m_bPinned) { w->m_pWorkspace = PWORKSPACEA; @@ -2108,7 +2108,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return nullptr; } } else { - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { if (!m->output) continue; @@ -2168,7 +2168,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon pWorkspace->m_iMonitorID = pMonitor->ID; pWorkspace->moveToMonitor(pMonitor->ID); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == pWorkspace) { if (w->m_bPinned) { w->m_pWorkspace = g_pCompositor->getWorkspaceByID(nextWorkspaceOnMonitorID); @@ -2255,7 +2255,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { if (w->m_bFadingOut || w->m_bPinned || w->isFullscreen()) @@ -2347,7 +2347,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); // make all windows on the same workspace under the fullscreen window - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->m_pWorkspace == PWORKSPACE && !w->isFullscreen() && !w->m_bFadingOut && !w->m_bPinned) w->m_bCreatedOverFullscreen = false; } @@ -2388,7 +2388,7 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { } void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2400,7 +2400,7 @@ void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { const auto PWORKSPACE = getWorkspaceByID(id); const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() != id) continue; @@ -2453,7 +2453,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { const bool FLOAT = regexp.starts_with("floating"); - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) continue; @@ -2463,7 +2463,7 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { return nullptr; } - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || (w->isHidden() && !g_pLayoutManager->getCurrentLayout()->isWindowReachable(w))) continue; @@ -2617,7 +2617,7 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con } void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); } @@ -2744,7 +2744,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor } PHLWINDOW CCompositor::getForceFocus() { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace)) continue; @@ -2763,7 +2763,7 @@ void CCompositor::arrangeMonitors() { std::vector toArrange; std::vector arranged; - for (auto& m : m_vMonitors) + for (auto const& m : m_vMonitors) toArrange.push_back(m.get()); Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size()); @@ -2795,7 +2795,7 @@ void CCompositor::arrangeMonitors() { int maxYOffsetDown = 0; // Finds the max and min values of explicitely placed monitors. - for (auto& m : arranged) { + for (auto const& m : arranged) { if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight) maxXOffsetRight = m->vecPosition.x + m->vecSize.x; if (m->vecPosition.x < maxXOffsetLeft) @@ -2807,7 +2807,7 @@ void CCompositor::arrangeMonitors() { } // Iterates through all non-explicitly placed monitors. - for (auto& m : toArrange) { + for (auto const& m : toArrange) { // Moves the monitor to their appropriate position on the x/y axis and // increments/decrements the corresponding max offset. Vector2D newPosition = {0, 0}; @@ -2838,7 +2838,7 @@ void CCompositor::arrangeMonitors() { // reset maxXOffsetRight (reuse) // and set xwayland positions aka auto for all maxXOffsetRight = 0; - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { Debug::log(LOG, "arrangeMonitors: {} xwayland [{}, {}]", m->szName, maxXOffsetRight, 0); m->vecXWaylandPosition = {maxXOffsetRight, 0}; maxXOffsetRight += (*PXWLFORCESCALEZERO ? m->vecTransformedSize.x : m->vecSize.x); @@ -2873,7 +2873,7 @@ void CCompositor::leaveUnsafeState() { m_bUnsafeState = false; CMonitor* pNewMonitor = nullptr; - for (auto& pMonitor : m_vMonitors) { + for (auto const& pMonitor : m_vMonitors) { if (pMonitor->output != m_pUnsafeOutput->output) { pNewMonitor = pMonitor.get(); break; @@ -2885,7 +2885,7 @@ void CCompositor::leaveUnsafeState() { if (m_pUnsafeOutput->m_bEnabled) m_pUnsafeOutput->onDisconnect(); - for (auto& m : m_vMonitors) { + for (auto const& m : m_vMonitors) { scheduleFrameForMonitor(m.get()); } } @@ -2917,7 +2917,7 @@ void CCompositor::setPreferredTransformForSurface(SP pSurfac } void CCompositor::updateSuspendedStates() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped) continue; @@ -2926,7 +2926,7 @@ void CCompositor::updateSuspendedStates() { } PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { - for (auto& w : m_vWindows) { + for (auto const& w : m_vWindows) { if (w.get() != pWindow) continue; @@ -2970,7 +2970,7 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->updateSurfaceScaleTransformDetails(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5ce380a0..f402958b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -45,7 +45,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** std::string parseError = ""; - for (auto& var : varlist) { + for (auto const& var : varlist) { if (var.find("deg") != std::string::npos) { // last arg try { @@ -863,7 +863,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { refreshGroupBarGradients(); // Updates dynamic window and workspace rules - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->inert()) continue; g_pCompositor->updateWorkspaceWindows(w->m_iID); @@ -891,7 +891,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { Debug::coloredLogs = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:colored_stdout_logs")->getDataStaticPtr()); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { // mark blur dirty g_pHyprOpenGL->markBlurDirtyForMonitor(m.get()); @@ -978,7 +978,7 @@ void CConfigManager::tick() { bool parse = false; - for (auto& cf : configPaths) { + for (auto const& cf : configPaths) { struct stat fileStat; int err = stat(cf.c_str(), &fileStat); if (err != 0) { @@ -1059,7 +1059,7 @@ SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { SWorkspaceRule mergedRule{}; - for (auto& rule : m_dWorkspaceRules) { + for (auto const& rule : m_dWorkspaceRules) { if (!pWorkspace->matchesStaticSelector(rule.workspaceString)) continue; @@ -1132,7 +1132,7 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo // local tags for dynamic tag rule match auto tags = pWindow->m_tags; - for (auto& rule : m_dWindowRules) { + for (auto const& rule : m_dWindowRules) { // check if we have a matching rule if (!rule.v2) { try { @@ -1297,7 +1297,7 @@ std::vector CConfigManager::getMatchingRules(PHLWINDOW pWindow, boo bool anyExecFound = false; - for (auto& er : execRequestedRules) { + for (auto const& er : execRequestedRules) { if (std::ranges::any_of(PIDs, [&](const auto& pid) { return pid == er.iPid; })) { returns.push_back({er.szRule, "execRule"}); anyExecFound = true; @@ -1317,7 +1317,7 @@ std::vector CConfigManager::getMatchingRules(PHLLS pLS) { if (!pLS->layerSurface || pLS->fadingOut) return returns; - for (auto& lr : m_dLayerRules) { + for (auto const& lr : m_dLayerRules) { if (lr.targetNamespace.starts_with("address:0x")) { if (std::format("address:0x{:x}", (uintptr_t)pLS.get()) != lr.targetNamespace) continue; @@ -1391,7 +1391,7 @@ void CConfigManager::performMonitorReload() { bool overAgain = false; - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (!m->output || m->isUnsafeFallback) continue; @@ -1448,7 +1448,7 @@ bool CConfigManager::shouldBlurLS(const std::string& ns) { } void CConfigManager::ensureMonitorStatus() { - for (auto& rm : g_pCompositor->m_vRealMonitors) { + for (auto const& rm : g_pCompositor->m_vRealMonitors) { if (!rm->output || rm->isUnsafeFallback) continue; @@ -1531,7 +1531,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { return; } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { ensureVRRForDisplay(m.get()); } } @@ -1632,7 +1632,7 @@ void CConfigManager::removePluginConfig(HANDLE handle) { } std::erase_if(pluginKeywords, [&](const auto& other) { return other.handle == handle; }); - for (auto& [h, n] : pluginVariables) { + for (auto const& [h, n] : pluginVariables) { if (h != handle) continue; @@ -2534,7 +2534,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin }; CVarList rulesList{rules, 0, ',', true}; - for (auto& r : rulesList) { + for (auto const& r : rulesList) { const auto R = assignRule(r); if (R.has_value()) return R; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 2fc5cc7d..40708cf8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -57,7 +57,7 @@ static std::string formatToString(uint32_t drmFormat) { static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { std::string result; - for (auto& m : pMonitor->output->modes) { + for (auto const& m : pMonitor->output->modes) { if (format == FORMAT_NORMAL) result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0); else @@ -445,13 +445,13 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { escapeJSONStrings(mon->szName)); int layerLevel = 0; - for (auto& level : mon->m_aLayerSurfaceLayers) { + for (auto const& level : mon->m_aLayerSurfaceLayers) { result += std::format( R"#( "{}": [ )#", layerLevel); - for (auto& layer : level) { + for (auto const& layer : level) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -484,14 +484,14 @@ std::string layersRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n}\n"; } else { - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { result += std::format("Monitor {}:\n", mon->szName); int layerLevel = 0; static const std::array levelNames = {"background", "bottom", "top", "overlay"}; - for (auto& level : mon->m_aLayerSurfaceLayers) { + for (auto const& level : mon->m_aLayerSurfaceLayers) { result += std::format("\tLayer level {} ({}):\n", layerLevel, levelNames[layerLevel]); - for (auto& layer : level) { + for (auto const& layer : level) { result += std::format("\t\tLayer {:x}: xywh: {} {} {} {}, namespace: {}\n", (uintptr_t)layer.get(), layer->geometry.x, layer->geometry.y, layer->geometry.width, layer->geometry.height, layer->szNamespace); } @@ -510,7 +510,7 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& m : g_pLayoutManager->getAllLayoutNames()) { + for (auto const& m : g_pLayoutManager->getAllLayoutNames()) { result += std::format( R"#( "{}",)#", @@ -520,7 +520,7 @@ std::string layoutsRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n]\n"; } else { - for (auto& m : g_pLayoutManager->getAllLayoutNames()) { + for (auto const& m : g_pLayoutManager->getAllLayoutNames()) { result += std::format("{}\n", m); } } @@ -557,7 +557,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "{\n"; result += "\"mice\": [\n"; - for (auto& m : g_pInputManager->m_vPointers) { + for (auto const& m : g_pInputManager->m_vPointers) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -572,7 +572,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n],\n"; result += "\"keyboards\": [\n"; - for (auto& k : g_pInputManager->m_vKeyboards) { + for (auto const& k : g_pInputManager->m_vKeyboards) { const auto KM = k->getActiveLayout(); result += std::format( R"#( {{ @@ -596,7 +596,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"tablets\": [\n"; - for (auto& d : g_pInputManager->m_vTabletPads) { + for (auto const& d : g_pInputManager->m_vTabletPads) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -609,7 +609,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { (uintptr_t)d.get(), (uintptr_t)d->parent.get(), escapeJSONStrings(d->parent ? d->parent->hlName : "")); } - for (auto& d : g_pInputManager->m_vTablets) { + for (auto const& d : g_pInputManager->m_vTablets) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -618,7 +618,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { (uintptr_t)d.get(), escapeJSONStrings(d->hlName)); } - for (auto& d : g_pInputManager->m_vTabletTools) { + for (auto const& d : g_pInputManager->m_vTabletTools) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -632,7 +632,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"touch\": [\n"; - for (auto& d : g_pInputManager->m_vTouches) { + for (auto const& d : g_pInputManager->m_vTouches) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -646,7 +646,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\"switches\": [\n"; - for (auto& d : g_pInputManager->m_lSwitches) { + for (auto const& d : g_pInputManager->m_lSwitches) { result += std::format( R"#( {{ "address": "0x{:x}", @@ -663,14 +663,14 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { } else { result += "mice:\n"; - for (auto& m : g_pInputManager->m_vPointers) { + for (auto const& m : g_pInputManager->m_vPointers) { result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName, (m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f)); } result += "\n\nKeyboards:\n"; - for (auto& k : g_pInputManager->m_vKeyboards) { + for (auto const& k : g_pInputManager->m_vKeyboards) { const auto KM = k->getActiveLayout(); result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tmain: {}\n", (uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, @@ -679,27 +679,27 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { result += "\n\nTablets:\n"; - for (auto& d : g_pInputManager->m_vTabletPads) { + for (auto const& d : g_pInputManager->m_vTabletPads) { result += std::format("\tTablet Pad at {:x} (belongs to {:x} -> {})\n", (uintptr_t)d.get(), (uintptr_t)d->parent.get(), d->parent ? d->parent->hlName : ""); } - for (auto& d : g_pInputManager->m_vTablets) { + for (auto const& d : g_pInputManager->m_vTablets) { result += std::format("\tTablet at {:x}:\n\t\t{}\n\t\t\tsize: {}x{}mm\n", (uintptr_t)d.get(), d->hlName, d->aq()->physicalSize.x, d->aq()->physicalSize.y); } - for (auto& d : g_pInputManager->m_vTabletTools) { + for (auto const& d : g_pInputManager->m_vTabletTools) { result += std::format("\tTablet Tool at {:x}\n", (uintptr_t)d.get()); } result += "\n\nTouch:\n"; - for (auto& d : g_pInputManager->m_vTouches) { + for (auto const& d : g_pInputManager->m_vTouches) { result += std::format("\tTouch Device at {:x}:\n\t\t{}\n", (uintptr_t)d.get(), d->hlName); } result += "\n\nSwitches:\n"; - for (auto& d : g_pInputManager->m_lSwitches) { + for (auto const& d : g_pInputManager->m_lSwitches) { result += std::format("\tSwitch Device at {:x}:\n\t\t{}\n", (uintptr_t)&d, d.pDevice ? d.pDevice->getName() : ""); } } @@ -712,21 +712,21 @@ std::string animationsRequest(eHyprCtlOutputFormat format, std::string request) if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { ret += "animations:\n"; - for (auto& ac : g_pConfigManager->getAnimationConfig()) { + for (auto const& ac : g_pConfigManager->getAnimationConfig()) { ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden, ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle); } ret += "beziers:\n"; - for (auto& bz : g_pAnimationManager->getAllBeziers()) { + for (auto const& bz : g_pAnimationManager->getAllBeziers()) { ret += std::format("\n\tname: {}\n", bz.first); } } else { // json ret += "[["; - for (auto& ac : g_pConfigManager->getAnimationConfig()) { + for (auto const& ac : g_pConfigManager->getAnimationConfig()) { ret += std::format(R"#( {{ "name": "{}", @@ -778,7 +778,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ std::string ret = ""; const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto& sh : SHORTCUTS) + for (auto const& sh : SHORTCUTS) ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); } else { ret += "["; @@ -800,7 +800,7 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string ret = ""; if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_lKeybinds) { ret += "bind"; if (kb.locked) ret += "l"; @@ -821,7 +821,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { } else { // json ret += "["; - for (auto& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_lKeybinds) { ret += std::format( R"#( {{ @@ -935,7 +935,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "plugins:\n"; - for (auto& pl : g_pPluginSystem->getAllPlugins()) { + for (auto const& pl : g_pPluginSystem->getAllPlugins()) { result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); } @@ -1006,7 +1006,7 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { // decorations will probably need a repaint if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m.get()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } @@ -1359,7 +1359,7 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) std::string result = ""; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - for (auto& wd : PWINDOW->m_dWindowDecorations) { + for (auto const& wd : PWINDOW->m_dWindowDecorations) { result += "{\n\"decorationName\": \"" + wd->getDisplayName() + "\",\n\"priority\": " + std::to_string(wd->getPositioningInfo().priority) + "\n},"; } @@ -1367,7 +1367,7 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request) result += "]"; } else { result = +"Decoration\tPriority\n"; - for (auto& wd : PWINDOW->m_dWindowDecorations) { + for (auto const& wd : PWINDOW->m_dWindowDecorations) { result += wd->getDisplayName() + "\t" + std::to_string(wd->getPositioningInfo().priority) + "\n"; } } @@ -1396,7 +1396,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) { if (g_pCompositor->getMonitorFromName(vars[3])) return "A real monitor already uses that name."; - for (auto& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { + for (auto const& impl : g_pCompositor->m_pAqBackend->getImplementations() | std::views::reverse) { auto type = impl->type(); if (type == Aquamarine::AQ_BACKEND_HEADLESS && (vars[2] == "headless" || vars[2] == "auto")) { @@ -1464,7 +1464,7 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) { return "no plugins loaded"; std::string list = ""; - for (auto& p : PLUGINS) { + for (auto const& p : PLUGINS) { list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description); } @@ -1673,7 +1673,7 @@ std::string CHyprCtl::getReply(std::string request) { std::string result = ""; // parse exact cmds first, then non-exact. - for (auto& cmd : m_vCommands) { + for (auto const& cmd : m_vCommands) { if (!cmd->exact) continue; @@ -1684,7 +1684,7 @@ std::string CHyprCtl::getReply(std::string request) { } if (result.empty()) - for (auto& cmd : m_vCommands) { + for (auto const& cmd : m_vCommands) { if (cmd->exact) continue; @@ -1715,7 +1715,7 @@ std::string CHyprCtl::getReply(std::string request) { rd.blurFBDirty = true; } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m.get()); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 22c741a6..2da64e63 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -217,7 +217,7 @@ void CHyprDebugOverlay::draw() { // draw the things int offsetY = 0; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); offsetY += 5; // for padding between mons } diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 3f8bb579..29da20c8 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -44,7 +44,7 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC PNOTIF->icon = icon; PNOTIF->fontSize = fontSize; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pCompositor->scheduleFrameForMonitor(m.get()); } } @@ -87,7 +87,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { const auto iconBackendID = iconBackendFromLayout(layout); const auto PBEZIER = g_pAnimationManager->getBezier("default"); - for (auto& notif : m_dNotifications) { + for (auto const& notif : m_dNotifications) { const auto ICONPADFORNOTIF = notif->icon == ICON_NONE ? 0 : ICON_PAD; const auto FONTSIZE = std::clamp((int)(notif->fontSize * ((pMonitor->vecPixelSize.x * SCALE) / 1920.f)), 8, 40); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 331dba9c..155a2605 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -366,7 +366,7 @@ void CLayerSurface::applyRules() { xray = -1; animationStyle.reset(); - for (auto& rule : g_pConfigManager->getMatchingRules(self.lock())) { + for (auto const& rule : g_pConfigManager->getMatchingRules(self.lock())) { if (rule.rule == "noanim") noAnimations = true; else if (rule.rule == "blur") diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index e48b7400..a4952ef7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -251,7 +251,7 @@ void CPopup::recheckTree() { void CPopup::recheckChildrenRecursive() { auto cpy = m_vChildren; - for (auto& c : cpy) { + for (auto const& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); } @@ -282,14 +282,14 @@ bool CPopup::visible() { } void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { - for (auto& n : nodes) { + for (auto const& n : nodes) { fn(n, data); } std::vector nodes2; - for (auto& n : nodes) { - for (auto& c : n->m_vChildren) { + for (auto const& n : nodes) { + for (auto const& c : n->m_vChildren) { nodes2.push_back(c.get()); } } @@ -308,7 +308,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { std::vector popups; breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); - for (auto& p : popups | std::views::reverse) { + for (auto const& p : popups | std::views::reverse) { if (!p->m_pResource) continue; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 71ee16f0..64dd7cf5 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -65,7 +65,7 @@ void CSubsurface::checkSiblingDamage() { const double SCALE = m_pWindowParent.lock() && m_pWindowParent->m_bIsX11 ? 1.0 / m_pWindowParent->m_fX11SurfaceScaledBy : 1.0; - for (auto& n : m_pParent->m_vChildren) { + for (auto const& n : m_pParent->m_vChildren) { if (n.get() == this) continue; @@ -75,7 +75,7 @@ void CSubsurface::checkSiblingDamage() { } void CSubsurface::recheckDamageForSubsurfaces() { - for (auto& n : m_vChildren) { + for (auto const& n : m_vChildren) { const auto COORDS = n->coordsGlobal(); g_pHyprRenderer->damageSurface(n->m_pWLSurface->resource(), COORDS.x, COORDS.y); } @@ -183,7 +183,7 @@ Vector2D CSubsurface::coordsGlobal() { } void CSubsurface::initExistingSubsurfaces(SP pSurface) { - for (auto& s : pSurface->subsurfaces) { + for (auto const& s : pSurface->subsurfaces) { if (!s || s->surface->hlSurface /* already assigned */) continue; onNewSubsurface(s.lock()); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 64337097..582e96a0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -296,7 +296,7 @@ void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) { } void CWindow::uncacheWindowDecos() { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { g_pDecorationPositioner->uncacheDecoration(wd.get()); } } @@ -305,7 +305,7 @@ bool CWindow::checkInputOnDecos(const eInputType type, const Vector2D& mouseCoor if (type != INPUT_TYPE_DRAG_END && hasPopupAt(mouseCoords)) return false; - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; @@ -337,7 +337,7 @@ pid_t CWindow::getPID() { } IHyprWindowDecoration* CWindow::getDecorationByType(eDecorationType type) { - for (auto& wd : m_dWindowDecorations) { + for (auto const& wd : m_dWindowDecorations) { if (wd->getDecorationType() == type) return wd.get(); } @@ -666,7 +666,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { return; } - for (auto& token : colorsAndAngles) { + for (auto const& token : colorsAndAngles) { // The first angle, or an explicit "0deg", splits the two gradients if (active && token.contains("deg")) { activeBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0); @@ -889,7 +889,7 @@ void CWindow::destroyGroup() { const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_bGroupsLocked; g_pKeybindManager->m_bGroupsLocked = true; - for (auto& w : members) { + for (auto const& w : members) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(w); w->updateWindowDecos(); } @@ -1282,7 +1282,7 @@ std::unordered_map CWindow::getEnv() { CVarList envs(std::string{buffer.data(), buffer.size() - 1}, 0, '\n', true); - for (auto& e : envs) { + for (auto const& e : envs) { if (!e.contains('=')) continue; @@ -1511,7 +1511,7 @@ PHLWINDOW CWindow::getSwallower() { if (!currentPid) break; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden()) continue; @@ -1536,7 +1536,7 @@ PHLWINDOW CWindow::getSwallower() { return candidates.at(0); // walk up the focus history and find the last focused - for (auto& w : g_pCompositor->m_vWindowFocusHistory) { + for (auto const& w : g_pCompositor->m_vWindowFocusHistory) { if (!w) continue; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 72d9705e..35fc5727 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -94,7 +94,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { // set floating windows offset callbacks m_vRenderOffset.setUpdateCallback([&](void*) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->workspaceID() != m_iID) continue; @@ -386,7 +386,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { bool wantsCountVisible = false; int flagCount = 0; - for (auto& flag : prop) { + for (auto const& flag : prop) { if (flag == 't' && wantsOnlyTiled == -1) { wantsOnlyTiled = 1; flagCount++; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e4e3900b..cd000223 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -139,7 +139,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) requestedClientFSMode = FSMODE_FULLSCREEN; - for (auto& r : PWINDOW->m_vMatchedRules) { + for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("monitor")) { try { const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); @@ -326,7 +326,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bCreatedOverFullscreen = true; // size and move rules - for (auto& r : PWINDOW->m_vMatchedRules) { + for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("size")) { try { const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp index dd0ff2b0..ea567ad6 100644 --- a/src/helpers/BezierCurve.cpp +++ b/src/helpers/BezierCurve.cpp @@ -12,7 +12,7 @@ void CBezierCurve::setup(std::vector* pVec) { m_dPoints.emplace_back(Vector2D(0, 0)); - for (auto& p : *pVec) { + for (auto const& p : *pVec) { m_dPoints.push_back(p); } diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index afc8b1c5..bc54b76e 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -252,7 +252,7 @@ DRMFormat FormatUtils::shmToDRM(SHMFormat shm) { } const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { - for (auto& fmt : GLES3_FORMATS) { + for (auto const& fmt : GLES3_FORMATS) { if (fmt.drmFormat == drm) return &fmt; } @@ -261,7 +261,7 @@ const SPixelFormat* FormatUtils::getPixelFormatFromDRM(DRMFormat drm) { } const SPixelFormat* FormatUtils::getPixelFormatFromGL(uint32_t glFormat, uint32_t glType, bool alpha) { - for (auto& fmt : GLES3_FORMATS) { + for (auto const& fmt : GLES3_FORMATS) { if (fmt.glFormat == (int)glFormat && fmt.glType == (int)glType && fmt.withAlpha == alpha) return &fmt; } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index ef319946..b9970399 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -180,7 +180,7 @@ void handleNoop(struct wl_listener* listener, void* data) { std::string escapeJSONStrings(const std::string& str) { std::ostringstream oss; - for (auto& c : str) { + for (auto const& c : str) { switch (c) { case '"': oss << "\\\""; break; case '\\': oss << "\\\\"; break; @@ -251,7 +251,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::set invalidWSes; if (same_mon) { - for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); if (PMONITOR && (PMONITOR->ID != g_pCompositor->m_pLastMonitor->ID)) invalidWSes.insert(rule.workspaceId); @@ -301,13 +301,13 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::set invalidWSes; // Collect all the workspaces we can't jump to. - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) { // Can't jump to this workspace invalidWSes.insert(ws->m_iID); } } - for (auto& rule : g_pConfigManager->getAllWorkspaceRules()) { + for (auto const& rule : g_pConfigManager->getAllWorkspaceRules()) { const auto PMONITOR = g_pCompositor->getMonitorFromName(rule.monitor); if (!PMONITOR || PMONITOR->ID == g_pCompositor->m_pLastMonitor->ID) { // Can't be invalid @@ -319,7 +319,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Prepare all named workspaces in case when we need them std::vector namedWSes; - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) continue; @@ -463,7 +463,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { int remains = (int)result.id; std::vector validWSes; - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) continue; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8b533d8a..d81ccb3d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -171,7 +171,7 @@ void CMonitor::onConnect(bool noRule) { setupDefaultWS(monitorRule); - for (auto& ws : g_pCompositor->m_vWorkspaces) { + for (auto const& ws : g_pCompositor->m_vWorkspaces) { if (!valid(ws)) continue; @@ -242,7 +242,7 @@ void CMonitor::onDisconnect(bool destroy) { // Cleanup everything. Move windows back, snap cursor, shit. CMonitor* BACKUPMON = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { BACKUPMON = m.get(); break; @@ -259,7 +259,7 @@ void CMonitor::onDisconnect(bool destroy) { } if (!mirrors.empty()) { - for (auto& m : mirrors) { + for (auto const& m : mirrors) { m->setMirror(""); } @@ -298,13 +298,13 @@ void CMonitor::onDisconnect(bool destroy) { // move workspaces std::deque wspToMove; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) { wspToMove.push_back(w); } } - for (auto& w : wspToMove) { + for (auto const& w : wspToMove) { w->m_szLastMonitor = szName; g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON); w->startAnim(true, true, true); @@ -332,7 +332,7 @@ void CMonitor::onDisconnect(bool destroy) { int mostHz = 0; CMonitor* pMonitorMostHz = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->refreshRate > mostHz && m.get() != this) { pMonitorMostHz = m.get(); mostHz = m->refreshRate; @@ -516,7 +516,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff } else { CMonitor* BACKUPMON = nullptr; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { BACKUPMON = m.get(); break; @@ -525,13 +525,13 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // move all the WS std::deque wspToMove; - for (auto& w : g_pCompositor->m_vWorkspaces) { + for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->m_iMonitorID == ID) { wspToMove.push_back(w); } } - for (auto& w : wspToMove) { + for (auto const& w : wspToMove) { g_pCompositor->moveWorkspaceToMonitor(w, BACKUPMON); w->startAnim(true, true, true); } @@ -605,7 +605,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo pWorkspace->startAnim(true, ANIMTOLEFT); // move pinned windows - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == POLDWORKSPACE && w->m_bPinned) w->moveToWorkspace(pWorkspace); } @@ -714,7 +714,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { if (animate) pWorkspace->startAnim(true, true); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { w->m_iMonitorID = ID; w->updateSurfaceScaleTransformDetails(); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index db69cc04..c936d59c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -104,7 +104,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for CMonitor* PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { PMONITOR = m.get(); break; @@ -1075,7 +1075,7 @@ std::string CHyprDwindleLayout::getLayoutName() { } void CHyprDwindleLayout::onEnable() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden()) continue; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 9b3d02b4..f6339beb 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -591,7 +591,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { if (pWindow->m_bIsFloating) { // find whether there is a floating window below this one - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) { if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, @@ -611,7 +611,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { return PWINDOWCANDIDATE; // if not, floating window - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) return w; @@ -660,7 +660,7 @@ void IHyprLayout::requestFocusForWindow(PHLWINDOW pWindow) { Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // get all rules, see if we have any size overrides. Vector2D sizeOverride = {}; if (g_pCompositor->m_pLastMonitor) { - for (auto& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { + for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { if (r.szRule.starts_with("size")) { try { const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index d234d300..8fa324b0 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -172,7 +172,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire } else if (WINDOWSONWORKSPACE == 2) { // when dropping as the second tiled window in the workspace, // make it the master only if the cursor is on the master side of the screen - for (auto& nd : m_lMasterNodesData) { + for (auto const& nd : m_lMasterNodesData) { if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { switch (orientation) { case ORIENTATION_LEFT: @@ -619,7 +619,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { CMonitor* PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { PMONITOR = m.get(); break; @@ -1106,7 +1106,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto NEWFOCUS = newFocusToChild ? NEWCHILD : NEWMASTER; switchToWindow(NEWFOCUS); } else { - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) { const auto NEWMASTER = n.pWindow.lock(); switchWindows(NEWMASTER, NEWCHILD); @@ -1141,7 +1141,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri return 0; } else { // if master is focused keep master focused (don't do anything) - for (auto& n : m_lMasterNodesData) { + for (auto const& n : m_lMasterNodesData) { if (n.workspaceID == PMASTER->workspaceID && !n.isMaster) { switchToWindow(n.pWindow.lock()); break; @@ -1469,7 +1469,7 @@ Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { } void CHyprMasterLayout::onEnable() { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_bIsFloating || !w->m_bIsMapped || w->isHidden()) continue; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index e2e98735..e2fe7089 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -70,7 +70,7 @@ void CAnimationManager::tick() { std::vector animationEndedVars; - for (auto& av : m_vActiveAnimatedVariables) { + for (auto const& av : m_vActiveAnimatedVariables) { if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { av->warp(false); @@ -113,7 +113,7 @@ void CAnimationManager::tick() { g_pHyprRenderer->damageMonitor(PMONITOR); // TODO: just make this into a damn callback already vax... - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) continue; @@ -214,7 +214,7 @@ void CAnimationManager::tick() { PWINDOW->updateWindowDecos(); g_pHyprRenderer->damageWindow(PWINDOW); } else if (PWORKSPACE) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) continue; @@ -263,7 +263,7 @@ void CAnimationManager::tick() { } // do it here, because if this alters the animation vars deque we would be in trouble above. - for (auto& ave : animationEndedVars) { + for (auto const& ave : animationEndedVars) { ave->onAnimationEnd(); } } @@ -293,7 +293,7 @@ bool CAnimationManager::deltazero(const CColor& a, const CColor& b) { } bool CAnimationManager::bezierExists(const std::string& bezier) { - for (auto& [bc, bz] : m_mBezierCurves) { + for (auto const& [bc, bz] : m_mBezierCurves) { if (bc == bezier) return true; } diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 1c047f85..6f8292f7 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -193,7 +193,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { // fallback to a default if available constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; - for (auto& s : fallbackShapes) { + for (auto const& s : fallbackShapes) { m_sCurrentCursorShapeData = m_pHyprcursor->getShape(s, m_sCurrentStyleInfo); if (m_sCurrentCursorShapeData.images.size() > 0) @@ -288,7 +288,7 @@ void CCursorManager::updateTheme() { static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); float highestScale = 1.0; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->scale > highestScale) highestScale = m->scale; } @@ -307,7 +307,7 @@ void CCursorManager::updateTheme() { setCursorFromName("left_ptr"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { m->forceFullFrames = 5; g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } diff --git a/src/managers/HookSystemManager.cpp b/src/managers/HookSystemManager.cpp index 208c79ae..624d2fe1 100644 --- a/src/managers/HookSystemManager.cpp +++ b/src/managers/HookSystemManager.cpp @@ -30,7 +30,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal std::vector faultyHandles; volatile bool needsDeadCleanup = false; - for (auto& cb : *callbacks) { + for (auto const& cb : *callbacks) { m_bCurrentEventPlugin = false; @@ -70,7 +70,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal std::erase_if(*callbacks, [](const auto& fn) { return !fn.fn.lock(); }); if (!faultyHandles.empty()) { - for (auto& h : faultyHandles) + for (auto const& h : faultyHandles) g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9fac656c..df3f2572 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -908,7 +908,7 @@ uint64_t CKeybindManager::spawnRawProc(std::string args) { grandchild = fork(); if (grandchild == 0) { // run in grandchild - for (auto& e : HLENV) { + for (auto const& e : HLENV) { setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); @@ -1720,10 +1720,10 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { // we make a copy because changeWindowFloatingMode might invalidate the iterator std::deque ptrs; - for (auto& w : g_pCompositor->m_vWindows) + for (auto const& w : g_pCompositor->m_vWindows) ptrs.push_back(w); - for (auto& w : ptrs) { + for (auto const& w : ptrs) { if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE || w->isHidden()) continue; @@ -1895,7 +1895,7 @@ SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { const auto PMONITOR = g_pCompositor->m_pLastMonitor; auto specialOpenOnMonitor = PMONITOR->activeSpecialWorkspaceID(); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == workspaceID) { requestedWorkspaceIsAlreadyOpen = true; break; @@ -1922,7 +1922,7 @@ SDispatchResult CKeybindManager::toggleSpecialWorkspace(std::string args) { SDispatchResult CKeybindManager::forceRendererReload(std::string args) { bool overAgain = false; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!m->output) continue; @@ -2390,7 +2390,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { if (arg.find_first_of(' ') != std::string::npos) port = arg.substr(arg.find_first_of(' ') + 1); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!port.empty() && m->szName != port) continue; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 80f1ab4f..f0f74428 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -76,14 +76,14 @@ void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string m } void CPointerManager::lockSoftwareAll() { - for (auto& state : monitorStates) + for (auto const& state : monitorStates) state->softwareLocks++; updateCursorBackend(); } void CPointerManager::unlockSoftwareAll() { - for (auto& state : monitorStates) + for (auto const& state : monitorStates) state->softwareLocks--; updateCursorBackend(); @@ -261,7 +261,7 @@ void CPointerManager::resetCursorImage(bool apply) { damageIfSoftware(); if (currentCursorImage.surface) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { currentCursorImage.surface->resource()->leave(m); } @@ -306,7 +306,7 @@ void CPointerManager::resetCursorImage(bool apply) { void CPointerManager::updateCursorBackend() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); if (!m->m_bEnabled || !m->dpmsStatus) { @@ -600,7 +600,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { // static auto INSIDE_LAYOUT = [this](const CBox& box) -> bool { - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { if (box.inside(b)) return true; } @@ -608,7 +608,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { }; static auto INSIDE_LAYOUT_COORD = [this](const Vector2D& vec) -> bool { - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { if (b.containsPoint(vec)) return true; } @@ -619,7 +619,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { Vector2D leader; float distanceSq = __FLT_MAX__; - for (auto& b : currentMonitorLayout.monitorBoxes) { + for (auto const& b : currentMonitorLayout.monitorBoxes) { auto p = b.closestPoint(vec); auto distSq = p.distanceSq(vec); @@ -673,7 +673,7 @@ void CPointerManager::damageIfSoftware() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); - for (auto& mw : monitorStates) { + for (auto const& mw : monitorStates) { if (mw->monitor.expired()) continue; @@ -748,7 +748,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { if (POINTER->boundOutput == "entire") { // find x and y size of the entire space Vector2D bottomRight = {-9999999, -9999999}, topLeft = {9999999, 9999999}; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { const auto EXTENT = m->logicalBox().extent(); const auto POS = m->logicalBox().pos(); if (EXTENT.x > bottomRight.x) @@ -787,7 +787,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { void CPointerManager::onMonitorLayoutChange() { currentMonitorLayout.monitorBoxes.clear(); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->isMirror() || !m->m_bEnabled) continue; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6e5cd16f..bace4451 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -151,7 +151,7 @@ CProtocolManager::CProtocolManager() { PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); - for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index e296dcc8..3e4063f4 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -483,7 +483,7 @@ void CSeatManager::refocusGrab() { if (seatGrab->surfs.size() > 0) { // try to find a surf in focus first const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); - for (auto& s : seatGrab->surfs) { + for (auto const& s : seatGrab->surfs) { auto hlSurf = CWLSurface::fromResource(s.lock()); if (!hlSurf) continue; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 86108cac..81e22889 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -67,7 +67,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { m_pSessionLock.reset(); g_pInputManager->refocus(); - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pHyprRenderer->damageMonitor(m.get()); }); @@ -75,7 +75,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { m_pSessionLock.reset(); g_pCompositor->focusSurface(nullptr); - for (auto& m : g_pCompositor->m_vMonitors) + for (auto const& m : g_pCompositor->m_vMonitors) g_pHyprRenderer->damageMonitor(m.get()); }); @@ -90,7 +90,7 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64 if (!m_pSessionLock) return nullptr; - for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->iMonitorID == id) { if (sls->mapped) return sls.get(); diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 6f000f9f..7fc21a28 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -304,7 +304,7 @@ std::unordered_set CXCursorManager::themePaths(std::string const& t scanTheme(theme); while (!inherits.empty()) { auto oldInherits = inherits; - for (auto& i : oldInherits) + for (auto const& i : oldInherits) scanTheme(i); if (oldInherits.size() == inherits.size()) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 4654eeb7..b37e796b 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -255,7 +255,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { CMonitor* pMonitor = nullptr; double bestDistance = __FLT_MAX__; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize; double distance = diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index d1b85cf2..e9b0fa3e 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -19,7 +19,7 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent } CEventLoopManager::~CEventLoopManager() { - for (auto& eventSource : m_sWayland.aqEventSources) { + for (auto const& eventSource : m_sWayland.aqEventSources) { wl_event_source_remove(eventSource); } @@ -46,7 +46,7 @@ void CEventLoopManager::enterLoop() { m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); - for (auto& fd : aqPollFDs) { + for (auto const& fd : aqPollFDs) { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); } @@ -56,7 +56,7 @@ void CEventLoopManager::enterLoop() { } void CEventLoopManager::onTimerFire() { - for (auto& t : m_sTimers.timers) { + for (auto const& t : m_sTimers.timers) { if (t.strongRef() > 1 /* if it's 1, it was lost. Don't call it. */ && t->passed() && !t->cancelled()) t->call(t); } @@ -93,7 +93,7 @@ void CEventLoopManager::nudgeTimers() { long nextTimerUs = 10 * 1000 * 1000; // 10s - for (auto& t : m_sTimers.timers) { + for (auto const& t : m_sTimers.timers) { if (const auto µs = t->leftUs(); µs < nextTimerUs) nextTimerUs = µs; } @@ -122,7 +122,7 @@ void CEventLoopManager::doLater(const std::function& fn) { auto cpy = IDLE->fns; IDLE->fns.clear(); IDLE->eventSource = nullptr; - for (auto& c : cpy) { + for (auto const& c : cpy) { if (c) c(); } diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 4bcb4df3..a6f25142 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -49,7 +49,7 @@ void CInputManager::recheckIdleInhibitorStatus() { } // check manual user-set inhibitors - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE) continue; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index a4a63a84..6b04c13f 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1033,7 +1033,7 @@ void CInputManager::setupMouse(SP mauz) { } void CInputManager::setPointerConfigs() { - for (auto& m : m_vPointers) { + for (auto const& m : m_vPointers) { auto devname = m->hlName; const auto HASCONFIG = g_pConfigManager->deviceConfigExists(devname); @@ -1268,7 +1268,7 @@ void CInputManager::updateKeyboardsLeds(SP pKeyboard) { if (!leds.has_value()) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->updateLEDs(leds.value()); } } @@ -1402,7 +1402,7 @@ void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; - for (auto& c : m_vConstraints) { + for (auto const& c : m_vConstraints) { const auto C = c.lock(); if (!C) @@ -1416,7 +1416,7 @@ void CInputManager::unconstrainMouse() { } bool CInputManager::isConstrained() { - for (auto& c : m_vConstraints) { + for (auto const& c : m_vConstraints) { const auto C = c.lock(); if (!C) @@ -1434,7 +1434,7 @@ bool CInputManager::isConstrained() { void CInputManager::updateCapabilities() { uint32_t caps = 0; - for (auto& h : m_vHIDs) { + for (auto const& h : m_vHIDs) { if (h.expired()) continue; @@ -1449,7 +1449,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { uint32_t finalMask = 0; - for (auto& kb : m_vKeyboards) { + for (auto const& kb : m_vKeyboards) { if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb)) continue; @@ -1464,7 +1464,7 @@ uint32_t CInputManager::accumulateModsFromAllKBs() { void CInputManager::disableAllKeyboards(bool virt) { - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { if (k->isVirtual() != virt) continue; @@ -1540,13 +1540,13 @@ void CInputManager::setTouchDeviceConfigs(SP dev) { return; } - for (auto& m : m_vTouches) { + for (auto const& m : m_vTouches) { setConfig(m); } } void CInputManager::setTabletConfigs() { - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (t->aq()->getLibinputHandle()) { const auto NAME = t->hlName; const auto LIBINPUTDEV = t->aq()->getLibinputHandle(); @@ -1711,7 +1711,7 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { bool onDeco = false; - for (auto& wd : w->m_dWindowDecorations) { + for (auto const& wd : w->m_dWindowDecorations) { if (!(wd->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT)) continue; diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 7cfd54b4..1608e123 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -57,7 +57,7 @@ void CInputMethodRelay::onNewIME(SP pIME) { if (!g_pCompositor->m_pLastFocus) return; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (ti->client() != g_pCompositor->m_pLastFocus->client()) continue; @@ -80,7 +80,7 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() { if (!g_pCompositor->m_pLastFocus) return nullptr; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (ti->focusedSurface() == g_pCompositor->m_pLastFocus) return ti.get(); } @@ -101,7 +101,7 @@ void CInputMethodRelay::removeTextInput(CTextInput* pInput) { } void CInputMethodRelay::updateAllPopups() { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { p->onCommit(); } } @@ -138,7 +138,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { m_pLastKbFocus = pSurface; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (!ti->focusedSurface()) continue; @@ -148,7 +148,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { if (!pSurface) return; - for (auto& ti : m_vTextInputs) { + for (auto const& ti : m_vTextInputs) { if (!ti->isV3()) continue; @@ -160,7 +160,7 @@ void CInputMethodRelay::onKeyboardFocus(SP pSurface) { } CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { if (p->isVecInPopup(point)) return p.get(); } @@ -169,7 +169,7 @@ CInputPopup* CInputMethodRelay::popupFromCoords(const Vector2D& point) { } CInputPopup* CInputMethodRelay::popupFromSurface(const SP surface) { - for (auto& p : m_vIMEPopups) { + for (auto const& p : m_vIMEPopups) { if (p->getSurface() == surface) return p.get(); } diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 23d328bc..f33937e8 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -229,7 +229,7 @@ void CInputManager::newTablet(SP pDevice) { SP CInputManager::ensureTabletToolPresent(SP pTool) { - for (auto& t : m_vTabletTools) { + for (auto const& t : m_vTabletTools) { if (t->aq() == pTool) return t; } diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 398d4ce1..ef3ae06a 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -124,8 +124,8 @@ APICALL bool HyprlandAPI::removeWindowDecoration(HANDLE handle, IHyprWindowDecor if (!PLUGIN) return false; - for (auto& w : g_pCompositor->m_vWindows) { - for (auto& d : w->m_dWindowDecorations) { + for (auto const& w : g_pCompositor->m_vWindows) { + for (auto const& d : w->m_dWindowDecorations) { if (d.get() == pDecoration) { w->removeWindowDeco(pDecoration); return true; diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index 122faafd..0f1f97a2 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -98,27 +98,27 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) { exitFunc(); } - for (auto& [k, v] : plugin->registeredCallbacks) { + for (auto const& [k, v] : plugin->registeredCallbacks) { if (const auto SHP = v.lock()) g_pHookSystem->unhook(SHP); } const auto ls = plugin->registeredLayouts; - for (auto& l : ls) + for (auto const& l : ls) g_pLayoutManager->removeLayout(l); g_pFunctionHookSystem->removeAllHooksFrom(plugin->m_pHandle); const auto rd = plugin->registeredDecorations; - for (auto& d : rd) + for (auto const& d : rd) HyprlandAPI::removeWindowDecoration(plugin->m_pHandle, d); const auto rdi = plugin->registeredDispatchers; - for (auto& d : rdi) + for (auto const& d : rdi) HyprlandAPI::removeDispatcher(plugin->m_pHandle, d); const auto rhc = plugin->registeredHyprctlCommands; - for (auto& c : rhc) + for (auto const& c : rhc) HyprlandAPI::unregisterHyprCtlCommand(plugin->m_pHandle, c); g_pConfigManager->removePluginConfig(plugin->m_pHandle); @@ -139,7 +139,7 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) { } void CPluginSystem::unloadAllPlugins() { - for (auto& p : m_vLoadedPlugins | std::views::reverse) + for (auto const& p : m_vLoadedPlugins | std::views::reverse) unloadPlugin(p.get(), false); // Unload remaining plugins gracefully } @@ -147,7 +147,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vector failures; // unload all plugins that are no longer present - for (auto& p : m_vLoadedPlugins | std::views::reverse) { + for (auto const& p : m_vLoadedPlugins | std::views::reverse) { if (p->m_bLoadedWithConfig && std::find(plugins.begin(), plugins.end(), p->path) == plugins.end()) { Debug::log(LOG, "Unloading plugin {} which is no longer present in config", p->path); unloadPlugin(p.get(), false); @@ -156,7 +156,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vectorpath == path; }) == m_vLoadedPlugins.end()) { Debug::log(LOG, "Loading plugin {} which is now present in config", path); const auto plugin = loadPlugin(path); @@ -173,7 +173,7 @@ std::vector CPluginSystem::updateConfigPlugins(const std::vectorpath == path) return p.get(); } @@ -182,7 +182,7 @@ CPlugin* CPluginSystem::getPluginByPath(const std::string& path) { } CPlugin* CPluginSystem::getPluginByHandle(HANDLE handle) { - for (auto& p : m_vLoadedPlugins) { + for (auto const& p : m_vLoadedPlugins) { if (p->m_pHandle == handle) return p.get(); } diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index f906740c..37f2e2eb 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -14,7 +14,7 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPparent; requested = request->requested; - for (auto& m : requested) { + for (auto const& m : requested) { if (!m->monitor || m->monitor->isBeingLeased) { LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null")); resource->sendFinished(); @@ -26,14 +26,14 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPmonitor->szName); } return roll; }()); std::vector> outputs; - for (auto& m : requested) { + for (auto const& m : requested) { outputs.emplace_back(m->monitor->output); } @@ -184,7 +184,7 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc resource->sendDrmFd(fd); close(fd); - for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) { + for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { sendConnector(m.lock()); } @@ -234,7 +234,7 @@ CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backe } CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { - for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; @@ -292,7 +292,7 @@ void CDRMLeaseProtocol::offer(SP monitor) { primaryDevice->offeredOutputs.emplace_back(monitor); - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->sendConnector(monitor); m->resource->sendDone(); } diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index dce64508..d2d06644 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -37,7 +37,7 @@ void CWLRDataOffer::sendData() { if (!source) return; - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { resource->sendOffer(m.c_str()); } } @@ -191,7 +191,7 @@ CWLRDataControlManagerResource::CWLRDataControlManagerResource(SPself = RESOURCE; device = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 2d6b2ee2..aff232e4 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -103,7 +103,7 @@ void CFocusGrab::refocusKeyboard() { return; SP surface = nullptr; - for (auto& [surf, state] : m_mSurfaces) { + for (auto const& [surf, state] : m_mSurfaces) { if (state->state == CFocusGrabSurfaceState::Comitted) { surface = surf.lock(); break; diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 59888ce2..1f8cbcbe 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -30,7 +30,7 @@ CForeignToplevelList::CForeignToplevelList(SP resourc LOGM(LOG, "CForeignToplevelList: finished"); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; @@ -112,19 +112,19 @@ bool CForeignToplevelList::good() { CForeignToplevelProtocol::CForeignToplevelProtocol(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) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onMap(std::any_cast(data)); } }); static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onUnmap(std::any_cast(data)); } }); static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { - for (auto& m : m_vManagers) { + for (auto const& m : m_vManagers) { m->onTitle(std::any_cast(data)); } }); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index bd597a91..291969db 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -179,7 +179,7 @@ CForeignToplevelWlrManager::CForeignToplevelWlrManager(SPonManagerResourceDestroy(this); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->m_bFadingOut) continue; @@ -313,42 +313,42 @@ bool CForeignToplevelWlrManager::good() { 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) { + for (auto const& 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) { + for (auto const& 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) { + for (auto const& 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) { + for (auto const& 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(std::any_cast>(data).at(0)); - for (auto& m : m_vManagers) { + for (auto const& 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) { + for (auto const& m : m_vManagers) { m->onFullscreen(PWINDOW); } }); @@ -374,7 +374,7 @@ void CForeignToplevelWlrProtocol::destroyHandle(CForeignToplevelHandleWlr* handl } PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) { - for (auto& h : m_vHandles) { + for (auto const& h : m_vHandles) { if (h->res() != res) continue; diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index d39fa67c..d8010eac 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -24,7 +24,7 @@ void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { } void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, SP surface) { - for (auto& [k, v] : m_mAddons) { + for (auto const& [k, v] : m_mAddons) { if (k == surface) { LOGM(ERR, "Surface {:x} already has a fractionalScale addon", (uintptr_t)surface.get()); pMgr->error(WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale already exists"); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index c902d00e..cb75a202 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -25,7 +25,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out return; } - for (auto& g : PROTO::gamma->m_vGammaControllers) { + for (auto const& g : PROTO::gamma->m_vGammaControllers) { if (g->pMonitor == pMonitor) { resource->sendFailed(); return; @@ -180,7 +180,7 @@ void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, } void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) { - for (auto& g : m_vGammaControllers) { + for (auto const& g : m_vGammaControllers) { if (g->getMonitor() != pMonitor) continue; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 92bfbae4..b02126ef 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -54,8 +54,8 @@ void CGlobalShortcutsProtocol::destroyResource(CShortcutClient* client) { } bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { return true; } @@ -66,8 +66,8 @@ bool CGlobalShortcutsProtocol::isTaken(std::string appid, std::string trigger) { } void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) { - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { if (sh->appid == appid && sh->id == trigger) { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -84,8 +84,8 @@ void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::s std::vector CGlobalShortcutsProtocol::getAllShortcuts() { std::vector copy; - for (auto& c : m_vClients) { - for (auto& sh : c->shortcuts) { + for (auto const& c : m_vClients) { + for (auto const& sh : c->shortcuts) { copy.push_back(*sh); } } diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 8d915ac6..3517a62d 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -86,14 +86,14 @@ void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t i } void CIdleNotifyProtocol::onActivity() { - for (auto& n : m_vNotifications) { + for (auto const& n : m_vNotifications) { n->onActivity(); } } void CIdleNotifyProtocol::setInhibit(bool inhibited) { isInhibited = inhibited; - for (auto& n : m_vNotifications) { + for (auto const& n : m_vNotifications) { n->onActivity(); } } \ No newline at end of file diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index a0820e0b..5fd1e893 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -268,7 +268,7 @@ wl_client* CInputMethodV2::grabClient() { if (grabs.empty()) return nullptr; - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -282,7 +282,7 @@ wl_client* CInputMethodV2::grabClient() { void CInputMethodV2::sendInputRectangle(const CBox& box) { inputRectangle = box; - for (auto& wp : popups) { + for (auto const& wp : popups) { auto p = wp.lock(); if (!p) @@ -293,7 +293,7 @@ void CInputMethodV2::sendInputRectangle(const CBox& box) { } void CInputMethodV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -304,7 +304,7 @@ void CInputMethodV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state } void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) @@ -315,7 +315,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc } void CInputMethodV2::setKeyboard(SP keyboard) { - for (auto& gw : grabs) { + for (auto const& gw : grabs) { auto g = gw.lock(); if (!g) diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 32625792..d9dd1d01 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -31,8 +31,8 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec size_t i = 0; rendererTranche.indicies.clear(); - for (auto& fmt : rendererTranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : rendererTranche.formats) { + for (auto const& mod : fmt.modifiers) { auto format = std::make_pair<>(fmt.drmFormat, mod); auto [_, inserted] = formats.insert(format); if (inserted) { @@ -53,8 +53,8 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec for (auto& [monitor, tranche] : monitorTranches) { tranche.indicies.clear(); - for (auto& fmt : tranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : tranche.formats) { + for (auto const& mod : fmt.modifiers) { // apparently these can implode on planes, so dont use them if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) continue; @@ -270,7 +270,7 @@ bool CLinuxDMABBUFParamsResource::verify() { } bool empty = false; - for (auto& plane : attrs->fds) { + for (auto const& plane : attrs->fds) { if (empty && plane != -1) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT, "Gap in planes"); return false; @@ -402,8 +402,8 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { - for (auto& mod : fmt.modifiers) { + for (auto const& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto const& mod : fmt.modifiers) { if (resource->version() < 3) { if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) resource->sendFormat(fmt.drmFormat); @@ -442,7 +442,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const // this assumes there's only 1 device used for both scanout and rendering // also that each monitor never changes its primary plane - for (auto& mon : g_pCompositor->m_vMonitors) { + for (auto const& mon : g_pCompositor->m_vMonitors) { auto tranche = SDMABUFTranche{ .device = mainDevice, .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, @@ -505,7 +505,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { // this might be a big copy auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); - for (auto& feedback : m_vFeedbacks) { + for (auto const& feedback : m_vFeedbacks) { feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { SP mon; @@ -562,7 +562,7 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { SP feedbackResource; - for (auto& f : m_vFeedbacks) { + for (auto const& f : m_vFeedbacks) { if (f->surface != surface) continue; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 9fcd5f9b..b4efd2c8 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -60,11 +60,11 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { uint64_t mod = DRM_FORMAT_MOD_INVALID; auto fmts = g_pHyprOpenGL->getDRMFormats(); - for (auto& f : fmts) { + for (auto const& f : fmts) { if (f.drmFormat != fmt) continue; - for (auto& m : f.modifiers) { + for (auto const& m : f.modifiers) { if (m == DRM_FORMAT_MOD_LINEAR) continue; @@ -100,7 +100,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME); auto fmts = g_pHyprOpenGL->getDRMFormats(); - for (auto& fmt : fmts) { + for (auto const& fmt : fmts) { resource->sendFormat(fmt.drmFormat); } } diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index cfe388fa..09552b19 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -28,7 +28,7 @@ COutputManager::COutputManager(SP resource_) : resource(re }); // send all heads at start - for (auto& m : g_pCompositor->m_vRealMonitors) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { if (m.get() == g_pCompositor->m_pUnsafeOutput) continue; @@ -67,7 +67,7 @@ void COutputManager::ensureMonitorSent(CMonitor* pMonitor) { if (pMonitor == g_pCompositor->m_pUnsafeOutput) return; - for (auto& hw : heads) { + for (auto const& hw : heads) { auto h = hw.lock(); if (!h) @@ -96,7 +96,7 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any d) { resource->sendFinished(); - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -106,7 +106,7 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : } pMonitor = nullptr; - for (auto& m : PROTO::outputManagement->m_vManagers) { + for (auto const& m : PROTO::outputManagement->m_vManagers) { m->sendDone(); } }); @@ -147,7 +147,7 @@ void COutputHead::sendAllData() { if (modes.empty()) { if (!pMonitor->output->modes.empty()) { - for (auto& m : pMonitor->output->modes) { + for (auto const& m : pMonitor->output->modes) { makeAndSendNewMode(m); } } else if (pMonitor->output->state->state().customMode) { @@ -158,7 +158,7 @@ void COutputHead::sendAllData() { // send current mode if (pMonitor->m_bEnabled) { - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -189,7 +189,7 @@ void COutputHead::updateMode() { resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED); if (pMonitor->m_bEnabled) { - for (auto& mw : modes) { + for (auto const& mw : modes) { auto m = mw.lock(); if (!m) @@ -346,7 +346,7 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { LOGM(LOG, "Applying configuration"); - for (auto& headw : heads) { + for (auto const& headw : heads) { auto head = headw.lock(); if (!head) @@ -577,15 +577,15 @@ void COutputManagementProtocol::destroyResource(COutputConfigurationHead* resour } void COutputManagementProtocol::updateAllOutputs() { - for (auto& m : g_pCompositor->m_vRealMonitors) { - for (auto& mgr : m_vManagers) { + for (auto const& m : g_pCompositor->m_vRealMonitors) { + for (auto const& mgr : m_vManagers) { mgr->ensureMonitorSent(m.get()); } } } SP COutputManagementProtocol::headFromResource(wl_resource* r) { - for (auto& h : m_vHeads) { + for (auto const& h : m_vHeads) { if (h->resource->resource() == r) return h; } @@ -594,7 +594,7 @@ SP COutputManagementProtocol::headFromResource(wl_resource* r) { } SP COutputManagementProtocol::modeFromResource(wl_resource* r) { - for (auto& h : m_vModes) { + for (auto const& h : m_vModes) { if (h->resource->resource() == r) return h; } diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index c83e3887..4eb74102 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -111,7 +111,7 @@ void CPointerGesturesProtocol::swipeBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -125,7 +125,7 @@ void CPointerGesturesProtocol::swipeUpdate(uint32_t timeMs, const Vector2D& delt const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -141,7 +141,7 @@ void CPointerGesturesProtocol::swipeEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vSwipes) { + for (auto const& sw : m_vSwipes) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -157,7 +157,7 @@ void CPointerGesturesProtocol::pinchBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -171,7 +171,7 @@ void CPointerGesturesProtocol::pinchUpdate(uint32_t timeMs, const Vector2D& delt const auto FOCUSEDCLIENT = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -187,7 +187,7 @@ void CPointerGesturesProtocol::pinchEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vPinches) { + for (auto const& sw : m_vPinches) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -203,7 +203,7 @@ void CPointerGesturesProtocol::holdBegin(uint32_t timeMs, uint32_t fingers) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vHolds) { + for (auto const& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) continue; @@ -219,7 +219,7 @@ void CPointerGesturesProtocol::holdEnd(uint32_t timeMs, bool cancelled) { const auto SERIAL = g_pSeatManager->nextSerial(g_pSeatManager->state.pointerFocusResource.lock()); - for (auto& sw : m_vHolds) { + for (auto const& sw : m_vHolds) { if (sw->resource->client() != FOCUSEDCLIENT) continue; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 638435c7..b1108042 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -114,11 +114,11 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint when = &now; } - for (auto& feedback : m_vFeedbacks) { + for (auto const& feedback : m_vFeedbacks) { if (!feedback->surface) continue; - for (auto& data : m_vQueue) { + for (auto const& data : m_vQueue) { if (!data->surface || data->surface != feedback->surface) continue; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 4fede706..f1db2d65 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -38,7 +38,7 @@ void CPrimarySelectionOffer::sendData() { if (!source) return; - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { resource->sendOffer(m.c_str()); } } @@ -177,7 +177,7 @@ CPrimarySelectionManager::CPrimarySelectionManager(SPself = RESOURCE; device = RESOURCE; - for (auto& s : sources) { + for (auto const& s : sources) { if (!s) continue; s->device = RESOURCE; @@ -272,7 +272,7 @@ void CPrimarySelectionProtocol::sendSelectionToDevice(SP source) { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { if (o->source && o->source->hasDnd()) continue; o->dead = true; @@ -321,7 +321,7 @@ void CPrimarySelectionProtocol::updateSelection() { } void CPrimarySelectionProtocol::onPointerFocus() { - for (auto& o : m_vOffers) { + for (auto const& o : m_vOffers) { o->dead = true; } diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index e4818758..16248c02 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -65,7 +65,7 @@ void CRelativePointerProtocol::sendRelativeMotion(uint64_t time, const Vector2D& const auto FOCUSED = g_pSeatManager->state.pointerFocusResource->client(); - for (auto& rp : m_vRelativePointers) { + for (auto const& rp : m_vRelativePointers) { if (FOCUSED != rp->client()) continue; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 1559476b..63024541 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -155,7 +155,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ lockedSWCursors = true; // TODO: make it per-monitor if (!PROTO::screencopy->m_bTimerArmed) { - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pPointerManager->lockSoftwareForMonitor(m); } PROTO::screencopy->m_bTimerArmed = true; @@ -365,7 +365,7 @@ CScreencopyProtocol::CScreencopyProtocol(const wl_interface* iface, const int& v std::nullopt, [this](SP self, void* data) { // TODO: make it per-monitor - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { g_pPointerManager->unlockSoftwareForMonitor(m); } m_bTimerArmed = false; @@ -411,7 +411,7 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { std::vector> framesToRemove; // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { + for (auto const& f : m_vFramesAwaitingWrite) { if (!f->pMonitor || !f->buffer) { framesToRemove.push_back(f); continue; @@ -428,7 +428,7 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { framesToRemove.push_back(f); } - for (auto& f : framesToRemove) { + for (auto const& f : framesToRemove) { destroyResource(f.get()); } } diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index fe44face..b1f701bf 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -187,7 +187,7 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get(); SP sessionLock; - for (auto& l : m_vLocks) { + for (auto const& l : m_vLocks) { if (l->resource.get() == lock) { sessionLock = l; break; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index e4424ed7..308b385d 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -48,7 +48,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa SP surf = CWLSurfaceResource::fromResource(surface); const auto CLIENT = pMgr->client(); - for (auto& in : m_vInhibitors) { + for (auto const& in : m_vInhibitors) { if (in->surface() != surf) continue; @@ -74,7 +74,7 @@ bool CKeyboardShortcutsInhibitProtocol::isInhibited() { if (const auto PWINDOW = g_pCompositor->getWindowFromSurface(g_pCompositor->m_pLastFocus.lock()); PWINDOW && PWINDOW->m_sWindowData.noShortcutsInhibit.valueOrDefault()) return false; - for (auto& in : m_vInhibitors) { + for (auto const& in : m_vInhibitors) { if (in->surface() != g_pCompositor->m_pLastFocus) continue; diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index b974152e..d7f741b9 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -96,7 +96,7 @@ bool CTabletPadV2Resource::good() { void CTabletPadV2Resource::sendData() { // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - for (auto& p : pad->aq()->paths) { + for (auto const& p : pad->aq()->paths) { resource->sendPath(p.c_str()); } @@ -140,7 +140,7 @@ void CTabletV2Resource::sendData() { resource->sendName(tablet->deviceName.c_str()); resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID); - for (auto& p : tablet->aq()->paths) { + for (auto const& p : tablet->aq()->paths) { resource->sendPath(p.c_str()); } @@ -287,21 +287,21 @@ void CTabletSeat::sendTablet(SP tablet) { } void CTabletSeat::sendData() { - for (auto& tw : PROTO::tablet->tablets) { + for (auto const& tw : PROTO::tablet->tablets) { if (tw.expired()) continue; sendTablet(tw.lock()); } - for (auto& tw : PROTO::tablet->tools) { + for (auto const& tw : PROTO::tablet->tools) { if (tw.expired()) continue; sendTool(tw.lock()); } - for (auto& tw : PROTO::tablet->pads) { + for (auto const& tw : PROTO::tablet->pads) { if (tw.expired()) continue; @@ -367,7 +367,7 @@ void CTabletV2Protocol::onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_res } void CTabletV2Protocol::registerDevice(SP tablet) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendTablet(tablet); } @@ -375,7 +375,7 @@ void CTabletV2Protocol::registerDevice(SP tablet) { } void CTabletV2Protocol::registerDevice(SP tool) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendTool(tool); } @@ -383,7 +383,7 @@ void CTabletV2Protocol::registerDevice(SP tool) { } void CTabletV2Protocol::registerDevice(SP pad) { - for (auto& s : m_vSeats) { + for (auto const& s : m_vSeats) { s->sendPad(pad); } @@ -391,7 +391,7 @@ void CTabletV2Protocol::registerDevice(SP pad) { } void CTabletV2Protocol::unregisterDevice(SP tablet) { - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (t->tablet == tablet) { t->resource->sendRemoved(); t->inert = true; @@ -401,7 +401,7 @@ void CTabletV2Protocol::unregisterDevice(SP tablet) { } void CTabletV2Protocol::unregisterDevice(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool == tool) { t->resource->sendRemoved(); t->inert = true; @@ -411,7 +411,7 @@ void CTabletV2Protocol::unregisterDevice(SP tool) { } void CTabletV2Protocol::unregisterDevice(SP pad) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad == pad) { t->resource->sendRemoved(); t->inert = true; @@ -426,7 +426,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { std::erase_if(pads, [](const auto& e) { return e.expired(); }); // now we need to send removed events - for (auto& t : m_vTablets) { + for (auto const& t : m_vTablets) { if (!t->tablet.expired() || t->inert) continue; @@ -434,7 +434,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { t->inert = true; } - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (!t->tool.expired() || t->inert) continue; @@ -448,7 +448,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { t->inert = true; } - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (!t->pad.expired() || t->inert) continue; @@ -458,7 +458,7 @@ void CTabletV2Protocol::recheckRegisteredDevices() { } void CTabletV2Protocol::pressure(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -468,7 +468,7 @@ void CTabletV2Protocol::pressure(SP tool, double value) { } void CTabletV2Protocol::distance(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -478,7 +478,7 @@ void CTabletV2Protocol::distance(SP tool, double value) { } void CTabletV2Protocol::rotation(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -488,7 +488,7 @@ void CTabletV2Protocol::rotation(SP tool, double value) { } void CTabletV2Protocol::slider(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -498,7 +498,7 @@ void CTabletV2Protocol::slider(SP tool, double value) { } void CTabletV2Protocol::wheel(SP tool, double value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -508,7 +508,7 @@ void CTabletV2Protocol::wheel(SP tool, double value) { } void CTabletV2Protocol::tilt(SP tool, const Vector2D& value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -518,7 +518,7 @@ void CTabletV2Protocol::tilt(SP tool, const Vector2D& value) { } void CTabletV2Protocol::up(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -528,7 +528,7 @@ void CTabletV2Protocol::up(SP tool) { } void CTabletV2Protocol::down(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -545,7 +545,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP SP toolResource; SP tabletResource; - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || t->resource->client() != CLIENT) continue; @@ -559,7 +559,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP toolResource = t; - for (auto& tab : m_vTablets) { + for (auto const& tab : m_vTablets) { if (tab->tablet != tablet) continue; @@ -587,7 +587,7 @@ void CTabletV2Protocol::proximityIn(SP tool, SP tablet, SP } void CTabletV2Protocol::proximityOut(SP tool) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -599,7 +599,7 @@ void CTabletV2Protocol::proximityOut(SP tool) { } void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32_t state) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -610,7 +610,7 @@ void CTabletV2Protocol::buttonTool(SP tool, uint32_t button, uint32 } void CTabletV2Protocol::motion(SP tool, const Vector2D& value) { - for (auto& t : m_vTools) { + for (auto const& t : m_vTools) { if (t->tool != tool || !t->current) continue; @@ -620,7 +620,7 @@ void CTabletV2Protocol::motion(SP tool, const Vector2D& value) { } void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, uint32_t timeMs) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad != pad) continue; if (t->groups.size() <= group) { @@ -633,7 +633,7 @@ void CTabletV2Protocol::mode(SP pad, uint32_t group, uint32_t mode, } void CTabletV2Protocol::buttonPad(SP pad, uint32_t button, uint32_t timeMs, uint32_t state) { - for (auto& t : m_vPads) { + for (auto const& t : m_vPads) { if (t->pad != pad) continue; t->resource->sendButton(timeMs, button, zwpTabletToolV2ButtonState{state}); diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index 7f3c0a18..66a4efd2 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -38,7 +38,7 @@ void CTearingControlProtocol::onControllerDestroy(CTearingControl* control) { } void CTearingControlProtocol::onWindowDestroy(PHLWINDOW pWindow) { - for (auto& c : m_vTearingControllers) { + for (auto const& c : m_vTearingControllers) { if (c->pWindow.lock() == pWindow) c->pWindow.reset(); } @@ -52,7 +52,7 @@ CTearingControl::CTearingControl(SP resource_, SPsetDestroy([this](CWpTearingControlV1* res) { PROTO::tearing->onControllerDestroy(this); }); resource->setSetPresentationHint([this](CWpTearingControlV1* res, wpTearingControlV1PresentationHint hint) { this->onHint(hint); }); - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWLSurface->resource() == surf_) { pWindow = w; break; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 916f7395..b28a827a 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -369,7 +369,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { std::vector> framesToRemove; // share frame if correct output - for (auto& f : m_vFramesAwaitingWrite) { + for (auto const& f : m_vFramesAwaitingWrite) { if (!f->pWindow || !validMapped(f->pWindow)) { framesToRemove.push_back(f); continue; @@ -393,13 +393,13 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { framesToRemove.push_back(f); } - for (auto& f : framesToRemove) { + for (auto const& f : framesToRemove) { destroyResource(f.get()); } } void CToplevelExportProtocol::onWindowUnmap(PHLWINDOW pWindow) { - for (auto& f : m_vFrames) { + for (auto const& f : m_vFrames) { if (f->pWindow == pWindow) f->pWindow.reset(); } diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 27a4f248..bb51315d 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -108,7 +108,7 @@ void CVirtualKeyboardV1Resource::releasePressed() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - for (auto& p : pressed) { + for (auto const& p : pressed) { events.key.emit(IKeyboard::SKeyEvent{ .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000, .keycode = p, diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 9c2c353c..5d620667 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -39,7 +39,7 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - for (auto& o : m_vXDGOutputs) { + for (auto const& o : m_vXDGOutputs) { if (o->monitor == PMONITOR) o->monitor = nullptr; } @@ -84,7 +84,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 } void CXDGOutputProtocol::updateAllOutputs() { - for (auto& o : m_vXDGOutputs) { + for (auto const& o : m_vXDGOutputs) { if (!o->monitor) continue; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index eaf5c333..39a511c3 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -388,7 +388,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPm_vWindows.emplace_back(CWindow::create(self.lock())); - for (auto& p : popups) { + for (auto const& p : popups) { if (!p) continue; events.newPopup.emit(p); @@ -714,7 +714,7 @@ CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, grab->keyboard = true; grab->pointer = true; grab->setCallback([this]() { - for (auto& g : grabbed) { + for (auto const& g : grabbed) { g->done(); } grabbed.clear(); @@ -779,7 +779,7 @@ void CXDGShellProtocol::addOrStartGrab(SP popup) { void CXDGShellProtocol::onPopupDestroy(WP popup) { if (popup == grabOwner) { g_pSeatManager->setGrab(nullptr); - for (auto& g : grabbed) { + for (auto const& g : grabbed) { g->done(); } grabbed.clear(); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 75f1e646..f7f6dcda 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -241,7 +241,7 @@ void CWLSurfaceResource::frame(timespec* now) { if (callbacks.empty()) return; - for (auto& c : callbacks) { + for (auto const& c : callbacks) { c->send(now); } @@ -257,7 +257,7 @@ void CWLSurfaceResource::bfHelper(std::vector> nodes, std std::vector> nodes2; // first, gather all nodes below - for (auto& n : nodes) { + for (auto const& n : nodes) { std::erase_if(n->subsurfaces, [](const auto& e) { return e.expired(); }); // subsurfaces is sorted lowest -> highest for (auto const& c : n->subsurfaces) { @@ -310,7 +310,7 @@ std::pair, Vector2D> CWLSurfaceResource::at(const Vector2 void* data) { ((std::vector, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, &surfs); - for (auto& [surf, pos] : surfs | std::views::reverse) { + for (auto const& [surf, pos] : surfs | std::views::reverse) { if (!allowsInput) { const auto BOX = CBox{pos, surf->current.size}; if (BOX.containsPoint(localCoords)) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 943c790f..b7640af3 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -80,7 +80,7 @@ void CWLDataOfferResource::sendData() { resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); } - for (auto& m : source->mimes()) { + for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); resource->sendOffer(m.c_str()); } diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index bcf62fae..394dc8e2 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -65,7 +65,7 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) { listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) { - for (auto& o : m_vOutputs) { + for (auto const& o : m_vOutputs) { o->updateState(); } }); @@ -95,7 +95,7 @@ void CWLOutputProtocol::destroyResource(CWLOutputResource* resource) { } SP CWLOutputProtocol::outputResourceFrom(wl_client* client) { - for (auto& r : m_vOutputs) { + for (auto const& r : m_vOutputs) { if (r->client() != client) continue; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index f7764389..6ae0ddc4 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -525,7 +525,7 @@ void CWLSeatProtocol::updateCapabilities(uint32_t caps) { currentCaps = caps; - for (auto& s : m_vSeatResources) { + for (auto const& s : m_vSeatResources) { s->sendCapabilities(caps); } } @@ -534,7 +534,7 @@ void CWLSeatProtocol::updateKeymap() { if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->sendKeymap(g_pSeatManager->keyboard.lock()); } } @@ -543,13 +543,13 @@ void CWLSeatProtocol::updateRepeatInfo(uint32_t rate, uint32_t delayMs) { if (!(currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - for (auto& k : m_vKeyboards) { + for (auto const& k : m_vKeyboards) { k->repeatInfo(rate, delayMs); } } SP CWLSeatProtocol::seatResourceForClient(wl_client* client) { - for (auto& r : m_vSeatResources) { + for (auto const& r : m_vSeatResources) { if (r->client() == client) return r; } diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 9996a607..b09326bd 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -171,7 +171,7 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { }); // send a few supported formats. No need for any other I think? - for (auto& s : PROTO::shm->shmFormats) { + for (auto const& s : PROTO::shm->shmFormats) { resource->sendFormat((wl_shm_format)s); } } @@ -193,7 +193,7 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, }; - for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) { + for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) { if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) continue; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index e0679eff..46e20305 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -22,7 +22,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP void { - for (auto& c : parent->subsurfaces) { + for (auto const& c : parent->subsurfaces) { if (c->zIndex >= idx) c->zIndex++; } @@ -53,7 +53,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP void { - for (auto& c : parent->subsurfaces) { + for (auto const& c : parent->subsurfaces) { if (c->zIndex <= idx) c->zIndex--; } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 2aeda8be..67c11c23 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -213,7 +213,7 @@ EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { return EGL_NO_DEVICE_EXT; } - for (auto& d : devices) { + for (auto const& d : devices) { auto devName = m_sProc.eglQueryDeviceStringEXT(d, EGL_DRM_DEVICE_FILE_EXT); if (!devName) continue; @@ -435,7 +435,7 @@ void CHyprOpenGLImpl::initDRMFormats() { std::vector dmaFormats; - for (auto& fmt : formats) { + for (auto const& fmt : formats) { std::vector mods; if (!DISABLE_MODS) { auto ret = getModsForFormat(fmt); @@ -460,7 +460,7 @@ void CHyprOpenGLImpl::initDRMFormats() { auto fmtName = drmGetFormatName(fmt); Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); - for (auto& mod : mods) { + for (auto const& mod : mods) { auto modName = drmGetFormatModifierName(mod); modifierData.emplace_back(std::make_pair<>(mod, modName ? modName : "?unknown?")); free(modName); @@ -476,7 +476,7 @@ void CHyprOpenGLImpl::initDRMFormats() { return true; }); - for (auto& [m, name] : modifierData) { + for (auto const& [m, name] : modifierData) { Debug::log(LOG, "EGL: | with modifier {} (0x{:x})", name, m); mods.emplace_back(m); } @@ -654,7 +654,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (!pMonitor->solitaryClient.expired()) return false; - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; if (ls->forceBlur && !XRAYMODE) return true; @@ -663,7 +663,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return true; } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; if (ls->forceBlur && !XRAYMODE) return true; @@ -673,7 +673,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { } // these two block optimization - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { if (ls->forceBlur) return true; @@ -681,7 +681,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return true; } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { if (ls->forceBlur) return true; @@ -704,7 +704,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { if (*PXRAY) return false; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden()) continue; @@ -1168,7 +1168,7 @@ void CHyprOpenGLImpl::clear(const CColor& color) { glClearColor(color.r, color.g, color.b, color.a); if (!m_RenderData.damage.empty()) { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glClear(GL_COLOR_BUFFER_BIT); } @@ -1327,13 +1327,13 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion damageClip.intersect(*damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : damage->getRects()) { + for (auto const& RECT : damage->getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1523,13 +1523,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB damageClip.intersect(*damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : damage->getRects()) { + for (auto const& RECT : damage->getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1582,7 +1582,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1640,7 +1640,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1725,7 +1725,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURPREPARE.texAttrib); if (!damage.empty()) { - for (auto& RECT : damage.getRects()) { + for (auto const& RECT : damage.getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1778,7 +1778,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(pShader->texAttrib); if (!pDamage->empty()) { - for (auto& RECT : pDamage->getRects()) { + for (auto const& RECT : pDamage->getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1848,7 +1848,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBLURFINISH.texAttrib); if (!damage.empty()) { - for (auto& RECT : damage.getRects()) { + for (auto const& RECT : damage.getRects()) { scissor(&RECT, false /* this region is already transformed */); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -1924,7 +1924,7 @@ void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { }; bool hasWindows = false; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pMonitor->activeWorkspace && !w->isHidden() && w->m_bIsMapped && (!w->m_bIsFloating || *PBLURXRAY)) { // check if window is valid @@ -2215,13 +2215,13 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in damageClip.intersect(m_RenderData.damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -2512,13 +2512,13 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const damageClip.intersect(m_RenderData.damage); if (!damageClip.empty()) { - for (auto& RECT : damageClip.getRects()) { + for (auto const& RECT : damageClip.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } else { - for (auto& RECT : m_RenderData.damage.getRects()) { + for (auto const& RECT : m_RenderData.damage.getRects()) { scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } @@ -2928,7 +2928,7 @@ void SRenderModifData::applyToBox(CBox& box) { if (!enabled) return; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: box.scale(std::any_cast(val)); break; @@ -2953,7 +2953,7 @@ void SRenderModifData::applyToRegion(CRegion& rg) { if (!enabled) return; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: rg.scale(std::any_cast(val)); break; @@ -2971,7 +2971,7 @@ float SRenderModifData::combinedScale() { return 1; float scale = 1.f; - for (auto& [type, val] : modifs) { + for (auto const& [type, val] : modifs) { try { switch (type) { case RMOD_TYPE_SCALE: scale *= std::any_cast(val); break; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2ef7e208..c601e369 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -35,7 +35,7 @@ static int cursorTicker(void* data) { CHyprRenderer::CHyprRenderer() { if (g_pCompositor->m_pAqBackend->hasSession()) { - for (auto& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { + for (auto const& dev : g_pCompositor->m_pAqBackend->session->sessionDevices) { const auto DRMV = drmGetVersion(dev->fd); if (!DRMV) continue; @@ -348,7 +348,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); // loop over the tiled windows that are fading out - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!shouldRenderWindow(w, pMonitor)) continue; @@ -365,7 +365,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // and floating ones too - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!shouldRenderWindow(w, pMonitor)) continue; @@ -385,7 +385,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // TODO: this pass sucks - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { const auto PWORKSPACE = w->m_pWorkspace; if (w->m_pWorkspace != pWorkspace || !w->isFullscreen()) { @@ -418,7 +418,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } // then render windows over fullscreen. - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) continue; @@ -438,7 +438,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); // Non-floating main - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -465,7 +465,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); // Non-floating popup - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -483,7 +483,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor } // floating on top - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; @@ -585,20 +585,20 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (TRANSFORMERSPRESENT) { g_pHyprOpenGL->bindOffMain(); - for (auto& t : pWindow->m_vTransformers) { + for (auto const& t : pWindow->m_vTransformers) { t->preWindowRender(&renderdata); } } if (renderdata.decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_BOTTOM) continue; wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha); } - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_UNDER) continue; @@ -625,7 +625,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; if (renderdata.decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_OVER) continue; @@ -636,7 +636,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (TRANSFORMERSPRESENT) { CFramebuffer* last = g_pHyprOpenGL->m_RenderData.currentFB; - for (auto& t : pWindow->m_vTransformers) { + for (auto const& t : pWindow->m_vTransformers) { last = t->transform(last); } @@ -700,7 +700,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec } if (decorate) { - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { if (wd->getDecorationLayer() != DECORATION_LAYER_OVERLAY) continue; @@ -852,16 +852,16 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } g_pHyprOpenGL->blend(true); - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.lock(), pMonitor, time); } @@ -892,10 +892,10 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } g_pHyprOpenGL->blend(true); - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { renderLayer(ls.lock(), pMonitor, time); } @@ -945,7 +945,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC } // pinned always above - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() && !w->m_bIsMapped && !w->m_bFadingOut) continue; @@ -962,21 +962,21 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC EMIT_HOOK_EVENT("render", RENDER_POST_WINDOWS); // Render surfaces above windows for monitor - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { renderLayer(ls.lock(), pMonitor, time); } // Render IME popups - for (auto& imep : g_pInputManager->m_sIMERelay.m_vIMEPopups) { + for (auto const& imep : g_pInputManager->m_sIMERelay.m_vIMEPopups) { renderIMEPopup(imep.get(), pMonitor, time); } - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { renderLayer(ls.lock(), pMonitor, time); } - for (auto& lsl : pMonitor->m_aLayerSurfaceLayers) { - for (auto& ls : lsl) { + for (auto const& lsl : pMonitor->m_aLayerSurfaceLayers) { + for (auto const& ls : lsl) { renderLayer(ls.lock(), pMonitor, time, true); } } @@ -1456,7 +1456,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); else { - for (auto& e : explicitPresented) { + for (auto const& e : explicitPresented) { if (!e->current.buffer || !e->current.buffer->releaser) continue; @@ -1579,7 +1579,7 @@ static void applyExclusive(CBox& usableArea, uint32_t anchor, int32_t exclusive, void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; - for (auto& ls : layerSurfaces) { + for (auto const& ls : layerSurfaces) { if (!ls || ls->fadingOut || ls->readyToDelete || !ls->layerSurface || ls->noProcess) continue; @@ -1725,7 +1725,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou CRegion damageBoxForEach; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!m->output) continue; @@ -1752,7 +1752,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); windowBox.translate(pWindow->m_vFloatingOffset); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (forceFull || g_pHyprRenderer->shouldRenderWindow(pWindow, m.get())) { // only damage if window is rendered on monitor CBox fixedDamageBox = {windowBox.x - m->vecPosition.x, windowBox.y - m->vecPosition.y, windowBox.width, windowBox.height}; fixedDamageBox.scale(m->scale); @@ -1760,7 +1760,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { } } - for (auto& wd : pWindow->m_dWindowDecorations) + for (auto const& wd : pWindow->m_dWindowDecorations) wd->damageEntire(); static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -1786,7 +1786,7 @@ void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { if (g_pCompositor->m_bUnsafeState) return; - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (m->isMirror()) continue; // don't damage mirrors traditionally @@ -1814,7 +1814,7 @@ void CHyprRenderer::damageRegion(const CRegion& rg) { } void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion) { - for (auto& mirror : pMonitor->mirrors) { + for (auto const& mirror : pMonitor->mirrors) { // transform the damage here, so it won't get clipped by the monitor damage ring auto monitor = mirror; @@ -1932,7 +1932,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) { bool found = false; - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { // if delta of refresh rate, w and h chosen and mode is < 1 we accept it if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) && DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) { @@ -2035,7 +2035,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR //(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution if (RULE->resolution == Vector2D(-1, -1)) { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || mode->refreshRate > (currentRefresh + 3000.f)) { pMonitor->output->state->setMode(mode); @@ -2048,7 +2048,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR } } } else { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) || (mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) { pMonitor->output->state->setMode(mode); @@ -2099,7 +2099,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name); if (!pMonitor->output->modes.empty()) { - for (auto& mode : pMonitor->output->modes) { + for (auto const& mode : pMonitor->output->modes) { pMonitor->output->state->setMode(mode); if (!pMonitor->state.test()) { @@ -2148,7 +2148,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR bool set10bit = false; - for (auto& fmt : formats[(int)!RULE->enable10bit]) { + for (auto const& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); pMonitor->drmFormat = fmt.second; @@ -2245,7 +2245,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // Set scale for all surfaces on this monitor, needed for some clients // but not on unsafe state to avoid crashes if (!g_pCompositor->m_bUnsafeState) { - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { w->updateSurfaceScaleTransformDetails(); } } @@ -2317,7 +2317,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { if (HIDE) { Debug::log(LOG, "Hiding the cursor (hl-mandated)"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pPointerManager->softwareLockedFor(m)) continue; @@ -2329,7 +2329,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { } else { Debug::log(LOG, "Showing the cursor (hl-mandated)"); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pPointerManager->softwareLockedFor(m)) continue; @@ -2421,7 +2421,7 @@ void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pW if (!PMONITOR->activeSpecialWorkspace) return; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PMONITOR->activeSpecialWorkspace) continue; @@ -2452,7 +2452,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork static auto PBLURPASSES = CConfigValue("decoration:blur:passes"); const auto BLURRADIUS = *PBLUR ? (*PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES)) : 0; - for (auto& w : g_pCompositor->m_vWindows) { + for (auto const& w : g_pCompositor->m_vWindows) { if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != pWorkspace) continue; @@ -2476,7 +2476,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork } bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { - for (auto& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { + for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { if (!ls->layerSurface) continue; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 94d00184..91e70afa 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -120,7 +120,7 @@ void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, cons } #endif - for (auto& rect : rects) { + for (auto const& rect : rects) { GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, stride / format->bytesPerBlock)); GLCALL(glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, rect.x1)); GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, rect.y1)); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index f5e6e945..1eaaa0af 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -118,7 +118,7 @@ void CHyprBorderDecoration::damageEntire() { CRegion borderRegion(surfaceBoxExpandedBorder); borderRegion.subtract(surfaceBoxShrunkRounding); - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow.lock(), m.get())) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); borderRegion.subtract(monitorRegion); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 423256d7..628a579a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -66,7 +66,7 @@ void CHyprDropShadowDecoration::damageEntire() { shadowRegion.subtract(CRegion(surfaceBox)); } - for (auto& m : g_pCompositor->m_vMonitors) { + for (auto const& m : g_pCompositor->m_vMonitors) { if (!g_pHyprRenderer->shouldRenderWindow(PWINDOW, m.get())) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); shadowRegion.subtract(monitorRegion); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 8163a8c1..4cdb9043 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -192,7 +192,7 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { } CTitleTex* CHyprGroupBarDecoration::textureFromTitle(const std::string& title) { - for (auto& tex : m_sTitleTexs.titleTexs) { + for (auto const& tex : m_sTitleTexs.titleTexs) { if (tex->szContent == title) return tex.get(); } diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index d66a5760..4666a59e 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -125,7 +125,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { // std::vector datas; - for (auto& wd : pWindow->m_dWindowDecorations) { + for (auto const& wd : pWindow->m_dWindowDecorations) { datas.push_back(getDataFor(wd.get(), pWindow)); } @@ -296,7 +296,7 @@ SBoxExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOW pWindow SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly) { CBox accum = pWindow->getWindowMainSurfaceBox(); - for (auto& data : m_vWindowPositioningDatas) { + for (auto const& data : m_vWindowPositioningDatas) { if (data->pWindow.lock() != pWindow) continue; @@ -337,7 +337,7 @@ SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { CBox accum = pWindow->getWindowMainSurfaceBox(); - for (auto& data : m_vWindowPositioningDatas) { + for (auto const& data : m_vWindowPositioningDatas) { if (data->pWindow.lock() != pWindow) continue; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 995ec7f2..07208072 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -417,7 +417,7 @@ void CXWM::focusWindow(SP surf) { // send state to all toplevel surfaces, sometimes we might lose some // that could still stick with the focused atom - for (auto& s : mappedSurfaces) { + for (auto const& s : mappedSurfaces) { if (!s || s->overrideRedirect) continue; @@ -1025,7 +1025,7 @@ void CXWM::updateClientList() { std::erase_if(mappedSurfacesStacking, [](const auto& e) { return e.expired() || !e->mapped; }); std::vector windows; - for (auto& m : mappedSurfaces) { + for (auto const& m : mappedSurfaces) { windows.push_back(m->xID); } @@ -1033,7 +1033,7 @@ void CXWM::updateClientList() { windows.clear(); - for (auto& m : mappedSurfacesStacking) { + for (auto const& m : mappedSurfacesStacking) { windows.push_back(m->xID); } From 09dbcabcc71f412dcaf86dbed7b67d58a273fa50 Mon Sep 17 00:00:00 2001 From: raf Date: Mon, 26 Aug 2024 18:24:57 +0000 Subject: [PATCH 0538/2393] CI: disable stale workflow on forks (#7535) The stale workflow will run unconditionally, but will fail on forks due to `STALEBOT_PAT` not being set. Trigger the workflow *only* if we are on the main repo, where we can guarantee the PAT. Also formats the YML syntax to be slightly more readable. --- .github/workflows/stale.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 51f6b91e..b8be5f55 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,22 +7,22 @@ name: Mark stale issues and pull requests on: schedule: - - cron: '7 */4 * * *' + - cron: "7 */4 * * *" workflow_dispatch: jobs: stale: - + if: github.repository == 'hyprwm/Hyprland' runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - - uses: actions/stale@v5 - with: - repo-token: ${{ secrets.STALEBOT_PAT }} - stale-issue-label: 'stale' - stale-pr-label: 'stale' - operations-per-run: 40 - days-before-close: -1 + - uses: actions/stale@v5 + with: + repo-token: ${{ secrets.STALEBOT_PAT }} + stale-issue-label: "stale" + stale-pr-label: "stale" + operations-per-run: 40 + days-before-close: -1 From eb42adc4c090918ad6be9fcb24066da8cdfd9bd0 Mon Sep 17 00:00:00 2001 From: Serenity Braesch Date: Sat, 24 Aug 2024 01:53:08 -0600 Subject: [PATCH 0539/2393] Fix missing include needed by clang --- src/managers/XCursorManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 7fc21a28..1e7ca535 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -1,3 +1,4 @@ +#include #include #include #include From 6a8824253c38584d233380ece1e090dd9e7f2e3e Mon Sep 17 00:00:00 2001 From: Nick H Date: Tue, 27 Aug 2024 21:41:46 +0300 Subject: [PATCH 0540/2393] build: Fix NO_XWAYLAND compilation (#7538) --- src/xwayland/XWayland.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index d1cc4421..40c0ba65 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -3,6 +3,7 @@ #include #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" +#include "../macros.hpp" #include "XSurface.hpp" From 17ed4fc04cedbaad365bdebf6bfe0160c527f3fe Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 27 Aug 2024 20:42:30 +0200 Subject: [PATCH 0541/2393] hyprctl: avoid parsing string::npos on invalid cmd (#7544) * hyprctl: avoid parsing string::npos on invalid cmd invalid lines passed to hyprctl keyword made the string parsing try to parse std::string::npos, avoid that and return an error text instead. * style --------- Co-authored-by: Vaxry --- src/debug/HyprCtl.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 40708cf8..ddd1c1ab 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -970,12 +970,26 @@ std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) { } std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { - // get rid of the keyword keyword - in = in.substr(in.find_first_of(' ') + 1); + // Find the first space to strip the keyword keyword + auto const firstSpacePos = in.find_first_of(' '); + if (firstSpacePos == std::string::npos) // Handle the case where there's no space found (invalid input) + return "Invalid input: no space found"; - const auto COMMAND = in.substr(0, in.find_first_of(' ')); + // Strip the keyword + in = in.substr(firstSpacePos + 1); - const auto VALUE = in.substr(in.find_first_of(' ') + 1); + // Find the next space for the COMMAND and VALUE + auto const secondSpacePos = in.find_first_of(' '); + if (secondSpacePos == std::string::npos) // Handle the case where there's no second space (invalid input) + return "Invalid input: command and value not properly formatted"; + + // Extract COMMAND and VALUE + const auto COMMAND = in.substr(0, secondSpacePos); + const auto VALUE = in.substr(secondSpacePos + 1); + + // If either COMMAND or VALUE is empty, handle accordingly + if (COMMAND.empty() || VALUE.empty()) + return "Invalid input: command or value is empty"; std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE); From 7dd0f76e5aa1e3726f9d9fd1871bc667237ef6a8 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 28 Aug 2024 06:19:06 -0500 Subject: [PATCH 0542/2393] logs: don't get timezone every time logging (#7550) its expensive cause cpp dum --- src/debug/Log.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 4fc8ed5b..d3190d4f 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -55,8 +55,9 @@ namespace Debug { // print date and time to the ofs if (disableTime && !**disableTime) { #ifndef _LIBCPP_VERSION - const auto zt = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}; - const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; + static auto current_zone = std::chrono::current_zone(); + const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; + const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; #else // TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}; From 00ee1cf98e3d8ef7cf71a9a505ba8d1382697e35 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 13:45:06 +0200 Subject: [PATCH 0543/2393] data-device: send dndFinished when dnd offer is destroyed while unfinished fixes #7496 see https://invent.kde.org/plasma/kwin/-/commit/711c5bb43f2823766d5189dc8d567c8f4cec253c see https://bugs.kde.org/show_bug.cgi\?id\=482142 --- src/protocols/core/DataDevice.cpp | 8 ++++++++ src/protocols/core/DataDevice.hpp | 4 +++- src/protocols/types/DataDevice.cpp | 4 ++++ src/protocols/types/DataDevice.hpp | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index b7640af3..8c1a48d8 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -67,6 +67,13 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPhasDnd() || dead) + return; + + source->sendDndFinished(); +} + bool CWLDataOfferResource::good() { return resource->resource(); } @@ -173,6 +180,7 @@ void CWLDataSourceResource::sendDndDropPerformed() { if (resource->version() < 3) return; resource->sendDndDropPerformed(); + dropped = true; } void CWLDataSourceResource::sendDndFinished() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 22bb9376..8aaf46be 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -29,6 +29,7 @@ class CMonitor; class CWLDataOfferResource { public: CWLDataOfferResource(SP resource_, SP source_); + ~CWLDataOfferResource(); bool good(); void sendData(); @@ -63,14 +64,15 @@ class CWLDataSourceResource : public IDataSource { virtual bool hasDnd(); virtual bool dndDone(); virtual void error(uint32_t code, const std::string& msg); + virtual void sendDndFinished(); void sendDndDropPerformed(); - void sendDndFinished(); void sendDndAction(wl_data_device_manager_dnd_action a); bool used = false; bool dnd = false; bool dndSuccess = false; + bool dropped = false; WP device; WP self; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp index eb6969cc..e95f1c76 100644 --- a/src/protocols/types/DataDevice.cpp +++ b/src/protocols/types/DataDevice.cpp @@ -19,3 +19,7 @@ void IDataSource::markUsed() { eDataSourceType IDataSource::type() { return DATA_SOURCE_TYPE_WAYLAND; } + +void IDataSource::sendDndFinished() { + ; +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 948f47a0..f6757e1c 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -21,6 +21,7 @@ class IDataSource { virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); + virtual void sendDndFinished(); virtual bool used(); virtual void markUsed(); virtual void error(uint32_t code, const std::string& msg) = 0; From d105c7403c2b700e4572149ecadd21e1d1ad24d3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 14:05:31 +0200 Subject: [PATCH 0544/2393] hyprctl: add next and all to switchxkblayout fixes #7555 --- src/debug/HyprCtl.cpp | 95 ++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 32 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index ddd1c1ab..683665be 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1136,46 +1136,77 @@ std::string dispatchSetCursor(eHyprCtlOutputFormat format, std::string request) } std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string request) { - CVarList vars(request, 0, ' '); + CVarList vars(request, 0, ' '); - const auto KB = vars[1]; - const auto CMD = vars[2]; + const auto KB = vars[1]; + const auto CMD = vars[2]; - // get kb - const auto PKEYBOARD = std::find_if(g_pInputManager->m_vKeyboards.begin(), g_pInputManager->m_vKeyboards.end(), - [&](const auto& other) { return other->hlName == g_pInputManager->deviceNameToInternalString(KB); }); + SP pKeyboard; - if (PKEYBOARD == g_pInputManager->m_vKeyboards.end()) - return "device not found"; + auto updateKeyboard = [](const SP KEEB, const std::string& CMD) -> std::optional { + const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); + xkb_layout_index_t activeLayout = 0; + while (activeLayout < LAYOUTS) { + if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) + break; - const auto KEEB = *PKEYBOARD; - - const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap); - xkb_layout_index_t activeLayout = 0; - while (activeLayout < LAYOUTS) { - if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1) - break; - - activeLayout++; - } - - if (CMD == "next") - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); - else if (CMD == "prev") - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); - else { - int requestedLayout = 0; - try { - requestedLayout = std::stoi(CMD); - } catch (std::exception& e) { return "invalid arg 2"; } - - if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) { - return "layout idx out of range of " + std::to_string(LAYOUTS); + activeLayout++; } - KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); + if (CMD == "next") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1); + else if (CMD == "prev") + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1); + else { + int requestedLayout = 0; + try { + requestedLayout = std::stoi(CMD); + } catch (std::exception& e) { return "invalid arg 2"; } + + if (requestedLayout < 0 || (uint64_t)requestedLayout > LAYOUTS - 1) { + return "layout idx out of range of " + std::to_string(LAYOUTS); + } + + KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout); + } + + return std::nullopt; + }; + + if (KB == "main" || KB == "active" || KB == "current") { + for (auto const& k : g_pInputManager->m_vKeyboards) { + if (!k->active) + continue; + + pKeyboard = k; + break; + } + } else if (KB == "all") { + std::string result = ""; + for (auto const& k : g_pInputManager->m_vKeyboards) { + auto res = updateKeyboard(k, CMD); + if (res.has_value()) + result += *res + "\n"; + } + return result.empty() ? "ok" : result; + } else { + auto k = std::find_if(g_pInputManager->m_vKeyboards.begin(), g_pInputManager->m_vKeyboards.end(), + [&](const auto& other) { return other->hlName == g_pInputManager->deviceNameToInternalString(KB); }); + + if (k == g_pInputManager->m_vKeyboards.end()) + return "device not found"; + + pKeyboard = *k; } + if (!pKeyboard) + return "no device"; + + auto result = updateKeyboard(pKeyboard, CMD); + + if (result.has_value()) + return *result; + return "ok"; } From 8210a1d7ac38f6af76ccbb831dc1d62b1ebc53db Mon Sep 17 00:00:00 2001 From: diniamo Date: Tue, 27 Aug 2024 09:48:38 +0200 Subject: [PATCH 0545/2393] nix(flake): update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index fd06ac7d..0eb6ba07 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724273991, - "narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=", + "lastModified": 1724781866, + "narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4", + "rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a", "type": "github" }, "original": { From 98e99cd03df5b4421f72f2a3f2d7de53f8261f1f Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:07:13 -0500 Subject: [PATCH 0546/2393] renderer: ensure buffer format on commit (#7556) --- src/helpers/Monitor.cpp | 11 +++++++---- src/render/Renderer.cpp | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d81ccb3d..2b8404ee 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -915,17 +915,20 @@ CMonitorState::~CMonitorState() { } void CMonitorState::ensureBufferPresent() { - if (!m_pOwner->output->state->state().enabled) { + const auto STATE = m_pOwner->output->state->state(); + if (!STATE.enabled) { Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled"); return; } - if (m_pOwner->output->state->state().buffer) - return; + if (STATE.buffer) { + if (const auto params = STATE.buffer->dmabuf(); params.success && params.format == m_pOwner->drmFormat) + return; + } // this is required for modesetting being possible and might be missing in case of first tests in the renderer // where we test modes and buffers - Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible"); + Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer or mismatched format, attaching one from the swapchain for modeset being possible"); m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr)); m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c601e369..7d63468e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1910,6 +1910,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + pMonitor->drmFormat = DRM_FORMAT_XRGB8888; pMonitor->output->state->resetExplicitFences(); bool autoScale = false; From 9642311ac2ffa6605d84fef2bb5179f6588ae074 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 20:33:29 +0200 Subject: [PATCH 0547/2393] window: don't focus on activate if window isn't mapped yet ref #7089 --- src/desktop/Window.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 582e96a0..7da616c1 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1307,6 +1307,11 @@ void CWindow::activate(bool force) { if (!force && (!m_sWindowData.focusOnActivate.valueOr(*PFOCUSONACTIVATE) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY) || (m_eSuppressedEvents & SUPPRESS_ACTIVATE))) return; + if (!m_bIsMapped) { + Debug::log(LOG, "Ignoring CWindow::activate focus/warp, window is not mapped yet."); + return; + } + if (m_bIsFloating) g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); From a95df6b57e68785c13fd2d7f93d9eba28b9406ed Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 20:37:07 +0200 Subject: [PATCH 0548/2393] xwm: don't mark selection events as succeeded fixes #7401 --- src/xwayland/XWM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 07208072..5ad146e4 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -539,7 +539,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); - return true; + return false; } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { From b9b8e6220f55af34e862b541a5a4b30ae6d8f15f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 28 Aug 2024 21:54:49 +0200 Subject: [PATCH 0549/2393] renderer: fade out windows on silent moves --- src/desktop/Window.cpp | 10 ++++++++++ src/desktop/Window.hpp | 4 ++++ src/render/Renderer.cpp | 21 +++++++++++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7da616c1..a4ba366a 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -31,6 +31,7 @@ PHLWINDOW CWindow::create(SP surface) { pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -52,6 +53,7 @@ PHLWINDOW CWindow::create(SP resource) { pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -407,6 +409,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1; + m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); + m_fMovingToWorkspaceAlpha = 0.F; + m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); + m_pWorkspace = pWorkspace; setAnimationsToMove(); @@ -502,6 +509,7 @@ void CWindow::onUnmap() { m_fAlpha.setCallbackOnEnd(unregisterVar); m_cRealShadowColor.setCallbackOnEnd(unregisterVar); m_fDimPercent.setCallbackOnEnd(unregisterVar); + m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar); m_vRealSize.setCallbackOnBegin(nullptr); @@ -542,6 +550,7 @@ void CWindow::onMap() { m_fAlpha.resetAllCallbacks(); m_cRealShadowColor.resetAllCallbacks(); m_fDimPercent.resetAllCallbacks(); + m_fMovingToWorkspaceAlpha.resetAllCallbacks(); m_vRealPosition.registerVar(); m_vRealSize.registerVar(); @@ -551,6 +560,7 @@ void CWindow::onMap() { m_fAlpha.registerVar(); m_cRealShadowColor.registerVar(); m_fDimPercent.registerVar(); + m_fMovingToWorkspaceAlpha.registerVar(); m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index e1850fb3..bdc275bf 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -352,6 +352,10 @@ class CWindow { // animated tint CAnimatedVariable m_fDimPercent; + // animate moving to an invisible workspace + int m_iMonitorMovedFrom = -1; // -1 means not moving + CAnimatedVariable m_fMovingToWorkspaceAlpha; + // swallowing PHLWINDOWREF m_pSwallowed; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7d63468e..33679731 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -266,6 +266,11 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { if (pWindow->m_bPinned) return true; + // if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it. + if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && + !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + return true; + const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_iMonitorID == pMonitor->ID) { if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) @@ -540,14 +545,18 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec if (ignoreAllGeometry) decorate = false; + // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws + const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_iMonitorMovedFrom != -1 && !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace); + renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); - renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned ? 1.f : PWORKSPACE->m_fAlpha.value()); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later - renderdata.pWindow = pWindow; + renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * + (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); + renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; + renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later + renderdata.pWindow = pWindow; if (ignoreAllGeometry) { renderdata.alpha = 1.f; From 92a0dd164e9cc74060b63abae67b0204b6b6074c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 29 Aug 2024 13:41:03 +0000 Subject: [PATCH 0550/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 0eb6ba07..219cc08b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724781866, - "narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=", + "lastModified": 1724850097, + "narHash": "sha256-3BHxvFb3NJzch1X8puRMkVZujOoarQ1llu3ZcwuvsKU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a", + "rev": "23c7925dd31e79e8c06086ace3edb129a070ac01", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1722869141, - "narHash": "sha256-0KU4qhyMp441qfwbirNg3+wbm489KnEjXOz2I/RbeFs=", + "lastModified": 1724863980, + "narHash": "sha256-7Ke9wFRYPUIXwm5ZndGHkWBKj6BsFTkSEXUNXQRHE54=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "0252fd13e78e60fb0da512a212e56007515a49f7", + "rev": "aadf9a27dddd2272ca354ba5a22a0c2d1f919039", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724224976, - "narHash": "sha256-Z/ELQhrSd7bMzTO8r7NZgi9g5emh+aRKoCdaAv5fiO0=", + "lastModified": 1724819573, + "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c374d94f1536013ca8e92341b540eba4c22f9c62", + "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", "type": "github" }, "original": { From 604eb21a7e55d85ec7f6cb8cba39fc4c20a07a9d Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:30:12 +0200 Subject: [PATCH 0551/2393] renderer: better lockscreen dead behavior (#7574) --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 10 ++- assets/install/lockdead.png | Bin 0 -> 113201 bytes assets/install/lockdead2.png | Bin 0 -> 49466 bytes assets/install/meson.build | 6 ++ assets/{ => install}/wall0.png | Bin assets/{ => install}/wall1.png | Bin assets/{ => install}/wall2.png | Bin assets/meson.build | 7 +- src/managers/SessionLockManager.cpp | 5 ++ src/managers/SessionLockManager.hpp | 1 + src/render/OpenGL.cpp | 119 +++++++++++++++++++++++++--- src/render/OpenGL.hpp | 6 +- src/render/Renderer.cpp | 53 +++++++++---- src/render/Renderer.hpp | 1 + 14 files changed, 171 insertions(+), 37 deletions(-) create mode 100755 assets/install/lockdead.png create mode 100644 assets/install/lockdead2.png create mode 100644 assets/install/meson.build rename assets/{ => install}/wall0.png (100%) rename assets/{ => install}/wall1.png (100%) rename assets/{ => install}/wall2.png (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index e8ea4797..84a856b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,12 +336,14 @@ install( install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) -# allow Hyprland to find wallpapers +# allow Hyprland to find assets add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") -# wallpapers -file(GLOB_RECURSE WALLPAPERS "assets/wall*") -install(FILES ${WALLPAPERS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) +# installable assets +file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*") +list(FILTER INSTALLABLE_ASSETS EXCLUDE REGEX "meson.build") +install(FILES ${INSTALLABLE_ASSETS} + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) # default config install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf diff --git a/assets/install/lockdead.png b/assets/install/lockdead.png new file mode 100755 index 0000000000000000000000000000000000000000..f8bae2255f9a4f576011355c8242cbb8a88079ce GIT binary patch literal 113201 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}VqjoM-xwysz`(#+;1OBOz#w-Bgc>200A5Oih{)C?9>v4q}24xJX@vryZ0+8 zWTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i=|mnkaMm6T-LDmj8IREY2mP;kyKN>wn`Gt*5rG%->zx70Ha)iPA=L8)nQ%_W&>IP`*KPy!&eA`^#FkPKXDft7PnYGO%# zQAmD%4lL~iz(QQX*%_2pEEF`tGxJjN%ZoKZ-hk>!bxABqwN)}QFf!3Ku+TNK3^6ja zGBLI?vCuX!vNAA$DD_P(NlZyBNyJoaWMyb%WoU?^I6oybt&*Tpc$8Z?=jY@X`R1pj z+A0|ucqiS6q^qmz?V9VyjeY;J6+Yh+Wc%ryU^%=FB>#2jQ( zL9R*xxhmBtG1>7OQxz)nOBHhR zle1G(K+GbA;^d;#)I5cx(h`M|j8w3c61u4%Cs1rE)S|?K0)>>!)D#6P4Fv_yG>{_{ z$`kWS6iV_HO7lQ20|~+0rK6CZuaKEnlCO}MmtT^RTBJ}?QmLSks+X>(kX%xfqn(&j zqU~m^siTmSpRSOZr=yUVm!eQqnrEe;kWpDslw6XdpsSk+P2CCx3Xd9QWT#e^=NF|Y zF4`nQWg9ZGK)bL zfg>%iG&d==NFg&1B9dRAkdvBLqL7?ll$Tnhr=)MEV51MJ2qDQ^ACa&@sSljEK^XvC z8(Dc|f}*GrnhkOa*WSWR;i<$>7PL;yX1(2`UUr2%usLRG@&1Iid;_h_U4v zsd;$IbcnLz{Irtt#G+Kk^whi(VyX?0=RtnQaDQ=P8GhHBS{PecnwXpGTAC-B=~^b6 z80lJAm?!BPr5acoTcjAJrWzZ;e2?jRa3y143aezubUie1lQRQj^nCQ!LB~_y$_c`4AA96WV{G7_RT#+eRMQj0Q?QUbCq za3?5G(LRFdj=07FBm!`xI~v6kxDbI93Hs=z1%&Sc2~0Oo^ne?jR@lk~VpC#JYMNCF zQu7B?t`Of)f!LoQ=xC)F2l(5EI-30`-RM6cF94)Vvg1r6MJJyIH@I zgcumtxO=)dhE&{obGNfPIlR`s?)2^y&+y-RH>agWZpt}5O=tb4wP&ZLL~eT0V(M`7 z`W6!rjVbvH0yF}qIcYFDDYTd>wy534o=7R=CMvv~h z|2L58{o>e}zs+rNWJH9%J zonwlQ5>Bp67EVipBG+EKdGn@=(!{fA+qZ9jDgPz@*McL)8FT%_yN`bR_N|ZY!qFr_ za7ZvPI8-|`@G=yXP4Q~IYO-VJo$vST-|T#@YwVv2tY^f8MEIOo@bG(e*QEr5 zGiT2}E!ugQQSa|`y9^Vlr7_*jX8Fa%pI3Qx9bI((`Q(2pc@PI$7=n^#y35KC3mxY5 zyLSDS&wE+*Eb03Hn$>@v&+NX-U!U}#a^|OyjE4JxD?=79Uc55oRYse){1Sgpv%{j{ z3U}_^TPNZ0{PWL=69sjgIKYNpI0g#&If9Gp9vp3bSN|{R`qTSM&p(=fTD&^1dVNi4 zp2vYxIUl04wpLYD?F!HcIaBa5cv9?f|CJ%T?!N1a*3)y!*c!F59+FRPNibzFG#D>1 zkY<~=_v&B&_#H;I_x@l0+aE7c@$%gS$M!a+i3%JK3wA{4$ek_lUMf`UwfLe(@#&*4 z_B`ThsjjX*nQ|$?AmKk~Jcxl|3)s77mu;BIK5zcty{Dx2|9Ag3+4}eYA5yK72W9?D z1IOfw9ewdDL%Lj)Ch;!FJS-+IuAOIDTTodUxha|t>_di9Q2t-AQbg?Xf$mRt|9>xD z^JS-u!~X}`%=+3%Y$h@nGE7dNKD~yas;(|hfF(0;XV~iAqe-H#^Dj*E-dO<&CWb4l zAg`qbYMm~gA0IQ}?*r{MFCzb3F23*n^x}mHQLSdo6T?==#>c0#Uf8^O^CaE{y>7{7 zv)4*EynpwuueUdm)d}nvNM2ard8%}N`~>auwa=EF-}L`q+JAXl|3t%uM;|o!E%#Ot z5>397w9&%SQuAizk+R*k^UsIhDf+eJY}(;-tYA|z@#in)i3ZCWxH7IYj;@K}CX*Svqmwo`A*E{lcT`Q)RPY$CO>7#dU3AnzO#X8Cz4 z=RC9g>#ARgXd+z>=$6a%(*YwjzS1p<2xBP3>UX$%H%P$vR^P4k!_T-$GSztpL zR)~W#3h&|&tvT2BZQmdCZFP13%-?@rz7DKpzVX+?(#$MOLqv=1!pab@<(EB+Py4D} zzIIJ4`>o6R>#Ktno`)3kTP#6_^e!@Z$sRXl`rj|F_k8);33A8MId;ic9TNgph6oD_ zuUYy>sIw)7Ib-+Td8eOh<$XJMuJ82IphdT#hFF6QS$LHvZ*58a@5@iQq}P1;dC7Ti zd>y}5KEr&krL*SD(GlwwoqQ)kNA2v=KU2J(zIdUL{isZBvf=ErH+Dii1TJD7m{&~s z^fckT?EB}sHb2fBoyTp?cTCy2sez4|Z)=pTt!=Df!@b+LZ{N5vA&p^e(8?M+`Rqq! zMl+`%!bKV6ny<_5#8-TnX8*qG6;t}dgYWk5&D=0W;*vsbTk?vluWsJF8MHFQupurw z`f`TJr8{pD3{Kp7^Yv?K=CfxI#{|TKQr|1Dl_5Phe&74~YTfbk#a{NO>neU9Ftu#u zG0yy4P)~q{HPjcO}7VY3tXl@hIL5Nq!6Vfl8e#lMf}ntUtRs#eV2~%-`Tt+fw@-2T#S<#XqA0`n{_WdPpQ7p0r!SrP6Q~Y&gKR;AQZo zIbLh7W+iWoI4a7~ee}_jCriAR9)e}ZYH)x!t_yMZQq-T)s;)< z*B9J=5V}&aneQyC>BS5aZ*T843|2CH-o_2rUVn{_j$Xr1RZCP>k$Sr3nfh6VTS*(A z6z%L{G^w3q*KNxUcEbfuP>jrJ3R?MLcXj^H&+EL!Z*cS5UHN^p{KWG=xjQ~A@Um3l zcxs;|IxRFuW^LH+jT-|EPwGzfGB!5O+8R~m-gfC_$+OQtyJpWlo7U^5{7naJtOLYV zL0(IfZruBRF1*~ftZ$}W{JtB1x100ko#E$vyY<5YuaySUPl6veZ#r@7}%JHGA*YtxK;jmVvZB9NfX)cH-K-^uOu(Nq_(3 z-85znP#R!TdVZ&GK^QOQ2 zw}1ZQrRV$aT>m~VTl8Dm>eAI4X0XlMdiC>zipX9%5~ern(qb1 zSM9CK&R(4~DOy9s&CN|k!eRB*S37s^3|d)IGW+|tZ`ZD0-x{Th5^4d~y#_n>Ui-V< zyiiQ;&90J#-@D&WJOAs}T8m9yn)5$@uX~mIf3}_cpUOuy=kLnPomr#hvtnILx&DI9c>kU+3fA@EybG`0*)Dm5*ARhHNBMeM0>OCbGtCb zM%ypTpEvgN=IL!ujC@k`L+T-1utPX!CU z7r%eA>x;npAIJ9JHLD2CI&q;dG;iyygGqaSS8p%67CYtdgKdrBZ!~kBDaKe`Z@!v! z_GytQ^NSp_Y@?Y=ZuoAw)!WN^?NDcMa4;z2GBEIQG$m}lxhF1PL14lDm-m^jeP?Sh zYhsXMSdgW)v?goM_hZ}3Yzya!@BjBm`tSN`zuVIm3bY)oSn_;d|0V6Gt{?1wW&PiJ zKGb6E3)AIGLbT@krQ6M4FYzqRNOEyt*W|OMRC#Z_<%_=iVCF z-TD6RdYNtAyvuw^Y_=a(tq$ydeC6$08Ch9f5iZfgch;`e-5b}n-6~_XnYno+xB9NT zd7vm_V0d)&-iHq#E{ZOnd~(UAG-bX>iM$#_xybU=N9Oyl`NVZxH80Ue!r-L`ee_!eqBqColP@dowqeb z+>eEUfg!`F@R#xG8&NiL*R!@}s4`?QgJQ97aoE(=a`qoKu1ml1^0Tq{ZuwtF5|Rp6 z6su`Ud~Lpcah|pPg|Amw|Jl5FSO4$PfzO-Y?o>&ByfS3f$&)9OHr|LjEHwMr+#W!{(SZO=e}R})@=NJ+niS{ z$$1uEwTs{Ksq4>ut@{@n+dtP@t@+=(bhgcbzp6@BM6JB~>gCIqU5qBZq1Uco&%C3w zx4F%Hy87gk5t6gQbgNvOdCfUFB{S2rDZGk-K^+u+4dtOLBuc;Sec%6Ma?S4l zUr#fiKg}cgb?yxpt)(@WoPAZQztqLC{XKJZ-ugdFYwR52`}0DDw?@hGuthSKm`F`c zV>r7qdal<}gX!#`zOnt^nR@?g?B;tdb#i8OkOq}}2bL7v{Pq7u<);7t)YPM<{skrS z+HHrHyuXtcq$N7B@yYE_CTd#R}J~}!&Y_;fXGiHZsuyqMn`1cen|1H1&fcJd) zo!j5h!cUi&SS&JTN$<$6IUnx+%wsY+Po4d276e$RSX|<^?6}sTnN?*G_%6e{bjZ4-bOH ztL$s{+E_GR6FSK}Zy*1EPW|S6H5-4+?+?&p)8)ummsP#UZS$5bA%z7_%9DTotaPmE z^_+cV=GMJ?_Vi@6F)%P(IQb%}bMvV!JJODQ_+YTip4s6x$TI~kQL6Jlf4}o@-#YI- zm(JUk*L&=cbZj#~+<6Rpj-Rl;~_~p)>IVQ|6 zKi%RZ#j9>If9~9=56nRACzH2cni4!=HDPZS{Mvl^<&iJx3>oU6e8d;1CA#?BzWo(z z-(37%xwYs2=W~tI-}6cuXfG6Uw2kN}{eM_@58I!gcmL+sYG$Q}J1@ViD#Us1){DCR z@lDx_v$x)=usL_@*~ych5HGD<%)9h%-u+v*l9rw?*(k!nvgBKbbgo(Mq&)e*%nvOX zu5f{R-T#9kdj8he^uAdhZ=d$?VEJCRhg%lytT_AQR{H6GuV?Q``}0wjdHs#x2;U4n zyIrU5-?_8K!tUnXyI(78gk%_AeEl`;c3Oj&ui=%ftqL4p%=xq#8m1kX|4&EndX9;d zYH8SVbE)N*CAnIYe!r0a63qRufM)5+4V?3b^iI?F?yWK{7kZL-Mg2!HkU2K z(&W?jn>lgo%>_6v-2alF!pOiNRQ~2m`mUg&-FJh$=iAEp8_l#?vCi%Pg8!G;Kkj2@ zxC$B~*x;|sb4z^|7&tL!770&ake&5x9?-Qz|gSp=vvJ}J1McX zObip=H8?Mol9fH1wt3CV^VZhZhYuf~WYxR+YS#So;UA->*m=x9bV!aNKoyjToVk{7 z-SgqW`gd=4o$2w~{r_h-v%VgWSbF9R)SD#_IpM`r7Tk=iE{|AM1g@Bi%3ZEx zl^RH_u?Sc=@#?Kxv#z*>F{~~1E3lgTv0~2D_#;V%GD!>!LN4MSj~_o?bNtqkm*-2a zs&8E$VIp-F)B>BO_{H&;2vY{b3L%h7a=>-;Z)@|<%U;-(t$Y6~T;q+$e1DgvAwTZa z)_<+Kx&FNDWXJoT1%IB>d6oS??(xcyxb@RT9hL`aa-LHYV`(%ExOw|_bWF?<2i6Bi zeAF)Ax+SGuE5@8*lfn=n?zJ>%ZP?}6Qh$3-nH5yIEiOz=Z8iQInRRu3y>-Z?jEK$K z1RabP;2V__vrMA=+HUn?SKrjxmw#XU z^T!4rJ|SL9lajW)KU{z5>yOHNTkibMpWyE7JmY6k)~A&p@AdE9`MUG-p2`dTb6@{n zeO>!cp2-f6wPF7L{+mxldVG$op6fT=Lq&@(gwpM)!~d=lpF=XZMi75$tRx{eJMAQTH3GB+$Mba_1Et1?lmvZFAdTJb=yuZ)xCe? z#)=&`OJdEft-Cu}A<6r~LJ_g#|Fh$Dejhcj=zd)L{#xVnCGB5UERW>Rnp$)2{_mUR zAB;0@o`3)D|K{lnADqm;?Xz~7c6FE~cjmQVGYOvP=x9-PtyZUlZ_AWrnO98pS}G+c z=eIOy&X<{e`c|@89n#X`KA~blsP$joC#f{vv)+mPA%`dl*k=V<8 zX3kH>7CioTE+FRt#I`nYKD89MIplao;|_ zcDW#ihTuibC!Q8<^|-v+WqcIf-8NG3Z@nkW1IKzdxM8kih%z`Sa(Io6jFPWo9>@U)6%~)uFuY z=|+;*9&X#Sr^o1ZfUuRNzpwAcyffY90;pzV^czCP@s;0fisz zt*mC9ej0I-buPP@n3#d8@PfGf#LJg2ula5JrEvcFc6Z(dYGU23dUY0;=O2E!A?1D6 zh3W~%A15w-{-yAjP9F!u3OP`jD#F#B`9O8|rulVqr`y?A)&HNrFCx)+@y=Nr-QC{& z&9B?|W@5GF)_`66ziR%hs_?kGFnoK|S~Ickjc$j6gM)>57Nn=8Y4zR9{IYf1Hn;U1 z$Fxl37CZhscI?=-Yhgw+=ggm9zB6V<7+V4B-njF-SXCDtW?wp=@zv23BTzF+aJt{} z!X1ul#a$;)p1g)(deyCG&z4QGo~po6(t50ld6Dv=w9Se7%np#W*YkL5^HP`Z_wSyG zuK3XTdGGum#;vzIuVo2ct#h3MD%~!zKJ%-5<@A2}y=5~b-k!OtP--R1+ZM^V<^KEW zw~h!)t!_D-7`FDn)TyGqZpkK6;$mWa{l{MfOG``ZP3Qi+fbrjVmX$%iK0XCq`ETC5 z@$vI}w1RQPb;0Lft0GVHU-~Vww|Lrl?{<@nDt?`eXzf`ijY`$iGJSC(_Z4; zuIsONvokR)Py=O}yP8wGIxpTkzi02B4+^V)9DCY*m%ld2V7uLtgNK@Z)j6J?eEI(e z>$xXiz}?2;OR^C>vyL5pSu#u1;qn28CdMzXUTI}tJ+gDB<>ZrF_U()N$UW(#O79Va z8H^SldM{QavR;UejxJ$ykYNj0?(Mqt@WX_?54-wbUid98#kDGZ^GyrU*cV!UO|4hf zRY)&7ZFcSUg>T=?K#5V5DT5)Sm}~jg|Nr;wdA+fCPEGK)_vJh>lR>S(b(?Rxn-%Yr z_)=d#IhbdcjeTw9w#(0!OZOhjF*`l0SM}ho#y^X$8XFt?EuYM$E4p7{^2r5z)DB#z z6LUL$=-M^0^tT6BuGF03%f3QfZ@CQ!fC5-eeyjLqIGoUKb?=S z&VLb#(G$-;#t?ggm5I@&iJ4)m69X?puFbp)JnvL@|9>c!_LTS6=NmikN#9%ZfoJj7 zb2Ai9Tt9SI-2SBY@b8>4+Ii zd=Oz$*!f^8lK{W!_S?NWJPZ1A%%oqJt>4kWs8;Rt^~mgwHMiehS^VhZjw!3{`QNTT zd9qTiflqAu>DKLv3@gC#7u>W>-G5A+X^^US*_k4_`G@3{~uDt z^|p2U-aB6}J(tz;=V`o|xp}G8+$-B|rWkF^YJ2ke=f{tQVWEst{b$dg_pUS(aF~2= z_c!@FX}(U@!U*AHt)sLp}Un%+ctiU2d+oOBB^W@2sh4w#y zjvbpWef-g4+5y%EVNk#It;gC){?*m_mF&xxIA4F-Z7ZH9b7#i!L(P{KZixPM?{C!2 z#ovw99qXT`{jA#ItmSxlLPbr@oKOdYnLb_y4cnsD&Y7iXH^1L>;q16&#~&Z$kUx;L zv0zg7+_|!6teIEnHy@nfp%TF^E8AaT#lC9!#SEu~0_nd#A3N5@;=LmFV2aVkdz~*- zTMj3lkzjy0DA#>uNDu$_y`QgciZ2$I`?LKv+q|u&OAgx@WxlokIcNX#bNnT?e+!=O z{dT(gSN!KSinZ=wOQe4SL2!v%gHCtoH?^0&d+T2(V|xjkAlz7d3j!g zl_B7JxnBSA!@I6~v){dQM`oIQ%d6d!FTZ?pCE(W0n;(DH2)z${BwVrP^iHRR4U)_Z z1xDa0775-m3eu+V{SNE3}TbT7vocuR;<8M9NE7gyqt(I`H z_xeZpKe{}jA~)AJi*bwB(nmax&CSil#l<7fTdZHdUO9~U!t1XeD`YOuXPnh`&oewc zJo3G-#ft@MC91-F?UtA4zkKBTYy0h&zlyW6x=OW0yxo`&bSgHmHGEUzXl{-8{yp#M z)VhCXnZW~rXIigKQagGiWXJ1J%WpOP^wzz5&+d9H-0SwW%2tYN)f>M@ zU((P0*gL$tos zzIb6QUwu)%@b0RI4-+U0ywV=FEeRj120{3{niYT7y;=SpT*wkUM?u{(n9HzU9$flSz@0kt=7oU1V@*(mrs3tyt*u+O@jZR_IJWZ7IX2l6~P} zj+u1!8Gn_CQuYN`C3}y3{aSi0c7BLfYY=n5R}B|S8=Eth?U$GOdHd8qv+oWDkG>ZK zFdR4us@cpy8Rq^ErJL*DJ)Khb?%#BM-gm0)8wxgm`TlIf-sj)Ght4}0r^oy^to7`j zZ@mkyW-Y#`q1`ZV?%b)j4BQr9++a4tZpY@$hoznzPcpPQ$0_T#H0bBwx@$f@zjj=I zeRPKWg1#e1CWO{I@448$$UNY$>FrOSj9y!{+wI%5>5|ap`K*o{txj{8F6e&LVsMxR zYLZ49ykd{rary86eP?{;|9>96>HnV1|954JhzUonW|b)Un_nGyeKLR8ovF6Z?Uof- zTPGSEo;5R6M{N1>xTI>o34Ix%=+@e+t-&gfnQcG?#A11C01vxYMwoRZupFS#qZfU zI%3JPC13t^&zu+V_bb2p7Tu{{-rnA9%?nlU^}Lvrlb+sQ`caaD#UPo1!4I^|V~fRB zFT1yI|32DXxpcmM{F}d@s-GO>oKlx3>9w>b)9ssl{OXEe$8W2v**{C??&nkN?VWrw zg?sI-bfcLOSNSdZm%1$uBp@MS+_I*e2q=j}vY8J54&d&w2lQ_4Vz4t0u8EH%|4u_@UvL@uXW(Q@uCe_swLFiy(wg{0F5bMShSdZsg2Rq;)ibc4mD5L`%?GjEZ2VNwO6}D_`Khz-;1+s zsQYyAFT<|0-0ZV`)OOujZ^3ip=FN$>lz*D!&73(iu{S#6^NxvY7&ErsTDnvRzgCr$z9%GVQ>bUYVhnoNY zIeKvKlL>5(zlDX)WBmKGJd|&Ny#4*}@2+e4l7WOi94e0vAgwt5cEHmJ>a; zT==!|%JY@aH}`Q@%~V!a-jT-K5DaSb>AEEvf8YPob<_MiC!;GqsF#0>FZaEDog?qF zZ0`0ibuaIpk-G4{=IexobJaC2hVHxkGR5}#Ouywz&B`N|Up|_&@zrws{JcD=UbipB zFAAi3(-IRKOP{y#2~S~SSfT&1Qudr<`qrd}0xMo^YLEYGDZ#Vtf|mG}m7t-W>}?@h zsb;e`US@nS1yu5S8@^zhH-GBi4`p#LpWn9$Sa<$`tYh|8lh(_(ihuv!HE(A`AzMjh z?#XTQ7|-hKcqpf=WWBJ(*2HdQ-OqzBUuOCkGA~fHl|8rSa7tz-r>QyPs~W{jgAe>x zI=$RiW0q9f$Xz?E{it--<(D}NZ?}I*I}-In%G-_EVK2B00j)97E3f~3d8+ft`=a+> z{JmrS)L2;K@10j7deP@&|#U`S0@YtHjTf724qCb~>2ncJ;gc z3m=7)-&}wG>;I3YZ)F`mcYjo!?75Qlg4^Q4>gwI6Knom_V@(;XxSlYYd3ozXv2C`NWBW*Rr}wHk>(sKKT*@)FF-9%11l)zMs2(nr)T6 zdhN8o&*%PKUnwRgmm}R}82K$+Qr6aO7h=n*EK3rPRav$=9en&T0p_3yR;^b}K76vhdH&s_kb4tstLp#Xj$0HB}*z5D-1>#5zp_wTcu5uN|u=>DAJE#JR=Gcz+&G2Q7_BQtfg)cMA@Z{J>% zn!#w&p}?_u^X4^%^=gw3HZw7l)~_zweRs{Ru%9*a?wu&OaBw5I@1As2+vL}SCr?tc z@1`zaZFElQQl|@3cNqgX2Cf1NWWiqzW(@mPx}6<54+n#B+Rz(S6V3i z-hNw){lfps_LgstTFb}QyoRBwwl+2h)Y6_cV@5*nEB^eSXU_1bl``?XU4Pq? z-RQMPr`zH$tQo2ezxHixb5itM7(JQO|Dt2)b(^~V`yU0zmxP(mKC4?I-OSf@@}%dr zuhA<*X3d`MY^VWQJf`sUw9?cX-8;qS-7C2H^mogr zE#KeO|J_t`?fSRJDPgUSQa0{Noy}-z%r4sG{%*C5L;ZK- zuFi|!@)#TioE8dbH%z-_5xM%Rp04gjHUsul7Iif>gC0hSTl%aH?aZrB{62TC@AAtd z2bluyH=lc0kg_@QTI~FjCp~QzFoy=MzItWup@#)Z6HlZV&7M8GB+<;w?3zADXT?Yf&&Eg2W|fn4Xp&h@mF{r=xu>(u3+Os)I(@GbNCTT(`kET3*mzVLPb z*QK%kbJo{ffB24HyY21Uy9`YVXU?DB%=BXEQq`9%7fe=_Tg_b)`1fG&922v{25b&4 z$KM}1#PoWeuhC4Gzq}2<9!>AMb?;u;&X^sqnN7cHEWYS*H!UY8r=;Xc(#8u@qq9pD zZ~eP^HT0VGM2mce@>B+hqeL`gw*7m(ZsOlha&f=@oUZ=0zP9gBOJJ3C8N=$8-!ES; zw=LdyXkGoUhxh#V`6e1~FXz5speEG0VV($RuGxdZH(7V})l-#qpA`ZQcV#iOxBo2( z*q}DI^>89%|5pZ+kFll`JuU=xhBZa44AI&e&W}Evz}VU=uit< z&Ui9##usM&`>+39*Z+L!x%>O~zb};L+VgHJ{@qZ&=J)RTFL%XgHq*;l@{A*?8zaKP!hT$xf7H`NBZFH(NM0&IwBg=e&_bgbC2RrlY|V+q z#gj{~s|$55U@$4Ua$6vF|Jt={H>UB6bRTt4XwWuiSfS5yfkDC0>g|KPJ->g?UoT_V zRX=anh3eDRPm2F3`mD(D)_R&y<@#;&DQ$sMay#=M?3}5%@a+0dR>z3AxOEl=8dJSK zfBu{<=g?g|-;zIHZh;`*D^7+#?Dl9rN|_FjH@jrR7nYjwMiHnlM|`~p?mL5l>RWIvquJO4%1uf%g-p3f_m zmj;hOsQY|8KYBx(u@Y#|sa$EqM1n5;X3++wNx0wY1F(r!H9B*U{O@d9B%^n=Lz>YxTwLj&^Cq{&oou7w@luDI*K=BTw9sthYYYeN+#dMhrqdGPY@ z8|z*3Y9`FIi{Gd5`@1z;T&by;Tuy$Mp!<1S`IUQ^9xmmsegD_F_2va|A2M?5&vON7 zT|q0C@P7VTGt=kUs#i~nEH~fmiQ_FO5U`wk?(N%LKgJAj6Q=vDOU;; z-I`<8U24s+z!8*fSyoKx`uK3)_x<}`fBd|sl^wJi<5##wOoh*;vnSKlPPrb?{?-^j zU%KMty9vwwE@#i$dh6@guU(8K8zbh-o0s?RMnjvn+v38!yuMJk%}P?AFPAS2Xa4i; zt>4m5ReN{u-n}M>0kpcXH2W!Y zFv*IaO!@R-soGw4Utiygl|pZs8G1p>U(VH~ERZPu2AMy2y5xMU|D5-~AC%4ws9tz^ z<&@@5*PHeCA}t&Ky}ZsI?ES?w_dZX_*Zmte9-O6o^UuIx?;88s`kDtnPpnr)4VS=HI+5Fx}ll*RNnUV%{RM_dvA>R^0P)mAkh8F zjFN3ORqqz{o2*@Vlu03LYt-ice~$l;vK&s6E8%NrW|w97Z*b6)lVKJEqY1+tSx4RY znQtpUJdX9ZKQr^+oxdN{*|;|<%BlsHv9y*ic|N=TY((RSh4=dRyC#~JI$6H}t+71G zwZK-+UzqL87wt1?#Tp{FZr+u+<%du*|+rN3@Lf}^s9^R-n&<3 zHP?gjm50u<_>Eg%KJKlvaMrQO-5T|>N0x_8{M$wQW5o!tMACyeRlXS zAAebKyV94czt5hjWgk`9e*5kV#?4V{mnHr@b&4zdPMzz8n2(Q_24&{u@%fiH38Sty z6x#FI@wk(QNRq66rwh~8jMt|V3^pv=mu58c*wou$D?`2vbGjwT{NpKyvS!c(ag9ZZ1q*M*}doH|9SEAgI|1X z?9yO8qZh~K%E<7sujXICV8X!QU47tGzsvvYkzb2wWCDM@$x)bY3aqyiykd|_vXz4 zvD~|+#tqAwxBp^y=ew>sYySNF7{dvC>g$|NYN@!^GO)`sFgRQWbqCelS+joDEO@?- zKP)cwU3p;gd)@aF{CoLV8fd*x$-4R=)Du(~%@h3p;xF_0dyCe;oN#Qz&73t$|8KgP zb65QxXH&xV+sYF;cu%bM^!HkN>DaNh(@%p|UrmqJT~fL-L~HU%6GOv|TeeK`P`UK7 zL~CkPM1+K-sP^04z~&TM%1?!vM~V!3xO-t7FU!CAW}j@NIw z#V^-`2_I5kZ@pCh^KYHbwObRs{Tvs3H@!AH%0|xp3qLdmF6f-%^>fMc_lNUeRDE(x z`}OC{(Ru9ldhy)l9xLN57Ho+AWmge0JhI%<{_Xo-i$nq_^NJWFrCO|xCKf9KA~^`3K+js{7!giFr7 z&|y2*&)?5a?jFPHtEYZ_V+-ZZEWPq(@#4j6N;e+4apm>bq>sn63b~eDFP!%JWntIV zDPF2N*Kcynkp!*oFSWD|WM3Sdu`y!LE0MDD^5%mIhc4{eKiO)o-?c3zw^B=HxxRo0 zcx1^fP-jBEcIx&I56-`rtGIfVi(Ah5olVu-1KR5+{rzsPUEUKv|MmWFmd>~QR(dZ8 zT6ygF@yJx|*Fm8UbAG(}{`>OFlBuHJ-b;gY#EN&{ZGWEmNj=*;>)%S3j_#z5YENb7 z31)6g;JmiVq;la-;rHcMK@qnjHALLp-6ytQl}#_RnY;Cchs{&FrOhR!rCU#>yZ?A` zByVff#?!Ar3v>MZHofD`$V80&($Jj zDSC4~9?HJl`}F+od38HJ?fFsv^U{N7MbAYV!d8aNNi4RJvp>7|*Q2E7yzSMswR?X> zR<}AO78YL2+a7P|Il1l@Xa~-wZ`ZDc$*ykQ!uT=s@6@SNlcndB@qT4|#hI}sd8Uur zH5K=lEEoP9y>RKJ$)*i%3qJGDZH<`Rcl_8fKbc>b`Ig4I9WMfnAe{a7txRd+1DkB8 z+s3A*SBoYunEHE#>5+PmtlKYoi!w7iOWUX3WBmAyg@NIM4`^8J;}xx+k9^LD-@9Ep zbMuD>&bHh4`-4_>az(HUwH$oA;tl)ujlbO9PrtYJLtn`S!Ns8EO5r~3nL56QpG{`H z;I(wpzQU4{lGIey`RBteKSt{8e)#=&sny+!HI8%EoaI`ex|L;)NQTKQ2ZaFNclz%# zw#1p{m`N|^=y74na1=Q7&|o#gmt)7+Kz=fgQ<|7?_wmBZw@$wM*ik%x`t<4jzVkDm zry0%Mxzlp@-8=({7e~(R;&hCc>^>T`C{1v0P1WQ@nso&D*!Gi!VkoXBbw=$;rh< zMV)$D6zX>V(ULt+pQg4SJ}9+fb%@sf`{%nt9(}A3RtmYrR#jTHciz8gpQa?Fr&}#V)_K|N86HyG))-gM?u%i{3kiDnI1m+Wm%wz$gB>&efxzE4=L z_hs+%sMe!b0(}=<%n%b7k7P8dU3H3KmfHid?$oNPs^a3!zlzR3a@jL=s_697rEl~X z#S4O##DC#b%f9Zi{<^!;#KV>xe`nh%9b|DAV7VnYhik(cqYD)te{RTG7#kOdZFg9; zBt+}@v11V%ll7)APF{OeJ^9kNV0H7^XTNy8oa3-u)2dxZSNGz6NL4;rC2G&ib7uZXPK`Qeedl?wmfTA?@go z4->ffoys(hb}W9r?fa&xjyK24r%acBv*F#rnOoiE=ggn~{QNE9$qK8lT3K33b{~z{ zD4xv~r#1D{&zjJ4%3|8LuVrs4^F6Y&#XY*yPHF4UC08c-EjOO)7a!W4w6S875aZmh zc86oHO~)T6{!O{1;-~oIa>%kgmbGEt z>s96Y!#7`3dY;=V)f-ivle6Yg6jQIm`-U}N)n9J)@%Mjxg^PjVLJBAl0-b|?&e{L{ z+3VeUu@9!yz598r{pmu_CFkdQFO~7pJz4jwG>m_t-jaeS>$RaKQoO6fn0x0ufA%aw zIep``&4(Xyur+tOEDF%LViKL3o~|y#cX`L&Uq76|TTre14A#u^TYme-jTJwfRE*w# zWys}udm&0#=GU(Pjg~1-OxU@6w$x5O>5^}5sw;h0pXcW>(^Vr`P+EE!u(L{p%+|lM0|+pAE~u z2j{;AH-bP5`?lMK##IFLaxIrVv*308?b9<(^Z$Ew?_kg(=4uZ0by{NG#>U3(?(ZMn z3Q$&7p6H=6*YA2rf%Bh@uV245QCn}SzifScTwI!JHg9ay*&MUYhZgv#DbLlC*^+G| z$Db~@%OX%D`|{i$35jcsj$1|e_3&-{`0?Y^sZ-CM^|d;cwDHE9H*3zOS(`O4+jlCe zW>cwpa@Y3VYHDgnPVrowpSwcSLb&C1w^UhC(Wa!MJg4>f8Mum z-Lf*PmAkb+zufih0`0JKOYWB*6ED=7dNe6ACdOvl4Ue@eRtFfH?PBgQz8|UUV=KT4 zI)q^s=!}6YwGS4BRJ8s6_bKY;`tyaC(r@;^m#7G=JF&pIxzyXWmb}fJb6y`-um2t^eyVoM>6Y3r{2MQ{ zOj*tq^t}K02%}Ux4HetgU?F#NA;Iky`ppz@&7ULlmC9tKJ#Vf zKbx|3|8w<&Ep#$A^eqeGOIy6Det+}UKMDV5|4Z<=-g%lOb8FPK2bJaJ-xY!v@6ViJ zYiGA_+qP-vpJ(?rdM&+l?b?#*V!|6Ym;az5wGu8I|!$*AjB|Lly?nWse?Bi{IA z&FI+LlgWN@{e_n$YLh#w4&AtMI+FNzW?XZSpPZcdiFO~ibj=K#Tv~_NzIB| z9}eEPGylAJ|M8c~Tiwoo`8v}lt*-9g)1u6+w=TPMB`H4Zl6H_bv$VXqpwRAb#5t$9 zD>_>eg>FvG&dy#Vt0HzYA|@v1lT_7}dLFjs!w(niGch;czG;)wU)|YfpMC!6v@pP? zrA(<-W%}u*mtSU>c;))tFFj=!9AC9}-qu~pxj#>wIFV^Kb=S(%2r~UPc?CjS!jxC?>u(xA>lg8f~ zE0Zj%keA(-p%y_auSAAETrj!${`>WtKC$K6@BQ}nZElulmXejvi;%FtzXfXz=Z3zR z5_Eq%=da9?wB)@kw>+vIJ2Pg0dh4Ky`l~WW^UVy<^wrKqO+TK$Y_C37Ut_Sb;nMlJ zevx`tFBSj(9pM^PweRQkr@KXDJMC8*3vl@O`(JMO&vM?qn^k_=^yzo=w)-u&{<|T5 z^;IgR!#5UiIS^sk5mru{1J(IG!8os9f(5kD>bAR5Dyr4F@^J~u`M|KXj=B;welRQpY zSzchfymIkR#g!4SW_^7Zyzz$MUanU{ziP$0TmN}4zn>Mh#KvOjnzd_h=4`Xt7hz?3 z(Xwmn=@$tmQoTD^m>C!{>_9nmy?5Q#nsfJyzqfh-|`?n zHL;mr&F9r@cz<_&XoOYCloKx4yiV`rffO zY<22coxGB_FK3w*m6lH3y1DDimw_bg*^toSokdFQD^IrRoyg8O* zR@{{_-D~NtmVhm)TV}8Dopdrq_VuoJ@7{I2em^&t%{O<(>8BB2xBfiM9G0WK@saV{ zxmigTw+c&AEa&=#DF@ig$jhgPGT*p&ugpSbZ4j@+;)@q7TP`ozw#@5k{Bs$iUr*y_U~sSo4Iq?qM2Q^! z20p{$#os+&e%im6sdySHYrR}_-2#ciFL%BkJash+G(l0YI4NmMvUGcJ=mQp3b2BqD zrbdR|ldO&_s;?Yff56(t=1xaJZ{4!P4-;6Uf7bk)GPVA-)9S06mYH>1a=aDU8g+K2 zQ`~fwxwj4`ZEQLGaI)_l`!dOm9x6_Ezw$)iPTO4g=;*9@TbJK;{F{}Tx$@W6uPZ)R z?~U^_75X)EVZaLBRg4`=C-mFuzkT;EXnXnYyH~VLerK?6Ts5cr`3g7jGlnyL))XK8 z_RVbd-?DzfLUv%aRUNraf_um|qmYsb%$IQG^ym*@1njNiwKKw0^ot@n6 zb-D8P^UrhlZQ%cVY2!x2Yl=S4xpv>}<2GPmXfOtCmG+xI?Il~>KK0)h!z*8YuCL$x z{_Xk@i?tcL8o`?En*(pw*Q|a0>1bE$q2Kqu&QgqRzm_Suy5Q4t-muRB#b&c(qoSnb z<;|sfv$pPX6jV&#^et2CgWToX9Z!QZtIuWqU3b{JFeRmBb5X3(%q&fb>dq^S63VrjV;g4&Q3~NG;2>p4U@6} zhs^I~ZuXzQeCK<4HZLu$ZR=y9&Lf#+k_-$Cb3mKcEK)_5Oj+N$dw+59Q!3WmnAG!dili76r3Q>wjFOTsKJ&7cANyEgvnE<_Wyq>i^BjI_3vh%4 zYd$3Iu1Wv;8;<-?A*uc4XY*I&5<(|*S@!uUr%3ue(n(mU3(jwGoI_s%*`{)wZ9jt zeMsAUQ`o+FebCA|e(I&mCx2bKxAv<4_T_gkUhrI_leN`KfMY{bpp{JD+*!W652P5i z9)75GIxk@JlFONeUr!|S8*WtJ@J+vVkE3bUtL|SyUxVsGtA6S17vcPxa;>xJ*20Cs zwU+*w8>X#XqPKD5#)FnDEBLQ0tuRk-+7ltR^Wrj z)Z&xf)7`nX)9>@NBd5L`J>;$dI##V9Ou&KpfF{SG2j|+}q?a3Bex9yZR{#9j!L?Ht z24DZ${B7ZNzCB6)-{SA5oSR;M{9R1L&#yN0S4H!y+g;q>J=M4FY;s#1858rwr=E|kImzYR`~%gqF0ot@Ugbak z<>?jgFQ&bD^JdBAmo7?CLo``)k$=D#bvh3 z-VazVJnEglapT4co48cxK<&WQa?xdv8B9CwzfXVq_^ke?YNIQhmVYB{F1>tmIA8de z;+(5qD?QI^HQ4={&{z@PT)o%e7R)bLbaE>Zfe?qBSjOXu(Y z|FpDG{2kBBtr^-s?&ldB-l~4RJ7V**RQq4A5;QM<`~39ii^`Ogl*-DVCaVu${H~{? z({a^ID*VOF!$})AXvya1=bLAQ>FkX-cc}Jkecsnw ziufG3lX_`&h^~>TaLY&u@gwH>JeMj=Nc(oT947ppQf>(+> zXA_du|N83HBdeBDd*(TBjy(NX5pnVDLCxBnoHtWWTGv|7&9&J7!sPRmm%CT!Z@gtZ z*U$XLLKy}I2Jp^Xi;oxLCH82k{=T~ROe=eRY5srdxCI+#UJNO)m?WulEY*I`+~5ta z4~w@KGGDNWUw*l_uMd>ncHC;4!P?@aIQ#6iCz|KO7w{&u2G8_a=D2l6ubXnVSMtID zi@!!;%dPaYOy+#p9-?*j>{;0*i?+N6EkXPF^39#LjUOR_FelytsLn(%GE1lh3v;@7)ri^T*?FSId-JUB5(4oqY8tnDy_QxV8T9 z!wm{Q)0{jH#tlV$4V?c27^@k`(P zYp2BTO{x=o|ST|%|)qj)AIC;?;HL0KhmB5 z?7j*!149GoG>iu=B6;cWr{6oP`S;HEg|9`F`AkIq#BG->3^@K`*O!2&v&H)F+^&CH z++LDvojR}W_~FBcSFc_jsusWIg{1^fl+Luxx+aRt)cM+*MIDx3e#y2}{mU)O&Y)*;dB*ykmj599Qcr3)$#3f=7Ope);FYewVY);@n}wFR!8=f!kHmpuUT` z%zB=fy_&zD+ManNegAKdjf_Ol!fSFe@628uJmU2Id*0eRxq8#J+fIw8-zxp-DD|t# zX5QMhYghXvrl%i&S>mO#{n7e`*B3C%ihpW6`)u4q4b#bPixa1+hzU>7c9N;9t7^(z zc*R0lS$WQpfH|=q@x@IFZaI}w zyu4g_V#n1i+m8?3?w{5=c1cKEVAk2REbVh8{|YQ(Ql-4_&I@i@yfD({xhAhwtc;$p zi}cA=FO=l0H%6>^w5WA?PRhBrTXyM`Mx4!@v-yO|-Vax=hTb}7mB%?(LrqOB!aV6H z)4Q$vYCFD9i*T2j8|W{V#moR%h1W1Sfai9#{r7Y0PK#@+clz5!%sam7>Vkz2zVGTi zdgK4J=_R&>^RDKeI?W%|ll$}5(T#?yV;sH)t(;OKr?gDm)XM4yf<&&tT~uqQJ8ep-fEWF&aWoyQu}`ymwwfbn$g_n zb#0-euZw$0^Q42X@+Wov?k@hktS_5i?%4j$M`gRE=gzzo+0hqs&T-?;ou0W7->q4` zR9ohElrYHcZ7g}S@7bD{UiKd{_U40*lL5^`1Xyp)Dya7T)}6m$nf>>e9UJ$a{&DE! zB!-_`wm<(TJ!A8;|6flxZ}ixGZkG7Us^EmCfaC(fEXxnX|MFPr@zXWy~>S^RLl zN5#=lc5!j>)iZz3@msF0rsfw}&~WSK`|q27IUCKiIc%+Zb-~%kPbPiYm6n#aYQB5E z(aea?H7{8n744J~cPP$dma%icXn*b6HH*y+D?ghgg@#(CtT5iND%pIOU$@)hh03#n zg}ii9FL#_0eU#O*Cc3j^PLY^k>fZx5Z$_TGxze%w5fcOC_y>oxB4WYsdGpi!>gyi; zIdIzBxk-wbb-#PS^wZn^d^exzdf5J#TIeRXU%bIFmyw4-X1JwKLc zg|$2=;m_(~Tl%DAUy?7&vU@i!Y%)taDtGPAYvJjKR>-|A4?CIm(JsK({Nam+q|hG0 z_wsYDMuQGV=>Uzpo^=-cSrqW?v2{dh&FRbY_bO+o?`S%d_U`YG=w0(x*4%gcc6m43 z_Qkm|CNXmu&q}`P7F4WtR1sRZ&?x&+ijLT1zr3YED=k)@b=(mg|0pYMP3!Np^z`#7 zxo%lp=ZbQZD!a6w-M?7I#>9B7ukZL{)3+J77=HbnyzCf5F<@xAeo=G~?H@)1oHTO*wM?4+{fB2Iz#l1=ke2*S&wc{tc)G zVfeL@n|b{{smt>pdhjfexie$>-v`=Lcb_#D2c7S9C^h>rn?Sb1=4a^_KU5SK7gtr? z%G>_>>#vn7S9T?T(oWjC`TpwPu51yECCzHt(mZToQ#*}g(z@iIzIpTJLR;*_B^f4C z=R)4SdaZf+^-?=yLqo^f=FKavpE~6gTh(_lBgMDp?DNmPtCtpt)a(5@*y8^29{=ip zhYw!Q&&|C!y|XYS*35rT@S(25SzHCu1T_hpEUd!T*d+#>#E)z`~8_i67cR1tb;bLrv&hNwO1$7X)<HqR7|FxfIg$Nsm3tZb_5oJYCMi?z?a{95JbU}PUd=nJ(zkj}@IR+Ha`$#z(rE8b@>^MGbu~DA&9f;=`y@A( znaDm6ivKLkz_36Vv@#`%xHQ4-?4 z6|!-L&T1AHz3H1Hbk63p_qrL|+n-+*zG3%nYg5zG5~YP#vr=`vJntJB8V344Q}s)J zvi$rbkvCPYpC8T2T*Gkd@kbNg@Tcl~l9+?)JyeAL>^%R)`A%N>UGv$S-^5K`-WA{2 zck1KELMzsbX#vg`?_XiM(#WqB9~^w4@a(JeU%r+It^Uf8*xK_bsptF%^|z1N+4Fw?T{DS(o`;I=JDMD?|Nr&;wA|kLmG>VtU*B5( zw^#ev?Iwkctx+E@zF+K|UFal}z3suRTeC{Sf)@GCojEhnRej6KUXBIs?(UI{C029y zEjm|JT(;tF-t#jXeU}EA&3@apW#ayX1ik62jTVTcGs^GYq?+rzH|p69hFzIEwd(c$ zoH)U;_sP+tu63s`_%Fy^SA9Y48`m|JN1JyAE4{O`+ACw*bmXe|Q77RmDu}eRnymn1&b+ySt@6X zoz%G}|KsBId}5ECC1n2b^-ezjs_<*n$8>SCq~M>Y<eW?p~( z*;HxfBmLd(yf^+>t3KM-WGwx+0PQq{7XIcawTEFylld zUFu~EEsfJ(&M~vIJ9kTSWyq>`(hh6ie*gV*^1iiU*_Yp`1ePzFtnxY~BK0fJ?6b$J z9yqM2Xl4SPH=Yh!iyY#s%(JH?{M+hk?c*K$ca=YAwRVo;y~SDA?|8lbZE@=UJA_qf ztBnN zE}t;yNZ8FmceUobPdl{COsQd7l+}5CPNlq{qds>Y7HoL-`r_)@vu3R_VpyfturB%N z!{qD&^Tex0g5V_$s(W6RSWWdR^hy@*c73(0cXr#E^?sNCSgV#i=;`k-J``4X_|Zp; zt)1teC!dvBK0hG)qd=YO%U9~Z=ksj+eCw9fYX@%?p*b(luW8=??zzD7%O`hE4Z0ua zwZE@8yTxVk#b^HKmw#q^y|XJz?QVCwbauGfWKS#qN0*ow7#^GfEgQ_zJQnj*W#c2O zqUmz4{vMgHDI>N;=#SjqZU6h{saHRV3%faOUbTJDzWm1YWd4WCcX@kzUs{>!8GWd# zVXtGM!QW$`bK;IXY+ILh?AAOFl|wVVEzHcyOnyEMe|zKRO-VVqbw>K@)EdsEZN6%A zIF7e)nWFl)+^7r6$7ZcDTVnPwL_*<;rLS7>W3}y<^p-g{Uk#jHBkeiocTLVpvBE5~ zw~l_HUA?`%QR+{Mo+)%k);Oy-Lk@D=#d*-O?1e$jp)ctZuV$sPf>!!}wOwX$KF*|G z_9F8Yc8k>G{d=dMTp6Xe^*HF5JS$1i;Y(%}6Wo`j*#Gc)s`AmCpJz`Ee`?LcQ+CG2 zf$RRAnf33_iM@aGe=)b-Y*=R16ThXTurM&lctK`xh{?eGoGkCD4oyXVehVF%xhWu{>IM-$EQtM>+KFYb-eV7+wyho z=FPh@roQ}q@Ky1eBikZ$e*OJ7YuWKn)w?b3Z(I1gDR|SI;^|50>B}=uXMXBWx-}^( zd)|k8lS_A9y&8J%OS)C++|V#<8=Etlk8-x(wyZt#u%O^qgm7OuZ1iPC(St>@6<@D{ zHfBhumDT@NYdzoV)^xbp>F1K=&$H`8cV_(fw`%I&`cF$sssf$h)tM_01vnFQw z<)e>3cJ1F7q2uT0XZHDFVe`QQk*B*u`<>Q?u{S%0u}wMuTs!P-f@K+7Nv(QY@ihI# z@hU{fol{Hi5nB7a;e08;VPft&QpZLazHE~<3 z{2J;^R}217H2S&`bjU`m!mH%3Sq=;g3>K=O(kb=Bg7?s-o70RRUk-!T;Th(*D<53Q z;AZ@Rz4E5Nw*SocRnL;n|203M96aM+jmZ9#RZEyM>Rg|><*f2sp3J&n_wL<~A3ye; z{qorQHl1r?D`vDw_qturmRey+41Q+8n7L z`{MTrX;CrZC{8}Td!lva=fm%vp7Za|iQ2#UHG<3RHzzTLO>GWZS<)o6hWBnrSlGP< zzE6+zwK^@#>~7tC2E`t#`#Hxr+)zyHoTwRvlppru*Ey5u{a((gb2jMyBx`DV`I z^v!a|*6%y3_4iGQ)$Gl!R|29xq`b7~LnOrPwvR4P{D?+s(E z)q8~I7F+m-UpSXEb+@4Wk%L?<2P|DX95+iC2FEYj9JpX>#)N%fDy8s$LkN zA=G){D&O9h>)$QzHnEDnx-s7D0lWed%(MV=4H^S40rkKo%Y#uzdSGck@>~5 z^_!314>{+R-FqYCT*$#1yZc)z0_Q}|Jed-a$@f~YuI_4Ij9&Qb%a2T=o`p+jh;Zpm zUma(x5&2#E$k*4i%q~xez}&bj*MOV{33QQphnu7pf(zbrB* zn!98dU#nBP^p#KIGnURfX;q;s#{D`XyDnBOL-dOF3(%O{%e5`{q+S%ImX=QSD~yhg zzL_)aUg%2~U-$UJ`8yI`-V=Ou{3Z7b?U%1#?tXE{`*@L#*y8V}Zr+Tv`fnk_S9O2+ zyIun+h6D~q6NV5^!&h(qU0bfjc43qId-;mWOpk6$wGX#NT&~u&Stoxuv$bRPUM_+xw0N^}DXmuBw_fbKC3d@#pm)WezBvEgwECo{r7n{Wroi( z50#+cdsQX9j$y}_nccZ@W5r6NO@7OhUArDliN5uq?H%jZC|M4ch~qD3-gmdGIhTHS zy4Ar${cDO%zw%z&cOq@`*_e`zeecz_oCPh=PMCYH?&~ajzPClStCq}jo6hwm&gXCM zIj1Y0M>>A8n7{pzZ}r9aWsZ-1eQ|MdW@hI(*DKO5m$Vy5F+eKPuB4hBzvc5*#`rzF z_?vy+Y{{VHKF&AgqMH}~_mB74yXaHRPf+9O_soMw4o%<^zkjCCLVN4N#Gu9UQR_|3 zAD)TiZgncXAF}x339UT^O-x&t-|YGNwbXBA`{J4Uy=J;%+|LDnOt#Ig&taH*Htn_0 z=T6i0k&gb8pZ9igTZY9ynDNVJaQzTkVg{oz&5qxlxFnnrQ1kmgx7ZP)*g+-n|5KYe+= z{$o_@-KJ%aS_J2WOb_M?&YFFyGUL|~i%RXXM_#m-rQ$y*m&%GS0>wHQB2 z4Sj1-*ev5>z~(I5wf1v*z_QCP)5In$?M+-;cXE}^#V60%euUP(j;?ZA8e}Qcr*%2~ zct!C0arwt8Q8P;>F2_**?6KYnz(?zSM8qt)r^{S_9g_e{Dx|LCDR z%irw1a?{PtEuy?XLq4=7Y4OeLd`$&S46|nSeLWyhJK^3uzk;AvGv#Y)pDJvmrKL;0 zWv9J6!?~D0&FymA#ordOI*Ofa4StY9MxwaX{!izr;wX9RaJ_>I1uuBb^$U%w-te8f z{-Dl2&~oAJ`BHag9RHHe=eO!~eD_Nqv#FxhrWvh5?>a^+V{f7GyQbe@+nd3^ETJnJ?~^J+&};4?vp3e9Ew-Hx?FyB z*D~!bl2(T=Y&5pA@)FllU*~(J#bDMwofjOXR&%TN%6XbFY%vGb)S^c>?2WnleWn-V zm&eb4|NnB-nN2ooQDUpOD6l*<~I|6gEnHU_;*IVEqe_E=r)^BrWbBJ z|14E4KK-oO+a>#XrjJ_K6Ggo%WhF}6Zssg&d(`9PZ}zwH#SVsDdM~eDsB3uo{kNs* zdgew4z5Z%eU$)$DdGgb*S7IJNe!RS2;)QyE|Ki0xRtGjpYRmRZ zOG|@7Rp{=uYhtC#L8}L2sK3&)8M#rUH?ibHLS1A!qE|>B=clK-{*TqZI`1$$g z=T!IcE|@-jy8nE=nLf*UdwKn4X0{)`c;=!}y6&mP+5Fd*GI_2ov69tRx)0tzXpySs z_j}4O9}}syX;Jc}8wxCPHb$^GKDgr{pl)$_-IDd`u3JLyJzn^DO4PjK@CBCM_X^)l z2tAWHd;gyY2P0d9l@|ZHGrx6njmF$fOpOO-UcWE#NbFGB-q|0(w;AOf(y5-HW_3OA ze#g-y)3uITtR-H{gAHRnZoDl!a)IGO9cUbPs&ZZJee3wUUyuCkx|#HSyWP?m60XXn zdRx8riM`wTe({+{(*Hl}-rRrRu)vqk_~~lN_RA|)wlZa0TjuBMd$l(B=TzQV2KRg8 zYb~aqzPR9HS4YdXuB{@oB_`?V=*+QDwlix;v)vVU*<)VtG{-gjFFtWv9kzOEe8m%m z7dcJ~6R#~4>^~m)Jxxtr-G5K$mBl=4%(5}j(a~33R$ux4Vu|B@r~4kqm9u*tH*MVL zI6K#9X2jjCr<{Fyf+IDzS!nOK4Ag%fQ}t!(+><^(568|j^`E@!SEg4=$7;t-W$b@1 zsjWYM@=)cP#;Tm7)n-@bzYIwF`aDFdG^||YL65%2)mIxg8opvE)%?Dv+~ehhW_~lJ zwqo&IV)WDrdL6>ZbsGfOOC z?QPFkLm9r!aZ+IlZ+uFoEuI`_+J8dEcjn7CF3ZEL9&Ovc{pE!Po7wk%zc_QwFQK`m z;$mVe_Md$Vy6Ehs?0h@#_{m;NU%W2fDO0Oo8g4jmT{w?#{-ctIjaknaF35q>+1BQ| zpP$yeagR?`?Xivjt=)RR_Z8RN%Dwg<-ss-+f0wchbZXkp|7<_!$Y=A1HOo7g@4T_@ zirG~8N`GHpQ*tG2OOYqcl$BcXPHU*j4H!So0RJC_G=kFJ)El!H( zg3p+I%PZ>TuCkQte}03-Z2tM*HTyPOMVLsPy>uz)C{L4}M5jyE+-ZL6qt;*d_wx&r zT+{LNM0606#r=uYir z^FYCw@qE*&lnsxrzxr%(&8z2;uT!9fd>5QyXLa}D zZf8^XzXuf^j*HI?dFj>Wclz?>%U|C5Ex(*&b~)2)yZ`Qfzn&{|uk2TTvzY(V@+0dP zI?veGy>EIQ(_a~@xtAnooNM_KR(i^2*1h`7&o9=_sbgK{#O$ydG*x>wXh#m{x+LS2 znm;xFqvM?7o7-OP=rgptQ+%C$=23IK_$hxsd}~~7-fkeWhR^=0?b*Y>b2qH~A|1&c zdQqZ(Ye48;2_CjR%kE{$5zZoaVQ&&G5!KgO=h zQ`jHg*|PZVl^4ZnQ-73CU2#2hPv*kwuOq!{gBJh%TlaELxKr`DUCGJGq07!+abEGc z<#6IJvDH_-YCX?PUwMAcvk-^--u8`keLqY%|EB!VoV zZoYH>+O@E$n;VXHp8vAg%-no+kM4`<>(;CZIiqQ@c{YDqPgm&aNOQjzkFR7}+IGc> zt1~R}H+{Q~Ay=ie?%c(~HrF%S^SmvW{`U{A?A+}Bg7;~TcD($9``;E!v)t8uzopbfoSnp#$|J>>lsqMGlmV_1vxXsTgb*XAB zIdkb@!#-XHUC=EAR~+n2?-l=he8%&_bp2Cx1=0WK?+JJ)>uCGp+)E+Q(RG`>V|HDr ze!csNv2ezUS1(Jf!az6v+IUE39s@{(^8rbMx@CCUGBI^YioNbu1$`@_&|B5O{w-LPspjlH-?=6<5Ue z$`{kwm>9zX{N(LZ56+A#XZ(6TIlI+crDf^i+}zyWt=Vbm>Hc@}O4t(SD)~jm?%J0g z?srn^*OiNU$M*+MI-BNS^Qw88^1a+g`r8%0sakFJ_4AYJJ@!og6Z_=FFLlpkZM~G) zZe=$2cJ^EW-*(--rkDK>gk&&exPqz?F}Ax0R5~$|1XOdcjcG-|C`SKSz2RX;N)){3#7NK{K5>{1>v8SzWL^{qkU4wfHZoflnP5w||SZvEo$Bl-6>ul-lk zusJSuV}wmvp~tINe#<9I?L5_4^d(hVS~@v7ncbUD?x?>d|1`HH`iuXa>~dYPdh;&5 zw^HY7r@wvs_ONM|l&{X!qMX;cd3p2R?(J$;?z{SIxn{bK-S&f?ndh^np3~M>{Ze&} zrQq74xqmz_uMAoBlRy1Hv|Fmj_Qjtvd14gOax8#=3i(gU$WaCYOW; z*9!SAH?^9~&(FX3lqJI!8Blh-o#FPd{QI513)iLV85zI$Yk&9tzRU+ZC0p+{l|H{U zZNaql?WzCEq&NRKw)i{fJTtC#R^L$Jx>eSOh8MMr7f1^_XixQ$a@eF4o;9D%w(RWu zTzCDjIksA1_Y%&^+5Qn(d-$Qn-?FZ?2Rl2<%gXwAuOG3DY|oCrw8BDwqd+aJ`{LEi zRo>?BRJ{{_eLi^c;7SR<`AJ8=f024w{nBH3T~MmZ#M4ioJ%7G7Oxym-GTYO)mK-*e zuixlf|C={&p2NFLH|JR_-A)*fWUZQ4>Iuy)Ow0Q1QY)+F9i zX+HSiW5u;=*Iopy{WM4a+_PodIlmM$Waxs@)wRM&RUcMOdE*}ccGsD+3-sgP{Clqd zZT~~ou8)aR9%neO`n0y=o`3xLmu$B2wfk#sbvHfOy67Q`eZw@rxAx~!-X2@am})dL zVzbWAuZ(`Bw}e|fR1S6ikI@t7ZSG(DTjyE%*InHTe)&&$_GBKmFqS!5`2NI+j(YjO z8o!eE#@XB2o?ZXbVSgd$P~ywm7ABX@KY!d)bm`|Q4N+^Cg+02GvvS7=+1#B+lQ`QC z|B+^B|7|l@&qmJQG}Q4Y;}^%d>>n%3!b)R{Oty&T^Azmj-7E8Jrf=WU2*#%ys~`F} znVjQ!Aw2(DhPkhwUzm;Sh4-r>qIdrMvHkms;82|u|8%WuyZQHSxh$gF7`96!bmg&Q z$9|-HTQ!M^i=R!~Jms}o_tSqbef*Zcc$J({_3%qwty;elBf}gX(1_j4Luv1J{}Tmm zI=AQC71Q@Pz5HwK2dkftcuo~=iI$hx_Wl3O(-qnL{~k#&UV$?v)#h+9PzXb+n(#d^788n&nZA7u;%UYA>>XJa&_cXmeUv z)oSY45LQoeLW zTn$`dJZDFl*>XP4zj{?agE$r(jW%6ldvw*rq^(hr&r_-v+pIXjpX;+`()p+@J6kV3 zKfL}$0Z;7H-3)W(4fv%PqCl5@TAWm!Wb@$V?+^1&$nE_hG`Jt^CN|F4}{{C?s0$N7O4Yco~}UwB#ahat-9v4)>#WZ}fUZf6`HUuQq@ zwCJkN`>@wDCK$gCoAcT?zTnNB^k1i1TU)Kd+69)I7acm4V|JQr!OO?R#l_)1GK=L) z-yB)JcCBvK!_8dfCQ`iVOEqs*R0Up|`E$kf*OC6l9kpK<2yt&+elurX-CoC6y&EHX z;y?b>a1>a<9=7?4bgpQrZrJ?&NtTYc*sN|?8hjBmmO2K z-=13WYt`Mr;|t!MtyF0H#UHyULTB2wS3F5PzT(v-nh|G1Uewt6FYhp}RO4h=5C%F# z#f4?7jm5?956w^1Rh~E8YH{S}hW2!ZQhoP#bCdNv5x73##KQ<;CpF8~TOLc$jy|rO~lJ?!qF_Yktn=O5*O;=z4 zdbym~-ZL|2N}gjdoqRH6&I8Zb6OTU@T=By%nARtFWKjW=_)ek=A1ov^r2#nd#r?d8KSbK(}?e*3IO z_3x9PKYw0sQU0>`@ZrPK($ekQ=hVG<^hn86_I1OedFR(3^SfPhDq_z*^_geS`i8BS zla{tFWH`GkR(+z7%$0vziX+)g-xl8bw|ISQOyh*o_q|a;O5NH{&eeRf``0Xf_CT=x z+Fnt|*}mdD4+~~|mN@%xv*cXWfHF3QC7?}@bEYhq=3n*e-p?%1W`cVqVBI`!MNr4@TF0rso8qi%3l#(& z`2S0tw?9-1wCn!uim!aZC-ko1bL%#z{RTRouCpuiF9^23Qm>%qr~PthW5}%1>vQGj7!u7ZXj-tHzP9PR6aDu4nvXyZXz`B^K9H3zHcd+CaPNm!D!5 z@q2xs*!b@KUm@2o^UKe7ygXlB{>{Jr^Iz}(C;I8>fm@6C;s1(zffWPZEUHwQ6H^*TE9r}tVDE32sWVT-08kbHXSxaCxKzI|?M z_5^;Hb$@$azhjQq(iPUSmbuz%!?bxbvc2ZNObxQ$z*S|^9D~5da8!x|n;`3JA+U%i72e2WpH1^yDiY>ff9vHM;~SZ~ zWVW1pu(&39Mt%PI_usd>n=cTy+k0c{R?~mC7#^*izWDtQ28KzXd&T_f3ztlDUsh%R zZ(5OFTu9#&bL`oEAPP+pQ|<(0(}an(*J%t5@@KEjXIdGgYti@P?|hZ#GBhbhe zXIi|*1Cte%k>(71Y3boS3u5)em!~-$?Gxu=`&#w)<~LivQYphi30c{x4+PJyPYwL5 zw;;KYts`U8K-9&1h}fhgB)xzuTW*{pIiK>dgFUr)v&t z76h5CWWDfb(x&X}?B42qv!goe?9wl8-sRII_MAT~xN+j%oK%MIHYstJN=jT0?=9+sfay3Us`aJD-9Wr|~)?Yup zYq!JM(h4Q}Ee{)if{H4S>&QrxQ$LXwn++f8YB!^y#e&X2ySIwk&;;!Sb_e$M5%f&)%N$ z7O%>$*nH@@TlU;KpL3cA6;~#T_A*CmJHCDUHa927L=SXI6X;$P9;Z1BrN0_H7hiNy znmF0DeM|0_y}Yx2*KDX|>7Sb|f{`~20 zn6Gbn8fy0AqGWD%cJ^}3-G!{Trmhh+^1$RB`Vu>py;Zfsc89HJJ$jRKO;C4TSLDam z%YBchxUPCH#h~E$=hgW~pOy$!p3l0F{rt`x;q3kdArl4WF3EQTT8}WU5;RXb@VaEplzxwX+S$m$!SU6m6RN2y_QS zMB<}^e=cyIs+Z0D`tYb8YeHogQlT)A-eEFnfQ2!*BX2)xbRhHXKd{trA@0Ek+v^vDO_iQLLpX*d> z7k_k~|Js99f0i!nzTYI$k^gtj_f)HPkDq%Ve0j0NJ^%inqwPz78VE2P5CC0>av&gj zWx-9hbtk{xsdok)V?W#ReYn88s#i^Kj+cL_`}OOflaFDN`z+1Y?pn~>CJ>-nOz8@~OlS##2&(`C^@{+-z-Qelh}nz>FKcT4!wsQ274zi#Kf z0F5gxf(yb{KUHtOn6c%NNXW)59IFjJ-n%Eaw*`Eni0VqqqmP;*vp(6*hjl!L?s}?B{>8_{(zbqVN8u;PTnC!h={BtW1rV zs_~-vim>106`$%WWKTc6UR73VAu~sd>&pEzX~jq1n@aGkvAlc5Fk++WmXjRG|5r7C z{va%?FI2C;;`GMDk!~}j7+)7KHKc$tC|mCemY-)_{?Gom;CJ=*ve;b#&OE;L^XekL zb?1Mnd8*GoZ|~9%Jj!i$&Rnx+mMwa-JpTF8^Y%L@?{iBuUAXg=)B5Yh^Jc7z5dO^5 z-UPa-&S&i-u8LCmw!$LAkAZiD#SdNpouZ+<;mao4SJ~NYB;=N|!j)Ms^ z=FZ)_=o(|K_sWn{DMnv3H{aCRD&v0V@yCikUAfEpFC1TL|FpL%L_y%e`Q~MdGb<}A zD=Kyra#!q%(Yt2oEx+EPGGJ|3_1=54rUfnO3(*n#{L`jZTz1LEh@9Nq+}hf?|0a4Z zeIerh)?t6&zGcgP$$dFm(sB0e*^STax^v8=pKE>%7TcO}#B#odirv%mav?OSUGSt+~u{l(Uk z{U)VH-;-r%U&>)-XR_WOzpwQBqwG^FY15+@rk`Fd^6k#whmF(UonoG+ z*v$8I;cVaKvY;(Y2g56lnuBJv=Uvx4)_yUnlt(#AwPBfV;qJR@0t2+BW_>Y=HxZjV zbLK;zAib$xpv|6h!c%u&oX**lU^J7d(ZTfeg4m4_GQ8YdqjHPC37YCJ=isc@lgM3o zGiTncSzSkyOd`%c|7=pSe7>2zy+3os$#V*eW1ZU%JbLu#*|TLcaxP_0x#g4l@7ra? z&AWDat@WK-{J#9f{Vn1zwg$wnJ)P7nE|hC$$5F}9^G5ce@QU#DNkNlyUjcg>fBp88Xx}fdj~zQ^ zQJ(bT!nT_^YodHtp8dU!N~twy0<2sM3BvVHrci zHBj3`%I-nfk2}ozC%)D^-MeZ2y{lip9Nv2DLhSy^1;3-`zxsb!{Pgw1U5URZgc-N& z{^fhK@YB%Qp|0* znzc8{>&->Sm*>u%d-O;tca`7r;FTfm(g8dD*M@O7IV?7nx^i(kYxBVfov`d*KKGsO z-#(MjUA*4u&XNL)GnEzd<19=&4nLHTm;YY1ck$xICfk;;pZ;TuW>(_nn?Am8KUTcR zpM3I4l>eRX+y2t_=Ag44gnHe?#l&jtXUt7H3pF{5HnX%S}hKegUuQ>fQiS@{p2PGl%K80W4OWnJC!n5h?7ruQM z^5WU`!ew<9rlzH8-24q9d}4mFI#s9Tq@`a^$lPBtZSnS;Yn9CxQu+7VFOuP9@ZbfN zp~p-gPjFP9|MlzsZ#QkrYXiP@=g(1T+gGyi_x$}gzE3pgv&r_hGhS#QZJ@Yo;qD%( zo!^)Jzg+rK@!p~4@Ann>eU)n0>H9JGHuHMg#+~Z-Gn(lmJg->1n_0%%usA=ze_L^G z?%DU>t>^k}zL{e*Q%9`(@WX=LcN-lN>gwuhYv*p8Stqi5ok{lomcxm^X8PVUbz3|! zShO*Y^||4Q#Y@Uid6ZWs^JO23bd?~*1JtLBY);h0}A(W9lfZ|U2G!6vV7uhiZY*KNVLZSU*$M`wuLeMN;Mg|^G(V5n_Q&erQjm(Sv-z;t8{~z#7bG|&^oBw3pudnlV z+uiuT%wEDrMV-tTpPboaEfgGR5uEoV1g?J-~4&@O)}!z>FKzA(_b z3xD~!A+0%;O7>3mTI#fL!{*JCPd|N;f9uEHyLY3wFUtMPJeg9Il(Z-_)tt|G z_Srd-E59saYGepgYEsTW`jlPVqJQK1wQFVLx+d(JaQw05Kd<%aWtGg^S245Y# zF5;=Kc}DD)X~$PhtIIi`dD?jA*|g-)_k!ys?&g`RIWjjaQD|UmNQ*a|n*74@{{ii9 zRr~+UE6RNlHC;pGwDbR8G2g%2-~WAbJFkuU+8GkAv3JOVtxpeh zj;XR;u$#}{>~C=@!(`pswHuk9IxT$g{Wq)Qg1%g%nQ3Wh5yvZ>`}M7O&z(CLq;9|M z*)h>GX~xfYED&y8vdZMb>TVaMHMJAZroEJ@{#9%@x6AVDBjcGq!qb$N6bn8-cl=;a zzSZJSyY*g&?BBin_MfV27mi$X{&`L^{qIS>JHH>j)jqfO;L@c_-Sm$#G6V>N4%amk zpY(K*%;kHH&r_@NYqG!ZuUYwe<>Vt5o^oE?zi0XL#{Dnr4|6{`?bv!a$ZwIM`u8Wy zE=v#DU;7@ue)`{EGU*Q;f93rDx;~)i#>Ir*1N;l-`Ym6=lrj0_ky$O?^7*%XoHsh? zE>|e3741G6q4Vrxh1A|SnR*jD8=EsLZ8z=S?H#@1$Xv@6C3}4Q{EAl1NjI7~bLPyQ zJ9n;KyEa+fuDe^~T6UeuUk$4XFT<^6`d(eb@x>KOmU(_+&e$k-^ksk2 zRIj6)tBzEC#GpRd$-~JxW1|2hS{qghczJ>MSic#MlTUXit z?rRi(`qbO_=_Q#N!m*z%B4XG5{@ zRPP#fhu52G!oHeFojr1drM@aQ_Q~g;GiS~;j{n`atMT~bhbbLbqTSrw3_i7VtqIfq zzp!y{?bRnoU%!4G931@l^XHWzS?THSIvK&Wa=Op1e~B$Qwm{z0(lT@NO+PVPc^UCF zQ@nhlR700K&N+O->&(kHQR|EM9e()0ey#u8YdfYb{N8l+YN+4(1^%v!1OM52XSH9v z7r?vgT>rb>{A=xtU5(Gv>UM`I7F}AU_m=hNoc%H1 zXWsvDKITo`3*qLC9A5e6eR1p0rx>j@V!oANQ1C3^oYrJ@ICElX!( zYK+QeGRe5{^80T~V_WXlrX^z0%$ajPna&E(IP%gyRF3ar#+9_qE3al*Y4o@)KK*o2 zo@A%X3xhkiZk>8slr*z+(Up` zGqABavwyXETJDJAeT$>X&2)y3;+xfVN z)6SZWzu((i7ko{tEVDEznsU{N(S-L$r1E^Hg$7nux1OvGT^W+LxiT#+EjxR)py8I1 zV?`!6_}H4~T;H*I^W`&=FD_)M|GOXNXJ7cTr}@jz4~BmKmn8=Xu*~&KH<5a|Sy@>b ze4n?^`^EJ?YW8j1XlOMx@c$CwjJn6h9xgxs<(iqHVd0xz+gIuj3uc(Im*wXA z23_5|aGz}F<_B`IIXmvY>#M!f?pIZkl{)uJS$Vl?#U*CQz95zInUU*GKa`ZyQLW0~ z7x!(l_3n9fKUzFZY9Hszz4$j>|KfSj4I(y*x3Z)zacG?VxZiiJ;FE)$|6a!{{=OLA zpZny~q2~Gt;SoIrE^6(yr$wz!3x6HEU~*vb ze9eiOVN$(q!B$~4756iaT;%d;Qea_X^iw+NKY#kPX??Ns{yY2qm|i)D{FW+_TRi_f z=YsB|i!Q&Maxc2Dvd>^{^otowb(d^gIyv2HE+1R-mycFvB6HV0fBxKZ_tpT7fY(>G zk1efr%#T>Tdi9^l2DQ`bGEFV5YtNoK#iiY_?DN8gm2A1yJ6Fj_OFs^Ye|d)K0=vc5 zi!U!k#KaugE6Ff{19YW9Xx7w2d6GUl-}b)m-?jh$&vokO<{Pvvdtdb{@#gyTrS;#9 zYvq4DZhW5lq`0p2tdITv&70Y`CY>?;@Fxd!tp2iRo|d(Bl`CT|u}JmUGe>2)ie`jt z-nTE#P*7v4m$9*Ny6E*T!!4IzF3IgU{@A48>6N9T_Nve9TE3=Enw7TnV#W{C(917P zT{h`qtzmoU+(ScVQD_-p<-lhZEa;0 z_1)C(=v0QE-CKi%eSLlB+O1nO|G~$Kpp_!^UADE;&LxLVJGWrIWcSesO|x9Hth?LZ zHYDs1v3kA3Pi?a7zclyuW2a7WJx_ATDi&v0kPNzGA~RT1RBUlg;j;h!aW{(JC2xwa zS^WBvv-&!LSieQ}b>-(d&(V37kZoNYsJ7xIgW*h{ zIZqZnN;&-UWoGk1g|imUIwp?GPjyMp_fT0<6L8_!>Z@5+sTVUhJD%0P*7sZ|PU~I* zNBiL`hJJhaR7{QLdcW*_bK}cQzoe_;^Ol((579bW_2Ag!j|xfI;YkNh&HA%%%a)M! zUZ!iULV{M-*vY@%v8?~{$Bx^^3<|8E$wX7Plg?FZ580c2_>=R#H~;Owduunv&$q5@ z&DiMi<^211JO8)+GvDK|&t|p6#>?mP|3Brrs?~bfXvfYw-yfQn{69T?RnI5T`5XsU zuh+YNv2EFdGY!)c7<4(9RtvDyPH^iHk`(JY$;X@YwQBFh43n8YX`5&MTXs!s^@Xm5 z{b$o|-@28Qs`|xi>1P>j^=`qVNrpD1+*f6!!d92&=Dxl0!gBt3eLX#^xqhAERtuVU zB`t~55o2z2_}tCp$vf9-+Vtr^Qw>+F4GRyK<#S)VP}EevRNX4{lkvOeNxzhpm9M@R zyj67V=gfODhQ~MeUYu?E`fuN_S6{xAv@c)%=rHe`)zdRfx+cXyLt-gM)1g%99@k&@ zKQzs|eNX%MdF$0P51d|ouJC2koBQuy?0tHkJ+5?XjqREO>)XbiVpq79Zjvcr+TB5;NVu>vYtFr*=DW%L-Rr7nk5*24ar|6q{rhY8qW|srf9v^_$uA72A6g>6Xknmt z`^A#AnjBxE*tj?D>)-Qn`_e6|b0&L>?~?y_DQzNxZx>m%m7Yos;_ z)j#;l)uhmJIPuz#-mRTed=fYe2=qu+?+@p8xq%V>EM#xYPQKs;a12uB*?ls@)TpZ#H}FvU}ezUAlDQ zL`U5EwBx8Uz%3FGiJ>~wNpulIyPPXjRk?Lh*YMeMxFe_;DO`m$}xqj=fYhSx||K`n= zY1cOYxP0lQN$q3KbAFF}ZY(a|9=uYdR_6Ei*g~z^&ZEnsUKlN2_~Jl{?ahYjOAHEv zphClTo&VLRmt;Cy|83v9=J~w-Dc;2~y9z!@M9mTYdxiC;{`;5zmg|4H^Rw~a>v+S6 zp3{dJk8aqq+I9MJo7JaJo1J6-_5a7LdB5$ney`8J7Pj=sC)b<&d9Uj)cZ=McShSDd zH{C!Yf^iE=x~K+xz%xQY~QxcM{SKN zA4571=$2=}sX>WmCz^$s&!7EL`(am6W}o|e`>Ro{kLIU;^LG7z-F)}|f15!UG5(j1 zGnf%K(Z6^4^{1CTm3x+5-0Bu^Lw8GP^U;dR-h=P!L3hh+-TUpd_{yDC`+vMUct*=q zx$3fH-&PCb1xv*o_zSZgbMo`OSLLv_N3ESVZ{9PTC)z7T*JWg@tE)#wduMP+b-Ebn zurqvXb+&BgV{5*eeqs5>-Me@1*x~VBeEFWq>g&W_f30F}Wccg*|5)d`y*J;M?V6U+ zS$#OY&ZT&s$Kt~^6%`WYj~O21fV%Hydsw6|Wr^s`u1TzV&}zMR{=T?x&FiOJzHwP6 zyuv_tR^18V=c)F)SN~q<|E2beFZ23cRRzg$hK8#)%sOSfnDuMG z*?jl=J^MF13l_hb{(a7qsdk0?e!sWB{r}qZQ|YzNQaw-41)XNS06L00b#_~yuHl1= zpi$8&rpL2tYv+FJF4;D1^S8$b&DswqJ~3iAu>4|1jh%eD>*ZZ1o)#TUm~c<$)u%EC z`<8Q!C3U+O>6mVLEV}p7>#v*MZM$U3wragh+Qx`WFHN-9%%3yIC4!$Jof{Nw`d9z$ zNthieH}h5f+09k^K23kB^2?n6N}}JF_grqL>uUYJ%`Y#je;vGc{*TT7%=cw%m@+~C zoW>sIF2UW0l5VY+x!aJ+6Z-q>+_z#sx0FA4b@o%u^Zk20zir;_7g5?0ca%Tx_3sz6 z*@C^Feq{^Y(Py9hM@U8}Ca2wOhUo)M5iVtAWnDvyC2gr^H)>7wI+zd;wEBC8si7sK zNv)O$7by6XFP_XTDKQc2z8d1c_}3=sl_6O*H8QC?9;VEl930lPON`4we%a-hi!N%c z=K1pIkY;=FMCCW&cxE(E8e&{`=$FIWLBv>8bm(=S}$cQ*|}&-?!(# z`uXa2b$&(h|JiXSAO5^aNOH7$u77@#T%kscS?kddy@JFm(@&RQXkD;l+rl61|6>0s zPkF9zS$^%ZKc;N5wR;aGh1@vvH1jUw`Gl&a|8G72R`)9R?)}|cW0Id-a#ruTGQTe3 zn|%E1y+1({4G*_0dbHVPOALcA^SrZXeXki`fBg9IrTK-6L$p9sjm2xYTAQxO#azuW zIeq%{oY4IlJM7HO+g0B)E|4l&x8e5NlCVVE{q;s)=85vP`^T3tTTS~>Afz4Wx^(4Y zcB8#tH-DBWo-+X`lJ_oNt| zteXA#XU&f7g+~L=L@tmJ^@dj1etR6W-PcvEO-d^Huqxy|Z~nV~--1V`H2ZAHH;?6))jJlxj4s+4 zqasweGiJq3#?qZiw{G1^y8C27UYlJR>%UpO9d8&Rh0(cXVN<&`-IuY&O?X}X|8@1d z-z(mzmrr{xetn}uyU0JA;=pe&{@$%GFTT(IucE*@YTnnL7m=%e7%$Kj>%L+Z0l7?d z-UQzE!$SRznLn(|%#Kxkh?y1YQeqWrBln#Bg0A3S<_3}VJy)_e-?T9`o$9spg-nFj zREtED+AcqfpEY(9JuYmISR3XjAi(Xk_uiWo@u6=jUY6WSF!Qw0V5Un{wv&OFUKSMu%!dw+YK-#24z@Bb+H zKRZq(o?rWon8=+87XNrMGTAPyVf~n~W%H&@N*~=f9G%sLx!D(QeEsqB-TVJ*-rxW8@_?!3&o%yum!`){dCWVQ zkYH=4d6pq+E%-JYvAqi~_8k%5yYQeyw%JCB1=(ApIP;3F=00P;pc_~#&7k79GK8zi zVY#E#+Y2Y}{ILF#|BItGX7R-fyBU_*I5+Q_fBB`)(jfQiX%3djVcos`{hP%?&pj{@X@gPaRK|J=ip?XWsTYyI`pT8WP9k3KB$D4XIT z?KXS+=FNvY3srY~bXz>}swbaTyN{2LLIWE^!!$LHrsIzzqoYr!7{Tsz3h-)b)e~8{ zP%BRQ!cr+y*`{g+3vG@Cj0~#+_!hS+E{-!yny!D2XHUWM_qFv`iods~+W*R`TzNqK z-2B3seW%4!L9_k+@h|=!ivP0z-_K85HzeJ#TXHqwRIzr}PRR?8SX9p~G7p;9wK{Ay zb0b6gx(RplrawrVeKsvDqi#ouDcej2h6}G)95>v|iCaJY-ujpMzsxVC^PMY>jgV(z zI0u?RZ;+A|>5-G4rhlH##{TyAZ{gqWeR_WP{;w%-+P9yst1GvhRQKuNI&Xecvq{V3 z|6O6dsr)#?!{bbM7_R@o!~b&YiMi2I>4Jx1^wP~{tL`}Kw%Bl@$A&CE zJzZVTZ2`)?mm{<_CiV96W`=n$d01{Y|2fNrR;Pn+%alO@w{6FluvJ&H90da2KaD6k z>UuqP&C-S9;^KkU(hTRgm@*g|f@1~$m!)kvyy!#U3FYAConITnWAA=ncl}Gr!jc!k)v%%lMyPVK-fNwEn{U^l$%Ts#e5& zdHnJ7Cii!f|GruG?)}|cpRaxg-5cH2(jO{}f84|Y0jxv4k3Ti)Svy1Sd3ffqXi!wZc+Q!SG= z&R_}O#?ZhAI$w7|-H}Zft=1mO3Amx#CD?xG`854=JZWK|`{nEJnm$eV)n@+v-mi7@ z*4Hn1eyI2E{l7lnzvsREH(kH<|6}n}|9||?d-?C&Sx^ZEs+#xxIQg#K{^I8Y_rKIU z2JNU{|9$iO7r#G9|GNL{QseY@m;5K6|0$Z6UK#7i*ne^B?65hEYeTf$-Q6Qo7d-yB z!^GYCQIzfO-MiQDgwLAXkvTczaKzf$4IlNUgPJ}J4(@>~L*``9K6}=;Q=gZYAs5t+ zb!gU{`gG^XDBnt3=gD!2rc;-D^WQ%G@ym}5hpZQU*m=7C@_fVV`Tuv!ed^!&f5G~a zo2Lr59W_b0^1p1EanaImSGyQZF1{?u&dwH{|9#H<`P0*Oy4_mkp>k-}4&P>z%x&9t zyi(52sSMD&leZm|AQ)b3NOZ4E<-3*~bo=)0OEuH@7_1nXG8h;bI3MabX*^|!n!_^p zWJ=$$9h2sEWt&KC-?mN5Z0nTQDyyz$?Z02213D+O(1ekJp+u_ts8e{)8ule~{M6t1 zGar}b*DrICh~fMh<)hqS4HrlyrgBS6>Ba9Epm5v0(KKA2k_Y1_p+? zZp$yL3UOZhTe{08c;$vXONKd&ETBVegpy38BKiHiYS^}TtPBC?kr(-z{u>Qv`mA{< z85tY9^y6%k?Q?FG6&6kuohvU=c|^+@bo!6S;)`q6uMgkjrygsn-_z36;+vx9=d&4-e_I*Tv92#vX!BgP22r;UBl>z1capLQ{p ztPJ65KRl_{ikIP*G&B;XKX8a`-4(FwcD9&KK+tL_m zAhE{6Kv?=_-gfWG-z)hyRGnz7u<2uvVqjRn%-IAwJ74SI#!Z`=Brh-&s0lbQGcb5? zFuhRQVvt>0;WU3zMM?JNn=8}{E~QsxZj9jhJez@m!Ac-q(COEMLx-4#YGPt@9JpT6ym(F^-Kq50v{U%#wCLEFIRBF?bpXjk{qBm;>l zpGx@{wirUvL6hVK-lah+|J2#@9*EGjF)~^dqNTd~@0Q%;j zzI*qHIb%&B=n}J;FTB(ypA6aKbmIAEz3JYk%x^I+=v4$o%LIWl4S5>fM-Q#sFUZx( z;yB^cx7Al)y?mK@jVCXpf`x(MMM2u;nW7GtRRv->7Irc`09T9*69noQbU*&wDYQI9 z>-h2GkuP%>27neQ{@9}6DDdprGq0sW>J7`zw;fLGRDa39z;I!K_DL6|z>oh*Y~-%L z{+gl0U;&BzC8jwJ40jcx)|M3(ZhW-sLrQUR@UOGl9Ebk=v9WJBCIm|Rb8EH=bG7!x zz4fSHn#z!o4@vYasuohmlQwRc_B3F`)Tqepp zY(JIF$iUFxCcu(dQc{wcnOR(HJo~KLSDk3YI~^XBBOQ5!EaGJvl7 zP=Y#Jz2V-?n+JJbOum?5^7-@UHJyiV-@Yx@y;L=>BW}IF+T=eBv*P&jLO^;L8cHC= zAt`_E$=-7d*jY)sTA#)XZls?O$k^rcmjffL8!@<eR{=)k`jC)-lZWTKc8R_M0_Wj|U4Vt1xgnGQ^fk^{R<*P4!yZwRYCY z6d6AE)jH>#Wff+h{lxqtLg$(gw-)G<7wDBG3<`>K7^Jq=`nO5xPV@-LxwLoh-VBpl zPM=$S)r419%hb894GLrdTLG(W4)VPC6{Iy4bOP-!=|+bIp|A3J-imKdo62F&0ouSV z2r3sC5MI`Ciiii_WuKRy-+y&U+3vlqaeZggZr{B5kmbVCAWfl8j;4lKey|-vpq2r+ zG`udpHNr+No%KR?cD8PaUgXLUD;d6PIq#YotiauUu=1DCnu}w>YmYVi56&`*(VEKC z*x{LKBOLR3zh_#nDLvEs4*`ug?jH;cVq>>rrD{le)$t*MV6 zKi<82_Z)^h<*V&mW8>3j-wN<=sIAG6Ms{C1_A=iOSUxTRlVf*yE34QHJl&tPEMTa;0Y2-(K*d z$~#V9&5wkeSXxHvh*>h4>|J;9;>BxKv0%$D+=Hal4)EC5z1z2~ql}vD`flyJdO2(B znqSf?6Fpvh{Wa~ibZ~I+akdMf>y%Bv8o?9H3=EusT2sZkQ*(3Q7O?sLU)CS7HjJhF zs`=u}FH=GE8#(VK2O`z+|DSq26M1zAY>~0vGxW3=9x!7;;^gUtYU@{br?G zDMpz_GowD1W}3`uZDsw(^PERVutjwF<(->12OG}6d;9k6*|W1R zK9w<*I(z97sId26yMBH4)~GMwa)tq#;4au*$tpFFcyi@_!Oj@nUzbdzK=YXP4RLXC zc}G881Dk%~7&xXKejCj6`B*VW^y0Ckjn{N1*5okgu3N9c!L$ovA~aqzguRv)<>cth zKfn3Y&6zW2iml!6xFzcCt5;g;4SHhTmoHyl`LI*tOcysI_Ia zwR43Xx<%JTnEIV7R(_S)n>KGw-WYK~7^IBB zAqe6>YXMN(sZsP?+UCgRmv3I$-2Al)bThJg!?_eAwq{0Ku&WtVz`b3DEzFy5&N-VF z`PDouENn|uuJ?Y2$tRCgH7-gqT6y^;n$f3&wWiw5@89|-VPk}hynO!GM<>d5*QTep z3p=b|zkYkw2}s(0%MOV~o4s-Sw{1HXwLpKa-}Wz`nw@`h{yuSnWA&k}7N@H#DLq=j!VM^HF-k_Bx z=H}PgrcPva>~K+9Ga+`)i??OFqiYvI%Q1Oy;dkK>I4!35@}7HIlp9droMAHS>C;p{ zhPmgT&-GJ>84X$r2r{~Aubo);#%oU(`%Ch)nN`e;T3eQz`&MgPj#>7`2$*NHAW^$I z2vjB-&p*HURlbkE|Mug%YOLn!$@LdAy+|=ydHwZ8Rgga!9AL_YKw&d2v_3gK{rJOz zEyuO5zWzFU_UtuZD)aO6OG~%%dc}f03J;l6DMm*h7lx%i`TDhVZP;zO^&#u8ryEK7 zG1yvL-K%Y3HAJ|K7HJ z`}AqkWcb*p$wLa(lb}H_1_oWXl_7pUJ{zXVFX_LWe!IxkZmL(R*=$?6^It$qSr%XH z_#z3mW(la9%)lVyzcOUiH&4YISHa!g>gsAy<`+I{$wo78Rm5M23wZDRg$Jzu61XqK z(6=ybwXfRb(@&)&B@3CS?s?w$TNBp=vF0jrHLG2Prz{tS*pRnaA5Jp3^zA7 zF)^`8CsVBE_8os*TwGkX`|lc~3`c>q^mNem01UeVG3Dp$DFHe5DnlNFL=1rw7&Yq_f6B}W8&k@C3tQW zLR3SV2MjaTguVXut?cN5a&SH{Dc-fwYw4%of7d)^fBCr4;lY||ZjiWZfcf`i%Bd71 zQRe%1@7~?Gabp_W1*^Gv$;pqk+Dfc)LDwNejE5GX1}{r?xhNfs`j}r;6}2|ZJl%VW z*Hh5>DnAeI-MbfDXl*!+sv{FrBs}fv{&$gGTuf}%w4axz6-<-Y5#c&~`0$N*h}xiL zaIrt*O4ipmZ*o?Ktdejzo@6-J@A@3whdTBiW@cuywn6ecLja`Fc3?@+$~|%V*?0GY z6V9v+l8}pQ%oc}e`TF@K{d9zw%n3@O|Lv>4pHp`)x?B05RV1xVoHyTjqid&jV9d4^ z(&amK*Qw}velU8pA^lqR_ShM@+iuG3`F5+hef!Tj>>m%_Y~C@ar^h=i?CbmNGwjSE zsi|&mZf<|HwS*YD;`UU0oL>KP`v0%-|EK!aJ$+yQp;;HR}|8JQ{ zQ~S~t`~Q7iU%U*YC7~UZn;V`>-~VxJ|Nr0nr_Xc#vHt(B^_%BA|MzHOd=c3u-W)n>SXTB|k>EnDW-|Ettw0;}t{|5tHo zdHv_v_y0WAum4%k{qIA&{fT`ae}LoYhAyb5vf;sHe|wPoLcJQ-uUoh8V{iVMA9uv{ z<6>fB{=D?B*IK*(V|VQpqaCQ80|Q_OKx{{N5T?`z*z8{2))j{kk@ zeEq-AK_C7e6_5Y(!reaU7r5emBMA!kh!2mBcJKf9dcU6Tkv~tT$NzhxZZ9dv(te!( z-}U;x;hGKqKtXgiziu+59<2uZXIkyAm&^D6eVgy?o%jdj^ADjGc0Zp?uKzi`UUTXB z$w8pY9T*NofWkZB=5hIYP-vcC8fszp|Ig=*{LE8)YybbguW$P^0Gt}WT=uur2ggt` zLWj^R*RNmC|NACgzW&e075$&X>;Ju4yVa?Y=- z>%BTZ)c-kN-!p5{pGQZ#<^McjU%Das&qMzDAE2m|1eH?_f5Bsgq5HmVUH|v8{ol*e zt9FTe+2HU9`FQLep~JSez^=v zQ#!U?AHw(lx*GrIXnaXsOU}dl|K8q@_zSKM&VgINE53d_F8}{cy1n+=Lmxp=_MzSW zjc0r6@A~iM_3F1ZSugDWefPcFS`%>kx&c}{!VvLL|Nkd_@6`o0U$2J$|6Kp?{QBCr z*=MEyf7`zQul)ay^5?!hpa1X6a;R^FL1h3#*pFY=_y61f|NDQv)Fboj|NTs#Uwdua zQ-8akPe2)G{{KJEFCDA@efz!<#Cd+;k=}@hN4v%C|9$KSU41!u%KxA9|L=Sl*s|&7 z{y(Sp|2dmq7wk2E|DR8%=l^-44z=zw*t%;!K^gz{{eRo0i2VQeegFS^-}h}Vn|=Ss zG4r~ApXW~xn=S^*;n0Xx2iJ6KK5t!L`*!}nm-F}idbRpe$Wu`4{`v8^|F!v#i|+D& zU%1={Rcn1 zIT*A^w_gAMFY)@1;!|uui4UqLD#CEFh-7?x{Qob@?bps>`3ov84%`1}{`}^k{oj}V z_P;Ln&w!-9dd)YGQ$DoYgNlT?s*q@6Gam z8eX0UIj>+5sL*rh29-hi|G(vfoM*{xUjOUm@^fN#|9&LjJR}}p^U$XH11Q4xf7`k~ z@D`H3#rd_bqyPVV|Nq^ZyMMOV|K7gT^MZcdo*!>EpRfD-I^McF|HQFy+cN?nEgL{* z`!OuI2+FvV=l@w^(rT%4;wD)Ag#G{J|39v;`T2DEQifms^?x4U|8w?!h}}tuMsNwc z;BNW8&vQY^&|lN#-=l8*x<8NQmn(j{zW?7>P+mUwNE#F-_J1$ipFFLR2(r;4ljQ;f z!-Bi&^J_kVvR(bZ&-1-4KdrC-`}%#|_ub!g6JI_*Z~y<#|7j<8@B2LW{f9T;qSB%i ztnGCA{Mv7`@BdjQqFVp+>Gc1<*8g8sJk$Q)kH_-=KD5{WI4nQs%g=88eFb9upxn$b z2eh4$;lk6&{&qiap06vbt$l0L`vFw2+tob>6$EqG`P&Zs65s!WwHs2BRf2Qz-hJQq zzW@6we1B2W)9L#0|3Jxa_Wqx<@Bevb9$)))>gF$>!7i@<|64>80kG0x&7ahp3^|-wC>-}=YGF*Kn4GwxA*_${<;8e(jMppS2WDv0`139{XaD~zk|wv zFU##yKY}y7g*wQ~2@T@jc%l@A8L51OiGoUtJL*l-FU)TTt^W6Ub=lTElWWD>m z|L^VnwcmH&U-|`P+Jiq}RTDu09}^o}`}67asV_h4*Z({XikmaFpfGLN>;kIj+U~}!4i|+UTzAOJ*c_F^$<55uI zQS&>ddeCbdtaB zLo=uX`Uz?RwA=rA_V=1QZcqW`ick6<{Vq zFet3ROv&)@a1o{pouD!TB+wBX6Juj*YinmGTA~g>WcF6@4sY!9^P#AL2A?IB90=3;OsZAzvt!UeT(GVl)P*5@AX^GMc%&MXv1z~ zanb1hRfp8=)^4#!U(UL+_{RRZ@f)@rK9F|(_t&pm|NK3C`0&P6U)bJm__F2xKIOT& zub40NFi1(<-#lgZ{mYjx-){M{^v;$iYPI)N6}H#gKB;xvxT`(c-S@ZshhO)uemK6m|K`sTiHWtZ9LUKl0IcI)Bh%=X5u*LSbIlz(rJ z<*A<4H{X7E`gEz>;y*KgF_KQB`I2Si;Kc(sSdOJO3N6Pw%;WeA50s zd-uNO>Em3$9v1a~jo_<^`g6QKIL03Jyl>tw=MWzgbLY;T6Qx(?_j|O5ZF~IRrIX>8 z&h5m6w_o%Ad&)dr-n;qs!{5KFm)SEr3pg-8&Ob9%PEPJzQEZ=i{=FB5c6N4l^B+F? z$6qt?if6Rz=C8r=mp?nQTwvB-TYrt?>j`l`)gKGiJra4V-mq`)UfI&p_J2L~E-V+) zZ}Kr`uP@K7Y+CHIan>z9{;Mc^P;r8Jl#0;XS{vzzP)>Gn^$hK(`>Z0FE5NUPkqiFXKz)s@8R`Z zx9xYRHpoR}dZ+gW^w&HLY2tsS<#(};DdVrH&-1IbrKPS6e{*gpE_hqDzv{Wp?ZmmZ zW#9S>nams*czIsCUt3?DnyxeN9rJ4mJv)DAwmB>pW`{;O*?wyM`(C0{^os`DJJ07= z*YdJ5elgBzZw%gZ@A=llzgp+?+*!%yV9%7XpgT4w`D(EEm%3w4LTfs#CL2z-_F*bSI zsgC?N=WUwXlixn4Z{zp%z5WyG@(!~uUHV)+Hr?B3iK0}gxSr{`D3RG)r!8KWw^!&k z(~CD(?-s;at>4%7%+G$;&ndZg_{`&1&E0!pR?w?Vw_o?|zDdo$*q$%l!Mo=|Uv=}l z%)`Ik%T~YmbZyOkMjl57UY;H5TT7LmvaP=y`h?#vJld?TzCJ(v?S*#5AM>SkjdkS} zWjnq&c61kSf6DqT;jjPtH__?k%bqRJI&F4$$De$QOSAI2_5@82_St^HX2l9k&)-{~ z?%uuoX!BM5=c(V>`Vw+YWU8t+eU2)5$a-y6JVOZEg|nvj-&OwlaDG-+{N=0L;vJVp zPww|CkNf7b?T*2^Z`x~v=lx|D@^krC6j7~{{JJdt@Q#STv!1`azP)k#_U)O?8&)N3 zUha0v#Y;{0`qeixVimQ1pUp^5^|*nnY^&b*N}WudJ@MC}oQmIU*LU2X|Al{T zy@J@eCXuE(ud0nE-*w&ZF3|pbe_pi1{}bnKZkpp#nfy)1qTGam<-&oooJp5t{@i4A z{xt_+NTMZ1M|M<9Df!pth;gU zyA5)I+h#u!pA!7wU*mc$&)fE&t8G55&+R_2M(UB9^QoYXJUk1mv+EY@SJs;-96QT$ zlZ4jKg=_y_pK|5=R%6X)tQY<@dT=gZ+4 z-U(OxbeGB5PCb~<{B-`CW7^%f;vRQjpHf# z-e-J_yMKqz+yCDG7f0W{`1W?g{iCH>7n6=hcPViNZOuDfy_vUS%m2FEm^~}E?yYUk z{xiX*VBfzBzu1#5Miy8-`PaHl;?TD{3&cO)KNs!r{KUFVy#D&~Yh#_4{a{dNV7qm5 zXUN&im9pB)q&usai(XHS&Y967YER~J-M7nJ7MEL|`EW1en)9|bf0*M#CzS>N z>j?QQUN2OeZt~{)o_6*Ne@*Rwm8rjp`xY{dO{H$dllYw%H+z;of6Bk>^Xg?L=eQSy zn>ud#|LIr3)?1N9tJzBbmR2Vmu2{ohm7DI=Ji+YrQo~%UFdfmRyNvb6a~{vUcK+O{ z2XjoTW7qI5c+21UNA1MAczN0C=PxBB9NK5Lon4z73WTn-da?}>9RJaWY(6v<*Ae2 z?ay^fnO&6I_F3X@#k!KsFUCNS?q%4 zrs%JCqra5B?RfQmGJ}8v^YO&$duNUP-v$`(O}%wRe{PM)+h%$1On#%eYjg5n1wKE? zm$OJxrv1D960iJ|-L={O7v$J4PTZ?|`=ZZx%UKzZSuT9ql<|CV{`>I1Yc?%ZDYgHb zfA?!e^|PMq{Vncm8K2jC)t}wYI?wNwWsQZXhPA>rADaW`u@cTQyBROLw#6x|p7q znZ4gE=iHnicW;mJs!w0`*m6DHEG(M)G^au@Z%V_G{a^Z*-CSmEu*6kr$EJd({Wlk{ zTy`^Va{b#A+;6n3ZnhSdaA#XvcC#jZ*L^#~wf9m|eCq772z$e7-IlMymy$c9cD~sq zS+wpl$JJ{rf1Nw{QkA#)yy*|TB)ehn>zshwpTF_0D_pzuX5y6l{jX#?crz2lzTRK( z*KIK*LQ+oKOLb>zZ@=xnjG5)af#SsX*KBM5UeYbz=s%f{;gVhISs$zC&0Ci5){0#< zhvQ97u=T9$`j08gD^hlEXz!9N-u`~dz1Jm)bD8rsP99CIPe`VFHZ#UXLYA|k@=av4fBBXup+x4@i z2H!HA{V7F%=DAY|;cJS@Zt!h>&3`KI&de1NtBU?EPtIYu`^WgzwrR)ZX3g0bIzRg7 z?QiE!8Gm?tv%|Qm`tbWTxqC~q7U(|z%)MaqeOA4=dAnLKy}6jdz517BU1Nx!(#E&V zldJPC^WDBs6DpIx`o$_!jYTgm|8(sO%TGUEa!2H9%en3O1-;%2JzF(J=l+#Dl&>z$ zmgF2Y<5zXYXWmMa-Tw%A@e`0|UjeUo0POW4<`+P|mU_ODv;CfU{f`nS&RyP9)@4L&SSbmw32 zJA2>TwZE>O@jKOFr(M0Id*Ry~A_;K}vBe5e7IjOnUWyCloc;RSjkdzy47d8eXoV|y znkVi5_r^aZE2#h6seqk_&z|irR&;Nby!*IqPTxbulG|EKb9MdCZg=b!@0iT}C4Anw z?crkHTjmr-KYmkg^Typ}`41kZ7qiwbjlY+n{Z@X5nS!5bbhN^)*fsIH)Nh@9d;8(G z-9cx=OH7qzpNqxs6r1zT^9o=2zS`#OJ&xyQ_9-R&lImda-Si&fMu=D%i_<`s5tGU$1%lM$eCV*im69(f-jd&F z_1M{(zwpW~jrN6%B~Kee;(V7HK3uYEZ|Y$S<%VsR%kGOsI>(a&=b6*e>Mq+h^oezKZr<9`@t?+ch?G^Vjn%uex;mlw51C z(c)yw_YAwfY|41~xh-YYPT6hGlRj39&*qljF1t;Cb-h7yt@iW&k~!aBofh*CC@b=O ze%pMJ53)9arP~yT2bi8uWIjqqX(T%We6_n^xb{VKgz|Vl=sMVwv>e=?@Cn zwCXy<-g>6)Uw%b*bG^PS)6L1V{^gx@d9WdD!QzMR{$D@GZRcNb+v^e=*SY-g+j5qd z%#O^Jb>Lt5(@G~s=8Q%5Di`;x={KVPG}f48W_WBb4Pl6_RM>Xx)#e5-sZ}n~ckk^; zoFnLPd*`n1+b8X=)`lwnuvSYycur$|q|?HMMpw=oy~~W7(|Yu6oU7=*|0O*93#zZZ z&CCFW$8)B_Pw&p1x_n>Yt$IV*tSQeW9d7UcetwPHip6!k>BcvY?p$<}Rcu>+`(>xe zVk_0sW3HZ>n$>jw{Fd_K{~=l0S?4{T-#)M0Aoof7)H%*iw&pJ``IT*Zc)RBf#{x#C zj0Y??tUunmm;UWoPX5f*zdSGA-Mjg|aPGl>MyKue+~9nWRTcR4RdwK3`}Nr`mbJ*I z-%P0qWw;wQiM{+FBQM{q`HeddGgNt;jSsC9leZCC89C3iDq*|bguQR4e`RKV@r$|h z8q10;uR5e&eLKecxQC%C^l|cZd0C?_y}4obUtg@@`T8=;|MMfBVAJ}-Yu9q@WDhgH zm=~DmeERa|gmtsN^R2PT<-KUf{Nlw_mJ3teSTC%eHS5hS&D+}#JAR2d{$bsR59cKh z#yqW-*1MF$aQE9cWwr~MMOG>eeN{TVx;}r!yB6nNFl8)pmbNQRfs_l&kNB<6{&#lG z+}6b1YO8;Fp3^zkR_AYapzGL{Tl-Ibn>u%H{)^Tt?Z3Y&cg@P{n)2%G*_61vNyZEAa$JOAY?H`Bj)a!*-Rc+|t+{>Rrby=a@3UdC`Y zvhtU-64Q&jY!`Tqh1_%xZd|qU4Qw0>8Yib*?rl3N%shAI)o-BG}K%Q^dBEt_KX{V(H}Ta$XeT?^Y>saom8ShDij`mPW!f2FQE zSsmwq-7d*bZ*?c0s`<6n`K-w+Nyd`DjazirT)eY+{hHg-<~{EG3v!)JY#R9N+jQ?X zvxT*tWqR>OYSy_$p3Z*9?=ijDs(XH#@d9gY|Kh+m1`T~pSJLg6t8x-dY#Pq}+m-aY z%wq3B(9EH+%BA(ww$EX_8}`xa{ytv@-P+}sYDAb`IN#-Yq1^XomZ=U0=K*&H-YuJB zkF})=JVmer?@u-Q8NruF+es#W69pKRsCl}~FIG-{-tkZ*+u^(ZLBq%YiiEri zu53T7y2-n!dGpPTFIPWJV=RgGxc(DV&HsLz9C6(vPvd5&OB>6Diw z#Cdng7lx?v1_mjKRt71F%e!-Du;hMz{o+{I|A3C>-QQB5x`o;Ht4??q`0}BvU%qqw zp*uF|dp>F0k_%Nlx{h7-{}fr~9RuzYW8Z*S@X7+dRgDM`z>`n&$FUsM}4jt z`-OAhFo@qFzyK-UEL(9Dkn>ZFU>Xos*UNvv>+ka{G9P&?%vaOG= z{$-nc{=_xA$iLU`ep^v3cVgR(onNXgm*#o-+S%DOlzAE5X5PGbie%u?Lgp8WruJM5 zZyBAM1#Mc{yrDY8p%A(|?eb%4dqoqIL+^Neyzx`#o;CH}e ziL2F4hFfvLXZt_pS$|z^x9f}Q*>7(@DESuU@@^D8|Gzi6*muSIlCu@RuVn8rvVY6J zU~XeXJ@@8=yti(ioM*PDKE-^MWMuVBW(~y#wp}+K=G9KW$XDfU>-2k%a(Z6Jm)Lh%`?Q=wa(VQZeytW=&)(O^}LDQYggTNmO3_zzi3|K4P&`& zv)9VMadpqy{55pziJOMjWxm3oR$luxzf+M_r{ar~Hc71Ivy`2h9bxId{cM-{&HfF0 zCvN?^C-Gj4^V63#zw4MXd=oF-K086|`oUo61=?-ZtjT*Y(~mw+!84-0+P(>96h?HuH>hb?e(7&P|N1m*4u+I*K8Z z<$}X{4c}?j^Dl3n=-0+uJI68q>G_X;+^6f<5HH{5?8CE47-ZX zv<6{_>I*Y~Y>mwTVDJ+{c|*izN^e_t&x^@$TR<@>tXD|=m2!J8n3 z%*d~MYBw|N`l9!Lb;mzY;tH<6oU_l-I&|q~-uE&$uTBW!z3x|bXGwZ`t}sgjgVYU; zX1?taFI7(Nef6|jQ8>obU>oDi9D`TaPW-);XK*`n!+cfq>o4wUN^hAvuY^1C#)P^r z2V-|1c)!locI}q^(pCp^Cnqg>Zsj)D!1i8H$D0~&{oR79&_<%{tpCog(YbBRQNmecNAFAYwH{ZqDU+3?9>(PdrnVg@l2?h_1=f}PzOd~f;}%}iOI1RP#O^j;VqW0US8#!<;%P0v^}%Eotzmx zVei6EU-s0VW{Bc8h~7IFlw?nuE&1izu_yM{fqCygy-ohU=-C$g2EWOROV;vK|5(kJ z@^Q|s&r0=udbuwRZckI3Z3~JG-euL*KMEANpTB-m5Zx1Hsry7jehvSE+<2#d6Sg@8 zHSF5@rF+-B?dSI$oBLjTapDwthwZ#a+O`<1&YP8Mp0R(`mn{$HD(~LfKA-Q*a=UVN zg$A|@9(j!yISxLzIlbtLDgXPbzkVhM^zMqhmHw-{Bv#CNwe}u|cLy)&PyFx3`RSJ5 zyb`rV{?q^SR*Ozu_~+~`%RPZUYmR46|94^DgwFzpKAZ}Fe?tDy{q}X|Z!zrJsWSKA zB;yDDhx#@$mP`>n_3!oZwXbIC%6X)pJzu9QvQ3~@%w_!*;d;(R-YkUTnD>ly&}T{c*Mn7i&0{ z>%Y2lcUw;T+p|`4rWf>{w!6`P`dx0Sw)kC>@U^S6&pERxAHD@hc10CcENa4w5iHR_VR4$AkZ*h%*{@%$d_B< z>vi7d7@rYY(fM=HL*FYiPp1`Jj5+j1`nFZ&r^1UtDy#dl-#VB}slS%{6>N8TU697o zHpvUQsxMhu{rF;lduBx1(AU*}vGX}|t<TVAxWUrpgN}hAoPs=Y2*F0y7 z4Gyi!W3*M??fQ==<2O^-Lk5lojka8?RoxaxzT9^r-s}3p#K?Oev>#;1P0q3ZC3`JN zM|FGpP4>GTcLJW)iyQZS(7XMYtGL2jcCNrSwr=Hb8Da(gny%5?f}IXce8t!PBf3mq z`gdErjQjhowWl`B^7?h}D06)Dq@|1xAH^i!Jp4hEH~#u-MT^4{zoSnWTwRxVWZw@> zTT^?kuth%|AAb3HRPX(zxnJDpJv6=LxV<`0J)@;5Yo6K~`H)|&X)A54`Ca(kw@sec z(bjs)8Wj49rZ@N5>dam8{;GD>+sM`V%!k+Cx@@-LUlZ5slQ(o*yn>=Ux1}A=nR`;t z=~j%S)1Bn{1i7tpQT)}bCf9jx+s63DM)s_GczmLke%H2X?)Rl->oQNo-t6Je@szq3 z7rD)Lxr2Z9j^!;oIRZ^r=q&mt<{2mKdn9k)%NvV3tO8f(=}pz2-0ObT-!7!j_1`Al zu+{d<6BqV>S^T;??{S$$3~S)}WuK0T$2wLmx%vHc7G@8FqbkM zkmNbSv7lVZW`j%B+M2z*UlbbHUVKluUecvu|C^~)T4Uqo`H|;X84B2#4Vhm2-LY#| zQXM~NzSSaq{k`g+pH!C?E?T#K{bA23_5o50@|c%SOkCl&ef#z)Yzz;0*pkf6%@et6 zHgY}Sflt{oECbK;gJx?Pd>la&+F<64CfFPfJv|Ms1y8A`|a&*^Za`;adAOXU-bCi@0)zVdy=v0yLa#I?K6IvGPf#x^6Vo2 zi>xO54+IK0Bj<`la!oe$8!fZ=XF|noA%qn0sef($` zGwJ*H?;&;7wx!F}Ei!o#%VPBBqIVJhZ{_6G;o3iSPhPz`b&s1{ zZsHHM^2xVvN2ecI&T8~BWo{nGV)eZjmh=Tm9r(tvVB_w->6e=)zU#hMBC07`;5Rp) zDI>u?FF*e+?{v-Z=Zy@%I_Axr=XBDzzUiK8naq~en^uK)eO}U9xb54A4-g(y< z+f!-0zSrvRIyLjBek>Ob6bd>dm&>jXvUj%9xFz2COHbs%O?8EbSH9=J`uA^MO7U~B z9rMf671w_3@t^p+&f_VE^LEWMpSc%g=e@hsYg1*qd*{x?U!OP5Y7ORJz+Tq&`t&N} zhHG5!Cp4d0wjx;FaeiKS@$A{3B$XT3`nnmUcJH1&&1zO+iQt{PcRx;j|9RovBY}7M zCY@zwG-=>6TRCTY%Gz&?91EaUypyWB;%<}jS5p4+{O$Q-ezpyAHze2TubyyutM0*t ztIxiu5)68K_|xuBRev=de%PtS_T2MplCyhZeRth6GxMjQWiK+~j3#B*Kb|TxdHOHw za=O=>$cv28&&!tRdvDtL|C~9a$p-D~*RS)xKlA%u_ z&CEHnSsrTjRmr%}u(R^%j~`!>Nw?mrF`F$*R$||ckDleG<~ua!8!}})*a42E@NJ7T z_q#qneJ}lX_=`Jzd^xNtK2RF(?|KuJ(sjQPc0+qulM zFV6J+yF70Hu?4$93#v9qTW#)VsG5DqW;4UCPtWSUytg#To-Dg;QQmzWlP`K^(O;7a zXI#E4dF}OHyTaG}3$||i9lu>i?#GhVZR?(Gc4goNhgBnkl;Hf2`8_=`y3vCF)ykU4D$#bYMd>wfvl;^L zuCrgeup>*4OSk6kraeC1{{LpLWxL50TwlVQ|9=01HV^Kyw{zA%d^@#1`BK^`vHTr2 zuetBLiGKAAuHU`oTg;E&W_!3?k80${?}@!8o@Umt?d{21-FkEQY;Vk(UA@9`+mRIi zE#FSbzdF6@)3bd))=b=Z_h^Sq=8qE1IlQx&(&sOZyOXv$@cMm=SJ|89nMT`v+qGFV z=QM*=wX22eUW+p?!2y4IV%zTjj|$QZ8?MbgzwYA2oXvIx&bKSR%>E>K$9eJQH2b~k z4eR#je&zqu&a>!nS;QU@mJ1HK47vaJrF{IiaR0qY_B!u6KTkH?$#~;_q!bGFMi zExvrg^4fe2D_i5a<;rhjH=9^_Eq{Ju;mzZr?(A`|f?mAje(q7Gyj$?+jx8^o)-V0C zaJ84_7yB=f8eg}1{M+U-14x3vFH>bZ7rYQILT!pkS7E4@D@ z?QNavlQn(LohL6sPwYJ9q&)52;ai7#-s$^&Pb<8(@V;qL(UXkzCG(PN--H$yuQ%DY z`^EAn|8x&n{`MuilaoSww{>%gY%nVZw@%US;Nt?XEQ-+6BIq?(qse!Pq&e{)yY zKe%t)ac$9sZ6%jpvT-bMWZ0YZxbBJg-Fsed>#U6KSTtO_a^vO9o7XKYx87U&Ch&w= zYR~qH2mkhz-fWt?d!p!FySaAvZ!zpj`yhE$Y5DOq&rZ`XZO7RzBqp_Pp1icZUq5VH z(DU>5g-h490FKzy0H0HU^D6EYHhZ+ms@V$9^jy4HK^%=s3~ zZr5GPQ00+cv7K?toRYOIen;nhoX~Ky_Q4A0Nx9P3w^eM;KlQh-jz3nW{07rY&IRK6 z(ag**+8j%){;c00%E)q|;u>Sg54q5&xaz}oUl$&I*YWoLkIvAS;d9EkAGWQPm#ULb zd0%$(_Rl>Gx8`q&l#U+bTP?^3o|{hWHX zu4=}DCDQ!+vp0vkymYydG^J^i{oKh(S5E8B5_s}v##^8DT0b>%3*%N!Re3ezoA`+X z3{mU6s$XUvi~6i=J)5cher`+Bl>coj)0aMUEZKVN{@>QViW@msj@{ZCnY;Ar|E;M@ zbwh9LyUYGlXYHk>7roEl{;j_v?ORXFjC*FMx3Nz9EL!(R`tAQK-&Pf^S?wwwx+;Tb z{=NIHvRS9*FFsaTu{%Uq&`s3AEYH8Ce){{BPT#b+RV8CnmkR#4b!dy~%v|0%!r@sy zi}Ke#(T$pS^YPZ)SdpD}dyStwTbJdvZ2#_v%iE@}bF8j=dOk2XK)%mfH2R;w-s^Fu z3sdEOfBv)8yl>vD9D8r!vg)np_!hhsKm4u9N~QR~<=Lg04RV(x@1-;3f_g?*=Vty+ z+n9LZYW@0)r!D6$kox;zWn%AKPxGgB?)%$s$!@s2@WRpFw!^lJUmoRVCotSK=r~s= zf6N%P#7>9(LbvT^uWicFr!wZKT)+3(Yp?uoLBALan}%)MZ@;PV?Dx)3xXIwRKc-i$ zu1#>+iEq6*`PRF8jy>{kd2@a9Ooyv~_pLE8*Mk7hV6BaE$H3x%U@y_WH&@ zn9^2~w52#^Rz^a)WXf+_)1w;4r_TFwsqdzL&WVdzbrZH8EZH&bvc|%; z*v#cyu2k=e+}-29@`H1}#joWnnBV>hxe)hq=?~}CB~gp5?%%6-G`$=cxiZaa_g=^9 zQ2T4Te~(=boA<_d)h17wBFSq{+&8tpIrjF4RX$`5G(c5{pvkWpF6`f%A6u8NG_LKlTGoBuzDMix1SUxd zhwmk-TkoyQO3BHMH;q^|r#?|#&gyCM>Mgc^&TZ%4x!~9BrI*YW-=C3xC+=#0>D>Eb zHx%QGCtEx*dh_sj-`~)T!oK<_zRcij1@)QMg;V91@aEt8D6!+&;R6i2mhX-zzOTP` z>8AQcf0zFHIq6%vM)&u*8~0z#+gB(PwcqPwblU&#q58#d9`Q%6=JV2Du|!h~ziCZF9tdx*uzwr0FRJ5*m`GNnD_X6`yO+K@){hE)7SSPwq?fhZk)r`!}qOu{GNp>chL>?OzMo$rK|2J*AZ2Dt%Un#@a95>+~-_BT?6;8I(&s;SJ8%9=L!q91$<8N{=ezd z@?-05edlhLy4-W=|5}Hr2Y*?OY#Q?ZDXvmu`pQ3L``@oy;{$HKzFxWhZ`A?&{ZSm> zKE0{=J%M}G{@7KOO;5kQ4gDLjU9I&@-(oFuqbEjhLSCtV30JJ1`g7;b`%`##?!Pj} zVsD}TyuM3YckVE{5y$; z`MfJSTkq`5%P(;}%dz0{(o(ITe|!J6f1JYfVteax@#%fF4`v+={(a!z*SPvbx!22V z&hM#SVOy}j-A1e7TYhvh^NVMWCJqd|GP(`l-uqbf_&?UI7j!;dCmFYYO>R9y?)&2x zXSleVKD1k#SQWzb?ZfQzv7h%|uD^MVam(L*iG|I){)cZ{G^~@%TdEyuQ}oH3ss9*+y~z!rnV#opWFJ;uh+U)!23d60+$d%Uv<@5Od z@cy{Luxsb;8!`^p>s!NwbEZn!E}yftP(s4t`yC6u#m_&zS7|6yJ7zbTAu2uPbnNbD zflJR`-M90iMA7<>_1i^EAG>odczyfu#%Fh(-?Bd1zQ`Gz_tF@@97r?*C!B+4v(E}i zzTEzL^`Tjpy3?0SFAa6snlHi@D3#)3?$?_yr6xWnl40%ol{4jcy*j#F$l><+*g1Uh zRfW+fUEcHdPu{dLJAK-dKih6qiu|6yBq{Ciz31Q}_f@CnFV*f~`6I|Iyj37s_s}tiL$*(Ah@rTRprBX7BDk zd$91=mpzkyX$pSrtn`hzc5`F?kGq$8WX`TsFS>u;Zug~oMw`k+9okv9&Q&jHYxi09 zhrM@C%%wlvY|;;`I_F(`2%22_E;TzTef83}ou*%MI2T-=e%1e?#8&|)ri=y#DV7V| zZ)AjjYnn~-st#P87qaxJ1<3cuBX4{)Uz9jimjB9nEe&~*T`w=q?PZ#4%)KDnuQB%i z2OZ`YN8>UxTffYkv(Dsw+KF5B-B(-rCPxRdV~*n!UFY8SWNKuJi5A%g;~c4k`(pW@XwCH}#gw(v7|h zxz)a3{WKc#UhA2$UnsM^=9SyO%J2EiTelA$U@iM?oiELPp*ue_`}Wdc-KPrQuf6!) z?8*2gNmKT(VoP0iSXa{an5N__d)@X&`KkNgNPT+im(X${hx|(ZwflE*f>xO%EM~Y> z_b|uW@E^;TQ1eyiekb|wS}54_kHavkUfC*Q?z5MF_T4U9{Is|3)Mp;%7u#yBmow}t zX#|y3IbqSSXNlXLlbd^Y79ZQC(={HAZ?qctdKc!{_bzlU7E~39X1lQTXQZa}qSrOQ z3z=VNyyd#j(lU2Trt3F#3+XN4%OxDj`wUWlUvfSXC;NB$^9c;MG<)ANXK1cI)xB;D z+ZR6O7u((?oz*5w<)7P?=NCe%3TqvrfBX`(YM5F3{!TH&-D{5a%NcI%tEgaD`(Abj z*Kx(~6_USYeSUdARAk+>ogvC|vAFKh8RsV5R%pok9r}C4c6r+dyB*o(UR(8Rzix7@ zF70C6QY@+Grf4?l^7?~cv>X4iYw&U|n5%dBn|Fapz5b5p47=9uj;P#ojx)BVCvNlU z)86TPj(?ST+s*$4S9|^C{c(#SO3Q7^?vsD7wDq%G@LQi#D6wff!>#?-mzYnHMoH-Y8E-2LESg?^BoP+#!R9e{Y?awnay?AWnwT5$T883fHU*ynw^)t17 z;;{@I9u@ zG+nW0=2Mp?TWe>VE)ZY8$#xCn-Tiro&oRGfdzbX|b=&#&7rIJM!+v^N6UZ`FRC?sr@M%!cVjX#d&BuTPKMxc6`m!>VyI`(5@6=iJvw^?x;I;?4AUew+U|--5$w()(g=F4$}J zM!7+*R5I)vuh;uo<`r?Gv#gcho@IJ5PyOt-ReFSjTeVMyoD!M)l>Zk?Kp^o8|51%zVV3`u41T)zVstqkBr6 z?Om-HXUQ)ATUR@0OKs%0_I#`L7b-2j&Sbq%rnJ*OEE3;jwx+nfz z@Wl#+s-?Pfw%YEw)OT~evsJx*j`q~J2Y#O4#7``IYD7jK^CWWTx9ziv<6 z>-D=O^X+9!8?MdG=lEonv7T=?=YsZ_HdDop%R1+!ZEnkc*sr+Zdh)MRXPI97T6eKW zWWmA@(oEC0-gTWH_8^CKwaxF`lE;(Pto6gLw6T4D!juv1ob|2j?cPsYm|k3Bo*%p| zJA9XUY2Cp++l+X2UVq`1RK;g4`GMLF@g@s;@fx@??3+@U(eSViy3*iV^EY7!{cCQ|bFRhjFI)P)&GFfa?cZ501R3!P^SrePI92&JprH9%mOA5? z38y!tB}8U%y@_%#X3D6ZYAJfstoh|>Gwua%^WASnE&0oSA$xcCRL0bA`}W`9joY*G z?!L*nEQ?ANuWg%%b;eWkxH|Ld2cS^``xF6P^}slTg11r& zuL=?EMY@^L@5Y-j@Bm^2IMX_{|H(_?Nw_)Dt$@TB_gQQY<`Yj@7Tf znYSiyI6v!#Lc_M@D;FAv|GHW9vb=cdWYzlQ_E28?^_%nkce4hT-m+`xJ0^FtulvoU zuz5M3Qg=TqvUvIPQc@4shN9zE@*Wxfj%RJA|6|&C*6&u2%haqm2HnMoR8cR#KYM$Tz?QU0fcHPEw?mq`lk8Uc_HCMx^E+)f*UjJ6sfm1+g@M;sh{&}%`(?lH zVYsz_XL`MJ@yBy3-X-~}O#dsSVfFjwWTo{JH%+Sdt=CO#F8Y7yuTUZk;RG@xJ?)%&Py2Ef*OS@A_NDe>*s1 zY1x5)J2qdLc>3P&DlO;#d(~>|s()1^{uEjH-}dlKN%Pd%UF*2?`s?^(-@I~BPt9Vu zYyaWByvuE|9hDn(z^#(xx`ZTaTT@%_>g!X!pZd3_#(mf0qQjd%I=;-y-JP_Fb?3(x z-4pU9>0g3pF)!0Nto62smwoP>Ti=#HHMNqPX5SJxVgGq&rWYD<6K$vO=WO3urjugt z!KXgQ?&jN)18MFtpVoic|FF3A&&{xT+fD|Q<$2ujxKX#lFEG`@iy^mK_n~Q2^3t#y zr{1s}+-A1yXvC~Ij7!)So~c7 z=cb!PUBf!=A4_^8LSn;B?*^9J{OWjd@zu*2YoEVmuK#^=!-Z9Q?ujjMw!7}%k+vmV z`p>QF@9HhGABqXrh8ir1UA43N*3WrW$2Xq+)N`=7D!cF1hP|2=YvX+r`>YBBXWrhW zE-zI&=NT(#q*&uE*HyQFn?AV*{@rhP(KnUb_?3jq)!Q$#Ze5%UT~TXM_1WiJlB zoFjd)?6E}LWcGW`+Mm_lE;x0+JxlEC>uY5**vs0sb1qnH=dbZC{QU{Zo@J31=`Qh- zvT0YkqkrFh#a5e8o&9a{i`cc@qNR8JU&zgxXPTS)b)04Gcgf&v*Vsix1R3 z5PHSHXu`2zx825NufuNEmj4nc>x$X-Uvc+B+po{g6`ItPKH53!!k-N$g=#hrtG;~- zU0M|VTjke^Y$4t*DXTu)Y|~|*S1nr4l5@ZIH^VL?k!YXFMfomSZM#ja!!~Q3TlF#2 zcf#Fxg|ax$vT3XLIC$r{G06VSN_?yMW2%{TU)1dqcg3QY!CrS?Jlo#SyCD4Qr_!+G z70l~}P0yaY@-3^G;nvOnFIG1xz72ZmVlh2^hx=>UvLFW8S3zfcDwdyIrFkY$UGMKp zx6Jm-`8{lG7p9t*FJ~?O)tJ4z+tmEXrK1_kL#-CA$u(@a#$dAK?Zg+ti|2*@@Bb{7 zCv!Oa6B}p=#ii^Q*E8FC}UaRlRf|}Fn%?0+Ry)|j-{e9rq<9>t7 zmXq=-uiCsg%k&~Ny`KMj!2YeA+x_-lOJlzw7{9k=qjb@5Fq~|{@V-NehszgqCs z9@7PLyY}Abn|e=LY|8sc=38QcnyUI&Xa3v%JwD){zgX5W^>gBlWp%rZ?el`Fx1Rmn zcS*W8m#2NZ_tI07b)DDVma06%y?{S$?Tj4Rbu+cMN6bhTztQ_D-Q+=h&4!42hS>UI zf8(22lW;+IYKUk+V$Z>id?$fm{5{KQRXe~aO-{Br1)^zjd~_V_Z$=2h11_v>Hr zFwSxVC?waOEzNwfWyj}pzoY}7%E&o`#e+ke-r zG`79#nx5Squd>GK_b-7%mxNAsPh35BuY{<##=3vM{r>hQSNP5=lPkzvfYLvPz%DY2YmHFH@n@7)cawF!6M&T?1Ep0i7fXKrmU-&@bm;ilC)+P9T% z&dxi<`#x9t2fw7tYiEwx`)9DXDK{J|USj)c);Y$8&x;S<-!n6yVqW>QQ0>?k4~h#v z!vPdAk{hc>S6n-k~Ny>W-_v6Y)YUFY&Pf1`Dc9dx3=$2T`BQvpV8)N&{pLEEsfbH&4gN;_T2@kF;=9swMMDx;y3}t2BzTBoC zu?l5}D!H~#(mqjn>b~Gj_SAOu+*9{oxRzH}XUqF+-|oy2Uvc>+g8?U_$vkoE`AdHm z-ed5aE-SHt#l|gjp0>(VgWp$voVa{h_`A*nn_b=E;o(JB^S>$Y+2GUo{_Je?8s+ZT ziCmhY*Z238-R_>eZrQo!GK=6P{u}L?!9l(!L;ugmj}tF3%u}5E_9=f(L+|lwBZ0Gh z;qm+H&c>)Tyi4joefso^=OP#R^?z82NqDbYdHZ(sZ*Jz_y_@cQjAR!&U<^J(VZ(IA z)&ByfKb^w_awr4C=z5aT^(2g-#Uu<2NGDFvB2_ee zE-Wto{OjxM?rv_-85naIUtYa)@1C8l?cS=dU6&ZZ$I{GMvU~UL>+esR!y?Q&9?5IX}I?pKNpI{ngds`S)+1 z)QgRY*;D!1?YkD2aN#RGef{_E-@nxq`?UYl^iTe_(bF1d=6G$}{NJmuW8Q+jzVEBl z&Q1*e7h{+HxJP?)-R~XSAK!Z0_wdEKb?cm#FI|>*qkDS35yKn}rVIx4PKI5Vo<4p0 z_U&5v7jFz=HZX6?nYZJ!Qmb?N$0;V$-=00|o0;R*w5@(O?}G1lWO8Aq8Z&;$oOpYS ziH`N3y{D&%CcoY8Sah&W-2QnHbHOE!1&ni4m|l4C^YeGFJji#LRdVJH$4~3TqE>1K z>F~{G(mWIXK4ay#BTDC1DmvcYf0yk-bza{#&3e80n+uOkoyqWPOUs+DH@`jn`ukI8 zsq^flXATS&ptHOEgc!fvYFhR3;ybOF3rjwI{8$*yKV`LMkWSx@CtKWB=brd~OJY}I zjcDB|t!TTcUVPcx8NbY%y*T&O{L|0p%*jqwYp^@Y_Pp}j!}ssrUAkX)^$PD>7ei(# zNRUtBSfKs#{qH%~-r^fx7y zl`Ad3-fFcd`JK7TSJi%@cDKCv`?Y^|)@-O}xv;!q)4WjmxGJ^&{{C;}31yyhX6+KJ zQ~mbki;E}|B=xB>N>@BXPth%4$=DgPtf80 zHmHf}F7sXg)cpEzsd~%H&0mU_RBv9DcjEO^;qX0Mw$w>0|onI)4}>TiGj z`t{LGm&Dgcy$CqI<>j9R8>jABYf$cYzBJt>=yFHu`pXX)zdV|EW=Fh9ywO+Q-%E1& zcow{UKJU2cr5cN~y7h;p-A%7gj%vGkck@=u_Y1LIxs9ntRvy5B%9)1;0^?xIHQr+$N zq`mPL$9G56zmlH(tSvTP|MnE8;&0nZ{Qk~;$-f}={*ou*rWVm*U$<@1%RL~j-+M_~ zT>9Q6(?|OYbMLOUnSECG@QvsQXX^*)mAqTGeEKu()Sk5C>(;HCb$#9^>ywHu(;j!p z)l835KKuReFE44KtlM_&(<5&xW!Ys%{rGiR`=@lY^k!ZEzkBPZZt&ebF_dx397oNR zuzEHJ2405aJPVe-pZ!hb?S$PXQ)15?`tm(5aC)G9Y}JQPQqo?_WUsw(f5Bm(qE>dc z@r^;WoyMy>%jK6Sv!vJOyeMX4EU{>=dpL!Sr)C@};Lwh}o56|1? zdh@KCVesFtw}oyBvEX*r%T=GV_fKAZXXC?{#kYKY&pT~VKl}Y}=+tkyty_+Ln`2sCe&Sv3t>WnF z_48vh7r#2rAi%(A!XTsDFfDLGY_yrrf{r%!!18NlKmIInKA!MNaNF(W^Yxr-->#Zw zXFGer&H3_a?p0;S7s+jw*;JGFL+5tjwY)9z4xou6Nyiz>CyRM+i_U+3su#+#78f=sCoIVyYQ(^#mQUCJYA!rw|lQ_(UsZVx+2MaX7`(IA?H5)zMS#x`z@ZR z{#~EGZ`*dje1+e)nx*PT#nLo9B?H@&IE^Q5x^MP%i?Lau_F3VcR}q>#moCrM+bjDt zyC`eZ)-5JaS1lKuyosxKMy}Iu<`)}`w;ggnE|m7lH9WP%H}&BVw|1{@6{-Fy&z++a(`(b#Yex4j zHoI?T^tUwsV@}yN9_PG7<4t>>MMYWd|F&b1=7BQyKeC&@Pv089<66n2%SQg+m;Btf zf7_*BH}lS#PtQI->#pZTN6GX{$_(U6H~6A1 zT?qbs_KnVi53f(>NCicP{d)P*Na5n2m0#ABUVB?IV|w3*uh(}3mTodk`u5@L4ll{D zlecyxzMUj%d-Y@=!{wXlpI+YLTXH#Yv4>KYM%AsEN0)Lg@>#g$LVMWM6{3@Z-}`K~ zt+B8)k3Jh_n)Gka?+m2^e}=i|0yc-oyfmEpZPuxII?MlUF;zRuyIXgKN#@mEQ_MQ+ zY~OP(Se$&)EoYl+SDeA_RpuKuR#b#VlOre3LKPcIQxAdga`$CR!f~Vs74_a^l!xtygbm{N+k~b8FwX^rm0!A4)ssI9B(5 zzw=#MD|c7*xxg>;x4yYPxv1$&wqmXK`Mq^POIaH}J2UV;P`N4ScXrFl62=QhSL&5X zJp043>r1t#^|}x8ozMQixKwxT*3$d)oEc)Jp3B?Kxe_d8x>nZp%Ji#mt-D{k&H7q$ z?QMqo>+3hSm|oKq)4dwHU*sLI*_o{1ZEJ zzhcVCYfI$Ha^{3}{&G7L*SXYfP2Hg#|L?td6JFiqb$fgJsw;^HcXv ztea-`;{S#PmJQdE3$Lm7u8LV{Djj$A_LkhWp8{7)72PyDcu(Y&_=ddI)l)D3oE_cv zFZxE0&ic*Mu5B^SE+pOX@mk&oXI|#*d%r#OR>t=~3{`I;KcC+DJkEaQC8h&E z6&u(JCTUr(KPTa7y=JMd#s24C-4EToSa+p#o3g`AkCo0j*1LJNneEycZk=2;$6|ry zE2+>hKh}5aZ-4t}_jPwjRKcSc7g@}GB+l`GrA zdf{7y*7RAP$vY}TYmePc|Csb~cAl-$?$x=LA-7c@%iNtXZQ*}0Gn><|*Dq!NuKl)6 zcJ?egcinl#fnV-?uRe5nmY30!HLi?XKIg_i-&_N^lWTu>=D+0XtGt_a%{UeuHa@#~)8@~w;_t{iSnFSIynpNY$sVo+ zZ-4Dfe!VUBX~ESqM!O4^|M%kE@j5;4ok7F4{cm-9|1W;3e7((U@vWI(dNO_~M_&k2 z(!KpA#{2iTqw6)^gj{$LJ?E6$nrE8DwwbpQQyJdY6keKkz|2H#E^l@JL&lQ78*ePw zxnM;-XUjQo*RQ&{Mw}gEKwicOF?g zH^oGyOWCO6sW?oSi% zDABKdSx5fJJSo`3SmK;)WK*?TbCJd`8BvGzR?{xoe5nlGJ9F;N^`a4Fi>J7_@Bgws zWqU$6%caZ{mlCWPQ*Za?T&XfzIxVrCv7}!2Ehm?EX>#1Jnuz@ZUbn$Md4F%hwxyqr z@b0|czjg~l!8B0MVu_;ioJ&*0eot9`F0XLq>MAqFEmN+pZhDh7@2mbiDTnrjyXVf9 z;b`h4}*jJnedyL4?=%G*p&Q=fXpe|GK;u~*6r&$TB{GGWTj zOXq8C@44y9dFcL&IXb&*YxAoL*LKbHdY)IIT($`0wM~u;x?BBT^#nKe3prT(JI)EY zS{)M~pME>{=MIyHxf~lVamSyF`Zncc-W0vAHtCxy7%jaLgwvI{QherB6_k~CfCkc@Go`ccOQnmjW-!f3Mwl#A5Sw$)p$DT zYij5z)^Cyy@^|h(`@T9p%EW5d(ag=fS3UVY{Q7lE@8HfKwa)1-m#&?=vBUSigs#_u zs}{e!t(Th2-MmvP?b7OIhFkVGejQ86Vueb&v<{g=gZrZP=h+WG# zy(H!F#UnxgpG&RIOIghHBItC%E5?#-)B3m;9R8%U&CRz<_WHSocXxWXPA#ioh|P+= zcCO*xn{ds)U%43k1i|Smt7Wp?=e=nrw*^+ZX!8p=l)wA4f+6apMyy*~8N>Xus@kWu ze#NfpF?-q@ba0E?*=Xin_6>2;|JT~iHdPEf8{BNQda|wi(izoPmR`JeE+u}No|izY zTAZ_MSeNhfjP-(9E9d^!>9Z0}r_A>*IJ5fI;u9}-@7ve6FL(>9sj|nU zw=tWozPRw;-dc_OH%diQPJdHc74zf7&WV=k#U7_O9A?5Y!p=`x^`MS?c;QciZRCr|`zR<6C-XGk~V!Hb1&-r=VWxnp$ ze$2DGwN0guVOQ>v70#Qs$#{JhOyAjA$+)GrN_+kfao%rP^DOQ=9B=Oy7A<{XRp9TX ze(qnbl=RID3ytq(Wuz}MZxfEya<+Z1_~6^|OJASg`f0a#VdY2mZ_mXYrh|*LDL<~T zEI7=Z5$*gZr^N8k?7*w(8zMuubxQxxIr8PnwdEm8r6bQ?=d{&5%*Xsfacjv(aZpYC z@9&5Awc6d~_iFF2-(tGk{K=Y7wLQ%5zaGwyV<_+g=l@1!nU|`!f37lR?m6Xu{b7cb zOV}~VZT@!*Jd_*qy0^?ZTA6*y>;AhZ`#&>fM1P!fwfAr1g&xKkvOZP|XW#8@>~6GB zUstqf+LWyGDqGvi)N)x&etvpx`ueoj?d_bi?4yl$SAAVocDPRY(VT$UVRM2R=H~iX zNq;-)RG{_h1H-L(7WOXDf3%X^Lg&wwoXWT1ALH7oQbDUOL2DpcwhPW#E9Xwwt)*R3 zcBW3;^xL-R$UVXDf6rz7GGTMr{11J*uJiA&WISLAZcrTSE4b8tG?Z_zSO2Q+Z8P)M z+MWBbeX(Hw9v#_B!Vc5p)E0BAD_kg9{Pu|MHLKmfKJ+l$a@)H!F}lJnDf8K^;EjhT zc%E9A*pfE+7xUARp7{3*|@PkNGje{YVwzRfsu=S$90&&sX7+C`mG zIIX7~V0GP0=He*{Rg*GQZTa zw6NN;6T9q~l{=dO+t1e&Uo}6sA$<%F$g{z+SthzUcYw2~@ zD`87mQ&;br;`yaalk4`Wn=^u5JKuVBYkm5nTeri$i%B0oH!X2K1ly#A>_# zte2ajyZxx_=7s-PtdD)&z5VCD`(c@vcdxoxa(EavP8 zfA2B##zMccUB12(Z;93&ZqUt%|F^(#_A`;mOfNFLG9`4|t&+d%{=MYHwS3v8wXq3S z(id75d3?|M5xgf$Yv)?gmkV9n*YD2N_R&bG57@P8uIAC)b1DA2?Yp~$T%Iqw(lPbf zueDj`i5o?d=hpX&c)|2NCzC}wuH3tx{v^4~Zo z{Oa{h(;I3gOo_Hw`>h~r9rynHgzQ$^@=yLRW0iIHKHIgu!pu6lt(NV=;;hUs&ePuP zRk(HNQJ*Wn${mY_ynUc5HAr^zR_#?A=cec89q>_ImdEl^Z)y>4uKbN!i@TQ=n~y*PYneeLBKO`*RV7VHNFz*J$6?4%gY ztmiR5*tf2_JE8Z+2iskDoJue8&b!9*V&1VO3lq!J9G1shFWtS6-N>wgPjS}$2PgJl zb1|E|>X%kxtJ437Io-CspR>9S`K>!+*7Gv@)~mR)H{WDRmPtGGuUdN1=I_zI__KXC zqYqDD7h0!#Z`<4^sXiBVSmd$d_g_cnDmJivun}}%w(vA!;MgqmCv(PB z{mrotXRWKhvYFrBYwPPdb~ZLYIOp*Tp6}mQ>s`-u ze}nPnpVdqMZ`l#G{qv@Pd1W(n*Y}8pWNKeJ{JYfhO|!;g)9Ht6c5O-PTYLLcXPNn- z5;@CbN52I38P4()x68hAN+R%Kdyp@fJdaiC1nI$q;ma{#3!!jG`Tawx} z?;gG6WB$6Ju5Ox$-?y0G>{l=3c|6^yd*kur#eY4wz9~5CI=9zPtbf%_&$bT>jaR*MbMfoFpCS%rNnZ@P zVBmT4=Isqj8veR^_#WP|?cLS+XSYpDtoWXjU~RB!THCI~?E-u%zjscxPCM^iKQ&ML zUfb`w=%rWVCe$)Ge~VO`o4$5mSkK<;`tQyx3cSwB@P>=ggrR1G%=1V&JpV-S}zweU=LhY1@rKiVNg87BJeB z|Jt*|JpW$EzE%dQ18>UM9Qs51|0E^OnHy1hs?EN>C|qoQoA|;{3=Cy`3{nS*m-k1n zls_rpz&zvbIffUG47FVx3q%=B7{Di)S6nNJTC}2mn<=A7!_Bum4RYe*;`-MoTo2B0 z-~MXK-11^A_wB1pR@g8!%vEk+`>-Z9K7N0d`@ewy>t@fM{Xy?q5v#$n;f*SBF zpL~3Syng(?J^T09S5Gk~A zuSZ4pHe&X%iJdu zy#GrHIM}y0r@Amdcq8b*d}Fg?FRUwxKL6N6Osy2*+2-n=ef zw|@Qdx_5lc8JRCEmRsb<-+-g36d8XEUH0Umsc;7cPr1ee|+pO z%Y`Uy3+uTY3pQ$ti;L&q+r#<%@5hf9|JR;b(w1lMU651xBfZjZ!ChlRqcqor=Ql z9XmMqS6R(wUC>|Qw^2S_(n0>-TDE8Q!G84{Tp9LCg6{Pd1BX|yfW!MaZjHY=7j&w% z&yQisc+=Qs+TY)Qe3$CnNQZB8&TE$4cv_uzeR^3E=Ys9}#Y`CtHzXKM8s=WA+{$uc zxsd!Dm4<6OKf6r+%dz0#4;zIByZyyoe=D|KpZ+hQn_-q&`!Rt7HVRBqY;30e zn~xtqK5c(7GnH!@1D$- zlau>mny8#>9iYXva53Lch24MOOwL^*aH#KP;|a%;_jUB7wWOy%UR%FdW{sV_*Ebcb z;LM$^tUgP3l>C4C_S61z7qUY+TbQ>iTV;RLIdMCF|8t#NE1sA>JX*wYQ#>X<{&p;{ zY1T)VmSXX^o8OG?8s22ob-Q`8VAGTRMbolZ#n+zGzCHc!hU6%akn< zDZQTaL*irgv4#AxRqNk`YF2K1{k`>H-fcdezEg)7y~>TX7Oj}C_4|QHlYOn*w+ou} z*4rlDt%z2Xay;p7eS3TI<2IoQ+x6f1pIss}d&kxA>svxn?Q{1{o3tuO>TpP3-<;{L z+{L#8->r%aF|}MT(^~wt}ued$${nYs~HSc?H z-yuGi&A;`VZ?~OZ^7(CG>&Ek~-mi1h-`psO{UN$0_u7*9fK8JFm-aFlJ$DdW?6ZIA z)cPX5^Rv7+Eu2<%&$^0fedzNm_nj@Xo?B1a8vf|f+MAjwH!E(vxOw`Nrq68d^x$ph z`npW=UT$nZ=4h|_n`wETJ8#Dux0P+vw*?40@ULHVD|bS0)-D&I;DO2 zfVoVL$tr!`rEF{$KKXBBXlK9h(m=mDZEj%UESAi>o1>@M-`@18{LH)1D2t*^i*%RE zPd}@y<)0n0?OV|aKKHlXZ_Oh%*?-#q@YmL>w@;eSzMrSvbJxS-fJVk=^=IL6MyuC# z&stp_${<@CyrNXWDrmQFwd~F9?OgNaoSwT+Z~AxCd(+x!-|kr7T4TF>DsSuMy!E?; z!mp-SP74SNvMbw^a_hy-^JmREtLiRqckhf?`7FhJ_5AGb2D*C%@@{#q&pdnb-qalC zByRQH?Kjmj3>)SJy3UD3Fkz7TW!}gYoF1+2Qy54@lw%y^s z7)!qx?VkJLa7y}<$VjG5b3ZIBd$OU7voAyC%ck!uqro|uH?dFU(|^0?=$mj;+x+eCufB}^=8*IHVT)@FU2hbgT;Jx&axSPTYPz%*{u7scz=oSugYA#)b@Ly zS@!vrxf)N-2l7s--Ig2pZTG!j+8h5ZoAYnUfqw#C+vfjUojZ5V<>}Kl&s)4@c4B%@ z+Iy*&0iZE0@2NNHKBH7J_=Yr`$8H-6cEDe$^RRDtrEH-dd8w{~n! zF6;C7_D9HpS)qZgp)A{Y$E^72>BpDe3iUny zDxy1;Yk5&nZp4<2CYw*TEjg;zH)X7aROv}CnXnyKzoBNq5L)K-hF82%Z zWxhP#pXcQ`E>$lt^jTWEpy>D;ot>9_9v-bdw{P{cEphuE^Kj3dao9~_srSic;ej(t z_T8P9{;hh4^H=|i-oMs&AMQvu(XF#z_|@!}di9T`TlxM}Z2Yu1_tGq}DfOP)u3nl~ zecbH(uUTzMvv$pXm-2M#4iEdIHxr-V-19ABQT^4+)9)5}?DKm4=URR6yZ_TxZ(+TC zXvy*eVW)%cZdTV=>srTPyT0qy(=e^#wSj(@m$%MW+g!IfX8)(sv-~sOc*ayuEQ5yN z`6Ty?nZ<2eE}6zE-`rF@*UkEwzUH(#4etU5@HKzdTg{q_m&M-j)C)X*w{PW~c)nW^ zic-7E-yK-ABK&QM_TS?|%dB(yx2tcF-Q={QZ0==Kme<}3{zqK;9IEAGeRP?K-jDsR zSJx=YZtCM*aJz28?uZ$tOQ-a8FS6ZOd2#OV58X)~BY0)HnXvxpuB;WbuQ* zndSTLPFr5A^rvCXCWhIdz+$kf^2m%1ezV1??Dto3r@vF5#!Nc9b<6X68_({&w_bGW z)tnzjM&~@Q+?sSZ@wYP1-Hy2|x4yZYouzN;Ejx8q$Nfmdooe+qJF-oG=ziX#l~t~( zTedgtYiix@Dc4p%WZV*5`qndMw_06#__pQOP4@iLDHEA%wtWB8ZU47?vzvN%}w?fS^Fn+ylS2s5O4o(?SIL%r>Fm1m3U>@n)&^{{D&!O z&#(F1T6^Dcww?9N>Zj#?OMhLMz&mx?#y$)FEob6h2J&6{`R&x|W1iu!xi|dWWzoa2 zAbZ(*J+q^J(yvn-&b_yp^KJRRNja;R&i&rU`|j(vS+R4ry_s|Wl=j9=>Kh{Jz2c+X z%LQuFqW-^e&1JakmauU`?pM97ihg%j=Q!k;iLzRp@)oHE+6`Sru4=8Q)b_1wOyZoH2bpUjelXg(zez8?YsHqX8b)C20tcHD^N<> zVR~Gc{fr*DOSYNze?N9ko_G3`n*>d&Lx$5I=-+zVjwqDlbt(=nd)ZF&lj!nOF zUU$x6s&8%Is(Mq>VLI1N`v$uy!anKjY2kr)mtJ}-bLjr-JeT`TKPE5U&a3xBJ&U;ttiyKQ1Djs$T{?a3 zuMBmcLO;i7-M9P8&+NOtepTtY@_gsKP+swv&+%RRoO@$p}N%8v3vcD_syA;=!ocBFtml^yoX0wzj!yHf# zzYC-{rN5aoeg`-IW4L7(lAAksitWV36N=M=SIwKxmm}}szP_X^ zp-gn^^x1#^U0SzaFr)wIw~j4;Hs7zcTg|X*?RAsg|E|b`BFKY5R&w_%K?WJntk&FH zY7N`$_tr$Jzp{O=(s1ofMBj=}4x46f`moRpgSV6+55Q`JUzeZ@7C8Ur&@LLdzcn%WB2@-bx&GXCgyOP?A(0& zH#!Yv(t}VXy;2r;h#q57W#ik1zLY#nnMzpUynTlUdv`GU36&h0Mm+10)-OJkG$wijoftx@#n?%_L? zc6@2-f~N=G_S-g`u&b?_HR1><*$5Lo5xt<49_`V zR;>#>+jp~d;q841Yz==EpoPNAl-|eh(m($=@@;ne`AHiN?{8!5zq|dC;v3@zyP6+! zGu3*?jSvU(y%1YF01O zFJ8CfxtN3bmsx4o=ZCsqyzg~8Ir28=$#*k!51)HJh3UXW(7?yaT&9fW*40z~zLA`7 z;s5T{lO=~undRR0Su20L%XVQ~+lz|BmIBWOBLwG)%CTkgwin!C*!AyL;i)6@WA1NA z4w^Jec?oN@^6u4Ux$(0bLZ(d$md`5LS6jwl`vhE-y$u&xy|3gA|AN=&CtjWrUZ=ig z6*R`e-YvWj+DraAyXdUq?J0L6ZH~O#Q=A6!&CNOcnWaMl_tq@wykNileq-i~ocL!g zQ_mYT#NE!mwcy_sdDnXF-2M8IziT%bn?_rEyJs$COb`Lp-&=hdYJU`za@22g`o(hS z@I0mrYlCmkC!b1O=N0$o_?s*27tZM@R*TK@USO=e+H;Lqd)c?|%lrHLmooO)t|;k9 z@=tx)zSk_r%8Q|P#qZP=x)Vw`vbMhuiPD^~;+U27HRBNNwPBL7t}nNo@>}*XAXO=W z{q4UeF_o!Nx8~;0mv!LZsmG_xl<`~8&v9vg|7-pQ;{AHMPqtWDE?=+{)U|xl{3Lc$ z^5;6&ke$2wVzce;&QxUF!aMKJ&5lq0H>)1CWSpBO?mr>-d!Mw!^mnXvr{BCku;-oc zENQQY?T@s+Mtm{Jyni6_#|ufe3)$7a(pTpHS}bwN>vr3Tmr^ICU(e6V({Id4Jhd#P z{b{d`C~v}fjs=Wwro_7W?#}qs{;*s0hWz1E@|$AKf1WmYl2NB|jg9fk!9Q(RBC{gh z!@k8kE1s}VJl1ZwzwTF6mU2FKu1|bIee^8Zu$KqjRxaJ2{7q!Z{`Bd- zC)?9rPpT7~l=gI6+)1%ZflEU+1V{z?uJ&hn<6rf3#pPMb^^2=#ysJMC%@l__7_7M5 zpPawQe)50Y;U2xc{}`;S+>7)sC2vukW9#-`#N_&=XVvYs>;D8he+#eldn>n0aLJoV zwrg)@=Y}xIUVW0YSxsK>l;tlSYipysywR15+O&7~?6ZAe^;X8VVVbQcbL7oscMpG2 z7As${yeq70-maKa@{85Aerw!qD9UFo);@#>&q{9zj#M;yYu~7_d{+SzL>;WdSf1I`lAi94_jvVXfLtd zd7O6vzx=sVoP|Cb1&Q2eXKv3}Zn`u)e&rgm@--%ono?F?*1}nf{~U~Cy(yVHb-C#( z#ns1JE>1W6ro8CW89kBPf4+fE8M%IR0>iDkmD9FO-ez`dma$61y8kaO*?c@2d?Czx z_IufFdvmjswa;g!IzKeI$b5O`irQ^&<4SnlyaTPhLzYWUUTYtCcVSn_?UP04uDr~(;QF^&W-IK!f{G_lpIlc* zZ2jlW#`Qr=paGBrT|En~+?BtYIc;8yNrUIf>hF74+NVXEF!-IExa{=vpY88moC5VG zoRxVyWn;*UbIW$$jbzGXN#@_P*6h|sm#4w0ml&@;idO)(yAj2zdk%Xay97b z$K~^_Lsytg-<)=Qlk?V+V|#=1!{<&3)IRT~c;eQloa*0Zj3xg|4OJSxz1LrwneEK< z!r3T%`@gv0dM>G~%+Gt3yI7yIUTA+JE*g1LKdp`Z0=x0_J$31CvO>=Be||fC-!>_W z<8tpfqCnZ${bKafARbfe3t_IWUGK+Puix@l)&5PKO~LXVZ^Hkni#x1;WttmY|Ehn{ z=BaTuo0s0df8|X?rlIz2nYFb?^gw~&khVc_?mrDH$s3t`+>y(Y_ZVDWb!GA0Xoj`2 z_qTkPc~)p~aq6GoZyz?>m-n{i2G;4e&s-K(o2pM56&g_lVWYUW?j6v z>auv4jmP9#%_pb6IxKN=%ilh|VO>Mv9fn^Y{;5CDoq9Y^QFnDv@7kM&(nfCCtGrxK z#VKravYMXq>z+ZZ_V0UbE)I4|vocec=jcyMKYZJqdx7=(?m)&Zmmi(HpW>Yv!jPLC zSk?DL|8Lm3Pa(6|a%Rd!nazz$@P6P!xnw(k}#tPb`(zwEQGTgjff=9u8um-LM< zovJBf{IV+U^0cqdH>4>}+!kiF>!xcoM{j5ux2bj7{tesTHb1+2?t3&tK?!I`UeD&F z`xe`XWzU5-`^(zsRw=CZTK_gSk!@OhM%1?3U;5o^r}25+KDIr|=qqE@x3{xnncVl3 zeM#89Qt^}KS^4db+7~xh|IMGj_Vcb8ftlO?f4TX5#m;H#_HwtpNI5<0TG@Q7=2>e> z)9n9F&M~w7ed?A!t3-9w`NgmIt-4+^<=5s^?X}S}qQae>k8BVGU6jMj@Ze&l>RIgy zh69qj_v}e|c=378mHfO9Hr2jY*XmfM(_3``n?bxwEgJDj~>C>lo@7`^me{WCC&q0nC)6;wR{(b87xV=?JEv>?*PoJ)TUo!M#N^t)D%oBxQ zv?e@jy>;W|yLWmb%ll4?{97#KJ1*aW69iwcFYXmN#zGJd#b*^dRslk zP5tbfTS>b;Q+U=_yS^$<(*y7Oy1%FL^R)^8r|zFp|LW$a%a?lg5 z`E9)QdFB7-$zC?rIIHkgk^wyP%)sL~e`0rc_w3oyntJNjZ>LuzE>@ZjMMsDsKMbU_JN0->lWvKFIxsbjg`Qd5fgL7FCh6(cio)eNZ z|6%J~x!*s2R7AOUP5S-2TKbutjm@4a_xi?rpRG&odfeV;$@nENJGuYdqfdek`JD{E zc*=bACEw{VG=L|a6F7d!aKC!Olri`0uV-gx$F9wa3SRQzd}c@C;?BBH`_0<&X3Ugc zCSb;X|P3S)~!_e17)q*=@EpVT@m{UKM5ha#Nwf?yKzX zefyqmV`8u{X1T!7P%PKfHveRI^4iP4KJDGMJw7h(+MZbZRKt0zJyp+X?wRm8F4E{` zR&eo;+|;Gk*Y@m7PrsXYyD?Pt@%0E@@HVX2tK#dsCVl-m!QbDX_iKs=!`=9#v-$C* zU2i347B(zph?>1alKbwr_|&<}*Cf9BJHh)*=Hd33{nF+qG9TX9zW!|G)>Ea^K0InP zVZX5H?1nnq%kvo-p0_YaF%sW~yGYhz#f zrM)g&DREi$gLb+_+)dtSMQ_#11qZLaDTC~`+N70w=Vq1CTQ>_0^@epj-Lzg`T4A;0KCDkHy?{k(ts_HD&n*KI6|+6*_u=l|HedFw}g z+e)MAW8SQnBIjjCpANWs`PPgu^}Fq}mY2VBiQVn8yKdLLpv~g5?pL{R?>H^CNP5@2 zQ>W&HZ&UbvIr7ld?{|L5Zst$AdUt~F$%9tfkC_bA?lzFHPJgo9otWB^~R8{ z*2=2NhG}L`F#qMM^;Jc>@`^~NMQY|Z!MTrezHZ*?9XCNO+wX24--XKj3BCXSd|LD8 zncAYrAm0;LKUB@Oy6R%DS>1J=?ZWC;kPvZQ822(Zdv%LUUC1Z1hH3Rhrf>Ou1&3H(uuzIX7`tupPrj|ZTOv#{v`FgrBrWw<-~`ZbABwc&QxDHx0Ye;)BJ8# zF1}6dsgrjsU%q_zZtKd$f3EKfe>`KWt5oXTDDy>l9*9cHVhoi~PLhoA-y$^|gIZY{eAen%d-TIi;R0Zzet6=E!%p zZ_b?$JA;gV`7eFne(TiceOs^e-dL5f+NH#Lvi)nj-||`cq2IJN%wOjo{_9K7ncV-T zzqfjQdpG~?`4`-omMh*YeOSMB^Q(E$o0GroF|TQ7XE<C(jUzW5l6}lv0 zJ}Yak-amn(J9yJ0`wgr8_|-amo?pEE*y}d??jLSjlFeqHI~TlddipG5v+3!z*^=Al z_-)vFRddzDZ95C>wuj6!ou9W{B|U%lMP9=zKPSAozb81d^zGLfwvOMD^h5V-t6sM` zd0R)s3rU6#KA?T>=Ne^SrcU0ZQQFm3^G`qVa$$~1NAI)v>5GJ=54uEmxV<^&mQ|-4 zH`!}WHbd;Gd5aFHYSr_`TwC`cAUcEvez#@?%=-M|zri8P_qnAj_w&A7ncV)0;nuqYtCq*#GM`qqX_@T0okDZpJDKQw zQx5#S{@=8%cjolmh@0o9XaB)-=S7|um-;d@UBuVlpSQ$ROUvi?%X3?jqMu&69JupM zPkiayoV@3oHd)W9^Sn@VUia;czw27RNHTn=0ekD4W-y8Zyf6HmQ5;mfBF5Z-`q9+7y2X|uD4`& zTfdz1ecP@p_uIZ)*?1}|EWRY$-d6YX)^4GU-*58cjo-a7H{3PZO8A;z!MS&n?pgeq zwdVQ)+icsXmP=xb>LL=BPfjn6-mNh8^UHJMoMwmo{Et7n^~E&wdfn28+ojKaG`nBC z+1l+F4@1Q^aPhUkXi0J0Gj<0vO^@Rnr_QhYQLysSrH;FjQ*QYbyyZD~SdDRu$d%KZ zz7%+^_gQ@AAH%K6nSVQL&mZ3ROS_<$;q9I^y6-mxTmKDDJG}K2cj9k`TWLXcN%t(7 zt3qR6&I@}00)wf0vGyMC@-aB4$P^rxJ)+qjcjJg%%Wn)qzP#an+(x1Lj5 zYx~r4_sV#liKf$HcRN*mD_MSX-F^r6)T>t`Dhrjrt(N`$HRZgm`CY^4gMZSGF) zL7Z>DWb@{Ymr{<~ajg4!d2YqhPv0M#ZOHhs_Zu5y$(AX(FE<7TX6o2|e`8?T&{t=y z_cTV5_l6lcw6m^H2W{Umg7V)$>Ew zYrb#W@g*R$chye-Mor%(T;xoOFH2JkKfh627{%rBZfmtB&7_{ze}nthd`O_xx6 zTfC3F_S6;jg6bj;@^)ubO*c=t{PsA@T*fVa64(9ZJ;A5?pJ&CBH+a|#G*)hyws`lxeb=rn_>$qyz;I3iwEj}2 zhik!QdD+`HmF>P@V>~mwdyYus6rVQ2RQCiL>hYkPUIkjomu3eixC(6sorLaHw zYC7}WMdlX|U*1T3IdlHG&gkDy_Rf3!if2JMtjs;9(eN&3)0_7RZ!}-e*}m_is@bZQ z+qc{ARWeMY_KD7S-sX)dO-`H0<&Q`A@p7MRsX)!Ww*w&q<6Q&;jWroFG*_6jl z(Z<>P+$AIC%{Kk|?IOpw33JmH{(Ds*ci2Lu;hbNV-quSu{om|-o>qS5+RT6JFEcP$ zD1uuB1_lk={P%9(==cA~lS@*U+f9WtuiNd-4bs}UH<|SUyYSIgPQW{KPA@pb-nhza(^>xvx$z9C&OJa2kVouzLA-_ zMW4D?GHzL0@m2jw9Ea_~xK7`iIbY8DGf3ZXIeBxz+z@Mn2EDm2&Y3OQ+!y+;;cWDE zwj-OFGj{*ay+2*2?e|UH+sE0~`>o6bZg105f_OH&` z{ag5X-s?9r{>rlPtFSQG2*X0ou4cxkD?PE``+frRT(9j(`1qM; z!Cd95zb=$L5;Hd4ZSbOp;nuU5#Kgu+Vv8c@Of~+R^83@NHi@HZ);G7`HWgsA+jct7 z*qSrS?u4C90q9=I=~lNVoU^)i&1~AYU_0+PG0`_~7;e?YKMMI2(DO1UHTv?R{=RK* zuCS!LwtjFq^`(2-vrlg_b+7L`6Sim8R^_ZyN5W3L+45JB@yo$AD}%C9_~iXu{q5KN z1o*jW@ zZ|=jmUn_%e+m;s||MR|u0oKDaFayopaNi7NPOuJt_tpC1osDl2szaYiA8k_1<(!}D z{`Ka8L(e!K#y-?7L6caykqm$L!CcvzuVbuowol*M#Tzd z28QLW;ErP(`-QTU9Y1bA&-j%nVr60MFWtl-%fEbMh{>w+eM>KIaQ^Pg|5@@}!?dJG zo%5H>vb#)t9WLD|D+A4^nBIOfZ_2gB8(v0x@$FA9O?y7+x^SNZnIoi`0`v_|5DDKWgmId*A`ocT3X+8j%AyRth}Z-*T*n3zu4gI$N4*b`OkT~xA{J6Y+-2l?8d;$V8L!wRQ)&Z z|7pH=oA!4zKiF_*`CJ24d3E`>J^9WVqF2^0)o#wZX}f#D+C8y$xBSnf{=2=)OS#nodL_NK9H)4<5wQG=? z^Cr{9DY|o*>N69ft3DMzoRV4|WM?8W-Tw0CPpSJh+-keK{eoFqxYl)U_qg}s>-Qen zWEy-b{@koyP3M_9+fMR6y?Hsx%;f8@r!HlCpKbZ%zO&52q+0jH&JU-TZ1RjRjh-HU zi`yl7|F5rG!|xVrm;1c_lf=uy@L&ljCr>!3Z^F7_W^JVXMk$62=YlAc(Dgsp9=5A@ zW@cdM>t>K*XqeIFxYS)}YMg%s%Yx-+7xEswcf(<4T9+PZK+gkYhQQ^Q=cj5j2*@$M zaFlMkd+DmNmVAo`XfFcj%07k~2l3rCpP%_YjppcQ__Bcapj~WS+^yru*Y>r=oWb}Xa+RtSj27}qWyn7L!mo;`c_E|mc*xWUhq!4Mm_ zucorJbZfgU__n-xe}3-i{u?Qqv-JA<`2Dr%ajiC08;kFK51zDi+4=jM_Ne}u{Q2JL z)82jpPN9~MmcM^;j_*N_yTHMF@2Ym+HDmyv1tk?56Juj%*LLFlzkm1Y3unyw_2I*Z zUvqcw-u-Z|)l1ENweLF~e>-b+{QUC-?Mw#Ut*>Lc=YHPTKIzMByZX~n-cR{2+Q-Jm z?ydZ+_UHB4v%Jq=SWd1I&1$-`rR2dqwYKBwEEmq-`TF(in+q)rv$QidzRc!ZATKBPr8ocHo`*8F(LsxISZ`NE zDn>W{)MK&8JO6Eupab)PVrK^41fS=-O+5DP-d#O=^Q-53H+?iP-%xa;W{si4**d=S z91PIqx+ z*n4op+da$~`#}!RUHA9Lj}uS-V3J{+e0Kv2dCM;}^Ew<=+@fK2Q70AZ5{SE#h!q?5nO2qY0$d z`R!i&<%GiLj3rO&_#7GL?%KJtP%KgAQ->2%#(lQ)jd$ujg&dOSZ`zCC-U^w<5J_h;uP$)}%;DnA}R>|F8q@88;& z64&27*Ge>h^RJziJ^X0;_3PKm%gc8O{@ncL)hgGt%}WC}w`Tl*y4c%$R-3Wt+y!4g zcrVu%`8V4<->Z6Qw;3P*g4wSloDcqbZX46Tef##MoAu?le7mwfDDuRn=NETQi=A|r z@2SH7skPUB1w_tUsM7o_c;=+NT(^6?u4ewKV#=^>`O+Je@$HMNdU)BUBFCW0Z3QSYPP&_h|t=#jEQHbbE(;t&94*7zCY35 zTFE*8(fhcnlc!%^xTR5lV&0b*!B6;CzhkX(dV98NbZPut!-xY z<5h>(+oztjjow@6Vm{@lbihlss~2{!&Wsj|zgE`!WlGAG6CS*4_TRsGId}EC;$7Kg zIwtWi&t|`xyXAlLrJ{)FNema78KfL`2hI4j?a-rR&hejLzC3xe_DKipZP`SbTIzs;MaH?gJ*Jl$hxW4ce| zcI&1|vc-J+O+vhn3oU#fr`57G`9xspnw<&ShtGcS|8zfR>y)?pb+b2}y5)4O^U_28 zr5cO=^3<=d*Q}4Y!(LnXbkQ8s@Cmh-LPECAk=d!_Is5g= zTgNv4zpyN9(!AB7;hm*&!D_r6?}9?)xA=H{_gbFYFP9Wq+`cMb`nU9}m0u0++TQHF z)hF?>TR$JFI?Yvc&buo!!wn(OGfZzDd30Trk&4K(!ni96&ZSA?mjK5#roD_5CzsbA{m&Fg+{eS!QXJGV+pvh6&u5LWn zw3f#__5PxM4_+CgwYn*?H%~oPb3Xnhrd|9tmWj!TlQfl|Nl79sSo9+iAa9^7r%?>3we) z(@cG4=G&$IwT;%~{rlo*-oiM+O9p&z?)LI7$X+*b9>Xn8AMw}zwdE#%%P!wHj5ePA z_`$=!hmY}NmCQ4h4$VY#5g>-9`;Cp^B|p5=7ogV*l48OqyEXMARTyZt5q zwL|Ca|K7Rwt>me5X@c-I_6y(Lg5O?y_k5AYq{)5DV&5vtTBjyYU-98-M2Ut{{kFis z%qffbr<^_~uyOaqdA`=a{ipMCKKEeXcrowxW$|r$zI{o3nXmHJ=j4kwSM(Y0#2>ff z-ez>?%BSgoxAwZDdulnUiw+LH?+LC&*z)_T79|xADf;3uJ6n3P5-~pcdg3Y@YOOqgoAEW zO=`>V`z8E#lCH+w#=QQG&-g@FaxRz+N}dH0f$@0^&m+h5-DI%|4atf-{_Lgm(ryRTi_m6PtkcW|Cp<@z$$ zOKPXDO@5(rYI(a;vDn>JD;2Z-Z%&xEc5R4Xj+S+>@ymq^%gxOi;`X>zF=g!j7{I<| zXGhcfAhz6mfrSS*epkD>KrHP`S^DuDhdTl+=XXC2xwrW87TaI8r#^)41Z|c-aED>n zrsBwzn|8~zHs8Ge|5jvXW|SbCjneIpoBkepfec7khe(R|D zrs%SFYE`qm!XqP`_CDtem2}v?wK4d0;+AUD&-Ir#bqRgbP(44-Mg9LK&YW3n*Y2!& zx?qvj{Yc}#JlZOIF0R{lb=Ry7TT6CrP4Uv)oKx`jb8`EfP3PvV&F!8eweDa` z-yLJS@XvJ9iJSh>jozPC-n@C1b9PJNp3jFDeAyOy%kX#S;p%|DnykAiZMtD zI55wcVJ@rPP*x|Lez|LF^&@>nE0uqo1XTk{}&$UnYHr=Z(*48+Rd4>KI>Kgy_Fo+X7CX0oB&T&3ZijiaBZ)#k_E&rMEEd|MeKEtX!Mll9ByNnh~gN4np#+Vr)U z7{ox0i^|IznKIHd5}B86_22NZ{)nwg!#3%{Wr`N;*_$)}o0s@aSrB>tQS*{ZUzOfg zEO@*8va#R&4-C6<)vLL_T@cSpE6;z+vq`ZvNBid^jdSM|&+c>RE(ukhtm|3-DB|hF zJOPL6TLLo+UC*!h68+|(Irs99G8Gxg+Mds^MxAocnl*72!!Enpi0bxLJPU5$IDxKanaTB$%K1%KQQb{Ka{gldvffSMr!Mo~L$y zo}I(Vvp>=TRJ@#Bq4GC8TWV=*t3}qb)@wQkAFheLT&!-}!?9rQblYqFhIhSK-_T|?i+0EVCf1H1pXZE4*u}ROl^Ilsd zI2SPbxH9l2B;9jixO?aI*WF)D5C5KZQt+m@`}xAEx2NQazI2pHcIbUuKHr()Zu|yk zri|#bZ9H$TzdLYC`zYTZulYN^ec!N6<>}razSVV6)m@BR+QgS`Ui|*;8Ifyd^PHI` zKAgJbf7aHM(|iA9-Fkj%i*3$_Z{N11)!p}Fda?5BhJS2{-pXB*vwrFRGgi@#-}5TX zc0-z5x5CNOZzl7L+i%%)Z7Kf@-IMRe6v_GwQ8V{-wMj0PDClU3V`L>4t#;se@Dk{4ex6G}c?Y1#lJT3BS1s|tNTll1ZtFLYn z{xyevfvL=zvpRo#3e*|DT&cPNn(l~^cF=#feD3Ak?KjK9rGkv#vK0K@x_z?C`n9E1 zC$AUF{YcyVew#|w2~Fu6n{`b)tFkVwUcA4&+~OcZRiX0IrF*N(HiftzUl(QezHjoS z{C}5r_rKlf9~H~OAOgv?nrs)0rcCOaWnX4Bo55=L`HNmVOub%9q;&^Y?Rxp*<4)EK zxval!m@}-+kN2GvUmg@T@07vq6aU^PvDJ1lmV_`n_X)3>`FGcf^q`vP$Cghnw1rO! zJex2p{puN`XdPkAS2=Aj?pT)zIry(_|IM?&`}Q0D1=U&0-jscbRz17i>%Q>%Ri$PL zYww)@vS`BVsDF073!P)`?R*pTIn-cJ`fAR7_Q6|0zB$gYt0WDym7#a(maS}hb>%m5 z-pHy~cW>cc6JwXCT;zIt@$1No(hOOU(s*tRgX~`uQ<+&`&O5oEwZ9k4vtYCR)8abD zTMkyQ%gf6zw!GLP{Qu6h2N~Ko9x{Hpaa2r=^+G%U^?g?^IJ*0O?Y~syWfV1K@lTKM zG7j>mg7-^b6Op@G(Py<~I`>TIW zyWRfp-ra{X%r7oY_jG2;h-JQIcGo!Up+t4;^i^}_iqF5dUVW_|yqwKsy-=3b|HpFf zvkgzBF8rIZR;}Tj-JNA6Y;QA;`(2a%QSJOP==Q$+khb%R4e#`CC^CLom2TLZD==&Q zlrIN6tzuU!n-@N9$zRp=_S;{$FlWqVR{hVru%Mv4{JOAhx!JtMOfNQ0O-V4$_--@n znb`-aiMqEPF8r_Bsw*mWHQ@YeP(ky&GB2C?#nIZh80M$yF-Vzu{f z|KGX2H7$SbcK;JIdoqRh&COeB!QRor-`>c5`~HqkUBW?s*~ac{2lE=%N$+OteV1mV zmUyXDHg@f=*7kLMqRX6&KS~}*<5zk0joh(&zam%HweE_TWad%o_py`h!o$l;8IJpvyvnh0 zXT5M(`{aZ)gIJ$yZu6JM7jKVME}IosENXRze}Ved!=dIJd#^4F_SOEa`}OMLDa+P+ z-Q2d*(fm%L_tw17@RUn?(|&;Rm~G9Exihyciuw^Wuedm~=z@cQiNCAsC!3=*K@U5*$Y;AFjE6@7f>tqqP0xu5mZ8y?E6IcxnV)6T4; zCvN4^i)MSbd@|uZZ`#%$-rlZ1m(^OOVcnYK&rXfow2#W|_6uD%XIXgsq_Vj#>9$9L zc@}I<{UBbSap7hKAJ2m0VUrZkCj6Sa=uOYLVx76&&vti)ZMe$@N{xTt-F%>bwn_`+ zA?Mc)U%aZhpc9o7hL7t`yUihZm#O{S8RWFDXsm>yEpch zrzPdh8|-FWo&4wL>2Kn(7q#Dp*JeK#nO=6LZ2qyjdi&qIuJ!WY&t-@JdvVXp7N!@o zzHT3p=6^KP%rc6-GT*rLr^`8%i{+&5c&TDt#xi^Dt4~eO=GXi2 zF5utUS~5FaywvN{r%y$N3qe_RvFkeae7@}jZyv)6%}eQ%#yIqv-2EcDxUa=d?-DU)e@;OVWG zKdd?Q?{(BRh5R#dJIm~L#BgL^zf-V{hhepV1GB^g>l`tM+jf(URk9@{-1p!0+x__5 zucNEK6;G@^@-C3uL>MnoQyLxin^_gbjyJvXfq>YX=~**5+QE|ZXQaF5*=dj5aLySq2n z+g>Wp@_x|4xFuI()9=b3A2#ydynp{jg;n(PrN3GocK-8R@{gG_x9t9hyXogkbEPML zX_tK&+;n;Q{!`0Ow=cWCa(^m=LIYbt7-PwmhtuXw_~ZK`@%F)!2TT{db@2YDU@gCE z_CKbxQ-AL~QTEkI+$_iIpSJD(4eDllPROl!TXs77N&R8BmOnT7D!gJ-tdDUkZ#4Mp z_vOwrKN58EFUpH7d5@t80_X z_cOO17H#J_uXe0gtWS8WOTyTlY!guE!;>eP0%v^D0+#hY(>#NWQ;sMeMj zw9{7E_DwHlmSAS|voC46#umG`pEV7(me}N2>0Polt$*+GYd70W_S~J<_u_U*_3RD0 zZEuP#%0Tyk`8me^c6~V^*vzbY**mTI_Maips)A+V6TmRDk!iAlR-O?Ll{~xUsyXlf& z#vsdU{hB-RnBO+hH;HG3Wd42ITpY28Vb{Z1YjvK?W4N_%d%EV~S-~&Q1lnGdykN#x zH#cLSo|W|Zhm2oVcwH*qI!)}p#!>Bys*zR^E8DxRAOERY_=(T7n(fP;Dv7^k2Q^hK zpD2Dz@}2R{Wu|HQpG)_)UG-U6+HHJcvC;cArGad*T8lDt|7pz5)3{o>JST_YZN0eZ z%JS#omX>qCVE!{6NbG}V@|AZ-{TIby5)oJ;M{f##+`Y8Qc8#UmPW>rNsm~ea@|{^F{ry9*Sq)>J?u}o|O}~AAx2c%*P4(8A zJ_(24e?6D)3Y(XgnZ7CdMWtAG?(SLQzIi*=&CNIYI`2ix*PwGt?>lT@VFwM->=u|8 z{>&!#@zZKsXV%?Y!{6VzcP~xc{aXKL_Xqz@A6oBqn0=}Ls|o*OYj$<)pP$=4$L_B) ze@bD2bluifwG2DrAs$Oe?E}8al&C&ku`UB@V%7^<9KN^^_#;S(0s-HG%Mb;)P+;ymNB0`x@Wz5uFvzw0fKHSM}TTK7~hyO|_nuyEoT)OW|K0c8S{8D}&!;Pg|pD8(^|K zl_3LkY}x_Kh(E4QPdh@~G?|z8@hxfI)wa}rrSw$cO@HF!-pfyYVtM`Wy!j^>j_=iQ zJG=atU!F5Bzv7%K|1~cqUv0_DQU(v1Ggz!H%<*TC4STrazv72Lz5?~fyMot9cc+Iv zUtwosGv~|1AkTS;wki$BGB=u*ov6ur1LoS)x{Ya5StvX)tXIyXO`$$=9zvHE<0 zeFGmi>$fM@Ki`m?$aCfTB@6wk8{tRnB3_CdpC2+QJ&vDqL19$MAWgg6#3GFY(xW!%ye^oRY_`@{wN&ezmDU$p%E$@zzWtv&el z>({$?=hi;CXt(@8u;+?)JEn{|0>4`&uYR?OiH&{x;WbMwN8*o9{$>9E+@$Y;Zhh*x zaJP(!aSl6Z>hzprJ%euY@>)KdHx6@;KiD$Sc(v(~k6*r&EK>DRT_`8y@VMoLcv^pd z|CD1lZ=|0tE-qgDd4cRXkxT}OCeW;Mu|W#&i&`%2VB-LJBeQ9OX=MspSD(44+ku?2 zE0QT=PD^(;_dbKe$3owI`*!Ug+tIp*>byp;!x(QcfCA{iX6f!%`URDD1Xi>&eDLu| zUd^i?JdZJ_lR*kRyT*Vq{RR;}Ai{D1!eXG>Ok~62%D?x{o;`c(dt7X+t&Poz>h))Sj|2@ATi1FQJLH|3Q?<5!) z7?i*+bN~EpZ}|GSwN;Og9z8nSJpapE{rG)r?r-|j`|tIEpcFs{oAMBIWMH)_m;n%)?a0r85kTui~boNWXxjDnEkEm_wV1obnV+2 zqRJk;eEBkW=AUdU-`zrtCe~~W3=LHfn=i{a#K*?ov@nfrePGFc!Q9;Z;*@kvdCRPy z`6i0Hbeq*0(vCAQFa-32!We9DVSW92#_U}Sj%?;#kZYo^I{97apWbzGO7$5L-OUWM zz|H`jy2jA3_$B9pqfeivN^Q`~`?-fX{OjA>8Gb!{xbRG{sd$?tVo zblv_tfU*pOA1gS4UDRQ_ATBQ6-`{_;o%fezQ98rlPft(({#_lb5xHFSbhS6P_It&K zxUZULU)D!86z%zSF)FOQygV>6HZJZJ_mg;WdylxquOpYwUzgo;VtMwbb@TO>``ewf z5B{Y0SNbQ%?+?eey3Sf_@K9NcxlmKv(qy;vF5{c|99d;P@>evi%hu$xGB7ZJ$|i;a zlRCCnOU}1vGH$8ynzGbw-n@C6BJZtBb66kMv{=1i+S`m%Gri8w^6l~ttlQOY)_B#Q zUvOL7m6buSR;6pPoZa;CMejEm-FX)KS-$N3cQ7tKe)+@FkV%2__U%Ysa-M;K!5TEn z$WUP7$Ch>Zxq1G*C7UDDSuTW!hnun2R8{TTy}SBr-#Z@@=dibm4g2=)T^n=rrkK-t zsSDqvn*stZx;%JMk*oRh;C8w099`?rvD?;2X1~0=+4T6k=GvTOXNKJD%pW`2+uPsF zTN1gaOXx$;+U~Lg_YG%v{_bDQ!oYAK2NGeAQzp(@KlNGuIgSOTy&OL;l-yHjeWEHw|`vy=cZ-w!#ypm z&WARg-oAZ%S@XZn&7aplZN4;VOZDu#O>>NF#Xq&1=u8toA$?ip?oGq}iE1AYnt#N;u*^F1%-p*VP2#ux-kG(q=ThHQ z5q$;*hHWm8^nG*2j-t1>R`M(6{J1ce1(eDzW*yq4apdmZ*k3)n+j=%_V)#1Ya!>U4 z4Ixrei(eNrZJr-jb>_jt!yLcAecM*DOe{J6`H`Dlug)v!%dQu`tbgjA#7koah68+{ z+vxe!#_SB`%f5gVboUnKOJoo;d%HsO^eD0lZKbHJu-126g@YGk*n@=}inZGY+ z=56Dx5ll;aZ!8ygGhP#HCbg~9S-tA?%E)T5MY5C6USog6z`$?=G-u6l;Np~`tFx{$ zZ{t~@uc!Bgvs7KsVfE?Lr#C!LT*&$R#O{*PZm++LUk=9ZclvG+%`3(9LgU`o^C3?= zqqhqFPMRI|{R-FaiY>0cco-Nqm_wW#d@3~CY0FK+r;D4RTKD zV%@uU@1Ez|%eCOGUaQb%$K00-Yj_z;woLmnQ}^J)_p%jTj0_A00+8Y=B{^xgPm9|A zm6D8G>b_jQ9BdY9bCDscD{%SoZ~7Mvv>L>I%{a0_;p^SIcOOaVd}S=j-1=IPu_QC7 zI816Q`?uHAwx%oYPL67r%Ds}Afgynz5_FS$Kj`V{WnH@T5EOb}AAPwU%(Gx|=3T#K z@tFw>x$>_vnKSsr!t@l2j|Z&mJ5jkhyu=BPdX#4hK-!2sEz%fR6Nm}PO<)us%#Yy58{3;EmL&i?%In}^f+ zp1*qK6(^Q@=Um@S(QvW!bddMWAnyH`{_Iwcp6|Oh_6tkZkFuJZn@hc#>&1}U?D4bN z*t>k{M#e33S!KR${&)HCdg@9H*^7bA-emo;P=-;nzmzo*h{(131 zN;;+eFsFWpQC|J=92WbOThh2c#c0_F7{|MLL zwvELW7sbTN&#V*JRMwcuz`(!*Eqb~)F5Z0VU=M>;FVoe_mxC*o%x0^uHdcyDKj&%@S66c{Jp%<%A8bC0=!B`)7Y3@HAJ$-%c z`>vqUz2P!wAvyzt45)z(S_$*@ebvuTPgj4}aAsg&cq0$Wtl$PH9rrG`JrMIuEy)q1b0 z^yBwknLE+GSXAb;WQ;7s_9%t}pFvFqi)fY$JzdLZ&FYGai`!>v#e8S+gxYQG3hrCZ zFN$krsNz5O;1$D;t4s{@L_zyJJi(j7e{Hq@-pep6@MB1DaG-QaS9^Q=GwwwGt8Sn^ zYP_1Ye*1&;j@v93rca;#{rmS##^K@Nrq5d$enn`l=WB@8g|=2KJWWp;F`6uX#H;nt z%y@zK%eV8gD@>TJX1~gs^kVu$GsZ2~iq#|48tyfpTFv|*jGN(rA1F5cgg|=ch8$X% z?O<uZ(yiOxT@5^c3|zaXkCT}F`z8%S24kj;p~bZ9er{R;c*<*%fw&G zF};|TGLu0H6od@dlt5bs=k4CT`x(QpPoF+Ld-m+A^(Xe9_kW$ADjpA7%bIUkw`Q?xV`zdxxed~ss-Lm`j#OkaQexFO@f zuk$KkdKJ@)#?W*7v$D2L6Wbv(cU$Zy!Me?h(`~G#F5EJAd-%2qyZ)Y1KD%$iyQZ*?_)H$C+4=~uUJOZJBTa@$*`b$^E3GMU!8sxt1twX65Yy8M25UwgK6n7Ggw{Cjxdv=KDsb=&9siga}?Y`%Sa%Y|{*tp1x_exb>e9X(_6JI2`XicOd%t%yqT9 z-yJw>ebzc)k!2sx@~8Ee6LU=ruibAqs5;*_|8L;NH*NbPC;DDyW4jQ<6x48&V~yIY zsG5AUmIV0yUusw9Wjt@r%9>lenoCt}dfegG%k`@#>7G89 z{`vJ$CZ6R7_RHn&y!e!vVGigd>H{Zt?B312S@8O~hHKYP?=bvxC*p+s8-q* zJAAmg&+qX1{!;FjG0D4`tybmSV053-n)*B}eX`3<`JeH7tTXU(h(o}GRTx*W5 z%!1yfDVsA7*%>r!YhCkO;eW5w&r4IBt=~+atW+(>rfh^w zr(VCkarN~sD69nRaW|gTa(sYxfXG=^GRa;7OxZ9Z`Vyz3i-V-aOtM0Du3oF?9zLp{O0Jq zzt5c#=&T1`pG!`}~bf`hGCKed}&UVfS# zx_#wx@XwNi87|ZLzAl!~IO~|RYBsOt8?j3ai|W~H%3NgG-X^Zw&R1UAY*ri5bL( z)U~2FjZ@Rv)7LB1-_-b>Jmu2z8#Aoee*1P|llF}liY@&f%dg(fzjA4QcF(TRsb2Tu zf^Q1N*|2_#1}CMT;GNp@wlZ${ygI`AjZbpZEZ3q^?u+_I+TS$jpE@*W?v;&&5v!Db zOG$IOR=-ZSeaPs$wEx-##kneWW({S_CfpXD_->EA{`tVoO=@Yj0f9L#Vx{^=a=IR4{1*ZuAPrrwde4{Cxr`;5p(JYcE0z9RpRdZ zP4}^9kZl2z@w(`t6?vUWmxkrmvg{5=v ztl0Ob?etEoSJ%I9sEq$|>f9{L$C*WEd#A>o=(gv(kZoD}G^tTX?Zh^!%%V0Z&MAm+iB9^M7s`m4`$@;$v%_NH!Gj@Y$t#@{Y! zFSdOtDSCTuj&#m<_6z4uYhAXo=Y7fVfBR6!KZaik`~G*7`9IztU?g?b)xLMTVUpCE z97%`oB3~0r7~bwVqZjt>ebCFq5a*>-G6nL#7Zgk>U{mMIsNj@lcD0JD+PY7 zo>O}x`OBT_X1Tpng*R=#dV3bbu7ySGxE6T--f*7bR^83V;p&KrVO}m%#_x_*UcY%3 zm@2KgF6%IFQY+IGxA+vVB;F8q^HEU z#cBWdeGxer$XK#+M_Y)cWue)%Elak>NIT~XILKQqYnkuGu=np;&_1CCW>E7&BzF&s z`)96s)zM9h6K6i275MS#)1`7vwHiqsbKaPo+_?A`Gvk*93|73q7eUV4j9t1tWGlyl zxmwS4*6(rrT=9Z$!SCo3huiNbW;EWYe6%!3O4K2{$44<1(8M<;S1(BkvRrt1`qG}S8fO;^o37hyFgyB$LaoR`u!F92SAE>ILAY+Q ze&DlE%bf*ZtfHnGZ!-=1W)*wKv-jWS*+)IuFC5<+dNcE%O^X1-ha5o%W(L3WW{g{E zEuwGtKP?w>xXrNW?eR}b12_8idF@v%cl(<8VN03Mz4>gnM5DsjZmG6d&k%LmF{|U+ zpOU!E^NfBQsq-l}_{FEmbKUx8uuJi5-`(C7&%&1_{MB7@sUTq09NyNsp9;%1?Q5C4 zC)By1ep1o@O%lA~FK-=NWw&!1KTkyUl4`yM*7>1-?@zt;WB2m2>X^iwq@0e z>5@g68E3+y>K{8W%&nd|m+$80sv`gDB=weUu8q!79!pC-%iR9IiSPfn%fZytk?Y{i zdR@14$qA?UKdpAZy*tb_%q+cJYpv~^Eot*g817cCe#O5)d%sP@94USFs|D=r3<><8 z2wm>ZzOnAr#rgklWd@&Xh>ufy@2h;}FUtk9&qecURHY{}7D(AnId;|Ty2jrXk;UuY zbVU6(-5vhP{G##VTV4n1Xa4O7;?qn0^yQ1l+lO^bFV6jV|KXv@&k3idZd)nX*;ekS z5G3#LJMhgh#x2J4%RQ!U&J0<3>ZIhv#S@C6cjuf-s-32L`}x|XyTj!j%C}8e%C_o% zVXoN;?b>y=+%F}!_ePg-f119n(0lcqoP{MEXZhQ5v)ANY(fd7TZQ!=Bl>N(XUNY?Z z9A;X!bwy6HMs=!o$}ZOGrnH(uR>+8N!{y}qMA@|Xwhd}rhV4)Gm-%QUS4e(-eIlmq z33{-fhoZlq>@xzA&>pSJ7#O5wo%zk02xRdJao0gwv<+{H5FLWX;ZsCom zB`4*}XxZoN+nllAyAw^w9YT-a3p zgV9_09Q?UohS;ayD?ICWOY`1CgT>vqrqyo~Sd`{y=T{zgDwsPmUO3d!*CzGx#XxIpGQDsXx_c`)|MJ7Y z&~xj5{<@ewJ$zfX`;V==zPKJ;#jtC6>y|f69Nk}6rKxA@y*k=?``^lm;x9J3yH9`i za$)Y8KN;@P$y+Ndx@Z1?cteq~YFTi6A|UsZ?;Bq z#(y{ABbyX6Z%^ZwX1nlEx9neXRKv|L2PMOouTEJae759CJlBRz(Hxh*EV{FBElXBh zS!rpg)r68uF{x6UUZv(X`kieJ(458eX3r%z%YQC=X6=&w`ynPifBPO^hS*0o-VbWjkh=Stn}Z@C9fDu&ach#V5qH_?l?WK>{qY%*|X>BRM{8~tOV^DoU`hK z^H+m@Pqqn}Qxxhyzmm02T~TxM;awTqzehf7(D_~c`I+wZ_YPLGYQNrFwcypOS6Vvy ztCy-Tj#u}bvgjIrl#RGi+w`?J|8mN2xA<>(t4TKD^!~K%0g+5!Sw*M%SR7rta9>_= z;l^9DrkjdXKWz>0U%g0P`!#1Q&&5~zj5mvQKfhUZB)B{3d}|qE*B3kKKeRe@$&ZT+grX`OHQ-!@ZPa+=GIW9Rr3=sN-sav z+PtZE?d2tFHm%y&buXjeg%iAM_*rGfBtJH0|Nv2DF1+`(2=+@Y3q{8%Ac=ne;WU`KXrP#{_ph* zg6*x-ul;B#mYU<9ncn=My}f;L&AWR{8MfDp?(Gbg*=Twr@n^942ODjl7nASYyB8M| zbHSM9uv>yL%Z1gTUA1-Z-@VJb3R)lVb#Kx6#Ri2=OD@fObZ4FL-M8E9CY$MB^2z;h zZ12Q}6WAP{_k|I_xG%~y6@+lJ2%tR&dlttXXIK@)37R+@87@c-|wEp`gXtR zm6S^FihL`LtNoMf?%JK-G4J)}pZgYWX13qPbY)Mtf8&-FS9s^F`@F(n`t<3byTsT( z{rKT=UO@W$oh8LevTT2K>MUB*TN!p8J$$%%oA_7Tz|8C~dFu5yewwd4z}c#K{BG{f zX-k7EzI1Y$1x8)<%&k+t`{ntD|J&+yyvp@f{?EKuUX=d))vK%r`{p__=q}xOc6w0$ z_3m?1)h&3VVKZg)KI>-F;GOU<`eFYI|RQ=uX64V$UU$?xC4-#TLOSMtuJ z^U2$nn%?k?pTjVVq3V^WNXq7(*|TRKy?gKf&5PAviZhI}nO+z;+)8`CoqxggHa?aM z=?P`5D^}hsip(_&S$Xr}ubWl9VQ>ALKgaD3oNU!}zmvOn3+IAzQ9S{N{-o&- zCLEj;-|A=8aBbTo%Plia8NW=k&bRi^f9-PruQ|&FBaSuypK>vNk(?3B==DZOX0~hW z)VY(v&X7=C%g$)h>)D&Z*_ZrRW9PE#g<7_^H%GcBm7QN}+l1zaB{v zzvicu%&A`BZ8!VwwN6Wx3%j|*ITo<*+O_M`{Nsx@SAguV{#Be|EY6%U*Y4;4t>y1L zCf~7=ignO+(w@Qlh3VKk+Y?hYgO}}jee$*F8MF3_J>3llRD@XMr+)oz*|zBF+^Hwo zIhy3-+gV?Hc`n5CWx|&RhQF*gavAvU@2|J7$&WU$_{nj*qr`B%zDlF*O#R0`Uh?06 z``@cjNmF_CqvOQ4f&(8e9(J4g^Mk(UwBsKvKYVp)h!Z~X%g<}kfs@{I81@xR|FiI9 z-wL^OhX%KXx@zs;8H`mw4Qn``Pu{1Pdo1?H*Qp=oY$`RWlXq!($)2ri3dW1t&iAIq<=oSGsxY&$qYDSu%bcQgAq5 zCa0wL{hjE=!+Xl_7BPJIp!c(Q^4~d*noK54Uv9fEnXm2e`pMplKW*F_rm^o^#SqI@ zQB`>0ZBj1F3;hFm%oS-LKC`mC@VKvdT@-B5IoaB(6boU4KS76&CFH*A@L-(B%=ATP z|NnoxFH63Dd3K)i>g541w@TR8{rU0x{r=jmyN;at|5M-Zj!ey)X_HRa|Nj%L{%L;w zzn`zy@Bg!JL(Rs&p_;1ck`=Z4QsU=n&exEi^pyW8|I_;PPewB}PloS(o3g?r%hluT zwEdd`FKq-Z61{y{Naw|En+U)f~J<7N#Hhd+w0@)gC;k5_`Im2I9=mTY_T>ha{acUAPd#!v@9r#y$=|o_ z`kV3RQbLK@>Vt2jSEvVx%T_>i;t0tm_ZQ2ay(_i(L3jXRec|2#Ed6p*Y)zj1MUaZ~r|DJc+ zmMbyKUh&VZxhnsy$=lfE>f8x>k}K781$dtB-Q(Cj`|VU~%b)j3PO9=gy7O3FYZnrEU`*{m5)PVaeDH0kT5 z=B;0{j%RXD4!^`-$$4BsUo~)X(JQU&?iURVZ@*9Ki?}Adp!%C+<@4j57moG(eL1t1 zY0I>BCC&09nw&XjR+rqhOgyue-P>Kf&|L4`QNyDh4L`(~J=!1nxnwQdI*na@bj|_c~*PWAF6;9+G6Vn&BZlUvlD7 zzfGb&zjwcpIP!k>&h@7!N%E$r8Y^_49jO{}+-6Qe!06 zJ7)Iy$!1EwW-T~(RpT^khOO4RwL5ZIcfPB*;=P3R#i!}hmAfW0l~@bxEzz7F#Lcv2 ziSO+OW$(Ab3$~`esN{dUZ_YHmZwX0$vO;S>mlnF-^pdz z8F1%|?{vMw`)_^--8SgkzHX83lr@?1rdtY9b~5Z$S<=aJ^5w_VPK;5r1GZ{xe(e{% zPvug`c6q*;vJ*Zoc(=rOrpSV9v1@JG#!O#)-fTI%UX7`()j9L;s?(Qd$iH2ub#g)a zJw*rhbMrd3-k4Jwu|8&<2{a#(I!epl|)eBY4t zuvc3ro|0sYQr|Rpf{5$M9lC`ks@%s6r_T2{yf5ecG0&~}7ZhLSvg|YnUdmS5J3}@r z)aY7bu=FzNtxo!7W}9~yNg2LQ?A3Z3UT%GHdARePcV@mJy%(oPSI;)&3I3N>AAfgA zJm$d)7N*3-Si8e z^Y7QwhUL9`UayobU2|#nXJg5Wimjf_nvJJ#tm}34(JK)z$n>_#oz9kUD|`>zR>}Cb zTTzkg;=eav`PLZs(4|b|n@obPMy_sJW@S>p_aW~S`#jPQFV+i{)i}L9D_(oFdwmtl@ufGvT-xK`pvSpG)Is_3mR(C{vtO&);8G%3 z{&=7HwYWp^8~%tfd$c^VGBZeSyk$S_o3+U6J~s8w+ZOJ=e!6w_u6_yIr#kyGZ69rV z<~(br!q2iln*ti9ExPdX`owKV=G=Ndv5Cy7TSDreIFZ7 zcKfBTC%2iLF{oe5Fjwzn(DJVg2PV50%-FcxvS9I^RcXs}mrqs--F10CPsUlXmeWEr zHhws5DL2zi_xyS*X#s%+;>lNfZ)>P8s>w9J`|Th*%Zmjz<(20gY(riLJ^G>?D0|@R zH!qg$lh>b}a*e%uVVk6fMQNcm>ve9XlKEG5B^XL9Kkm!F=*+~k(?b_~FYrCwljw44 z|DJ0bH73j17TXo?3N8qW>UP}AI72e^EXM_-kJ66U*Q~#N&+pZi^DbuoKh^P-4mW0 zm~XvJ(8z7J!!7SUOw&KPwtcrWRn&F3&U@wUjRjwit-X2wS@|=$dFO=|_?BOY{=WUI zkkj$jSF7IW7UV_$D&jYjjAgmIS%;MRLnhu`allwxq zaPN|HcLK%UBq`}-+b!W_JGt}Y=_tluMvshQZ=`yEx!!r6y)=E!NiD{z;2lE!R?mbt z-(G*rxBP9utx8X;Ip01T#ZPj~7u(Vst(1KJ|Id?A6SG##eRbyBxqBb^MQ5xLuWwXP zaIlxUd-v7lGQHZ3_qK|Jc=t}WRdD$IdU@KBs^ju6t9g|2C1g3D7%koZqI>GDVpG1@ z>#qLh*C*fDKFeu0gXN|a=ShaU>SDAr{4V|!syt`##lE*MPEWZr^i^>|&vTO}bJ9CJ zk}dzNoPLiruP>2Z`<&zlmhW+Uubth#^`gHD<1b#ng2@5L^DY{H>kI7c-m&GUhw3_^ z1#>%{bMs%$OLa5u<-TyP?MsJGLFbmH)Ah2kqVLxHh){BvZuRx~mMY`K+?~F=R(dkt zDp~OF+ZtJ>E&r-+@AXW|R$I;TLiV9o zRKq#dwC(Y=t;_4L@hz1-zbyJ=M%kP_XQn^#WQ_X#c41z2+!Cp*<=f*pNedqWnPB+vXTQO)x6!CV{P{xzx=YO z>V3cd%@e%LO`*wse$h!1J5S%NI%&4NO;+OZ%dd`w-qL4Zsxd~*{*ub`Q2znfHVfIj zSw9|sb2+5Sw56}-_I$DS zlbjc}&+T|@Tzs}TWRcL}&!t^k4*UO>S>CzVyP@uH^|vdWeq|gNZdGsjo7T&meS1pW zr52@Myyrxs&NZKP7k4y&m;X%Q%cKvjLC^Lus_c`Nv6L5BP`qv7Q7?PjB-h0gA4V}& z87-N~KWQ#FnQl8)9siNrCL`QR^_H{@T1fKFdbe@mmduRB%(m+KpH(Y^8v5S&e&n{- z4dUH;IU#MX=CqSl7pER7JkN1qzI*ktKdIglQtGc8ek@_IwVc6k^m&efm+~Inbnax*_VnIf zHp5BQ|G6CPt^Hoe#2+=NeDe2C$LjA91&4Iz*17K$DqZkzZ_i(!FZ!Wx^!w}-9M0=A z-`^#+(tJhTGKRM~)$R>>@kx1i4Ob^@1w= zzqY-7F7-Q)*`wxqOyRU0Mz0$f{zh&5qIk)PpX0)0#j`aN-q@5yG`tHvBE-1s`y}IY zPkI<^C5zXIE|~kdwe0uR1ux~Kz3#u7x^s_?=E=!SB{gq$#(+{-=ZEUty=T_UVP<*Z zo{*=t-x+cB=a$5WFkF7&;=gjM z^4HX`I?vr7-V0T3VzAvgxz>ouuP0ysW$fe2aXw#I7^CzQUY*VSns#W;W2XB>Y+KF+ zzGqu4?VT4=ohkR5 z<;9(@g&b8k)*KaC>~%USGq(ScZI$~G1qXfc1+~InDGRTZNUa0N%nQ%+CGyuCufEh9cP{8m#Rk=jt}2Yb4BE>%FHB~e@H?;Y z^mN<6&_$PxpQf|CFsrNH$6zabNx|VfOX=}BoJ?Ol_wRCUn0M#Dt+CpxrNy3}b%u<$ zBK2y08s@DRXUPCTeUX0(jJsUUJmr0B@FQGcLG|vsZCn?gvF(3wlY2JT!HGgeAn&gG zUiETD+OuzyYMDyj)qK9o^d)t|Lea_hel@vsUQnHQlp&A(%zO=pY<`8+GtT~$p88FM zuP}12E;q*of3XGLPiKivnYh_nV8PriFa2VcX_a$dxb@Tfe#*J~25+OTiT+C8;a>&u zncAIRgI($g+ZoT)Z2z;@BHfoWw&;1$9Ki)&FB%?C2gbs>uv{m#FNY!60jCSGb+QHeR3O0tg1O|4L!pWszeq0xRz0cR@jgVW-8a%_SN0n*IpRjh*&+WEvt(zVPGJWyZEt$mlb8W%T zs!M`0Pq#)@=^YC*3c8o+Xa6IB@mJ|q_WN`8Ctg|oZDU-qLqpv%hFmefYr$<^T;8^` z78?jGa9`^!o|7xi&XSQid(($&bM_~Oy!^KD-nn_9ayqiHJ#q&(e$aR_na$w;-AgM@ zKR@HL(vs&%Ak!9+(=R4wzZYF_S&^6NONveLv6%`E^S`WKKi9oLM{vP(`GXVnPU_dN z9N*3I;%Aj(gImKtRhEpskq@@5^f|}4O!{hoQtycs{Wtgid9nLkgI~JWl)3jlDf#BJ zzRqKe+HzNwyZUnKz1{ZZ#|+v|*-y%;HTaU^Aoemz_3`$_QqR}@+|GR=*FgPeQJv_S zbCYso4tCG;(v4wT%+8W=pFu5Ip_n_e`d?e-!qB~!c(-jgc&p6vLQ?-@C)1XF25VD( z7JW+iE_oq7qCxNI>hnx`caJbK?uu==Id6aBuHU!Pp4RK1FPQ&5;WH=+Tm9bKBO|<^ zm~F#_wNqJQ^p4ccV$j_j^DN-gbM6Z}C$KSE30~Qn&h@qoDf{+jM{RwU28MLm<^q8%f9#ReXaaR%OOSV%LazI=cbe$|7WvG zOu)BfYjnf3N#^diWW^R#dp+t&d=Zx(qQB3lY^54!Q}y&#J)YLbp^M9fdcQ5+&6=Uy zC%v<{XobK|&q}w3zL-7x{2RoSzqG%YY&c=vf=fPn=kFWb^|H07D3bi`3=f9Q>z*GJ zSdhNP+y2ja|1$0iyK<-f+G|sPxaXJG>wUI|Ywv-oz=JGXx`XbkIy~n|*cn}HW@zKm z(AR$4UwA<=IL-sg&&*VCkpH~e@v^Pilyyt=uM~bVil3y;nz8qq*1y%Ns2;a^C-!xX z-|uY~b$b{0dfoaQFh!s+`n}MC%QHV|D=F=l6Id|Uf4<0qYT0`|i7(z2Y$<=K8omC6 zUpMQ)G>P?6oHvEdH@p{HQ2OcBN6m>0szG*DYa_Lr&v9S)^?vS(^7#yFuX9*%&ggGk z66Cc&zdn!GbH1YV%H#b43)1%-QRlkwsYrb@$A!t)mU?GuJo0+(pB=@`TOUqIXriowU()5Lw)5whPTk-%5cAw z$-iXhm)DOp8QVkZ^J`uICq!GT1+C@Uul|~qQHt?bxZr|P?XDMv(>JwRblh9D>yvP; z`NfRImpV)ClzZ;?yZzRG%ZKu~hI6T}M6I_tw#TeJus6Eln%cwluXO)U`LN-a+5UT{ zOD`Byb);M{nDeyv>j#&~X3IV1URlT6x;1f%+D&cST*b*;x6~MS?LGKs+vff`b_>H# zor$q9E@qi$uQ5wz(d(kuQ=9Dq6=j(-HBbGVkmPuFFn(LWH4GK1#(=- ze4X{a^|qEn_j--LIcuBl-BNw|PPO&ivYC~-MMk?g)ExLT{>C1Ddh&={`(3sTch;Vr z<5lC!6~Rk6q6SEnnCr{Ua@`bPGw^IvMu4)8&yR4eb^d)64kE~AI`ly>G6Pp=$t65)6 zzqPI4rE_=c>lNQWh5q|k@a))Hm-j3BHFx+pXC5=17!_RXw#T&S(n>3Rhv!D2|KsF2 zZiuCQ%-B~~;?Qu7-6Ce*=9r?8x=>>ysa-GUE!(r_>jNvDyxo614_|oP@+n1n)@j+c zWx79HS4juHd$Hnl>XrL-k3xKJhfZhT(y01t8#B`u!{!s3b-x~7+T^qE)c;qFr&49l za$op&^47BzXJwhTXl}puaJqih{wZP$N(G)B@4FRw*Da^+Tj}j9{34UDU9C-Unf^`a zSnbRAR)s(L7=QK8ce%Ez<6_({?&LtuxlZ!eHQwvjclFcbCKc@XT&UHa8?S`&H zcImPCJtlFd?LMQX8L(so9bebL<8p6tp!S`}uuQO8_j z&Y9b7oc;QfqyB9YOJ0=8vU|ooO`p1py=^AZtQoSaw{Xqn@t0F_Sl+xV`P`F-OeF@d zA|}mPTW2a~utwJF`<;n(&WAi69X{sbsm79V+^j9~2Hk$G?SJ>kj7{quCUs`%5!PxpgmZ%FbNP?iAwOrQP19+c+o{*~gyFN<-EgV@W?JI! z%o;AfpS7CLyX@9J&D#C(1{RS?(r%(ggOD zir0l$YC3o)%kaMPvzn~Vec|AWP+f zymHsKV6T_DOeK23LaTn+zghdwLd{|SIs(R_@7AD7ny+;E)Hb*ywYTXU1r&dp2e=8eEF_xqjpA=*4pl zdFGmKKH+5d_WVz4*Hy zlW(gn+aCY&o1Xuv^X8lv((h~yn^x=V^*&Q#)sY7Ymnxc*m3OsFf5E!`srs?i_FfHj zD|_GWowp)ZUE;h)WoO~1r%xy6y>e#F$d%sBnz6RyXYkQoLh8>al(~y@o?US&dhNb| zQ`<@;qxBoSq#fSv-dj*&r`5rt&YinBWl6}{)QXzd)yn(My-$ie`;&j-i5in7mI@Bn zGdr(s>^3~n@=KaEBl2#|ZT6qGUnSE&MKD?kmFnzIOWqmp%fhp|?b6nhv)@cfd2%j9 zChNq`NjA0`?c1i+Y;? zoN>;RKTKCVQT_TI=h1(iq4rm_=1-fa=zaPthkt>cwbT@gpY0X5ZXZ0kM9c8zy85}F z8T(5UFLl|k@bufZb!*_$jDk-$dXDU#vE#H9Z|1(9$~a)~ zN_)=fWA{zv?%#D@TU)tnftu?o^JD+HUoV}dZ7y)GnSqyqAuwgFSHZ9Ht5Kp14D2i! z3^!yiF&vPN-1JI@;T|`W2?ImRgso2J?i#VNWH4ATFqtsC;mc%r(5v9UT*D}^fRRC= zMTSLe{}CZZDF!|TrZ4^S_WwS|^R3DH^X={I8b7}+E)8ryCMohV>=9(iXwU~4z|hlL z`%(FTzyihx48NLY{nX~2|38+&LjDrN0q0q|OeP1~n?Mfxej;k&{{R21|7nA4HrD&Q z_~8Mr7v;6$4CmTS7(U$VlVg;6aM`hejiEuh?)O{sn`w3>3qPFP`vJ7#VYZVLLxu9M zGulylP~$+NARO(`0NS<&Vlpr^=qflcLztlD31T1*!MF+B9I%rN7#J8fu(D*pWEdE3 zFo8k_#?N77gdK{&z`(Gr0pxm^+^BWnkQfb2a4;|om89}dexJ(bnEIz#k|1|`y85}S Ib4q9e0DV3oaR2}S literal 0 HcmV?d00001 diff --git a/assets/install/lockdead2.png b/assets/install/lockdead2.png new file mode 100644 index 0000000000000000000000000000000000000000..3f46c434aabbc47344a9e870766805d94505db73 GIT binary patch literal 49466 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}VqjoM-xwysz`(#+;1OBOz#w-BgclzqZ8JJlaTPi?-lAVH0QA(Oskc%7CuA-DQTcwPWk^(Dz{qpj1y>er{ z{GxPyLrY6beFGzXBO~3Slr-Jq%Dj@q3f;V7Wta&rsl~}fnFS@8`FRQ;6BCp2OG|8( zl%U2|FRSN}; z@XWlF{PJQ=kSn2jQe6^DQf-xt42(>44J>qxEJKV8txSxqOf0kwjI0a{AWD5xOA=EO zOA@gvHnlP|K~bEal9^UXP-#lCRa$;gZeoe8Qf6*qda8awUOLz|UtcTFyyB9?yyR3* z7h9!@+ycGK%oHoLB#UGVlcY3VgH#h!U6W*!RNbVcL{nWOQ`00fV@u0K^JFuaewX~@ zQcwy2>4#*7l>Fq(6f1bpStX{WCRv&#C+V6Sn5F1i8kiX9CK;Jq=%ytlnkA^Hih6WCP_?EoCu0O{j$6iXki9V z5DF#v3W(&7)1H*nqD-WaL$(F(1O+PEM=+j<%Z-o-pl>|sgDMnA7Sc!0T@bztBrx4T z(E~21t+3@IVpC#JYMNCFQh7sK$pEoGpVATrlyKl_$|@waqQob$GPS4}nh%{4)1j=K zOr*jHti~@fH`P|jKfj za`Mv^GV^p467y0Nic0gW6cjQl3yP9UaujrRVJSkvK;cotjO^6P^8BI{h1|^IWUIuS zoc!|m;?&~e%>2A~koECJsi5*ZRl)F4!%PKGpyVllgc6HNAT9$bf_f%DO(8iWKQlR1 zM$Sf`aaSDp^lT(X}Q;QYy z!C_hij!7K_a7cl4B2?~h2;F)+{C;T zJ#dK$&WVtur;j6Xf|Ve(2JIAVz(PSTZXhPO;Rt6qq_r2V6JlW7> zj~TfB*<;OU!XF@Vw8AD%M{M_9y=&1rYyZ~mk6NoXxsyjK4q@A^_urW^-t9f}>~rOs z74Ny8?o@nKwQ)k(?z{K1-xOH*EDv_Q@L?4=kUqRS zwdoDl0(*P=*~<)FVpeK&y)5~)_|MPmUft>5j3#@uAnw_{NoV`*+;9fl*=JjtV>G8- zsIlvR`sKAz^!n=?IeLZmsKAw7e_a~Ru-0no>!U(ZI$}&270!q-pMJW&RDiE&vZ-1_ z+jkXE1=~aVVVS#hNJ~c9L`|bF{2hX2B ze={dcq&4tSlGcKUxtyTZLPI_Kh1Xwy#mi1Ry_8{A_K{yR&p(Iz_rd+24~lk9;V;_H zYBu}qF0mVBySE;A5DL+#{PRKH_R0KwwRO?{HVrRJX6bCWn2|E;fht70e)a2J+VVCs ze4h?BYMtJ+YSl}5!=sNs{)jXz`SYc}zkeO87<<|#gz8nRwB>u&A1~*<_@Kva@yn83 zH*>!I{`;`t#@n*fPm7FZ+Nd`7sfrv=Xgs(ZoS+&0n@ROfswpsXjQ8AY)@28?>3c$gDLQi6?z`)><#T2|>y&NTd7#23ZvFNB z=bq)5RsYFR11CJIxlsupCV^Acf&Eiccizq0{psLxmuWG{Ml=6J72XkZw66<4`J;38 z*=5;{XP*~y^TbU8XPY0}ZRBHg#6BHl%>12SV*2%7-gbY^1@&uB{(H(fgBv(G+O_Fgyh?9ZBe z+Zn7P6JCFfV&H{)Cs1Vb%{Ac@Rj;2(3(EU5MeahONB7Y~!h99xkc9OAO6lFH{BnHl z7c){i+LT_tkezqw;_i0Wn+KS|*}36=aA@fDZKWT-{#d6d)papr%l-Ge%l^#vTkg-f zVCs#-(opB5n@Gv>wXeIfX40rFi?8Y}PQn4O<>e2;Ny z&GkD6Uqh40^6gVM&#~@5{d7}1ztE&uz4=>Bl?w8q0VLvTIM=WGhV_iiM@+tMo_Z?7 zq$~8w)fAg+^W^kDR6&wK{Z)|5USF~n`I$E9^wUp~miaO_(l)=e+VHbRuc7U_GN=q- z_?K-ov!wK;tqdR23&#`1_l_ogJi>5GZ~BKks41bLsk3)1e4V?nFu&ZL<()euNlwpw z6z4FX`9;cfZzPXPfy(NA+PiaR9TWH(A35#z+ilrG>6>o~TgM&|x|AYwuM3jq*4w2| z-*Z4E%ZTs28^}C|_ad%=)0Qsy9ND}-ZvE~}r=J#O#{F7;0t@KTchixuv#3<@OQY*yv;TL>=t6_t@5b$=m*V)wy|o%k|1C z48ajorMU9um2VFZe#(7R^78HeJw3JCZ`+zTY&)&GM-*({-U&Ir+it%Nx%(|eujHj{ z*S%>Qr>E|`nX`-O#nB|ihBk3%teK&rHc>_~Bf7^!I*?mhqn_fzs zQu$WAe*cf1mtUIPRJeFt_Q6qb{;Sw`uPybxrl!aBrR5ISL#_w6EHB@+;3N&r_Su+-CK#k=Jyq-WgMNb;Y_cZC@ca!%olT-Ot6O!b7KiSq=&rNJyWb z{$+LTySB{tp40DLzhL5fUFBHn*CS4kcifvCt5^GoF%DeqH$0c_b@Oyx(*MLh0$hq{ z@4l0_o#}<62Ul-$(eleLHy7R8^L)3QKFl-mat{5+lbydLcz%3Sw|~3uodCVn>#n_e z*g4yCn{C`KzMQ>r)rT0@yMR*RfzQ3iAEyKx6+VCLt2Q~s%|=L~CB^vU^JjYs6F&cp z>9pO$368|`;h|F*c7-2%To^QYo%VMHm9-&{y3g}2SbjNklj9-=sklyXN`3DAD%Z58 zqN^tQ#Inqim$Ij(etq5CvV42gy4O}apRiu|;01}B`3$@APi=aWCI9E=Ps`b7SuQjS zTtBxy)`GA7aPfSl9~YSS@I$PfKE?T6nRVus$5T^x#;xDY^g{hz{PD=7S!$C{_NQ|e zu06_Q_kGi;>OC1od{7Tf7InR7;w$9v+vZ=eTI$Z2veK8aYs1u19fB=q`XrfcznvT7 z`}%8@)m*#33;pgrcAZ>Up$bmO^VVldSx@@v6)4hubWwJY+3a3V$!j^sYI=`9UbV_? zaiIJ&J^lr+cbR2>FoJj@GEn65%MgaU+dXHVO^cnp>297c*Y%FC!qd0K>OGW&q#7f} z5_{Fumt}2Fyb1&J&1SFj<#@eI%;E59NK#H=dQmsaM=iE@C+mfn`m5z%D>}XRtRh%;)@z= z`?VY9`KYyZXdhiF%bmF~V$Jo}SF=p#`W=6~@rxuZ8D7rY(SB;vpWV)fpsg3Ru0 z?^#8-sZ&8E(3|q>=AogbxqOutGC6#l2Ld7KK>z0Zcb`8OZ;aqrFkk7uOi+FvLm#+y z1(iH&!d9M3SjI1P`{jGx z+FpDNS;kzT3XZ?M1~Yx^?Ck1zt@zsySJ;@j^oNTat+9L0wP5@0wG2`XbHE`VC((br z{qV!<3qC)7oD6Dy9oOzkvYMOK%XHu<#QZ}UCb!;ykNthu)Hk_f-lBD{*PSX^8^{0& zeFyz1;AR!mi=Q=dBCUZ{dseO5;>HN=y;LpKIsLWj?|Qz|PlFi#ibO4DDBy*-EkNXG z(#98A=6i1DY>}?xS{ul)qYdI7i(U8UmL2wAXv)QK9h?O&h@Y%0zr}0s9VoK;>Z;YI zUNzpSRt%6rr*`6-^5u6wY!-1foPU0|)@6v#TEHglJ8_%We|hj-IXV6OUZKxRO}Sv2 z0;fGq+k7!^N50x*&r4EELAl969PF;z!Yy|N`hxpy+i%VM z-b*IE?92=$(E8Ig(8PD~-2zaeyqmYxjqw2!ICWI1WSYywU(frYd1_P4`s=ZbUy?Qo zI51yu1*KMp{wHtSUhjfLM$yhIv!!8HOx&bXzB@L29l_~r4@8RyfCXFD?$FoNA~d#S8CAm_IE$!8OG-#xd40dC>Z zZM*O0nMg@4J-+(&uI%Cyf9vvt7+!#@qXqGk)_jI^A?5VjY-djSSdr7g@M9|2x;jZn z(pdBP@#DqovYoGN_Y{QtV}Fm^;=6g@v#+>&|x)c@=`$b$gM(FJNrg$gEEHzSUDSNl!doAz(KYnD)IwrvQK^yF+zd<5L zORV04^5)+R6C*GFFmU1Us$1yuQXScbcyK0vG52K3r;i^OJ}#(#!nozw9asceKmNF5 z_2Ugyx0h?2F4}yv)Jxi_v_f&rSoZB6C+>yON}|E6f-!fz(k`|R`2yzSkUKY#qV@&5bk zue;V|KRpi%zTlsBEvKIbz56-EbLHzQv)N~#e_ob(?D57(1_kg)^n&Hkkor=#d+W!$ zo1Z=HzQ~}U4i2Q{U5jS;Esy;zAjikPww-aobBGJCrx$1#A zwH&Kg8M!cAfb_eo)~;H0_~C`CY`Ze0oLLz5LL%?_sZDp@mVvY627X0`FVn!r#({fr zrEi^g+{}67%mG&nj%iQn7auEfrZ6m+5Anm@6r-O%e*7?P=mYg{1sT3f2Ai=DJR-Ai zHSd=kv&(E!48Op=REPVJR>>`g^zVaWGVQfC`cW46uUtXwpJZ2tn0qfSdhbubkRs;>B+5II`4_gxmV?EOn1FM@k12Mi#E?=6S--+y1sNSVU0ARHW0JjYUuUUDt4 zx3hb+8{}+o`F9|p$89k;;!Y2?nP&-N`YF&0R44^il>XhAOCHNExxK zAZL4Y?gB=b!Jgn6?_t4;Ri^|P9qPf^Ph!%lRg=sv_+FM!Vt4^*8afAo3k$9V;@z!g z7Z@(cgNx_3B^q5%i*9b^f0(ve^YkSRMhAbW0gE)2UCzA3R%Ih6t;+BMQo%4AgDcT3 zjcg77z=MAV2H>E{X69x13r_0^30;dK)`s13U_QT#wboDy+O}xa>`F45UAndL-uv&j z96qno-ml}m@Oklag*^Sz*yFkxR&)K-CSS}*af9TTgo;mQ7fNHLmEt@jr)_-p{PWME zojvu(xWb?PuW$`KqH{##P1)|l^0(ibEjui%e*%(P5O%7b(I-MsG~KMJ0<{#R)s z6Sn$liqXb%@|iYr$2a`1_##>?xcPA4`~yW^f3?bFww3Db5n8|T%IjTrGJN&+ z88`E`f7F%ya#$_NZ1&$@2fKGX1dS^~E1riZZ#&5Iu~!PLU#N3B<@8zb=w;6(<{r1j zXVWg19?qO~Y%;X`OqlS=?84=jR|GyXxh=j}w)=1R_8;ryj_`lTmfgi5gj88axL2&w z(r*fDsm=#g2LIin8}1Wq5F()fRmxdM9f;MFEu!Whg}ae_^M4_m-FKD=ga4E_DqU6v-zeDr}J$$nR&bK1Vm0dnYP?e z-1qX1lMYbTy`akVx+wqJ>)EoL6{;KOO+TF)ezpGh9o4u6nn%`NDV-ZK_xM@&`?-)- z*ntL7*NriHyB{t5Tc;%g?p;f@)< z87rNSbX(rysoH)!^GM;|J-vnQe{^|dwk9N4l{j0H%nPPvq6O!Db<9L64{J2n@ zQ9sjYX35om_3s50oA)`)d%xY_EsWwPB}S1UK;4#+&+8$**zyJIJ z)j||HzV^B_G}P!te6QPLo8#LTYsNqd z&u))h1uU@^6}j%K%lE(cd=d3SkuAk+_S3mOVXLR|2OVGq2jiZOiy2ei9NTs`uho6e zhD92Ec^*GXb&qJLUbrtSyX$Y=`k!nt^EALU%TsrGdHK>U zXlqpFKE`rz;5;bxQJcJu|6+Yzot_xCpwN2Vu!_qj%da>d&wjP5%=HL|&+^NAejcmZ zt9Sa+t0qVjr$Tn|MU9(Xx!Z5|9#39;B-?r~pVhjKWtsPEn)|8`U3@0J&7d_KT$onK z=8E^N>%UZAQ)A+rJf)(Yd*Qm*!LJs4|NYlG{X%M_-t^NcHIJ4p{K*yrt|t$8&-77i zKfF-eFG_E^o!5EmjPELU^0vDhzt|C%w)v)XoVcM&;Umw_z30!LznYc$IcNuXoVH>5 zB5w9Aw|IU{u>w_^SF=Q?ANxJ!*S52pKD((JmdwgO@D&n%Q?{+zxSHF&CRUv9-m4;u zjeJ&my=T*e_3I|{{K_!-|M8>YTtCzM4X?p@zrr*$R5jKjZ1vQD&hHnUXZ6!g=w<47>UDH8p=;o9w>(j@4`7<2Hl2ev{jS?nm2KTd{5j zH;W#yf=5KcPhAtU{MBLmex+}6`R==&k|itXf2@*pJ8%0dnaXI_z$>M-kG8eM&zFwS5i5-3eR0w^=5g+ox>K3QPRA{~ z&+!E`%=tjHu02PRtKt2rO))xRu?H_7KkgoT-L13y-~aZ@-p&8-&Drq$|6{@F^|Lq3 zuPEDnS1<1U|78!r%O;xtU)`8F3pC*-6Ba0RfcZ-4+#~*{pI*wHY#u%>^^g9MPSZp7 zNiXXD^}Elxm|_&UHmv>d!!MU7+8zE2N|SA?{(g8$Y4hp5q~N<7H*l9i@_c4ZA@l6;J4&O<&6M zFK??|c#!dj(d@Ik7OnVE1!|T3`+5Fc%k8({)&#xSX8t8>YnFZI*C{Gib&oPkR=wV} zw#x4BkK1QOSFf66cQ_W5$l88IC;d6~<#m2=_tB(|*;knFoUE|%v+I=q9`xNOL)0}e z^lH{ttL-AYc#F$--whY~JHuo9+Pm}4rY-+o^{?*0>8C-zjVc%zO&AU+)Z5STTOP}5 zcl+%%^;3-d?i+`%4h`D#vRU~<>}}CsO+hc#zqS4T`)|?CJ;A;ud!qNG?`C(4xs_ge z`^P;Sm4D%<4y#x2fDHN&68g3LGcTiw!}MjDlk{Xh|BT^Oskt5|c6{l^`|tmku3SIs z1t|1i3;iz+`cwE(acZjMd*S!nV)V}6HT_s^C)d8@Et?G}UnV3x`o8_gUhSV}wd&Re zU1a`nx5DPz9lmo{%bs-nf9)~r#+(^0$E}aFZi~>FwQQ!3TH(>D^_j}g)YnTwr_RyF-oD++Ft`9t7oL=HHX%z|E~2%wm)J8r6tMr|NlImB`@`UbA*nF z-Qi$xx=68+JH9^U-Va=c#49x!LA)~Zi_FLSjDctUYPn- zvGd=L9~s-Nt`snX8_xzjAFD(DI8D9sE;E6v;EUU=n!YCmkfy(QOk`;2*|g0&_RR|t z{u}z~j)`x~(SPL}zd%)z0nbP7t9jdl|M3*`zATw#b8`0Cv_;xGd}6F~h3;N+IsSiU zO-;=m)1H5?KFQb{*5&;vxvmfH)g(yFS{C?^r(o&Fiaqz=@BXyrZCSRq(~h9oF2}cu z{eQhFM(^>aU5P@npd@qqZP@CmcO=_DYn==j-0jWmX8QC99njo<`DxKilL@)Aj%gh9 z-QxKr!zAnUqVUyM%Xa5#FTU;Z>vZ^zKVS9ZZ;2oO|LVy6-v8pW&Oa}W?LVHp)0n4& zL5d-P;nSqOKWfkTSv&j}t=Ig2{d@l1_Y$vm{rmC5W1CWmd#iQqzueR>DMp#I(!d?s zqe&ZM^uq7!{O?$QoO{{j%$Nf}=N^4%<(qTT}3rg%&Yr)+|(bqD3 z?0dZ$-S17@*ERS0>#xer&)2C`?Z2-t*1bb`p0xArE&&EP(7^PCY}Y`Q)G9l5KAUH5 zA=93w7)9!c@#~e@1xh>559OU(ZvLr)pCJ#_&AX7D8mT6DvS{a(dgdLI*WanMn}57l zW2N{ze;(V}XZ`ARrq}FK*(aBu%4<`xF?Ro96$V>SRrg}+$BH{!gQu}wI577}uWFuM zVf#zx`Mt%ni*n3npG+w_wYShj>Sou6m!~$Zd0n+LChuQ_j+kNXulWq%@ok6os@4L> zu0P)0#<63eS=GF=Y0VmyeqIZgUw(N}z}T;BW5kWF51rj>SFO65^)-2^EMNPNN36Ab z8DFR~nlL!5uebEKQ`~p|edu#WbCK;+c09jhQ}yqU@;&2sQM>QvZN9nYf5cz4eRAvq z`q|p+_4W4k+1t%N+n09Xq_bVL;Jx4aJ0$)@@WckooPKb`tBj$_kAaur!t49z#k*ZU zo!*(kvg7LAG^3e+V!NvfAJtgMeEa=3ZF8jF^vyTdWX=LlHT?AbIDLKoQSIZ83uCW; zOn-Was_JKTK`)lXtZ_9Sa=D;>n1aw zu+I>R@1Iz>eDCp9-HoV50%Pzl6F_P?cE8nZXwXjm=^UI^R+*fC;UUh1_QbO5_mV|l3S-ZFD%$C@ zO(|#Av9sT{6^qx`&)xCCCYQB>5$s#3Uboo&i|T7?u9W6>Ja~31rFdh+7U`$8=Of}@ znjC-pv1q5w_Q%D0>NejzleU>%#CratBV6zP*3I8i)VDcf*0Hdb{yj(hUhe;>s^|Qe z-yj2GX8-Zn{fmxYuho*tTetS?owsH8na}RHbM5ul6r;+SJXY`IR$qPfWt(*F{NAHU zfuW)Ns}J2au(h1KZE8W$jl~x;cHfPg7GHcY)NJ-yKmEP^ANx6t@)!<-T4FEOpG>(V z>TrDhyE?`8+gaL)yKgbRFWX&Xy?fz`RjXF-{ImYz+p^tr&!#>8xa0hDx$lQEX6xj|=x1-YVNI zTcVm1D6)L{`T6tb8%k}ynWOR6{n3?4KA$tRAJ%9ek}%nRN4o1^&(f(pKkiq{NtiS| z1hsy?gxuy@uv#g9_gydN2iwB$)Y#cewdhVi%~<iDSM%H zGW>bjCQ?tIo{vBIro`%Py_ned_A>3GSF^Up=*?cXa#hyeIC7Zl@8l=<_i_N@PwfEa?i#q|A zP1N&FO&7oP?O=F)^ZEZje*E~cadT3*i}n2T?YHCiy?u07R7w8rp~4bvr|A9ns^9IJ zma)d?w*wQzwEg>g)vL3PZol&A;Myl|#s8f%6z_JOuYX|II{x;<`_FB;|9<)9mlx*e zfEvaw=j^S8imhg!&2jyq6B??@&p&IKp$h{uIHFf>(%Eh2ea~#s)aC6{mfK8bx&pBoV2+6bJw@LEwjG!>BB$&m`&U-F1{*d_~iqN+Thg4 zJhR!2VhM*Do|LYSz5XC;>#OvQA2Lj=w*RTze*0?aU!(0)PNrN6^{6h zg{3>b|2VDZW~#U1hqiv?F1zo{kO=tq&+pz>$D;Wx?b4^p*LmMk{l1x_%0_O!=(7D0 zzwY>Dgo_sUoVjSL@_8*sE<^R_{V&D3U3n^Qud#W*H}44}8)&%y!u|Nullhh9&jvII zhlZ9q9)EK09jnz$A3y#DkB`JJ{(P)|cKY?>?uRb+_xHFhe$o%lm2X$=oSJg^#QynH zUeq%g1c1|m*6B^FJN%iLwilJ$->D+|`uWs~DhAo(|0mU!-jI$z2D)-e%_z&Ks$>j`obzHZ>yweGbr^9zfQ(|x{t zV);46k1sT|w3cD%`Mcq56<`{aU|n%}EO$%z_G`{MrnI6gVN zVLGU9_+sV9iaS%gk6zz;DCI@hq7GNPpNm(mT7IOmkmvHtE!ych);UiiQ>25wYaRAI z_u_in34O^W$GTo|E%1NyMBubh*Ea2Z&kD_4B{)zEQWSZZGRJn*-K{$Io0p z_Wb$ti)VQ(Kj!Ze-p+8fi8)~hs7+yOI@4#}PY%m3VSys0vHxFe{QdLi&YL-MG6ucJ zA1}H3K74ko#e<_s6H_K`zPUy{^2tTsFaP$<+>;WTdC&R(k+sT?Q$5Y3wB6;ZCX3FF zi7``Tso({N~u5SMP`KzzKnkcI{>A20uuP;k}iE1C$o~%=}`|h_V zlWfcz>aL2Ih6P?<+$u5Wz47e*o|{-x_nfb>3umd_E8M-{?@@M0GM$$-Ynis|t+!?0 z_9yL_)ULfee0kjZxAwP7r^@oRzdxCCZ-OG9wcZW8p4_^i`tHe9Cj<1KW$(Tl7r${{ zPTCE-ih#-0lTUgz{nMX)_E>xkG&3%)$v0s%X^y+?=_D0je`8)<<(sd{Z@ZkmHk~+r zJx~2`b&_-Q`W^pOvnxI`{Q7e0>BS5YZAHlg|4QN|zt}#^xVdlHZH8vG1~vwXd-_jq zzYSwJTX4NB$m`FEGOmCD~RRqs=Y}J_duha3;I8; z@YeQed!4}`d-@+^?t;&H=Jrw!^)r3ce*fKf-Zty;9>2`xx35j!_uRPat zoG(>{M@vQ5=5N2fk|Ua-B{^occ(Z}LeM zy+sj+ci+`ZGidwUDt(jzycWd4zn)**;d5K|?`-G&)yw@p{);_p^6190%bDR0Gs{`} zzSrcLw+S=9Se6-AJyZ2@LFD##DF?T>UhvnitDpJX`Alq2S!igX=Fi!D4@|*r-e2B3 z7-ogX-uA4XnZkeI_Nj7(Gl!4d%$b(5`|`^#ork5%+m=Kg(Nw*+UQx3B598sZug%)7 zhJClVgQYKf0@WIOFZuO<(FSF7;3M#nA~st@Z#&#?HlXzn!8mhYFAGa z3=LHkeK%e8=-b?%bGMhVKqeu7c`%&iUjKGk=B`5rFaJ)6QO*~r@%mUAd;O&55z$|3 zem&Y__4}0F3Fb*}L?s^=e|!@XI+bU=-vtKnY^#I()4y)47kHxP-Lq3r^bNWtEX~sI zws;56Z{Ov<;w1F1DEGY zOj>vSwe{N1*<}iUb~$}^Q~GZGic;WwS7fdNtG(D7Yu)hzbW8g zSPyQgxHDzM-RR6!dN*alvzs3;%5v*dCU5&@X+?$_(0J5~#Wo(d-j*?Cv}uRsuX(tb^W|KlJJF^Q=YK!3S$h2F zMdx3FNA;$kp1x;tkK5vPtYt~vQ)A*-?utcbA7NyO2bY6WbFQd0q+Lk*y6*bxV4+Jt zYwAAdvHkRq*PFil|B+RzCaL`W7=7vK&0p)wCry8IXkw0N#pJWPx5ea7T5R{e9xKHV z1upiyZe5voPnDtS#g{o>yfRS@4wF%J>jP|d0lz-d{Ns? zvIUoZ?>Ie`cjE7zyC&JGZ2$GcV|UxFRrb#Z|>}MoRpVcGo}WMHkQA649A|ca@s$G2LZ$^?gEz zwVT<%y;uKUx5Z2RJ|Enh`f%GMy}kBKca~-5{V4wY)>c0wPdGo~dTEi~?YG|&=Z9Mq zmLK2US1|wm9P@fPfzv-S9?7!{E9*3~J(vse*~v+_&Uh?3SfHx;uzzXYZ8^cp-!IRm z6+2eu%<&E?`u*`^VOac2ZTGKJBL3I89;}@Zvg7!k``ey>y?C78D1+e#Xo=;8=#$G| zp1-TbTeV}4|C_Ly+Z87Fv^cxNS6^kF9vU4ww?w4VxYlQO_maYzOPY_SZc{pQyZip) z>VKWQXCJ4n%NJq*FR{K5?CDhgc~d~ehKRkOK~08VP1__oD^@>gW)=UQF42G7Q@ic( z!w)lx5ss<=^{QV#O~qo{r5hi1z=&ndkm_bat)!RMcQ?-%d>vGes;t4M~A zYsIrmnHZJ}J1{eR35iy^H8o?+^=w9y=CJEuH5tF;N}p5l)mrDX>-gisNgv*Q|6QFg zGi&?ydwJU{r@ouJs#*TcMBWAe;}|^IbQ@ryyh@|%XU)7Lo||~s)~;G5Tz+Qv8q?3~ zXDxflrSbjuUsK+u&)nY_WhFkn6aKh%*Sg8Q^6NDjynXWV6WaxTZHGSVVxHtPM<4cEEQyFR{Ca9W zBY0tb!#}TISM44=eo_$b8mRJh)priJ$y_(1bKlJTqOdPle`5Ukb*nkQhFAAi_+DD_ z=$D&{&=0*PI-BGy9;L*Je~dQ z?jD<;^OFVNt~GkM&Q9WcUEY)}CO_kxBm9KYy*%R~3icddwrwXmH zU&d$xEqd#pvd+HzG9*{FdD<7B9q!UEmMlNJ_Lk58$;a-L-+l4^OP_5aL*?hmSF=oa zhi$~~cdgs4RiA%D=5b`SpxWEz|L<)! z>HqgQ`f%00(vman5tn%xz$*tY#Gjm(`B1HT*+F4d-?Y4YY*z1oY`pz8@9HAOx&XQN z>%vx7Z)wh$we0nqe|!rbGdwc*G*6xRm63e=uPLjF86Jp$?bhm2(tN%9t{ z{roOcmceEssP5SRDdFk$08X|i8M5zqr8SRSo$_bRk88Zfrxs6qarXD~7=iWA>zBxW zaQyO9vj6zW)dz>p3sPy9W9!zkJy~jK4Yhp=Ut#ZLGG#s`b9T)`($4Jd^z^*vzB>ox_diMY1Z{}^|>ZV z5!YUq{^L=IyKp`|Huw4KlnJ@^91OJz4QvcAwyK!^{_`i~&hZOVQ)iYp?g+KNuk!NW zj~_eSC+5fOsmy;Qy=>R@E9J*`K96?XW_raoCuO4i&#AW23=Pqs&aDV|+FHSoJub6>OPt+?%9Kg|+hbdU$P zdfsljw$4B#{jIY^*y^jP*>;)B>-PV(IsUkCljuWUX_uJD`?aTZj{H88w)tPm1>egm zXQOTAGdKJLw_2hCMLeh8H?7{}=s#yG|HIUUxw~)2UH9L)Z0i@z>-j>H?yc%R_jUKw zd6#&s?!9`p+cZw?oJPL%qCb)hzaWE#KbQY_FFxns;W=CR6Zd>-sykcR`o3)U-uumS zPNqyM*?uF(?E3!~(MMmq&vxAY`2QEH7mLrD-%84TdY%C?T)xlymGk%Cd$sJ_^fF8S zWpAr+y!t`d-g839Ma!j*pF7jHN9gQ2_wGxN^*wbywU?5gO3!@$`6se}-=mnc&5`#u zTKV0aYzbLD;&5Me_VT0GK^v8lE}XmDUSKzWe)OGL|2w*Wd(Ho`c=D$wvya@bJXU+{ z=2rLF$9KP-o4zx~&hAO>ckeT=pML*c8+-lKe8vU#pk_tw^f$?6hvhbX(5ak1bM}*? zKhx%QAAPj0GWFhu9|aaMKP5CZ756Kw?=SDRFEVNFEAQ*9c%p9Lr+Fdoe0X{d!wXSR z2?bh6bo*^y1TR-H(sPRwcFgpIPwO{kZmHiFf90hP8(7?%^JL9K4knUVtVh9q!-FYBzkb zHsbKcN&Y+w_}dTf3|;5h`@we`qs>#6$u{3lnJIYw{lS|2wf4fJ8U8DM`XArV+kW|_ z$-fh4lV4Pv4~}X&!Y%hfff3qxeE-S!Oxf2^t9l>!@WjrpMI9IWUd}lGeD&3=zwUod7ww#LHqG~PNa)pP z7mvNV)95>IQ_TJA7WqMig`cXYUCa>iR=scgzG>=Y^BMaV#DC-ecsx0`y!YPv@+B5$ zwUb|bbBfjxTW*q;IXk18j~%jZOrl}cs(Eqye?GhAl4CYI*KGET?(_Eh+!GX^CGEez z{`%{RNS~P!zjT(rcdl>@lfL}%i@U{JvntO?yYJ@dTTI$ku}8b1?`lPDY{Bn}2Vd0g zzFl!_>ZLf2<@S>@?L!5$6E{Y@Dcc<^=W!%E$A*K!7S!;SXjsym8_k>5@otqy*RFNu zv(LWV%Tc!bZqmjXK5Dm^=Dhe)%aJU0?ryd5`$>N`Ji7VA@nqYg!j{c9-`sgF_ET-? z>Z`B9?ixH2dU5N7;mnoaCY~v=>ecMf{C9EFv(^2+zYjLO=dbYlBX}vD;e|bDq7bt3 zEdTe(T0i+eo1+B&c-$B3Zq0fjeEjE^T8{I&Z+vInI3i>FM$s|aYmP|OagI5&+w4C* z6VR^Q8Z~zwU%maLZ=V?pR}}W;KAsi!r@F>)pQygY>$$hjNh7Qfah+Jwzc+NEa=rHH zBD?wXZ%8fDR=b_Iee=yXVb+`Xeo*qSl8nE6YscH#i8+sdp3wRV8fg*V{`AK4ZQJ`w zuZGT$S#C4eFMs!|N5_vQ*{zm6ZhJ&^XN=z0TDAs9P*KI>09wTVsP1>qMb-RU)nRel z;?}?3Wft7I#P8>3_c^idqZKw`Tz^-uTIHv+)^>Gaaa{D? zn>liSLKOUrGndII7ldWa*}i>WaC=vo|2c`P7Pq*qiei3NHtkv$>&RfB0IFXTE4t8)Jb-!N3TEL73SBB zU%K(qyI&bvbycCEhTGC}rCv7DiWgl;_ zF|>i!AR6%S-^=PrxxK6G%=h1av$jU*P5*fQY+7;NuWQqsPG6~8@%q;hhF@RW^*j?x zqx1g!$X4gmoaP$@8n5=ZT=nNlQlZ_OE4L)9*o?!zuB~!Dt|`OUZgKEt&aw}Z3~k`~ zQl854rsXXe>uqm&p3RYdyR|byJ5K(;cW37AzkmLDvE-NO632pXIUE-;@hyHd ztN-EKS5IZ%8_zyFujs9cZ|ND$7VtUWm zGt-}cQ-0mD*I%tH4+c;AxN23^jhV}9RfLa=6^oRweOo5YE_wX(&;7S9{}Iyf=+;ZC z-xzUZ;&D;Ie5ES3260dYFVVILwA3)1VekF-?|0q4v3up~UD}RzQnlM$7i_+nv;Fqm zIL2Lf^VBDI?$C8hu$wP0yZ!R)kUyW7`|NmK=yaxt=l5p6ZJD#4IJ)X|F78*I)Tdf| zWA>Nd&zT)}Bv-HVgX8-rG#lC_ib^*)Tzc4VAgNDu}dO({cjyBj8+6Q>9D-V0#E?*oD zUM;ayyY zci-GMX^F`ysQ-7l@9`A5wWX_9-O4d@-|h3}`|n-r z?icvoe)}~~)Iq&ByJ}PL{fkO3EL!D{&n(yKFTXs29kM+2z=SEOGne=+FF*S9k>kFr zY5k8sT0DC_g{R7B=ALM_xzoSTlXlRbetO;ZSLanHmpA22KluInbJs^@3M`QJmVpX* zpWM0ypp|~rdrm6Yt8J3$Kfe0vs|>cick@=Ss@iU2_|mL6k6|v)r?qnGG5YK7tUIP3 zzx4b4^X8e8W%aN1vO`)+2M$~*y(?;S^m_di&!R?mvs{T@x0C08$!+U9{&@SW);-#; zvt{QS33}T8UMscgj@M>obRvHlA?)89c4(-o@XibXD`UZ~p!C`l0)88Kry%S^dwR9ME88o*drx z>Ti{BX{`OG^PYPiUgY`p`0?Yr^YotNPW0Dt^$)r$_wM%0ntcmnncp%VZ}Oby^i?aA z9X#m9<8$xww`X5>zF)a&)jF9Eet&u076%4h{`Gb7{VeB063w(5Ka@&;u6gaNoavgGgU-KO08+V`A4IhSeQkA;=&ZR>eC@287> zns;J3k89+#-FNdGBHyMMoh*;P^KT+gw>1O91#M8F|8S;{+DW^X(pc$5+N!mF?`~~h zxN23+^SwV_uD<%p*XqwR#xI>;PaB5CR_588ztuVYX-ci;D4>5(yQbe%-m5 zvyA!8)Jbz+znk^(=#i_XcTIQ3Z+to1r|=TT(ydWz`}&+?bUYdEo-g{e_`Kpeo~Miq za-em11~w=6WqB#&F9MGunB3YI&s%gmNtHhiv~JJj(TVaW*~cGd?C#t%x7>br=$34S z{392yivO;)+QPu#44Uzfn72q{693EjJ1nJlrp(`7%|3m(Nn*s>u=RguD84VPs}g>` zB>rsO{`YUE3bBJ04rLt?)bC4u{7@LOPQAhL)Z@U=3D>=~(&aB$|9H{XQpmHBEpEq6 zr+-tP9#OEnr?NAsYE&nuA7s{AQ_0GGUQEfEy zP1$ahf;)NJ|GrTu6gJ%BDg91(_rxQ!kNBvr4f!SGaQxtLsT0yo`xDa(7!nFV^?0+1 zRPUscqKy$9i`Gqf?_6=}TX}fa>hj5IC)VFBQaty1%CGx>5*_ZHuHJm}OU;*CrW5Sj zGuRcymK?KYaIgo}A#5vkPG8NsD(dmoKJxW`o82`&i{EaOESY2@$JZX7dt_qBg8zG8 zr(KUZazbV96!wj=>2sVwbLHD!>)iVCvo-r6W5YtwP!Lbhz37Df_qms>o4$qr-;W;^ zKKt*^IKGFWY;WBDCo#u8OHF6~tlnC_^-14pl}f+Q4MyLhW8WA`bstqa_vLf_(OVtA z8*ZgDEI1GHlXK|x(oNoRHP;1VHBUOoUuOF?-~Qp_5-Zwm-{f5d ze?Bjlv3TkJvC8$r+Y|HU9FBARxz(y%+44Yp^D#iTJ zjCbuzAMzVW^-fCsAIfv?zFHj zBz9wd&ENMIKG%IxdU5!n0Q+aAewj}zY&#$PkNe=MS{i;kgMlFr+>}YUpQ=Fgu$`>dK~-@l7xYWG&XepQk3TZ92J$|kXG4`dI@uc}J%zN1MW zH#qjmi`eT~&Ujj6`DLH>$&C7%nj@3^xGvS39P+F3l;>-oo;j13;X*p7^hwkPZIx27 zm1MbaUAq6c=iS1Z*AvgmJW5yPd~-inqfK?adH#95n_{2buhz$2_iUDuy~M~M=fJ?r z@PXxM{hcRkCr!F>H*fhFB{W{W8ygM4mi&#FFpJN@r=w^48NEPdwiJ zahAnyi{mMJw=SRmo^vP14CGICQ1Z0#1I>4?zyA7fUA=`&+3veVJLmYQg{NKkxhyv~ z?fW+7xX`QpVycE}hOE!iE-b#Nky$GA{-)S-yJveIv8(24JW62OC7Q@nB_K~+fRCQ{yeyKEb+@ZPGDDz-hH!%yxpO9 zQa10~W3gS=tUl$MJ^X_lEWSki)7;j&`dEXw6UkCT$tKZ?Sv%>#C>^r8Cc@ZC-y`<)7;P zt_|y6R~%l)Zft*#m!ScC0>GWv+m03c?>}dqef>|z65cNYn@>dZ{?0M;HhXQo-SXr` zzYF|*rjtGS58vwA@YZi~`OSYDd-|_69DluAZx{RY)y$Bg(*w1#zPkBB4&k9ww>0KO zKiW5Y3G?BjXFc5(U(DL-m2}_z*xy2flfk`r^UN2l<+$DGJL&I!_17=LS~lNYqrI?i z{r=~{k_-*UL50kn!078cZ@>LFb=N-MVxePub9djCm|XKj|8`rR(M*}z+s9S*8!rF+ z(-xI) zY!kkp-@ETn)q>{vDYL}+z5h&HviW#;@cZLD6_=ju%5^sEs9e8FYroGfKNUawm5lyr z|L00CW@fMfooe#{w92w-uivCoX3EhzV%O6Xb9o`Vg!W&3@SM3Qb#m9@-Gav&=HE{E z^~iLZ%*nd_@Bi=Fe%|lXI<@-g_Vs^nE-7@MmvOsM09t;OPki6-eedSCYoi!JgSMZ3 zw&gDH?^IiV@@fCH@b}+;uetGs40Z_&JwwRKmb@~tILKT2mfJG+_jNyHnEuLrF3ZqR463&B@+7i4>+ami$zo}nZyx>m=HiDh&(2HKg-%Odvvl@$$;t+^BmQ=(0>%|vLVmtrYh!-v z!^H3byz||>%uA{4^Ov9Vg>N}LpSncfjP>(RoA>oalj9Cl{_bc`y>N2RajQ4a_sqX! z`}oLdmAK+C!7tVCPI5AQ&;eym>D8;W^m}^W-_sQKkrJ-2tMgla*?eZx9*rMutcP+h z&0W4C_y6SGYV$VE*;VwR?B4Hdt;&7N*S+53eyVPN|MfXVPtrvl_a|CQF+fIT?*xHX z3LCxGDo9#W*0_YXB>L@dwbuEMKU(Pf>`QDc=&7`O9KZ1S-&YHgqb8@z)n+rxvK!Cz z`SfMyUG)!No=PQGKT>WlOLi;QVrXaw4Y1w`x@_Y4<>$|zJ7e_TPiGQ$6?{KG#NP}t5)@uorzd~J^ks|T+h;dZ=YY! z$N-g_9w0Bzw%nzCH*fpya_4)?GAETCD2?6!M`zAGhF@W# z%-*-R=KF1ngTlKFYo;EFljqtV{YrN2fn4tg?*-Y9?{}l{;rYGfIKP#(`<@wf zR>rIiJ84?6|J!Q@$bQf}Zj=6OJNbBLEURAdwA4u-k8Y3K_s5v+=aeuW^Bm^8S=$d; z->Tjf%V~ao!Q{<-^M5p`%e%9u8_hiO$vSG`o~X6!cKReG>^6EaW7e|F9D5Fi4+$V| zOJ{tS^O>~uZ(aTVz3lr>b8qBtKYTj80W{Yc_2Bo`#(z?ODpoJHx2=1Wwz;!&$HS@< z@-{Z*@`o(8Ez9iNrjZ$KA1{Bl-)-^D95H)6wMU=(Bfc407@E$?XJD`aEth!^^_DHe z^UaS3=QevXRUh84b$fB)7Qqkq!&YBio3{L|ON|%PzWeX_ zvFSe|J-5E(J$y~BE7*E98zxS9$ekara zpZ+W|?IlUpQ!Eb6?m2wF{bJEv!9-W9htZ1>%~{rADAh?VW`U4JHR z^U0J&Q6IicJo84y|yk= zN&Qi%!aw_qSrur;>yn?2Yk#=iGDltphJN)1wubU6Wt=a(j_-?FX6CEhc5drg^G{Oe zk0yP5kh1oz%bb?Ag=f}VDR0c!?Ps%ZUWwYw^Ut@>UG_)o_iu)>-LW!bi8r z`Sa)dUcOWMpDSe!MDp&qYRAm5#|9Kwa~Em&z8_M-hR@Z+0wQ6HT$KAu^ZYwI zbDtGgo%>hnvC-xI#qW{~4RL}F%m;33o-W!MGcRuGkB=V>=b!)j=*R68qm#4qbIfL^ zKi%_lTFLrbt&1~fEjf9t#L9P<%Ki75j(gH|K&vCdG7F@gx9?r(zvtH^UWwc4p4+W< zZ#!MglO_`<^Q6;%bDhljtgXBDy)|V3ZzFBk9t=7V!9v^k*8A_impi)lc^}%hzU$WW zwmp+is$_nyJ#4Ybp4+-|lTh}KRjc;6{Ho*Ux#jinYF24p*zLSPiFyOQ0~PHNr6<=s zmGwy48E5(Ug*CQ=8_T zO-uiplPg`=(fjYGzk93A!TWjJLql!vp|tvhmU_8!Hv#x<`85N98}BsyJWqyyCybt-E>R_Fo>|*%_Pv`l}UN z{6k}g1E90S4$Rg%y(x3n*Q&ku-}AR0)_i#>Z+mssid*cDKmN%0-21ZRR{I9Kmxlz! zx{sc=3C!rOpDg)PD_5@9%~QOOJ?H!lvw%L)O*eD&Ud;QW+>`hD#g4AWcf(eP{@MK6 zsV_KtcEukpzLmPgeYX$Q*!6GUwduys<7v%>`#vh$9AshuA1qf9A79${_~Vb&S2jM+ zRh_5jXaBP3LSN9H2a(nM|0a|_tZ=yT>xA*y+1B-IZ*McOnYnL=fL!s{qowAv&z`$G z=ff<8iv9QV|KF$){x9kL{jcMdwSDUM*7nYO?BjZ#0kVGK&-DxwFRLft5|j5n*8-iD zwx`l*eUDsX>La>pCZ1=epMJ{yr1|HwYC}!? zZDKvFb4&s=)ju9QE`Rw8lVM48ifpkU^S|$MoeT_nK&#?E*mr?;{d?BFI9w(2r68rx z?EZ_y?nxH&_Het`zuKxltz4=z|L+TvOM0JDwB#dM{{CHYOQLG`-ME|5zdr8VoF@&b zYCc@+x^kQEbcRXP+OW#$ozq{+*8B=u`P!__vi_*W$DcL- zzH>f1`lesM>7QMEVb0~3Tka}sInR1A_uZb`Z})l4`#YD3;lO>C3k-X@&4T~!dma~i z-S_gDe>2WM@6LY&>UQi=h!b0%Z}0ujZeq!tmnlX!-+%Y~@MZDJcc;5eCttbICb2HU z;IGVNoB6W8j!l~Wb!Xmor8m)nU%nsio-g-({tm&lVXGrz-+pVb?VR^GVcYH8J6ey$ zRy~nq0G+SWARaDqG{YpTc+S(Joi}sJcHezi@Z-m0R8i}df|WJiQrpLi!3i( zot>{t_fScWAjnj z1-Z^&p5=aI1RodEa6M4OH8iyQs8WBzyDuldye+eyfBrVt!ReBh_Uv?&j@efxSTZMe zPV&8)WP!IEKCis<{yX#ALxRt@#;w=aOFZ}6eY?MS)$Loqk9Tg7|Lw7jzxU#dzsLXd zZ@d5ZzV7?|yY6w%Wn|bfk3p&-{6d(myvqiZQFG3pDRq4Qm5{o+x_t$LUoJ9z*k)6vv3zp*!;VO~M>cA) zNso+rtPfvY{XS#$OvbI&{mpNNF%u_quf-Rnojzo9FnYZh!pRFyG5O zyA-O7W~v-aos%3Ix_;+-Jf&*IWt%8=TA2j&n2G;{8XZH?!}Q)Pis=xzARBZ zw|%u-%?{Uh3=BMT8Kf*8f3K0hvNS(?6KEGq>GE8*{1tas7wj-Bxy@er!gs>?(vs?3 zjHPKmcBM?JJMKK^xWxbHt0m9JHU1+urW=`wvfB$N)af!eU+T&$P`q zi+0B7h+TeZQukck`SX`l%b7l(&aL%K`1SE)A$YG#-uB!7HvUZh>;A{PMs=U)`p)os zS`YGWJ8$>3WHWzIX=C1z^G?Um{qs+onZF`zns3a0*S;tDQ^2pt`kjg4uVi_-tl_%Bw+ajL` z$g4d0Y_UdHwZBZn(%h%N`q0H`_iN?m+c@9P+rIwRYFWtGnS0&dcpb6&|7Ozho$NAh;c+UUyqDS1>y)kt# zN+tRGpuq=FYgOU0iSPCGkL2a$^>2QiIxqY3a~s89aqD(O=-iqnZXUBbSHf1R_tmbx z@AvbzPtR@q@$;u-y_sLS#>xP>{JlPcCD)s`zc1f!arxoBzez9E_GXvuzN;{=`$@FR zw&IfhoB7tM-#^dtO)C@l>&yV2Wm5QUYjgizZoyqA$z7MT=iA%aO*{RR`Bu!4-}R~& zbA7+C8kWR(edKHISoqlDbM>JM-a7tk8fCv^KI@fg`=p@wUUk#$w|aVk_EG=u-Trp} zf){_V(>{{vDoY%D2gcO@E>n8mg-JTR~3ch>z;|MUS#}{Sdju z>-V``V53J8&u=relYA|O?JplPGBbQoW4Yk4+-70M;bn}a+^H|z76-;n`w{x{$DMB+ zsgZtalb;qzPCvhs_2Nf&x!@hOy(&+nssz7iz7>yqyi9!ggem;>H8o%CQ~a+z{Cag? z?!=0^t;d4ihsu9gtoqPyBMZZU%^V9F{Yqoyb)VeH+g`W)DdVSQjQ6V}ebgq~J!y_N z{Iavwa^E*~nf~K{d8|J39V)ymks(-eyGD8cOWvyY2jxGpb6yV-uut3c=#iHlbKzf; zr?3BHPx(k5D(B0VymnpK>V2)-?yp{W z{_Tm4aqFvZOH^IBnL0gqRz45dEqbpLMMyINu0JG+z%Z{u&qnxC{d z_hTJ{6hlKgC^q(=mD9DzeR=5MUfH|CYkcQdNB6`}O9h>L{A-*u6sFV&&!^4YU;k3s6iA71{nWwkFPl#5nE|=WBb|zMX8ZyzMJpno$p%s{rBGztGA&oQ@%S$gdI(l$tu$O``*3q zY?jZv&$;Vv9cJe&ym8W9=~49d+7N-$k28#4Y~%YC*{|_wdCAAGH*=mfdoh5Qw7vM# zYWCCSefE}`rT^U)U#!|&w>QP$T(;Tlw`IF8CxcEacv^IGe$b1>yfVLL#+KcE{YmI| z_}TY;b`LsLZyjE4T_{>2``K13ZclWa*1s=2RSTxRVPF8QbN{e=GgHR?`$hbqGz`Q^*rg^yETfBp6HtwrCo75DXd_gwv`9_w&3NC4M@seS$aMmib<`DHm{C95^r5Z~5hWY&+bgf3FK$U0$(HOxR@h*|s2-xi+6W z)*ml_ZyWac=btItEOWhI?Cy(>`CVvm^2kjk35JGwV0+TkKhD>axf2~4`g2>9{?7x8 zbxtqKEZcoI@~y?Z8IJQO#eOqB+`IUc{S(2>A2zsg`J2o2PYzT0tJ!pJe$TO|9~u_? z$$0a7vF!1=^MsC8%jI%zid#R`o|)kSJ5$Dj&)@(2IsDS@)#=#j@te-ycs=Ci&}e)sHk-amcYo{vX@UhMEQpM7?7l#~44@Gl!2 zYkETMwr%`#?`@u0hti83A9e>_k7z7BY4eGzm(g;m`0?uu>%vyQPJS_?X~xQb!V;N7?pEKQ=GFBmAhU=0gSp zgM$+TZ^^%P)^q*Nb1k^dWRkmJXWiSUf6d?RJs+{Y?a`F1kEG^zr&SO`FpnnWE5cT{_y$I4!1vb%ZhH;^7lRx`m106`grql zK-YrL0-I$I*qK<@UCXtM~?*y!5?YA0uwKWc5|8f7|Bzs4ccX zm7lcbaZ#Un|Ma={imciW#UEh+&)mMaVsdsT=pe`M8{^ka`F_9R{HrTwPoma_EsvSx ze{#X&<43Q2+0S8>m+d*>`eeW3{!_}E>hc6jKKYoaz1u1M?&z()sl{Q|ee%rG%LVFf z^zKRgKP&(7eWAL|_HDm*Mo(g50G$)(u-s{U@=o^e&3(zIyBEx_F1EN8rs4Kg^RD-= zXBmQDg6&!b+^1dz%CC{PXf+&c}O>^iQ^92A>SKAUHHMR??+r@AkbGl3V_4bYGveOg+o~&HS9J zKlXn9q%6-NtJ@T}Hq4*1^7c8Q%7Z)peT`2#tFn4E?`!#(nE5pZN&D}A|FAOs_V&N` z3`_QWF5BHJy%T+WN|~x#uV6M(<)^_%eq<>IG<~n!(C*-=pnG^I4xURnC2!wmI8D07r+xUrcgX$peEAr4I}SsIpO>m4-c)b-@AkiZU+>{=?hTofevN?cJ|6^y)7fGk}-sSRK_r6YH8TFE8(TYza5Jxc<&{dV9~``nBf&D$q)m z$|a)HpVZjZN7T$0ceLMk)AdtgUs=JdWgEBDbue}&o;?26(Dj1*?|hyY&4Tf)7YonM zo9%ME`*Hu8>#tvyta>F0DKl=aKjkT9G5`GTO`P-7pBs5Hzc5oZaoKORRNOsgEq{09 z=OYI1_&48tllZ;;hhz6qCCQmztKJGr@9#?Ve6~?`7rV{X6StRt+4?8-1{L-pMuFQ*;Y z`HBBlHpAT6K5Fj9FWjfeT`!$mBGC8y@L{9-DaKdbr+wu6GO4H1Cd#Jn{oxMziC^wZ zd?{Y}sQ<_AA{)8mPQ4fVsvqQ-&HgX=UoO6L{qdtp-6KTxwl)`OHO27 z{_w=(-K~F%-p0?FVxKKsa&7BO8}E$&Ry&R-JmYtKJmHK20|QSJgVc*D;`_F)wV&MJ zx$kh~q_dCs+MBnQ?D})^LOAzab{qMwNbg_jceXOS@icvUF8wcdf_X@%_IJ6*GuO{Q zUQ)=&z_3oefz9ga!ozvnrF-2#r`4N;Y&{h@sp{(W+gWe!^-Wu|?KXqm1G!BRI+G6X z2wpsIn`~L!zZ}=Os%_et7yn)Dc)ZQtL~Y}1eTCdg28IL&mJ1HgGSp^-tl;FZh@CB= z=5Ia4D$ZbDrSXez&OG1kK<5n}?$~|Ywrj!XPtU90&;EX>UiOK0*5;dc3S5t}sJ8yG zOJrtXU{-2iGpY=4xtI|$Ej37Nd(_$`HglBTi|@Ic$9my;mteGxnCI;lv-Z8;56I~@ z?W=sLl`#jm^nlyB+H}_4pVqgHR zSanDJVDHFHt7QDAx#-iRwG%vzT z`u$`RzMy|Ke?J`K{hyIN{oBnaruG`^$`S6;bO_&jJG?vnw?NU}J@;4l-;Oul;F&*p zTgukVS=HN5o$OwaFTr)(>g4J9kJqJ!#we$0(U;HcWawuUb%Oym0zRDPtM?ufwIQ&+9p z^)K#6-PyRwg6h$eZru}OU|@4+;7#%CWc@thSDXC0=Uc<0!abx`XKaj!aJ_zFcaY68 z4y*pQ{7d@#?yCBKe_oyad(M+yi==h>`+h#}*Z%gqHZ(Mik%58Dg@IRwlWCH}^1m`A z|7MnNT|GyMf5Gjj>cu5zKODO{Ym0A%gW#8o&m^wbM?HFx*M4e#zQyd5>lViIo9StX z`kC#&Dk#SQUMQOaK87w<^KjZ`&C{QzT$k`HdiCPH?)}~m1r}SXyY79Jc;v1!@#)m> zT^2un*8H2Xmhb0t|Lo~stLCO(*!bj}?z;Tl)9!zDWMyCgO`1KZ5W661xMlt<`=_RE zlVao?vVT@h&bGX1{qEPYy~|JR4y>=Kxl&qtcD6cab5J~2o81)i>Vcqje3wj=fk@AIbZXHTcyZGE?E#j?wpoAy45+-or@?!()) z4>mnzWMHtF&LCx>bd&!TXi#jXOs|`JJagxg`lc%{+mci!zrAZV`|Mu(^%u&r&RI9c z2sD}dPEJ{HD((F$ozq8?3Qd~(TFqyl{lxYC$zhZJ$oUKm2W&xk=2O8=UEj0u%C=9Y zq^dR4HEhxeUwyS$+b91Xr;1*bf@Rq#{Z-)xwA4bfDT8H0R>9&)$`}imu0U{Vc%Kdd)cII;vHM27ZEc< zLyvx%eKzgm`E|Rz!@u-1Jz+mmQyQy2u~6pT%i{vYyCQVv-M%qv{pyOnaq?#u+%A(b z%)YOGa*t)j@A9*$(jiO?4F2j3Y<(VfVt>I0SKVT;;#^sqH!FBrDV!M0JPv_`I zdC&A2-*$G`*)TAGw%_--+9$1pS+(h5igkhw|EWr z=c>K?%2#II5lHfzT*tj!-ucq@g?BFn+;aXV|0j%L@DXKAmDjp;8B zW2^OAxaGMU1A{>ZQwG>g{BQEN-!^OTyH#S75N&*J?&WQHd#|?NJUKsc%iK7>`t27p zu88K@EjwQLU)&+6;m-^`nUDWI|Fn6@Qgo_$bxQY@Z|_omA58C@*niqgv&eqpyYmbT zADCD!94Pd?T=LZA_uo1bskxVy9X9yp=;LxG+~-Bo#)$RTXP;F|OShW4ZSs#h%)1{7 zc@=r?PTF?tap9%b$A;H)?r}buvXJFq`~|mb`u8v}B)nj`u%~Z* zmtW`Mv!HW9r#uIp%=K8}^V6c6qCxfxmg=a-DTjt0^*Oqx);H{SbLrNoqub|Iyq$CD z<VDUTy>CnAI<3jN&HpWN=G9W!>+e(F zTHNx}Sr-PWuJu1@=l$us6;`tC>6~1Ztdu;}W1kBwN=hShn@>wGYrm5(w_9rSG4c7) znKR0(ZoVx`*Ij5cYl}kkNp8pn%4XMiPNf;^p5S=cqCpRw!TxP zU*MCv00YB;0FDKft?_xwFTc#&{`*gVe}Dhis=s%N&WRgK_3pBBlVy&(zLlX$ApBI0 znYYn`8T)MB@7^Ba5$mnN_j^s#9h-A`zmG)-oorrud`sg$^|ycjeyv&k`n=lwGdmI< zd%dgu-}$r4`b=l+!sOIrJioe`85rW48D<^qzMuJDuPNJn-( z!GE{>=`k@gUVpXf2Mq%y&#Px(VCYwDNW1Y!{L0Uof3MeX`slj<;5`G=7hJ1u_3f(E z54TZrx=!x6 znEA9N|J&Fn)c)gMy0$HE_QiVf%d+v;ze_SO#Pu-DI{07i_SMT_Y=zFQfhxbJ9^IZa z=d-wn@I1R_&^Scx0XsXpSG(%2J)QGLM&fw=HLX*pt8GOxRdW~I{_85g&0_L7gUvVJ zytkifziz|%CklC98xJJ09!t^v-_beGN6m2aGd`F#Y_mn~ZTrjeN2_{r;W_IZ(0=%= zBim%VA}iL}^u9e=BU^i}@SR=D$wgP$c1_)GTX|z~#}et%@X)$ThI?{-@{8ENd_OI| zn2~`&-;?3&gZe^Wtsl3n+zl`L9ObX0m zzUy@>-eyyv=kLgAPZpl&XVaOd$H2hA)4?$7AZV@O{|nnX{C`#MP4V9Tw=O>PD(`Id zg8rA*OaC9cyu0AeHf0x~-Pz1{Pg!f)Z>sbwYX7-A^;Cw*t6dMb=$mb3U|{&G*pT+2 z&un|F-t<{}<3O7abk?8M{vF_cGWEJg{X9vT*tGP$(f2Bz+?gl0ewW#=4g3%7>y4hK zY)T5PSs&qlty7whfx+QE$AU`M#~&;9-!E4c&#he-xa+wckR0U)+Ec~R_yacXAyUy&$G9b{(JRgvi#@%6;ccg4aY%ty<2vb;gTzin|uP zJ!zU`HL1=kcm2=$zTB{vJDH%46RbS)ZB5a+@JZjhdh=E13LmLCUmC{z;(4B|qOp zdCr%vx1NHk_5Lycem1DQt*udgdGQ_B^L0x%=}f-+3X~CZt3Um)PLI7F%g=M`XV+ri zZQ55purn|$Xa|*IPnw^c*Lq%~TG@W>Z{2*B3wDD4T`FHz`NRYj{F-u4^JHtyLB*}P z3;N4SD?W=}3Js89{`bJf{C=0gv}~RJKWek4&ffxNzL&R8*c(1c>ErQoP0L-Pi8bbx z3pU-%xs%Jl!0^kB;q2=Z(Y!Kz?4FmWek$7)tGxgA+Y-wc&)01AEuGwS`Ny@#&-L_g z?t3s{k|2kj^hEXxn{U23__%n>!un4&hjN&}lU1{(8_o2Y)bi!dEzi0W-od+>UMz2! zQFHS3wbiRm$=|lwx6tvQ%F8A>?u~yYO}NXq^yCklr`syGEUdqjbu!qEfuTW8$l-I) zCq0=-7qp-L-dP&C{(9Tr$WLu-yYK4h&D>M@tHi4IPvZTu={wCXzKfdQe)!?pa*eah zFP2{sdCsjc(@S*7Ts)G)sJnitop-#pMQ%cduG?PRn}=*VnRr`}}?H zElk=PWxJHS;QG0W>858-{Px;k{QE&2+l5N$Y4g5xF*1PnsmBF`hI+o7W4G|SM6X-= zR8=`X_LUceL8Dg=_48+yeLolHT3zVz`RAWDU*k`*UiW``dPYu*jr?C+y~EtM_}6pY zHx3*O;K8G~fS?P@1K$1G=?g}%x1wJ&ek{IhM5xXD?Mdj@;n z=FQy8yTHHx&etPepd{HR1M8Loz(W=qu=un)1_oGXB1F{l&n*Fvp4E zY_^wONZn1ov@M_3@!5&r-@aO5WzOG;n$Nes^}pHvVg8o(uc;e6 zwEWK1mycd9tf^DK9>K}LkRZTvVb8KXR|@yv*PgyRBKG=n_6z5A=hqZ_a^Ky*Ty1~K zw%c!mC*8DYU6Of>)qm2XubvBb-hO-R@ki-(lh+0Od&%4FSM%uUWN?;OYj~FWbn9f_ z%My!DhlG}%YJar#cHOQef@kjs2aC8~vaH>I-+t+#Ejp){^p?)KyYuVLT?KPWU5{U% zKktOP>ubAAMg|504yKH_YoMJ82EQ*dOuwx9byEHF=KKi%Tk@V8e!RY-^0#ch#nhjZ zmvB!yZgZjLu(k7LliKPJAMRe%li6qkiPm(cjJPn+E d7pi%3E{QJWua(YFz4&(h z!K66DziZZ+7KWUx>dv2At@yk#OXWVQ{~-flt1if{<46Z0ld*-&ze0;4^-D( z`=|El?yI^tG3pKPp8vZ4wyfUY_mc6i&gtxiz{Ydk}4H4T7Db*J`dY=EPT?8_np5zpZOZ=ad=LS zdS6~$U?kN$$+KVeO1t-t+F75nE&o^T4g1H#z;L0MDI@M?hKZM5cKyNj??0bMWWMe9 z3S#^syj-)=Z$sSrdfo-Q*G+$(HnH+@&*6s!dDRmvCN8l*U$?(LZ2!dLr{`b#x?IBM zn!}m{?KsTd|($lB?DA{$0(wy7fo>S}DI> zhBkZW+1}L9pHrRV{`>Qh@??{HiZ^}OzBQ%%UzgJ871K9#?BUHOqwC42LFy~B1=|6RnFob-$>_%reOHfFzF4BJglKiAu~YSk{Oxb5=& zGyInOUOsXIb~XFlyj$s;S&G83{l-@MVd zVZQeM)$`rt-2dI$`Z)1Z^6munT^7@qaJ%n$_^{x{`|r6+->$x=`stq9`MHG*3=DB? z46{HBc5=)vw?5wX>CP#>7TcMNi_1m!B-}sbe#-uAL7w+_;pmy$=V~NH#2Iz@+MT*E zUzURr(z;%+e=}8EXS%oI>77YOlJ4}qbI4dQFT+HtbnA>4v*!NEJbRh>#gdgCzYSjA zQ3cHe>B-m|y@*%-y)gc0rE(7cb5O<1$!M}(|NPo5TKgQLwPv%I?Y*_{4R5d8;&spU zUyv*LG?bVmP zP}^(Ws#i_+Ukxg!zxwg3Xs3;~nQZ@Y_wASe{9c~3{dUBE!?44>8J|Br-{!ren}dO& zVYYz7XEC?Mftxbt72PeCeapCZ^S8@aOKTl)R;$0CzBqM` z%a)IuADusDaeM<$_SWrp=TA;k`<2hYz);}KlyUFSMLiiQvH7VcQcp`4Grd^uJprT~xAwobeP(izqo^eV1L#(+J>8phCeJw87rk7&D`{iIlj!Yl z%XZss$$nw=&tluM%tt!YPCwm{74C0;TqWfU^NV$C;(s|8Jbv)`-_dkif2&m6`Jn=` z$Hi8!-YzZbr#5*>dnc%b0A1jFc6Uaynrl61O2l2;jlbR5zWT&5qmIrvz3GOJW{_2&GYJ?s9wEZ(vdg$#Xp-nR#ETX`f)HY z95~Clpi5$-CVhPTBl(;8?6cZW^WNU8ie)Sb zdT&34!RmgP3E$StS(o*nOY}auyH3!36X;OqP?__^-?e(=ZRPrtUrmmB&ux{#%)kJ; z%Iw~W3LC#|=c3n!O`5*g?@joH+YbBJy^d$TcKG23ui68TU6O3$H(dG5VCA;n{`m}( zoq5jRHg_%fT;Bb(FtxvLfA%8zoi`pGKYAy3`|UqE=W^%sGB7YK7jXFOc50JP(9U~h zy)UK)|H|J|c)Mulo9KD7OWf)59>daZoR4j++H1i>~>tdz}NMXUDslJOxyK)O*xm}(yYa1aVs8W^1H%q>Mw9odFAXl7KeHt~sbJE% zL-udVcJJd&3wru1$@hSM->uIKyYg%ICOb_&{qv5}i#_gtt}obXdi3M`jfd9jcjVpQ zlPfCweg4lHx%R-&(AnQ~&>k zy`5K=8{aou#HF5p@nha(u}2BlUVly6*fIaovP&O@-Tw;)-}&cVW4KRxeWvsCACI5Q z`TSWkBl4^{s5}#9G|5+gdFbQEj|;i8rb|q#S-kDv^QoSluj}^PXP@6SPy6&HZSP)5 zpKZ}HVGMuIbGlww9)IyC+wA?o~eAN^g34sLXs(&+WGocAZ_e|499|&d*2f zt?sGx-S_2Z0Pke_T=vQ6-qoz7+{f2{s(pKo*GgWW|3dW*gD0m>zKVKMxp|^Z!@I8VZI4j7ln#n)Uxu@{HBTG8KXh^XF+p3y znLd+p-i4ojx+$EoWK;UxvfZ`w8LV#R6q`tuo-NAXJ>^ONlyg-ALd)-8-Sy;%m~C!$ z-^-F+aqAy{-RryP@qtG^rS}*Z7#=XPT-Y;rkC0ja^Lv#S#JZ2}RJ@+H`KAA=-(id; zaVKJ~mtL3m`IgyZf8%_*@p2Kz`4V%VcR%?uS8M+_=AQEC_19}xclK=+RR82<3v%NN zV@8wr8tpooefqYieD_>EnfqHsmsM^s?Z|!o$(Q54 zdV`*2!dlB2?{vx)_4B#yh_X6X1 zW>4?fw{XuN%eK|4GoA1Mn(3o9S*4+FX&;OD_M&sfzwGz}Wp0=4_7%EuG^y~BahpWT z67J(Kk6wv2pI>(T&=1W*kHRyC!G_Pw*Z2JUqnwtzH|}`qiid0r3=HR$8lL%vhE6@Q ztox|b+=SN|KZ~Q!RW9H1?%8C!BcJYZt1y<-*lK>rpOv;C*6Y@CFVD!2b^Gl%%Gsaa zl>dXX)8g5W$c;M5Hy+R19Jl`Q+5Mkha4Wt1=6}@s$VdI@rzIv-d=A%o%g(@%(7|$H z&&rD#TW;pCZLGdmtm^qU+`fIu{F7N*U->i4eY4?v662TDbgM75QvG6%$FppnihPRY zO+IVxTYNh-_K)CkvE>5A;@7W~SoJ1%F!xno%-eqZ{r6mhzuOPXf1I_0=W+j$jYmyy zZ@cwDgcsD<6L9#vtS`-HdTCXyA^0|wJ%23YCikSQ4?4Za@Tj)wzkNCS2mdU3@jrOx zV%H0W@6^k#gSLeiPZw@}qkVp9?~>?T1KCIWOnxf+E%`hBhgXeloPhph3uXp}3!r*2 z{F300&!3CUX7By^19XxK%RjC9y!dNVqn`1~%e{HD_9xr(O=-%8Q%`Xs-TyY(=g7^qVXL1UJXy8Z?&-}So%idG zi}t@f#K^$Fu-=j3Y_xaLuIe09GlkGl)u#^=H%8R(`bAFj+~4#syl}|RQ%xCsZB9!!#sa} z?*H^*+q6CZe+%q$>+W3qNM{mgxlF0AdkkOf&fGn>8=|IcnVqi2U9tIQ$G{C{yk7M3xID zueE;snpnC76q}oun%UX?QuDlAkoySKS9M{^xECdN^=lUM-ge1ex7b>(eOj~r^G%r? z`~KJF{qa8EYwX_7dN=)~@aNFEB1_`0S?-$uNM`b?KV>p~^8)`Jc~oGr=iy&aFr8Cv zcy{+`E_>Wc{STU-I=1;vu77JY!NmCGdAk1_OYLX&w_b~C+L+-$tVpZQ7c8GoH7 zKc}DOd+Zq)7(iDJ?b%(!yjQsT=)RtlDU(d@XZ#NNW2NxZU|rbic`3U+=SisllPaz) zWcZu(^r8FwWpgI2>OcPY2{YsSGSG-=12@Nl%JNFDugTl@UN@8K-SzFoZ>ipO^O)b- zwOrp~UC|SsRa|p((z~unkNs8uUU(estn>Bkk_9PV>C^Mw6F))-uncUGq|QpWIed_`&vNXzkL|OfQzS+1|_A7{T*V>qPfKf1Rej z*131&t1iWX3Xdvp2HyXAlYOd=@@@I{S*Nh6G`3uIbNs=l_pABq!b3wZ`R>k~Wj7}? za$2nFMtxzmZC782vs{P`Ke)hMO)U44%(E#h<>lqqU!1wn8`S;O$_y6pdwF0&`tFZw?NWBTSBLI*W0<=| z_uZ@x@ppZ;QoWOuUKDKES8X&?CDx+qQvoYzpv#ki_y4r*{Sq0>cY{nMztFf&MlRsy*GOe~Z>$^?EzpcwF z_eI{%+b&&|SP`@TB&*yft!I0<-ES{A7AwNQz)+{!&{ltXb$PsL!m3qT`Mwvz>gUVZ z^&Nk_&SJN{^vzzk#sB1=OzpOOx$=^zgZj*`+;28t&)Zz-D_HXBcy$JgS{``YE^0zirol z9(BD?Dc*NBZ811sf^H!FpKc=cwruyj_T}a_H-$GT(Ylo_zGbmw)`Eb{}`^2G9nR%ZZ=_1Uk{LU^LO0es`5L?!UV<^;iE`w@T~fhC7od=$(vytk7CW`j2~x_wBJN5_t4u`Q^;;Z@=~~e0y|ea^$p= z$J%Ufp4017d}(3$rSlx~i~Z-{W%y4D&$7Fmw|&NU+xMp?-fr|d^m@9cC_4i~gS3#t z;rgeyFXwK*?HF#c?XO|qvh#(ru9s{+d-=?~5~IxRFJD)B)txnZSH<=rn_;f`vWkuG zp8x-&dC7lW)1IF``$Au4zq!W2z`(FwwV~~Q7I(|!+GB0EWi9;Hu6w;?-*0V&zUi@& zi@xrk>^bK_j#>59Wx~(dF8t(cS%3YO#rtpf?3!Qhx|FT?+>^m=FIch&u9MQBeR$7{KqocPwj7J!NlpC;)0p~l~gkPEnhHa{m<(ewg0{g zy?qt(Z>v}R+TZ86|3H$@e$E9C>!1AY;oT_f2)elMNye`~;0=8FMP-%V?ek1_fR3k0 z>twFI^uhFBIxFZH!=n!lul;piziSDL-G2>-7++8Je(@I~pkN34Z(_a8es$fR^Hy_D zrc82qb>G`A|LVhE8O_~xDYGi~zjrjZ^OIZjXYN}0yNv}GYR?OMKAu=(erON(aqfNz z1_p*0HwIpNQ{TxZ=@J3%O~TppZ=b!KH+$AoUcIVIY`gx?R*ieMhT&Ih^N+>LE@xiX z@-0(7Gk^UHaGht*vEbqIJ@#*kcFG)af8)Qt_T8#4d)(sUZcR2kW9}`J*HaP3@Hfv| z;9ta2Pu=28D-$l6MvLR~@ziK|Hm)*rcvZ)c0I1 z+Igm2`A@Y#2{>0@=3MYl{G|Jv|9MFlwAHWKZBIQ>-Yfpu@Q+-xUE!KfW*3-ym~p1a#*jF$>09vN-Hx11L%&2B?Exa`o7^&AcVE?bL6p*RgizzWuy+^U*!LCH}_>Y~;SzZ$472%J`*! z+quanRZiZI-^cjnd+LPuZad=E*V`1II{p0j{S}~wfSelx@BZvr%d}^|PTW-z_O@8& zPjb;!iNpW4H~Lity!rlH@!H0D5sY))R~S0#-)H#s`>F8ZNpIY4uzj~*H){#EyTm)S zX`tYaX3F?+x57rwOZtVGopsdjKQqor-~DdcwXEBDYg0;q;@^YT~Hl#PvW=$d!^uHAQTMJ*!#^z>f3N-ac6MzMziR&$`BqKZ(*4kV*&OqW z*T6CMPtd`6`nL71lP=iqb$(Z26Q?)bGw$1+FF#*Md|Sd>BJ(82ta_=2Stjqt&||+R zon4<_W4`lX=|cg?Zab7R(DKfm^hoQw2}J@>!Y?UxS|@3U!`cmDaurkdAB*V|pp*NEqND?Io8 zYel_dOSs+Fmua(tCiMgyoR{xu{TO`9Vf)3zpxwWeYwN0tZcXd>w&$wzz1HM{#vGxA z+ZaoFDldJrQhWOHZR$MjlT&W5)48AgRN~B%Z1_%)d(HNQ7#vh1u-04M|5*qL0q#IGQAwJn#GciqB_E z@+aJV=k}xY?eqQ!xti&q+EY%*!Fk!LRZl*D<=5`f?MgD5Ip@X~OTLPY5ns~3Z&taT z%Ux7`sa5%;O#4>RL^;q2VG^I8OgvCxb=6eq{EOQ%|FxH$-(4W#&%nTNZw`Z$(aGnp zZ|l5gyciTY&G)j3{OA9Hg_g6=R)rp%^ z+@1Dr-lq7c{hPb(Rn`9*PP+Wkq>@kMepdFe&%Qd3Q*HM&6ZZ1 z^tP_~_SyMXa889+1RQNMxSUk$8sG593ug+`F`J$aR8$Vd~rEk9ZW!uZo_a6o9Zn_(1 zdQ!I6%~Lb`w%@}4o%NSWtZ&u@{QSILJnf&)qt%6Fm(rhA`+-K`-n%jI9#<{A_x1NS zQCCB$-n7j(L0#}H)4CT~Tc!GsGkftomf3AJ^NZGBo24AP{#$d^UIPm@(c_Nay|^a$DdZeh`r3V>+Q~sH*@^*XB1e-q;0ergsXK4xv`<~(SQ=>|+E8m*@&2+AUinRt%!{Bk(q8aC(dwzWvnY-Y2 z+4+xcAKA}q)%4jLy)e4Ehqq+?E9c}npAQu7zWc3G@6nA(U3d4NKl-hC`I>u+T`#0Y zs%`zes{k}yKab@?!K6LBUplYu&fWdIxH|8McKPnRC04RkKU3!XF54}8>RDaogNoGG zQ>(it`gj#?ZQGIKA>Qp8$8tCBF4%|z(Ww1A|e^I$NZvIy5I}2{-{judZ zsh4ZGXYZ=Rwo(?`b_;$hj(hZA@|yUcpHo+@@=E#}p;g%UJl5itpRAh@14F}hrG~c2 zPde{qZGFY1q~AC1woh5dZ(g+|nO#bE&Gx^(dhuCf^6jhJ=fBLow>8H1-Odi@ij|7xa5tb5`Z@>@VP^ZMn_=X61pAwS4h^IZRFXYAi zH}7#eZ`J;TdO!7YZSUOF?^D-T&66(tQm|9)uHU}*v(P zopga)Mz^U?bY4xA(zQ#S)zg?57!G6$I2>N-wm9&T;11qCP{_=aUcd2Xg5LR$)i)MA zc#+p)n{#Aheycj$-eVV!>AY2!fV6t1F-ZAM-QIuW{rB5%zcs!1x%&Ar?Od}NCuT<- z*8)S5w=AD0DDc)zk^9Cr}%QKqHd6)6~I`^XI zck{&G|2$-CUMG9(XU#p+9(j5B`@1v0Kc6vs*-7a_@X3+$?fRF?WbxGTN6+QS=6&vZ zp)huR*y=>xB4`J8&MKYL(X1Cfs{Q_3XE%R;=$AjKMl*TVIUdwZJ-YkuyO+KpeP;Is z9PYcsosd`F6Qc)dQrELwDCk@36`tKbX{bf0O zD*xMKPn&YLPayqQvqi*6mS=>>5d-pv(umda^O=QfadM8!6UHrWB(U-|t zkL=#}Pk*!Ehi!C?7u(%+mx8sv+>RAyy>OksB93Kljd`A0*9A}n3WG|lDa&>(dR~0B zbgqfUi(H#qX8&z}X*~K^dSUTJ4Ys#m(p6SpJr%U)UGfafcYR%>P+i$c!o^Sux*-z8t-rF+%+mkv)cig$TNtGOK}8+|XmRE3w=U;nKk3QX<_BCbYqnEu&YSgY-DdgxxX`OYqpl2h-%`!qTp^XJ zwafG34W`aKc=*`{P%B5ym4SEuiA`%>@A}Q0aq;t9C0&_=v$(nJlJ5KSA2#uQsG`zU zb@(zzwgu1O@XOC{3u~Xgr1)p&hMgZ*Ybx(v3@(=bGclUftXs9pI(gp*YC6we>{O6c`$UkbMb$IFi`}%92tA%Y^_qzJog2Ve&|J+!t zweWEBl+>TSQ4)XoJ8P_1a>YSyHhp1-!?Ag5xnr--^;;e-v{yt+w%`5n`Esq(MYEPI zo%-f?-Ba76^2Hav`y8*2asN5lUc9b$`|aMx73br5mX~B!9$w$B{&<0%R}F{Nr*kc0 zpl;2*c??qf6i#olIiFvCLATZGu)&XrzjGfgUOfGD>R(gA@82E&+j0H9n($Z5_WrRC z?{jMAEnE3|*HU%0Uo}5G-~Ik4?R?>}h1O#>28IWFITt)Uy-DZx+cIy<2R7$RW22YO zU!U@$>c_iZ&X=OuYOUtJ>uEd8`SQ1&%p{xh_J6O}x}1Oh`R6~$+nKWtU22W*S+eLM zC-(w*jhq+eZ3_;sZ#lbFkb!|=k0GN;jeG3%Q@nDER;@bWTlG5s;g5pZ-TRH3_o?Sk{#|Yf@CU?T*ot*3!`EdQ@Ohlgaa~YVW;Sv-J1(fXv+Y zW9glr-!hh8Ub$-3?ceer89#qeFF9%x_M}!*7c?O8Cmm$kCLL?J{)sN0Tgv}?9gDWO zwe9W&d-e05Kb-G8Q?lIne6hvk)X0B!wel}pXDsu4_w&QyKfQ`C&dP%F@ed(JlbYb$ z+q^fvH1W+^@IHK6>Ymo*=vuYPdFH;wcJudJ?f)a3$XLGn?*8ZR4&Tx{`$S9I|6#TB zh2xI{GeJ$R_g)OV_d`NMm#|d{Z-2hlW#04UmtWdOS>zqM*8aT4Ms9zh_FZ$f`M>x5 zUvc+`bD)U#!+*ISu4&f(xYl0#|5Y`Aw9OMx^`H)NMxe+lk_I57*8>M&Ud(ZzDo3HoX%yUtATRx9tdu~xNXc=9; zCj;+&k@>ghE?c=uYjw$T|7Z)dy)(AE^{sn-$o@&Y;TPR1I~hLjxzhjtU7lzV@?xgP zAKt0k!S3GR!oYi9d}l$d^{|(9xwrLP zmqzdJ`f%>?m&0p*uJ2kDq1DB?`mRZD^K_5MX%qcDGC*Sl5A2;7cEajftnT?M zHM$Zd&a~Tw&3o=`m|?MK_uX@XzE7l`FGTGGRSNb@89yd2(m410bI=@-eM?&(*M02# z!e=X<6{J)F-y0^0Ps?Xukskuf33bk;#_dp{{{0>+*tE|J|!B zm8r#lU&ui{_RrrsdCh4bLEUhMe18UB`>Q5rgASBvmu_|WetOfJ0t=UC&ZT1Y`JU77 zDO=7zZzVtJ*DHaN9}hohUjt3+Y*%b(o3GWSRCM*m%MzgvwVtupCpyG)9}hp;?R)5A zsoney|Gx7(w$IPGeN7S6fyo68?SONkcj2X{MTX~psD3>6Xv39FJJ)ydytJP0FOc8$ z|Fz=xbqt^etTO{I{{@q?ms&D^{L0%tdFDO+pxM&#~U~U;84BHRsLGJ-;Navc1|U^_RcJrFf|(zV+&0 zZJ>ck_Ky3X&CVBJHVJ#_{mF*E``Y)v7JbuCKdrHQ|GnDs-*)lOC04F#UsC7#3;4Y^ z;3;RjunQc8(o7i@JsxNCE|kvgdB6Hlm#Ayt|Db70r6$i`^W-^(GPQ$rtx&RQ0!rEu-rhcn@whaVO^7bvN?xZ?G#MT`s#8%minDrW3j zH{HlCeDBAoiCr@aGFa!HzteI0X;C_N`zvsoZeWm-Q>!}}asT@!mAIuET}$tLuG+gT zH@kD5^1b7K-&f_m)nH&?$e9aLCZ`*#Cmt!Ze$w-wmv$?w<<4KT?)8b*rEQl%>DHJj zqhiUn-04gi#mn{tOiNvU`DDdEsV9|kVt>x9=GY6GJ3nxZbHT%jO0Mh&KUSRid`IhJ z&Bxd8&pqEf`KQlBYsLQtJk9=o3=9k#GC@Y^oL1W0``BVyYUb36lPB-I|L)CLVlgx5 zT>7ccHbxWvxpTW;HVNZlU}$(N&oo$N_kZ_OD(^5O}h2Jzb84t zl|#;S1}V8Ut5z))>wEoG%llEQdhyG5yDR4%F4w(i{Is&pZvK1D1+_&?3=9pv!VZU< zkJ`tqzc@9#Q)J5P%8JetbC>@A_oT%flmKsNFq+sz?8zyg_k7p7wL<5oKmTdK3sitUMC9!L&9Q~3m+;bu4{h%^;YTJCH>F4OYB;bD=lPXPCxGsIhGAB z8EiQgJpB0R?Ybz7imMyn{I)Yn)^4cV_aVrj@9}cRFJG%l>p_LGv}!}!@zbF8)6#>- zGG}cm_%I1%(6qj%KWoB1eVF9iY4YvQyArFL3JeSk+dLR}J+GA7p8tHw;Bno4^W0OD zk8VDfDDh;re&DpHm!3|j-%}VGI`t_N14BYF%Y_Lpk<%u=KFVYKsU~vT*4*794)J>8 zXARchntu3Ufj@UU#Lr5MCMpwCZ+@)k*;240sONb%&ok@E`XW2Gh1A+GFfc@`H?)P! zS{BK*;PCbG-E&nRojkQEhRf=C<+TqVv?}Mx_aFCXezC#*Vd&8!P_ooz%J5jK(dDsq zwHRMmsaoso^`Y0l+JfrQi?2a56t|Tc+CuVlWhQDLeYI7;cC$ny6ga_BQD0yRTJmclq5r4vEa^d`})06ez^6$eiWhz97~W zv?k~o#{$KLn{=kL`Q?Xq?fll8-qnAzE#K2DeuYNY<(FSx3T*iX$`IRJ8F)GGz7vby z)m1PreJQ(5utiSnbzRvLpMUDytaju!=6pWK-CY6<3=L}q9Gr_Hr^)iQpO~5y8XCED`_0!= z&u@NSx$g>R@!q(p-0K}9r%k*k_ZBo}oYT!9HE-d%*Gnh5t-LSIaeMmn%FxiW`VZ~H ztmjJ2i@5*Y+ug9{bYRTk!mcmhYI3eUEZ7jqz`(F(K7-UeMWeE+?1u$QZ%w1t5!)J|9E*dN30Yl1H*w|oC_XGZqj+ZD^K(5 z=geQe+Mw3npTf=epBCMG|6QA>`0?efk1eNT%U_yny@|SUb3fl|zQY^NeHT@7|5&tB;#hp=kEcu5DS`5zHp_(%Dj&O#9@<_r ztFAk5^V|Bf#fQbe|NhH$KYYciEX@YK_;S8*rSqR3f0U4Knz!tv=rWM6<}gUjQ~5XZ z*N3m$a(Ny1-`qCOZ@K8Z%*bi=B5i-<9I~4u`!|SxRD4nJ;o46%&=7fzfWzU>F01&P z_Pwv2Rag9I>Z#W`TR8kPHLva2E0`1=uCzy?WqNA`_i+QBs9**Lh6rOu6C3||&!2y` zELu9l|8jodliJo&K9Tm~9aq?r7nS86`WYz|{{M!N^J|cMW->_4%i4b1)hl-Qy2*cY z{gzxzntR>b?H)&={Igqkj9F@Jk$7#LQoHnc78+9J>L*y5MT-)BeIZy(-%ZQJt5 zX|6_RKj>yYTXkf0bzZpOE-TQ0$Wc_eVZLj*ck|oJCTrI!D%KS~ z`dM?$b)QzEwcqmK8jh;%w-t%Fhp-ZlOEwSqSZ>DavxN2|Q^=oT{_FEK6 zu&Ed1-rCm7?|9pkfq@~+n}PSd*!=W8F?#Ei?#x-FF>T$~-L1{5vmTz9`m6W86JlUs_~*{RdwzOqK$U zuvO6EFn7(ZLmRgpW2@V-JbQQCCXKG8k~PQkw;o#8`&dG#ytfUsv1X^l??;WpEr$W{`?gKE26<`?!fOC^w#c zn|Zx-qT-80iLgtTWl2iNeb{5aslb=`C za8#+@mXbUm?yx>4_WEZVc+qh9^pi?C$+S7oD^)LVs`0Ghu(FWh)7SseXMUh1-?AdR z?ry{?|3XpFq8V+KhPLS^H?7H><+1qn&zd;TRD<|i*Z$VYOE&RY-`n;!Tliiy!`?3{ ztQWMm-+rsao-;3<_Y)}Dwlhe@t<>l`Ver_**Y|S7QuEu_Zs)eF*L}1jl#_eG_UZ$A z)4iWGl*Xn{1!W0NMw304mS5gfd;hn|U$O05GiOx#|pGv8lck%cTP|K%o1gdO-v0h4+gGhp zw~=K0V$GSJCec>kZ{MzO_uPV!fx)4LLF(Gm%Ze|y<@TE7g+xw!{`qJ9V!!2=h4oZK z9QIG%FgrA~b+YmK&tIp1a1t~#+%uzMEvQ5Dl;y$(z3u#0+@GbKe_k9YB9;Ym)U0Pk zJNNu?I`qM3*E(T`{gXdz67UPZaqaNK4Y%K}S~baznSo&g8&gKa+#dp8Cg-nyyz!IG z{rBHL8ol^%_k*$L_6UZ*>o(O#a4|42ggG(ruKt`E`N4pvZNdGD`uP{OE^1DS47<+x(dGVxT_$ zW;uq3PJOgKJyLAuAu-V6a)y4ThPJ7zR%OW?_i%N-Y!a5aJ5OB5?bJT|O%FEd1poQE z@BQ?D89%1|tO9vfk>$dMppV&)dRFc`F801`_m9?=hYVk8|9{B*UQl%CXXLN$R zFm=q2y>ZY(_OrVN=u9~YuIH8ezT7)@_`evaD-o~O&=$J-wN;RC4#zLsDXBX{IzA@O zdww_X`wGh!6%2Q`t@Q;hyOINi)wJi8_rH5T-uT%j+q;7QSy#U9>)p_wds~lJtzP2z#&xgd^Qt1Jd7I0(Ig9Sgwg%1rwF@{L zX1in6^#8xs`Rub0kGyI?=Fd0%gozG!#6o;afkC^$5jGH$f#oIbVb z&in7R_via9Km72+XF0ZOD>b^7UYgo|#<4yA<*vM!9}gdXR+$GH25bPiXj)3-wEs#~ zb@{G=GX2M0Bujq$-1mOEoN>+Rm!R+fIb?&IYv7;VKYlC5%2dwdKm6gkJ9quN0t=1> zj0_A7?t%`?Yp%Tgbn^e-GvUt{bT8Twqvy@|C2#v?P$3FRZH(7euUhr_=bucrze_D& ze3)_BY$v5E!M1_WW_e$QM-JCZoZQk?!b|*}HQzN5_L8&W{x@nkILAqXri@XynnRi$N;k?IxYyL2R-!o6mjT^ZxhJc>a2&KMky) z>J#h(#_c@6=IQl){wZ^ELHDAFstK>ZR$0ir+kXbMn*2d9Q$|DXk4rLNg5*nn{0ahf zTkgIsV*)kU9yGFCV3=L_U*?NNpYP>A6V=-P+sg2H?>F+jyj=7WC>_KrHL%^7q;vY! zu6@SMdAGlP=h>yvb^58$%-La(G(U|&Dk1sZ{ATcg=OT@~{af$9Uw{4eCI0sLSN4Mv zs0~O(bsi|I&QH5={q@%xJM;ZMmzUIoGqf6`$$_xDH;)RQ+3!-f;C=O9Y0z4=!<-8k zx4rsj_rm}2OM7rvnE{l}Hze|(T;RX_@>+E%P}pr`xxjF{>~*uywG_q`n9 z#=yX!z{+THz*^(hXbZ9T?%rA zke~zeo_?LvvzAG=J)CFNS19v(SJ`(^XKg|sgVckyDUhb~^wX)DZG7?e^UwQU_LvWf z-6bp+81gmFe_oc^cl@zM-)Ecn|APO17wv3WA0Db&3+gHb2|FGH4d|+^yH*^a5~H0#>cQF6|MOWvAvMnp9Ha~mLg2_@V3;HTF0L3Rv@n1?%+R0$ zE<+d?R6y4rfqcpd&KwL3p5Wxlz~BM8A&h}x)Ch*rumEM>(R9I}Fq%h3%L@kTmYpB# XjkJ9x8%_PO6`aXj{an^LB{Ts5xM=s2 literal 0 HcmV?d00001 diff --git a/assets/install/meson.build b/assets/install/meson.build new file mode 100644 index 00000000..19b49638 --- /dev/null +++ b/assets/install/meson.build @@ -0,0 +1,6 @@ +globber = run_command('sh', '-c', 'find -type f -not -name "*.build"', check: true) +files = globber.stdout().strip().split('\n') + +foreach file : files + install_data(file, install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') +endforeach diff --git a/assets/wall0.png b/assets/install/wall0.png similarity index 100% rename from assets/wall0.png rename to assets/install/wall0.png diff --git a/assets/wall1.png b/assets/install/wall1.png similarity index 100% rename from assets/wall1.png rename to assets/install/wall1.png diff --git a/assets/wall2.png b/assets/install/wall2.png similarity index 100% rename from assets/wall2.png rename to assets/install/wall2.png diff --git a/assets/meson.build b/assets/meson.build index 47de3d02..0648037a 100644 --- a/assets/meson.build +++ b/assets/meson.build @@ -1,7 +1,2 @@ -wallpapers = ['0', '1', '2'] - -foreach type : wallpapers - install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') -endforeach - install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') +subdir('install') diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 81e22889..7267b8f2 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -4,6 +4,7 @@ #include "../protocols/FractionalScale.hpp" #include "../protocols/SessionLock.hpp" #include +#include SSessionLockSurface::SSessionLockSurface(SP surface_) : surface(surface_) { pWlrSurface = surface->surface(); @@ -166,3 +167,7 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { bool CSessionLockManager::isSessionLockPresent() { return m_pSessionLock && !m_pSessionLock->vSessionLockSurfaces.empty(); } + +bool CSessionLockManager::anySessionLockSurfacesPresent() { + return m_pSessionLock && std::ranges::any_of(m_pSessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; }); +} diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index b01ee288..9b3b882c 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -55,6 +55,7 @@ class CSessionLockManager { bool isSessionLocked(); bool isSessionLockPresent(); bool isSurfaceSessionLock(SP); + bool anySessionLockSurfacesPresent(); void removeSessionLockSurface(SSessionLockSurface*); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 67c11c23..91849701 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -338,6 +338,8 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { initDRMFormats(); + initAssets(); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -2614,14 +2616,17 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } -void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { - const auto CAIROSURFACE = cairo_image_surface_create_from_png(texPath.c_str()); - const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); +SP CHyprOpenGLImpl::loadAsset(const std::string& file) { + const auto CAIROSURFACE = cairo_image_surface_create_from_png(file.c_str()); - m_pBackgroundTexture = makeShared(); + if (!CAIROSURFACE) + return nullptr; - m_pBackgroundTexture->allocate(); - m_pBackgroundTexture->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); + auto tex = makeShared(); + + tex->allocate(); + tex->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; const GLint glIFormat = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? #ifdef GLES2 @@ -2634,7 +2639,7 @@ void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { const GLint glType = CAIROFORMAT == CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE; const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); - glBindTexture(GL_TEXTURE_2D, m_pBackgroundTexture->m_iTexID); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifndef GLES2 @@ -2643,9 +2648,105 @@ void CHyprOpenGLImpl::createBackgroundTexture(const std::string& texPath) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); } #endif - glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, m_pBackgroundTexture->m_vSize.x, m_pBackgroundTexture->m_vSize.y, 0, glFormat, glType, DATA); + glTexImage2D(GL_TEXTURE_2D, 0, glIFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); cairo_surface_destroy(CAIROSURFACE); + + return tex; +} + +SP CHyprOpenGLImpl::renderText(const std::string& text, CColor col, int pt, bool italic) { + SP tex = makeShared(); + + static auto FONT = CConfigValue("misc:font_family"); + + const auto FONTFAMILY = *FONT; + const auto FONTSIZE = pt; + const auto COLOR = col; + + auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1920, 1080 /* arbitrary, just for size */); + auto CAIRO = cairo_create(CAIROSURFACE); + + PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); + PangoFontDescription* pangoFD = pango_font_description_new(); + + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + + cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); + + int textW = 0, textH = 0; + pango_layout_set_text(layoutText, text.c_str(), -1); + pango_layout_get_size(layoutText, &textW, &textH); + textW /= PANGO_SCALE; + textH /= PANGO_SCALE; + + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + cairo_destroy(CAIRO); + cairo_surface_destroy(CAIROSURFACE); + + CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, textW, textH); + CAIRO = cairo_create(CAIROSURFACE); + + layoutText = pango_cairo_create_layout(CAIRO); + pangoFD = pango_font_description_new(); + + pango_font_description_set_family_static(pangoFD, FONTFAMILY.c_str()); + pango_font_description_set_absolute_size(pangoFD, FONTSIZE * PANGO_SCALE); + pango_font_description_set_style(pangoFD, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + pango_font_description_set_weight(pangoFD, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layoutText, pangoFD); + pango_layout_set_text(layoutText, text.c_str(), -1); + + cairo_set_source_rgba(CAIRO, COLOR.r, COLOR.g, COLOR.b, COLOR.a); + + cairo_move_to(CAIRO, 0, 0); + pango_cairo_show_layout(CAIRO, layoutText); + + pango_font_description_free(pangoFD); + g_object_unref(layoutText); + + cairo_surface_flush(CAIROSURFACE); + + tex->allocate(); + tex->m_vSize = {cairo_image_surface_get_width(CAIROSURFACE), cairo_image_surface_get_height(CAIROSURFACE)}; + + const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifndef GLES2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->m_vSize.x, tex->m_vSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, DATA); + + cairo_destroy(CAIRO); + cairo_surface_destroy(CAIROSURFACE); + + return tex; +} + +void CHyprOpenGLImpl::initAssets() { + std::string assetsPath = ""; +#ifndef DATAROOTDIR + assetsPath = "/usr/share/hypr/"; +#else + assetsPath = std::format("{}{}", DATAROOTDIR, "/hypr/"); +#endif + + m_pLockDeadTexture = loadAsset(assetsPath + "lockdead.png"); + m_pLockDead2Texture = loadAsset(assetsPath + "lockdead2.png"); + + m_pLockTtyTextTexture = renderText(std::format("Running on tty {}", + g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? + std::to_string(g_pCompositor->m_pAqBackend->session->vt) : + "unknown"), + CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); } void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { @@ -2694,7 +2795,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { return; // the texture will be empty, oh well. We'll clear with a solid color anyways. } - createBackgroundTexture(texPath); + m_pBackgroundTexture = loadAsset(texPath); } // create a new one with cairo diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index f405cb7c..06078a00 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -277,7 +277,7 @@ class CHyprOpenGLImpl { CShader m_sFinalScreenShader; CTimer m_tGlobalTimer; - SP m_pBackgroundTexture; + SP m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); @@ -287,7 +287,9 @@ class CHyprOpenGLImpl { void initDRMFormats(); void initEGL(bool gbm); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); - void createBackgroundTexture(const std::string& path); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CColor col, int pt, bool italic = false); + void initAssets(); // std::optional> getModsForFormat(EGLint format); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 33679731..2854a973 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -839,9 +839,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSessionLockPresent()) { // locked with no exclusive, draw only red - CBox boxe = {0, 0, INT16_MAX, INT16_MAX}; - const float A = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); - g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, A)); + renderSessionLockMissing(pMonitor); return; } @@ -1001,27 +999,50 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB if (g_pSessionLockManager->isSessionLocked()) { Vector2D translate = {geometry.x, geometry.y}; - float scale = (float)geometry.width / pMonitor->vecPixelSize.x; const auto PSLS = g_pSessionLockManager->getSessionLockSurfaceForMonitor(pMonitor->ID); - if (!PSLS) { - // locked with no surface, fill with red - const auto ALPHA = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); - - CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale}; - g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); - - if (ALPHA < 1.f) /* animate */ - damageMonitor(pMonitor); - else - g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); - } else { + if (!PSLS) + renderSessionLockMissing(pMonitor); + else { renderSessionLockSurface(PSLS, pMonitor, now); g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } } } +void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { + const auto ALPHA = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); + + CBox monbox = {{}, pMonitor->vecPixelSize}; + + const bool ANY_PRESENT = g_pSessionLockManager->anySessionLockSurfacesPresent(); + + if (ANY_PRESENT) { + // render image2, without instructions. Lock still "alive", unless texture dead + if (g_pHyprOpenGL->m_pLockDead2Texture) + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA); + else + g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + } else { + // render image, with instructions. Lock is gone. + if (g_pHyprOpenGL->m_pLockDeadTexture) { + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA); + + // also render text for the tty number + if (g_pHyprOpenGL->m_pLockTtyTextTexture) { + CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize}; + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F); + } + } else + g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + } + + if (ALPHA < 1.f) /* animate */ + damageMonitor(pMonitor); + else + g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); +} + void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 0b16efea..d00c0a17 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -123,6 +123,7 @@ class CHyprRenderer { void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); + void renderSessionLockMissing(CMonitor* pMonitor); bool commitPendingAndDoExplicitSync(CMonitor* pMonitor); From ef33198e8f9fa874b3ad2e2775f8474af62d7fee Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 30 Aug 2024 14:10:46 +0300 Subject: [PATCH 0552/2393] flake.lock: update aquamarine and hyprutils --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 219cc08b..b26cd5e3 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1724850097, - "narHash": "sha256-3BHxvFb3NJzch1X8puRMkVZujOoarQ1llu3ZcwuvsKU=", + "lastModified": 1725016199, + "narHash": "sha256-2TMk7F2a27ZtOUW/bftkDyZKp3OQ71E5XnfKSUT8HZQ=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "23c7925dd31e79e8c06086ace3edb129a070ac01", + "rev": "cff00196f0fcf734a2bf164eb0dfdb6e58c5c906", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1724863980, - "narHash": "sha256-7Ke9wFRYPUIXwm5ZndGHkWBKj6BsFTkSEXUNXQRHE54=", + "lastModified": 1724966483, + "narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "aadf9a27dddd2272ca354ba5a22a0c2d1f919039", + "rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", "type": "github" }, "original": { From 259dcd838eef8d6eb2f88f2c0935e32bf7985ebd Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Fri, 30 Aug 2024 07:04:09 -0500 Subject: [PATCH 0553/2393] xwayland: update overrideRedirect on map and configure (#7575) --- src/xwayland/XWM.cpp | 15 ++++++++++++++- src/xwayland/XWM.hpp | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 5ad146e4..b5762762 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -81,6 +81,7 @@ void CXWM::handleConfigureNotify(xcb_configure_notify_event_t* e) { return; XSURF->geometry = {e->x, e->y, e->width, e->height}; + updateOverrideRedirect(XSURF, e->override_redirect); XSURF->events.setGeometry.emit(); } @@ -115,7 +116,12 @@ void CXWM::handleMapRequest(xcb_map_request_event_t* e) { void CXWM::handleMapNotify(xcb_map_notify_event_t* e) { const auto XSURF = windowForXID(e->window); - if (!XSURF || XSURF->overrideRedirect) + if (!XSURF) + return; + + updateOverrideRedirect(XSURF, e->override_redirect); + + if (XSURF->overrideRedirect) return; XSURF->setWithdrawn(false); @@ -1044,6 +1050,13 @@ bool CXWM::isWMWindow(xcb_window_t w) { return w == wmWindow || w == clipboard.window; } +void CXWM::updateOverrideRedirect(SP surf, bool overrideRedirect) { + if (!surf || surf->overrideRedirect == overrideRedirect) + return; + + surf->overrideRedirect = overrideRedirect; +} + void CXWM::initSelection() { clipboard.window = xcb_generate_id(connection); uint32_t mask[1] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE}; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 4f6f3f7c..7d6b63ed 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -82,6 +82,7 @@ class CXWM { void focusWindow(SP surf); void activateSurface(SP surf, bool activate); bool isWMWindow(xcb_window_t w); + void updateOverrideRedirect(SP surf, bool overrideRedirect); void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); From 25e72949a1cc2368425ed81712a394cb277f514f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 14:12:23 +0200 Subject: [PATCH 0554/2393] window/xwayland: minor property cleanup fixes #6921 --- src/Compositor.cpp | 14 +++++++------- src/desktop/Window.cpp | 13 ++++++++++--- src/desktop/Window.hpp | 4 ++-- src/events/Windows.cpp | 8 ++++---- src/helpers/Monitor.cpp | 2 +- src/layout/IHyprLayout.cpp | 14 +++++++------- src/managers/AnimationManager.cpp | 2 +- src/managers/XWaylandManager.cpp | 11 ++++------- src/managers/input/InputManager.cpp | 4 ++-- 9 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cacbeece..7ae3070d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -791,7 +791,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (properties & ALLOW_FLOATING) { for (auto const& w : m_vWindows | std::views::reverse) { const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (box.containsPoint(g_pPointerManager->position())) @@ -821,16 +821,16 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) continue; - CBox box = BB.copy().expand(w->m_iX11Type != 2 ? BORDER_GRAB_AREA : 0); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent - if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2) + if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect()) continue; if (box.containsPoint(g_pPointerManager->position())) { - if (w->m_bIsX11 && w->m_iX11Type == 2 && !w->m_pXWaylandSurface->wantsFocus()) { + if (w->m_bIsX11 && w->isX11OverrideRedirect() && !w->m_pXWaylandSurface->wantsFocus()) { // Override Redirect return g_pCompositor->m_pLastWindow.lock(); // we kinda trick everything here. // TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases. @@ -997,7 +997,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface return; } - if (pWindow && pWindow->m_bIsX11 && pWindow->m_iX11Type == 2 && !pWindow->m_pXWaylandSurface->wantsFocus()) + if (pWindow && pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_pXWaylandSurface->wantsFocus()) return; g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow); @@ -1071,7 +1071,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface updateWindowAnimatedDecorationValues(PLASTWINDOW); - if (!pWindow->m_bIsX11 || pWindow->m_iX11Type == 1) + if (!pWindow->m_bIsX11 || !pWindow->isX11OverrideRedirect()) g_pXWaylandManager->activateWindow(PLASTWINDOW, false); } @@ -1928,7 +1928,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // shadow - if (pWindow->m_iX11Type != 2 && !pWindow->m_bX11DoesntWantBorders) { + if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (pWindow == m_pLastWindow) { pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); } else { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index a4ba366a..7623d45e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -19,9 +19,8 @@ using namespace Hyprutils::String; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); - pWindow->m_pSelf = pWindow; - pWindow->m_bIsX11 = true; - pWindow->m_iX11Type = surface->overrideRedirect ? 2 : 1; + pWindow->m_pSelf = pWindow; + pWindow->m_bIsX11 = true; pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); @@ -1571,3 +1570,11 @@ void CWindow::unsetWindowData(eOverridePriority priority) { element.second(m_pSelf.lock())->unset(priority); } } + +bool CWindow::isX11OverrideRedirect() { + return m_pXWaylandSurface && m_pXWaylandSurface->overrideRedirect; +} + +bool CWindow::isModal() { + return (m_pXWaylandSurface && m_pXWaylandSurface->modal); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index bdc275bf..7197ba26 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -288,8 +288,6 @@ class CWindow { // XWayland stuff bool m_bIsX11 = false; PHLWINDOWREF m_pX11Parent; - uint64_t m_iX11Type = 0; - bool m_bIsModal = false; bool m_bX11DoesntWantBorders = false; bool m_bX11ShouldntFocus = false; float m_fX11SurfaceScaledBy = 1.f; @@ -468,6 +466,8 @@ class CWindow { void warpCursor(); PHLWINDOW getSwallower(); void unsetWindowData(eOverridePriority priority); + bool isX11OverrideRedirect(); + bool isModal(); // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index cd000223..034920a2 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -120,7 +120,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bRequestsFloat = true; } - PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->m_iX11Type == 2 && !PWINDOW->m_pXWaylandSurface->wantsFocus()); + PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus()); if (PWORKSPACE->m_bDefaultFloating) PWINDOW->m_bIsFloating = true; @@ -477,7 +477,7 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && - (PWINDOW->m_iX11Type != 2 || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && + (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); @@ -577,7 +577,7 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); - if (PMONITOR && PWINDOW->m_iX11Type == 2) + if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; } @@ -816,7 +816,7 @@ void Events::listener_activateX11(void* owner, void* data) { Debug::log(LOG, "X11 Activate request for window {}", PWINDOW); - if (PWINDOW->m_iX11Type == 2) { + if (PWINDOW->isX11OverrideRedirect()) { Debug::log(LOG, "Unmanaged X11 {} requests activate", PWINDOW); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 2b8404ee..8af0bc62 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -721,7 +721,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { w->setAnimationsToMove(); const auto MIDDLE = w->middle(); - if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && w->m_iX11Type != 2) { + if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) { // if it's floating and the middle isnt on the current mon, move it to the center const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE); Vector2D pos = w->m_vRealPosition.goal(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f6339beb..c5a5373c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -104,7 +104,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && - pWindow->m_iX11Type == 2) { // XDG windows should be fine. TODO: check for weird atoms? + pWindow->isX11OverrideRedirect()) { // XDG windows should be fine. TODO: check for weird atoms? pWindow->setHidden(true); return; } @@ -113,7 +113,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5) pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; - if (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2) { + if (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0) pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); @@ -163,12 +163,12 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale; - if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->m_iX11Type == 2)) { + if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect())) { pWindow->m_vRealPosition.warp(); pWindow->m_vRealSize.warp(); } - if (pWindow->m_iX11Type != 2) { + if (!pWindow->isX11OverrideRedirect()) { g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); g_pCompositor->changeWindowZOrder(pWindow, true); @@ -592,7 +592,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // find whether there is a floating window below this one for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect() && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) { if (VECINRECT((pWindow->m_vSize / 2.f + pWindow->m_vPosition), w->m_vPosition.x, w->m_vPosition.y, w->m_vPosition.x + w->m_vSize.x, w->m_vPosition.y + w->m_vSize.y)) { @@ -612,7 +612,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // if not, floating window for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && w->m_iX11Type != 2 && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsFloating && !w->isX11OverrideRedirect() && w->m_pWorkspace == pWindow->m_pWorkspace && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pWindow) return w; } @@ -631,7 +631,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || - pWindowCandidate->m_iX11Type == 2 || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) + pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) return nullptr; return pWindowCandidate; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index e2fe7089..092d9721 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -194,7 +194,7 @@ void CAnimationManager::tick() { default: UNREACHABLE(); } // set size and pos if valid, but only if damage policy entire (dont if border for example) - if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && PWINDOW->m_iX11Type != 2) + if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && !PWINDOW->isX11OverrideRedirect()) g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); // check if we did not finish animating. If so, trigger onAnimationEnd. diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index b37e796b..144343f8 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -59,7 +59,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (activate) { pWindow->m_pXWaylandSurface->setMinimized(false); - if (pWindow->m_iX11Type != 2) + if (!pWindow->isX11OverrideRedirect()) pWindow->m_pXWaylandSurface->restackToTop(); } @@ -80,7 +80,7 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { if (pWindow->m_bIsX11) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); - if (SIZEHINTS && pWindow->m_iX11Type != 2) { + if (SIZEHINTS && !pWindow->isX11OverrideRedirect()) { // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property pbox->x = pWindow->m_pXWaylandSurface->geometry.x; @@ -160,10 +160,8 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { return true; } - if (pWindow->m_pXWaylandSurface->modal) { - pWindow->m_bIsModal = true; + if (pWindow->isModal()) return true; - } if (pWindow->m_pXWaylandSurface->transient) return true; @@ -203,9 +201,8 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { } } - if (pWindow->m_iX11Type == 2) { + if (pWindow->isX11OverrideRedirect()) pWindow->m_bX11DoesntWantBorders = true; - } } void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6b04c13f..78c9e437 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -675,7 +675,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // clicking on border triggers resize // TODO detect click on LS properly - if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || w->m_iX11Type != 2)) { + if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || !w->isX11OverrideRedirect())) { if (w && !w->isFullscreen()) { const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; @@ -1688,7 +1688,7 @@ void CInputManager::setCursorIconOnBorder(PHLWINDOW w) { } // ignore X11 OR windows, they shouldn't be touched - if (w->m_bIsX11 && w->m_iX11Type == 2) + if (w->m_bIsX11 && w->isX11OverrideRedirect()) return; static auto PEXTENDBORDERGRAB = CConfigValue("general:extend_border_grab_area"); From 242e06b24212b61e7afbdf5cf4adae8886a28abd Mon Sep 17 00:00:00 2001 From: darkwater Date: Fri, 30 Aug 2024 15:06:49 +0200 Subject: [PATCH 0555/2393] keybinds: release mods after sendshortcut (#7581) --- src/managers/KeybindManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index df3f2572..72799f1d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2349,6 +2349,8 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) { } } + g_pSeatManager->sendKeyboardMods(0, 0, 0, 0); + if (!PWINDOW) return {}; From 1c9d56998dbf3a9b61e13573e9e91d149fe65969 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:18:12 +0200 Subject: [PATCH 0556/2393] xdg-dialog: implement new protocol --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 17 ++++-- src/managers/ProtocolManager.cpp | 2 + src/protocols/XDGDialog.cpp | 88 ++++++++++++++++++++++++++++++++ src/protocols/XDGDialog.hpp | 57 +++++++++++++++++++++ src/protocols/XDGShell.cpp | 18 ++++++- src/protocols/XDGShell.hpp | 8 ++- src/render/OpenGL.cpp | 5 +- 9 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 src/protocols/XDGDialog.cpp create mode 100644 src/protocols/XDGDialog.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a856b8..dba14813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -315,6 +315,7 @@ protocolnew("stable/viewporter" "viewporter" false) protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) +protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolwayland() diff --git a/protocols/meson.build b/protocols/meson.build index 5b807914..de650230 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -60,6 +60,7 @@ new_protocols = [ [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], + [wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7ae3070d..eac75bd4 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1888,6 +1888,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->m_fBorderFadeAnimationProgress = 1.f; }; + const bool IS_SHADOWED_BY_MODAL = pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel && pWindow->m_pXDGSurface->toplevel->anyChildModal(); + // border const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(pWindow); if (RENDERDATA.isBorderGradient) @@ -1921,11 +1923,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // dim - if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) { - pWindow->m_fDimPercent = 0; - } else { - pWindow->m_fDimPercent = *PDIMSTRENGTH; - } + float goalDim = 1.F; + if (pWindow == m_pLastWindow.lock() || pWindow->m_sWindowData.noDim.valueOrDefault() || !*PDIMENABLED) + goalDim = 0; + else + goalDim = *PDIMSTRENGTH; + + if (IS_SHADOWED_BY_MODAL) + goalDim += (1.F - goalDim) / 2.F; + + pWindow->m_fDimPercent = goalDim; // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index bace4451..2c421abe 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -43,6 +43,7 @@ #include "../protocols/ToplevelExport.hpp" #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" +#include "../protocols/XDGDialog.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -150,6 +151,7 @@ CProtocolManager::CProtocolManager() { PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); + PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/XDGDialog.cpp b/src/protocols/XDGDialog.cpp new file mode 100644 index 00000000..237cf3f3 --- /dev/null +++ b/src/protocols/XDGDialog.cpp @@ -0,0 +1,88 @@ +#include "XDGDialog.hpp" +#include "XDGShell.hpp" +#include "../desktop/WLSurface.hpp" +#include "../Compositor.hpp" +#include + +CXDGDialogV1Resource::CXDGDialogV1Resource(SP resource_, SP toplevel_) : resource(resource_), toplevel(toplevel_) { + if (!good()) + return; + + resource->setDestroy([this](CXdgDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + resource->setOnDestroy([this](CXdgDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + + resource->setSetModal([this](CXdgDialogV1* r) { + modal = true; + updateWindow(); + }); + + resource->setUnsetModal([this](CXdgDialogV1* r) { + modal = false; + updateWindow(); + }); +} + +void CXDGDialogV1Resource::updateWindow() { + if (!toplevel || !toplevel->parent || !toplevel->parent->owner) + return; + + auto HLSurface = CWLSurface::fromResource(toplevel->parent->owner->surface.lock()); + if (!HLSurface || !HLSurface->getWindow()) + return; + + g_pCompositor->updateWindowAnimatedDecorationValues(HLSurface->getWindow()); +} + +bool CXDGDialogV1Resource::good() { + return resource->resource(); +} + +CXDGWmDialogManagerResource::CXDGWmDialogManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CXdgWmDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + resource->setOnDestroy([this](CXdgWmDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); + + resource->setGetXdgDialog([this](CXdgWmDialogV1* r, uint32_t id, wl_resource* toplevel) { + auto tl = CXDGToplevelResource::fromResource(toplevel); + if (!tl) { + r->error(-1, "Toplevel inert"); + return; + } + + const auto RESOURCE = PROTO::xdgDialog->m_vDialogs.emplace_back(makeShared(makeShared(r->client(), r->version(), id), tl)); + + if (!RESOURCE->good()) { + r->noMemory(); + return; + } + + tl->dialog = RESOURCE; + }); +} + +bool CXDGWmDialogManagerResource::good() { + return resource->resource(); +} + +CXDGDialogProtocol::CXDGDialogProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CXDGDialogProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + return; + } +} + +void CXDGDialogProtocol::destroyResource(CXDGWmDialogManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CXDGDialogProtocol::destroyResource(CXDGDialogV1Resource* res) { + std::erase_if(m_vDialogs, [&](const auto& other) { return other.get() == res; }); +} diff --git a/src/protocols/XDGDialog.hpp b/src/protocols/XDGDialog.hpp new file mode 100644 index 00000000..a635bfac --- /dev/null +++ b/src/protocols/XDGDialog.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "xdg-dialog-v1.hpp" + +class CXDGToplevelResource; + +class CXDGDialogV1Resource { + public: + CXDGDialogV1Resource(SP resource_, SP toplevel_); + + bool good(); + + bool modal = false; + + private: + SP resource; + WP toplevel; + + void updateWindow(); +}; + +class CXDGWmDialogManagerResource { + public: + CXDGWmDialogManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CXDGDialogProtocol : public IWaylandProtocol { + public: + CXDGDialogProtocol(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); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CXDGWmDialogManagerResource* res); + void destroyResource(CXDGDialogV1Resource* res); + + // + std::vector> m_vManagers; + std::vector> m_vDialogs; + + friend class CXDGWmDialogManagerResource; + friend class CXDGDialogV1Resource; +}; + +namespace PROTO { + inline UP xdgDialog; +}; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 39a511c3..25d8b1ba 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -1,10 +1,12 @@ #include "XDGShell.hpp" +#include "XDGDialog.hpp" #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include +#include void SXDGPositionerState::setAnchor(xdgPositionerAnchor edges) { anchor.setTop(edges == XDG_POSITIONER_ANCHOR_TOP || edges == XDG_POSITIONER_ANCHOR_TOP_LEFT || edges == XDG_POSITIONER_ANCHOR_TOP_RIGHT); @@ -207,15 +209,25 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPsetSetParent([this](CXdgToplevel* r, wl_resource* parentR) { + auto oldParent = parent; + + if (parent) + std::erase(parent->children, self); + auto newp = parentR ? CXDGToplevelResource::fromResource(parentR) : nullptr; parent = newp; - LOGM(LOG, "Toplevel {:x} sets parent to {:x}", (uintptr_t)this, (uintptr_t)newp.get()); + if (parent) + parent->children.emplace_back(self); + + LOGM(LOG, "Toplevel {:x} sets parent to {:x}{}", (uintptr_t)this, (uintptr_t)newp.get(), (oldParent ? std::format(" (was {:x})", (uintptr_t)oldParent.get()) : "")); }); } CXDGToplevelResource::~CXDGToplevelResource() { events.destroy.emit(); + if (parent) + std::erase_if(parent->children, [this](const auto& other) { return !other || other.get() == this; }); } SP CXDGToplevelResource::fromResource(wl_resource* res) { @@ -227,6 +239,10 @@ bool CXDGToplevelResource::good() { return resource->resource(); } +bool CXDGToplevelResource::anyChildModal() { + return std::ranges::any_of(children, [](const auto& child) { return child && child->dialog && child->dialog->modal; }); +} + uint32_t CXDGToplevelResource::setSize(const Vector2D& size) { pendingApply.size = size; applyState(); diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 81d10613..9c766c20 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -18,6 +18,7 @@ class CXDGToplevelResource; class CXDGPopupResource; class CSeatGrab; class CWLSurfaceResource; +class CXDGDialogV1Resource; struct SXDGPositionerState { Vector2D requestedSize; @@ -134,7 +135,12 @@ class CXDGToplevelResource { Vector2D maxSize = {1337420, 694200}; } pending, current; - WP parent; + WP parent; + WP dialog; + + bool anyChildModal(); + + std::vector> children; private: SP resource; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 91849701..74d3d3cd 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1378,8 +1378,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB CBox newBox = *pBox; m_RenderData.renderModif.applyToBox(newBox); - static auto PDIMINACTIVE = CConfigValue("decoration:dim_inactive"); - static auto PDT = CConfigValue("debug:damage_tracking"); + static auto PDT = CConfigValue("debug:damage_tracking"); // get the needed transform for this texture const bool TRANSFORMS_MATCH = wlTransformToHyprutils(m_RenderData.pMonitor->transform) == tex->m_eTransform; // FIXME: combine them properly!!! @@ -1493,7 +1492,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); glUniform1f(shader->radius, round); - if (allowDim && m_pCurrentWindow.lock() && *PDIMINACTIVE) { + if (allowDim && m_pCurrentWindow.lock()) { glUniform1i(shader->applyTint, 1); const auto DIM = m_pCurrentWindow->m_fDimPercent.value(); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); From fd8d8e122ed9cf49f3f84d4d264f1b810c355a07 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:26:00 +0200 Subject: [PATCH 0557/2393] keybinds: fixup misused kb state fixes #7369 --- src/managers/KeybindManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 72799f1d..7ee5ae7e 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -372,7 +372,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) From fbd63543930417f3cefe36bdb9f2cdd20fc3693a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 30 Aug 2024 15:50:25 +0200 Subject: [PATCH 0558/2393] presentation-feedback: minor fixups --- src/helpers/Monitor.cpp | 4 ++-- src/protocols/PresentationTime.cpp | 12 +++++++----- src/protocols/PresentationTime.hpp | 8 +++++--- src/protocols/core/Compositor.cpp | 2 +- src/protocols/core/Compositor.hpp | 2 +- src/render/Renderer.cpp | 4 ++-- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 8af0bc62..685009fd 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -47,7 +47,7 @@ void CMonitor::onConnect(bool noRule) { listeners.presented = output->events.present.registerListener([this](std::any d) { auto E = std::any_cast(d); - PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags); + PROTO::presentation->onPresented(self.lock(), E.when, E.refresh, E.seq, E.flags); }); listeners.destroy = output->events.destroy.registerListener([this](std::any d) { @@ -861,7 +861,7 @@ bool CMonitor::attemptDirectScanout() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - PSURFACE->presentFeedback(&now, this); + PSURFACE->presentFeedback(&now, self.lock()); output->state->addDamage(CBox{{}, vecPixelSize}); output->state->resetExplicitFences(); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index b1108042..e1ff52cd 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -14,7 +14,7 @@ void CQueuedPresentationData::setPresentationType(bool zeroCopy_) { zeroCopy = zeroCopy_; } -void CQueuedPresentationData::attachMonitor(CMonitor* pMonitor_) { +void CQueuedPresentationData::attachMonitor(SP pMonitor_) { pMonitor = pMonitor_; } @@ -67,12 +67,14 @@ void CPresentationFeedback::sendQueued(SP data, timespe (uint32_t)(seq & 0xFFFFFFFF), (wpPresentationFeedbackKind)flags); else resource->sendDiscarded(); + + done = true; } CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); + std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor.get() == PMONITOR; }); }); } @@ -105,7 +107,7 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su } } -void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { +void CPresentationProtocol::onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { timespec now; timespec* presentedAt = when; if (!presentedAt) { @@ -119,7 +121,7 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint continue; for (auto const& data : m_vQueue) { - if (!data->surface || data->surface != feedback->surface) + if (!data->surface || data->surface != feedback->surface || (data->pMonitor && data->pMonitor != pMonitor)) continue; feedback->sendQueued(data, when, untilRefreshNs, seq, reportedFlags); @@ -129,7 +131,7 @@ void CPresentationProtocol::onPresented(CMonitor* pMonitor, timespec* when, uint } std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); - std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor; }); + std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor || other->done; }); } void CPresentationProtocol::queueData(SP data) { diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 2c6ce3e9..06c71c9a 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -14,15 +14,17 @@ class CQueuedPresentationData { CQueuedPresentationData(SP surf); void setPresentationType(bool zeroCopy); - void attachMonitor(CMonitor* pMonitor); + void attachMonitor(SP pMonitor); void presented(); void discarded(); + bool done = false; + private: bool wasPresented = false; bool zeroCopy = false; - CMonitor* pMonitor = nullptr; + WP pMonitor; WP surface; DYNLISTENER(destroySurface); @@ -53,7 +55,7 @@ class CPresentationProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void onPresented(CMonitor* pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); + void onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); void queueData(SP data); private: diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index f7f6dcda..37a4bdf1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -509,7 +509,7 @@ void CWLSurfaceResource::updateCursorShm() { memcpy(shmData.data(), pixelData, bufLen); } -void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) { +void CWLSurfaceResource::presentFeedback(timespec* when, SP pMonitor) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index a3245399..dc1c851f 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -124,7 +124,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, CMonitor* pMonitor); + void presentFeedback(timespec* when, SP pMonitor); void lockPendingState(); void unlockPendingState(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 2854a973..420f8d4c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -185,7 +185,7 @@ static void renderSurface(SP surface, int x, int y, void* da if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { Debug::log(TRACE, "presentFeedback for invisible surface"); - surface->presentFeedback(RDATA->when, RDATA->pMonitor); + surface->presentFeedback(RDATA->when, RDATA->pMonitor->self.lock()); } return; // invisible @@ -240,7 +240,7 @@ static void renderSurface(SP surface, int x, int y, void* da } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) - surface->presentFeedback(RDATA->when, RDATA->pMonitor); + surface->presentFeedback(RDATA->when, RDATA->pMonitor->self.lock()); g_pHyprOpenGL->blend(true); From c5fd5771814958ad274ea9abb961fff621a35b9c Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:37:52 +0200 Subject: [PATCH 0559/2393] config: Add a window rule to render while unfocused (#7582) --- src/config/ConfigDescriptions.hpp | 6 +++ src/config/ConfigManager.cpp | 3 +- src/desktop/Window.cpp | 5 +++ src/desktop/Window.hpp | 1 + src/managers/eventLoop/EventLoopTimer.cpp | 4 ++ src/managers/eventLoop/EventLoopTimer.hpp | 1 + src/render/Renderer.cpp | 50 +++++++++++++++++++++++ src/render/Renderer.hpp | 4 ++ 8 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 73b995ae..73f3c9a3 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1037,6 +1037,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "misc:render_unfocused_fps", + .description = "the maximum limit for renderunfocused windows' fps in the background", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{15, 1, 120}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f402958b..5940a6fe 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -357,6 +357,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:exit_window_retains_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); + m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); @@ -2155,7 +2156,7 @@ std::optional CConfigManager::handleUnbind(const std::string& comma bool windowRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{ - "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", + "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto rulesPrefix = std::vector{ "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7623d45e..a9e389a6 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -757,6 +757,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { if (m_sGroupData.pNextWindow.expired()) setHidden(false); } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); } + } else if (r.szRule == "renderunfocused") { + m_sWindowData.renderUnfocused = CWindowOverridableVar(true, priority); + g_pHyprRenderer->addWindowToRenderUnfocused(m_pSelf.lock()); } } @@ -774,6 +777,8 @@ void CWindow::updateDynamicRules() { m_sWindowData.activeBorderColor.unset(PRIORITY_WINDOW_RULE); m_sWindowData.inactiveBorderColor.unset(PRIORITY_WINDOW_RULE); + m_sWindowData.renderUnfocused.unset(PRIORITY_WINDOW_RULE); + m_eIdleInhibitMode = IDLEINHIBIT_NONE; m_tags.removeDynamicTags(); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 7197ba26..d14248c5 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -174,6 +174,7 @@ struct SWindowData { CWindowOverridableVar syncFullscreen = true; CWindowOverridableVar tearing = false; CWindowOverridableVar xray = false; + CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar rounding; CWindowOverridableVar borderSize; diff --git a/src/managers/eventLoop/EventLoopTimer.cpp b/src/managers/eventLoop/EventLoopTimer.cpp index d3cfdf8d..b8943b7c 100644 --- a/src/managers/eventLoop/EventLoopTimer.cpp +++ b/src/managers/eventLoop/EventLoopTimer.cpp @@ -49,3 +49,7 @@ float CEventLoopTimer::leftUs() { return std::chrono::duration_cast(*expires - std::chrono::steady_clock::now()).count(); } + +bool CEventLoopTimer::armed() { + return expires.has_value(); +} diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index ad7d3986..e5a8c5e3 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -16,6 +16,7 @@ class CEventLoopTimer { void cancel(); bool passed(); + bool armed(); float leftUs(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 420f8d4c..c5866e4a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -97,6 +97,44 @@ CHyprRenderer::CHyprRenderer() { m_pCursorTicker = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, cursorTicker, nullptr); wl_event_source_timer_update(m_pCursorTicker, 500); + + m_tRenderUnfocusedTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + static auto PFPS = CConfigValue("misc:render_unfocused_fps"); + + if (m_vRenderUnfocused.empty()) + return; + + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + bool dirty = false; + for (auto& w : m_vRenderUnfocused) { + if (!w) { + dirty = true; + continue; + } + + if (!w->m_pWLSurface || !w->m_pWLSurface->resource() || shouldRenderWindow(w.lock())) + continue; + + w->m_pWLSurface->resource()->frame(&now); + auto FEEDBACK = makeShared(w->m_pWLSurface->resource()); + FEEDBACK->attachMonitor(g_pCompositor->m_pLastMonitor.lock()); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + } + + if (dirty) + std::erase_if(m_vRenderUnfocused, [](const auto& e) { return !e || !e->m_sWindowData.renderUnfocused.valueOr(false); }); + + if (!m_vRenderUnfocused.empty()) + m_tRenderUnfocusedTimer->updateTimeout(std::chrono::milliseconds(1000 / *PFPS)); + }, + nullptr); + + g_pEventLoopManager->addTimer(m_tRenderUnfocusedTimer); } CHyprRenderer::~CHyprRenderer() { @@ -2800,3 +2838,15 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { return settings; } + +void CHyprRenderer::addWindowToRenderUnfocused(PHLWINDOW window) { + static auto PFPS = CConfigValue("misc:render_unfocused_fps"); + + if (std::find(m_vRenderUnfocused.begin(), m_vRenderUnfocused.end(), window) != m_vRenderUnfocused.end()) + return; + + m_vRenderUnfocused.emplace_back(window); + + if (!m_tRenderUnfocusedTimer->armed()) + m_tRenderUnfocusedTimer->updateTimeout(std::chrono::milliseconds(1000 / *PFPS)); +} diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index d00c0a17..b730d589 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -13,6 +13,7 @@ class CWorkspace; class CWindow; class CInputPopup; class IHLBuffer; +class CEventLoopTimer; // TODO: add fuller damage tracking for updating only parts of a window enum DAMAGETRACKINGMODES { @@ -78,6 +79,7 @@ class CHyprRenderer { void makeEGLCurrent(); void unsetEGL(); SExplicitSyncSettings getExplicitSyncSettings(); + void addWindowToRenderUnfocused(PHLWINDOW window); // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. @@ -143,6 +145,8 @@ class CHyprRenderer { SP getOrCreateRenderbuffer(SP buffer, uint32_t fmt); std::vector> m_vRenderbuffers; + std::vector m_vRenderUnfocused; + SP m_tRenderUnfocusedTimer; friend class CHyprOpenGLImpl; friend class CToplevelExportFrame; From 76b82fdde7d3f38cb70db0bec3318a7fb6c27a0c Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Sat, 31 Aug 2024 09:01:02 +0000 Subject: [PATCH 0560/2393] meson: explicitly specify path for find(1) (#7590) assets/install/meson.build:1:10: ERROR: Command `/bin/sh -c 'find -type f -not -name "*.build"'` failed with status 1. --- assets/install/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/install/meson.build b/assets/install/meson.build index 19b49638..1d4fb917 100644 --- a/assets/install/meson.build +++ b/assets/install/meson.build @@ -1,4 +1,4 @@ -globber = run_command('sh', '-c', 'find -type f -not -name "*.build"', check: true) +globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: true) files = globber.stdout().strip().split('\n') foreach file : files From 838ed87d6ffae0dbdc8a3ecaac2c8be006f6d053 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 08:07:52 -0500 Subject: [PATCH 0561/2393] renderer: minor direct scanout fixes (#7594) --- src/helpers/Monitor.cpp | 15 +++++++++++++++ src/helpers/Monitor.hpp | 3 ++- src/render/Renderer.cpp | 9 ++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 685009fd..5b01d651 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -832,6 +832,21 @@ bool CMonitor::attemptDirectScanout() { // FIXME: make sure the buffer actually follows the available scanout dmabuf formats // and comes from the appropriate device. This may implode on multi-gpu!! + + const auto params = PSURFACE->current.buffer->buffer->dmabuf(); + // scanout buffer isn't dmabuf, so no scanout + if (!params.success) + return false; + + // entering into scanout, so save monitor format + if (lastScanout.expired()) + prevDrmFormat = drmFormat; + + if (drmFormat != params.format) { + output->state->setFormat(params.format); + drmFormat = params.format; + } + output->state->setBuffer(PSURFACE->current.buffer->buffer.lock()); output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE : Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 01a5d28d..203cac90 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -100,7 +100,8 @@ class CMonitor { std::optional forceSize; SP currentMode; SP cursorSwapchain; - uint32_t drmFormat = DRM_FORMAT_INVALID; + uint32_t drmFormat = DRM_FORMAT_INVALID; + uint32_t prevDrmFormat = DRM_FORMAT_INVALID; bool dpmsStatus = true; bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it. diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c5866e4a..27fde129 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1277,7 +1277,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->lastScanout.reset(); // reset DRM format, make sure it's the one we want. - pMonitor->output->state->setFormat(pMonitor->drmFormat); + pMonitor->output->state->setFormat(pMonitor->prevDrmFormat); + pMonitor->drmFormat = pMonitor->prevDrmFormat; } } @@ -1978,7 +1979,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); - pMonitor->drmFormat = DRM_FORMAT_XRGB8888; + pMonitor->prevDrmFormat = pMonitor->drmFormat; + pMonitor->drmFormat = DRM_FORMAT_XRGB8888; pMonitor->output->state->resetExplicitFences(); bool autoScale = false; @@ -2219,7 +2221,8 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR for (auto const& fmt : formats[(int)!RULE->enable10bit]) { pMonitor->output->state->setFormat(fmt.second); - pMonitor->drmFormat = fmt.second; + pMonitor->prevDrmFormat = pMonitor->drmFormat; + pMonitor->drmFormat = fmt.second; if (!pMonitor->state.test()) { Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first); From 10d7219807dd726d231e8df53a357018f5526432 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sat, 31 Aug 2024 13:51:19 +0300 Subject: [PATCH 0562/2393] CI: clarify Nix CI jobs; disable on forked repositories --- .github/workflows/nix-build.yml | 4 +++- .github/workflows/nix-ci.yml | 4 ++-- .github/workflows/nix-update-inputs.yml | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index d0234498..ed0c2ae1 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -1,3 +1,5 @@ +name: Nix (Build) + on: workflow_call: secrets: @@ -25,6 +27,6 @@ jobs: - uses: cachix/cachix-action@v15 with: name: hyprland - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index b25ed9aa..2f35337d 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -1,10 +1,10 @@ -name: Nix +name: Nix (CI) on: [push, pull_request, workflow_dispatch] jobs: update-inputs: - if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') uses: ./.github/workflows/nix-update-inputs.yml secrets: inherit diff --git a/.github/workflows/nix-update-inputs.yml b/.github/workflows/nix-update-inputs.yml index 000900d9..a8f68f3b 100644 --- a/.github/workflows/nix-update-inputs.yml +++ b/.github/workflows/nix-update-inputs.yml @@ -1,4 +1,4 @@ -name: Nix +name: Nix (Update Inputs) on: workflow_call: @@ -8,6 +8,7 @@ on: jobs: update: + if: github.repository == 'hyprwm/Hyprland' name: inputs runs-on: ubuntu-latest steps: From cf6a1716ae719f9c59b1d175ca84a79015fab8e1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 31 Aug 2024 18:32:57 +0200 Subject: [PATCH 0563/2393] syncobj: wait for deadline instead of available avoids slow apps from lagging the desktop --- src/protocols/DRMSyncobj.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 4993f1a4..e0c90a3b 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -58,8 +58,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + // wait for the buffer to be released by the gpu before sending a commit to avoid lagging the desktop + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -70,7 +70,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); }); listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { From 1ac2fc3f7e538e47a5cb8fdef60d701987fe63ed Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:07:23 -0500 Subject: [PATCH 0564/2393] protocols: destroy new xdgDialog protocol at right time (#7600) --- src/managers/ProtocolManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 2c421abe..6b6d5acf 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -221,6 +221,7 @@ CProtocolManager::~CProtocolManager() { PROTO::screencopy.reset(); PROTO::toplevelExport.reset(); PROTO::globalShortcuts.reset(); + PROTO::xdgDialog.reset(); PROTO::lease.reset(); PROTO::sync.reset(); From cac59fefecaefe34be45e65713d54676444f88a2 Mon Sep 17 00:00:00 2001 From: TheMical <85638851+TheMical@users.noreply.github.com> Date: Sat, 31 Aug 2024 15:43:02 -0400 Subject: [PATCH 0565/2393] data-device: Fix selection mismatch when wlr resets primary selection (#7598) --- src/protocols/DataDeviceWlr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index d2d06644..69e28772 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -133,7 +133,7 @@ CWLRDataDevice::CWLRDataDevice(SP resource_) : resourc auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; if (!source) { LOGM(LOG, "wlr reset primary selection received"); - g_pSeatManager->setCurrentSelection(nullptr); + g_pSeatManager->setCurrentPrimarySelection(nullptr); return; } From a6315b0af4e417cf396649d9c5792d3c5420b713 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:55:08 -0500 Subject: [PATCH 0566/2393] core: fix crash on monitor removed with gammaControl (#7601) * fix crash on monitor removed with gammaControl * Update GammaControl.cpp --- src/protocols/GammaControl.cpp | 14 +++++++------- src/protocols/GammaControl.hpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index cb75a202..d7992981 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -17,7 +17,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out return; } - pMonitor = OUTPUTRES->monitor.get(); + pMonitor = OUTPUTRES->monitor; if (!pMonitor) { LOGM(ERR, "No CMonitor"); @@ -103,7 +103,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->sendGammaSize(gammaSize); listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); }); - listeners.monitorDisconnect = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); }); + listeners.monitorDisconnect = pMonitor->events.disconnect.registerListener([this](std::any) { this->onMonitorDestroy(); }); } CGammaControl::~CGammaControl() { @@ -119,7 +119,7 @@ bool CGammaControl::good() { } void CGammaControl::applyToMonitor() { - if (!pMonitor) + if (!pMonitor || !pMonitor->output) return; // ?? LOGM(LOG, "setting to monitor {}", pMonitor->szName); @@ -136,16 +136,16 @@ void CGammaControl::applyToMonitor() { pMonitor->output->state->setGammaLut({}); } - g_pHyprRenderer->damageMonitor(pMonitor); + g_pHyprRenderer->damageMonitor(pMonitor.get()); } CMonitor* CGammaControl::getMonitor() { - return pMonitor; + return pMonitor ? pMonitor.get() : nullptr; } void CGammaControl::onMonitorDestroy() { + LOGM(LOG, "Destroying gamma control for {}", pMonitor->szName); resource->sendFailed(); - pMonitor = nullptr; } CGammaControlProtocol::CGammaControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { @@ -187,4 +187,4 @@ void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) { g->applyToMonitor(); break; } -} \ No newline at end of file +} diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 963eea5c..bbdc0139 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -20,7 +20,7 @@ class CGammaControl { private: SP resource; - CMonitor* pMonitor = nullptr; + WP pMonitor; size_t gammaSize = 0; bool gammaTableSet = false; std::vector gammaTable; // [r,g,b]+ From 4af9410dc2d0e241276a0797d3f3d276310d956e Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 1 Sep 2024 12:04:28 +0200 Subject: [PATCH 0567/2393] xwm: read atom name from xcb (#7546) expand the debug trace logging by actually reading the atom name from xcb if not found in HYPRATOMS, will also print the proper atom for xcb internal ones and not just the HYPRATOMS ones. --- src/xwayland/XWM.cpp | 34 ++++++++++++++++++++++++---------- src/xwayland/XWM.hpp | 1 + 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index b5762762..cb4d8f4d 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -158,18 +158,32 @@ static bool lookupParentExists(SP XSURF, SP return false; } +std::string CXWM::getAtomName(uint32_t atom) { + for (auto const& ha : HYPRATOMS) { + if (ha.second != atom) + continue; + + return ha.first; + } + + // Get the name of the atom + auto const atom_name_cookie = xcb_get_atom_name(connection, atom); + auto* atom_name_reply = xcb_get_atom_name_reply(connection, atom_name_cookie, NULL); + + if (!atom_name_reply) + return "Unknown"; + + auto const name_len = xcb_get_atom_name_name_length(atom_name_reply); + auto* name = xcb_get_atom_name_name(atom_name_reply); + free(atom_name_reply); + + return {name, name_len}; +} + void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply) { std::string propName; - if (Debug::trace) { - propName = std::format("{}?", atom); - for (auto const& ha : HYPRATOMS) { - if (ha.second != atom) - continue; - - propName = ha.first; - break; - } - } + if (Debug::trace) + propName = getAtomName(atom); if (atom == XCB_ATOM_WM_CLASS) { size_t len = xcb_get_property_value_length(reply); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 7d6b63ed..59695720 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -119,6 +119,7 @@ class CXWM { std::string mimeFromAtom(xcb_atom_t atom); void setClipboardToWayland(SXSelection& sel); void getTransferData(SXSelection& sel); + std::string getAtomName(uint32_t atom); void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); // From 5b1375141bd77c26023fb4a8dc087272be82849a Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 17:18:50 +0300 Subject: [PATCH 0568/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- nix/default.nix | 7 +++++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index b26cd5e3..a3f905d8 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725016199, - "narHash": "sha256-2TMk7F2a27ZtOUW/bftkDyZKp3OQ71E5XnfKSUT8HZQ=", + "lastModified": 1725199881, + "narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "cff00196f0fcf734a2bf164eb0dfdb6e58c5c906", + "rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1724174162, - "narHash": "sha256-fOOBLwil6M9QWMCiSULwjMQzrXhHXUnEqmjHX5ZHeVI=", + "lastModified": 1725188252, + "narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "16e5c9465f04477d8a3dd48a0a26bf437986336c", + "rev": "c12ab785ce1982f82594aff03b3104c598186ddd", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1724819573, - "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", + "lastModified": 1725103162, + "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", + "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", "type": "github" }, "original": { diff --git a/nix/default.nix b/nix/default.nix index 64796a90..6a4979f1 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -89,6 +89,10 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov DIRTY = lib.optionalString (commit == "") "dirty"; HASH = commit; + depsBuildBuild = [ + pkg-config + ]; + nativeBuildInputs = [ hyprwayland-scanner jq @@ -97,8 +101,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov ninja pkg-config python3 # for udis86 - # re-add after https://github.com/NixOS/nixpkgs/pull/214906 hits nixos-unstable - # wayland-scanner + wayland-scanner ]; outputs = [ From 4b5b8a763073593ac48af3bdcf04cf65b219120b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 18:14:14 +0300 Subject: [PATCH 0569/2393] flake.lock: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a3f905d8..5921488e 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1724073926, - "narHash": "sha256-nWlUL43jOFHf+KW6Hqrx+W/r1XdXuDyb0wC/SrHsOu4=", + "lastModified": 1725203619, + "narHash": "sha256-Am4gwnu5q+6GFKQ3NnEkXeZYKIZ9rv9mRLk+DYqX9Zs=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "a08ecbbf33598924e93542f737fc6169a26b481e", + "rev": "8e5ca2a299e95a3bdcdb84cfbe08f31b0690ecd5", "type": "github" }, "original": { From 7a24e564f43d4c24abf2ec4e5351007df2f8926c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 1 Sep 2024 19:37:25 +0300 Subject: [PATCH 0570/2393] flake.lock: update xdph again --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 5921488e..99a544e2 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725203619, - "narHash": "sha256-Am4gwnu5q+6GFKQ3NnEkXeZYKIZ9rv9mRLk+DYqX9Zs=", + "lastModified": 1725203932, + "narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "8e5ca2a299e95a3bdcdb84cfbe08f31b0690ecd5", + "rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251", "type": "github" }, "original": { From 8bbeee20414bc0e20992076632d7d44ede443a1c Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 2 Sep 2024 01:44:33 +0900 Subject: [PATCH 0571/2393] textinput: send deactivate to ime on destory ti (#7614) --- src/managers/input/TextInput.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 5bff9fed..711935a7 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,9 +23,7 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { - const auto INPUT = pV3Input.lock(); - if (INPUT && INPUT->current.enabled && focusedSurface()) - g_pInputManager->m_sIMERelay.deactivateIME(this); + g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); }); } else { @@ -40,6 +38,7 @@ void CTextInput::initCallbacks() { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); }); } @@ -192,7 +191,7 @@ wl_client* CTextInput::client() { } void CTextInput::commitStateToIME(SP ime) { - if (isV3()) { + if (isV3() && !pV3Input.expired()) { const auto INPUT = pV3Input.lock(); if (INPUT->current.surrounding.updated) @@ -202,7 +201,7 @@ void CTextInput::commitStateToIME(SP ime) { if (INPUT->current.contentType.updated) ime->textContentType(INPUT->current.contentType.hint, INPUT->current.contentType.purpose); - } else { + } else if (!pV1Input.expired()) { const auto INPUT = pV1Input.lock(); if (INPUT->pendingSurrounding.isPending) From 6934e7aa2b300bc4565855a4092fb34de8a9a8d2 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 2 Sep 2024 04:33:31 +0900 Subject: [PATCH 0572/2393] textinput: don't deactivate ime if another ti is focused (#7617) --- src/managers/input/TextInput.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 711935a7..de14f1ab 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,8 +23,9 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { - g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } else { const auto INPUT = pV1Input.lock(); @@ -38,8 +39,9 @@ void CTextInput::initCallbacks() { listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - g_pInputManager->m_sIMERelay.deactivateIME(this); g_pInputManager->m_sIMERelay.removeTextInput(this); + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } } From f7249bd3317e79b9cb1564f2497df510f7a166bb Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Sep 2024 14:51:56 +0200 Subject: [PATCH 0573/2393] CMake: drop duplicate -luuid after 5262292abc56 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dba14813..ef3f4021 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,7 +266,7 @@ function(protocolWayland) endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads - libudis86 uuid) + libudis86) protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-global-shortcuts-v1" true) From fa39df4731e200fab031f01757ded9920a1d473d Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 2 Sep 2024 15:05:39 +0200 Subject: [PATCH 0574/2393] CMake: drop unused deps after 016da234d0e8 Found via LDFLAGS += -Wl,--as-needed (default in Meson). Some dependencies are only used by aquamarine. --- CMakeLists.txt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ef3f4021..d8424d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,6 @@ pkg_check_modules( xkbcommon uuid wayland-server - wayland-client - wayland-cursor wayland-protocols cairo pango @@ -109,11 +107,6 @@ pkg_check_modules( xcursor libdrm libinput - hwdata - libseat - libdisplay-info - libliftoff - libudev gbm gio-2.0 hyprlang>=0.3.2 @@ -200,14 +193,11 @@ else() REQUIRED IMPORTED_TARGET xcb - xwayland - xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res - xcb-ewmh xcb-errors) target_link_libraries(Hyprland PkgConfig::xdeps) endif() From 8f9887b0c9443d6c2559feeec411daecb9780a97 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 2 Sep 2024 23:09:44 +0300 Subject: [PATCH 0575/2393] Nix: remove unused dependencies --- nix/default.nix | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 6a4979f1..e1a348b0 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -9,33 +9,22 @@ aquamarine, binutils, cairo, - expat, - fribidi, git, - hwdata, hyprcursor, hyprlang, hyprutils, hyprwayland-scanner, jq, libGL, - libdatrie, - libdisplay-info, libdrm, libexecinfo, libinput, - libliftoff, - libselinux, - libsepol, - libthai, - libuuid, libxkbcommon, + libuuid, mesa, pango, pciutils, - pcre2, python3, - seatd, systemd, tomlplusplus, wayland, @@ -114,29 +103,25 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov [ aquamarine cairo - expat - fribidi + # expat + # fribidi git - hwdata hyprcursor hyprlang hyprutils - libdatrie - libdisplay-info + # libdatrie libdrm libGL libinput - libliftoff - libselinux - libsepol - libthai + # libselinux + # libsepol + # libthai libuuid libxkbcommon mesa pango pciutils - pcre2 - seatd + # pcre2 tomlplusplus wayland wayland-protocols @@ -146,7 +131,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals enableXWayland [ xorg.libxcb xorg.libXdmcp - xorg.xcbutil xorg.xcbutilerrors xorg.xcbutilrenderutil xorg.xcbutilwm From 9b54342baa27d8de0460e1103ec4c3cc65592ed8 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 3 Sep 2024 14:47:34 +0200 Subject: [PATCH 0576/2393] Revert "syncobj: wait for deadline instead of available" This reverts commit cf6a1716ae719f9c59b1d175ca84a79015fab8e1. Fixes #7628 --- src/protocols/DRMSyncobj.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index e0c90a3b..4993f1a4 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -58,8 +58,8 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPtimeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); + // wait for the acquire timeline to materialize + auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); if (!materialized.has_value()) { LOGM(ERR, "Failed to check the acquire timeline"); resource->noMemory(); @@ -70,7 +70,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); - pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE); + pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); }); listeners.surfaceCommit = surface->events.roleCommit.registerListener([this](std::any d) { From ea10592ad3c861ff2ce73ad7785bcb5a45a9e400 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 4 Sep 2024 10:23:29 +0000 Subject: [PATCH 0577/2393] input: don't emit idle activity when calling simulateMouseMovement (#7649) --- src/managers/input/InputManager.cpp | 6 +++--- src/managers/input/InputManager.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 78c9e437..d7ccc5e4 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -111,7 +111,7 @@ void CInputManager::simulateMouseMovement() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus. - mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000); + mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000, false, true); } void CInputManager::sendMotionEventsToFocused() { @@ -132,7 +132,7 @@ void CInputManager::sendMotionEventsToFocused() { g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } -void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { +void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); @@ -171,7 +171,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED); - if (time) + if (time && !silent) PROTO::idle->onActivity(); m_vLastCursorPosFloored = MOUSECOORDSFLOORED; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index ebf00b2d..70e4d40f 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -237,7 +237,7 @@ class CInputManager { uint32_t m_uiCapabilities = 0; - void mouseMoveUnified(uint32_t, bool refocus = false); + void mouseMoveUnified(uint32_t, bool refocus = false, bool silent = false); SP ensureTabletToolPresent(SP); From 027140b7315efe3cd2e7b78fa608bd36da839894 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:59:00 +0000 Subject: [PATCH 0578/2393] sessionLock: ensure sls focus in some edge cases (#7647) * input: return early in mouseMoveUnified when the session is locked * sessionLock: make make a commit an opportunity to focus session lock surfaces * compositor: allow resetting focus when session is locked * input: remove redundant PMONITOR checks PMONITOR is checked above * input: check isSessionLocked earlier in mouseMoveUnified A bit of reordering, so that we don't call some stuff that is irrelevant when the session is locked --- src/Compositor.cpp | 2 +- src/managers/SessionLockManager.cpp | 3 ++ src/managers/input/InputManager.cpp | 56 ++++++++++++++--------------- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index eac75bd4..ba9ff96b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1117,7 +1117,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo if (g_pSeatManager->state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->state.keyboardFocus == pWindowOwner->m_pWLSurface->resource())) return; // Don't focus when already focused on this. - if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) + if (g_pSessionLockManager->isSessionLocked() && pSurface && !g_pSessionLockManager->isSurfaceSessionLock(pSurface)) return; if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(pSurface)) { diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 7267b8f2..260a3992 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -30,6 +30,9 @@ SSessionLockSurface::SSessionLockSurface(SP surface_) : sur listeners.commit = surface_->events.commit.registerListener([this](std::any data) { const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); + if (mapped && pWlrSurface != g_pCompositor->m_pLastFocus) + g_pInputManager->simulateMouseMovement(); + if (PMONITOR) g_pHyprRenderer->damageMonitor(PMONITOR); }); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index d7ccc5e4..cdf7d615 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -153,7 +153,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { Vector2D surfacePos = Vector2D(-1337, -1337); PHLWINDOW pFoundWindow; PHLLS pFoundLayerSurface; - SSessionLockSurface* pSessionLock = nullptr; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -190,17 +189,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); - PHLWINDOW forcedFocus = m_pForcedFocus.lock(); - - if (!forcedFocus) - forcedFocus = g_pCompositor->getForceFocus(); - - if (forcedFocus) { - pFoundWindow = forcedFocus; - surfacePos = pFoundWindow->m_vRealPosition.value(); - foundSurface = pFoundWindow->m_pWLSurface->resource(); - } - // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); @@ -227,6 +215,33 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get()); } + if (PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) + g_pCompositor->setActiveMonitor(PMONITOR); + + if (g_pSessionLockManager->isSessionLocked()) { + const auto PSESSIONLOCKSURFACE = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID); + surfacePos = PMONITOR->vecPosition; + + foundSurface = PSESSIONLOCKSURFACE ? PSESSIONLOCKSURFACE->surface->surface() : nullptr; + g_pCompositor->focusSurface(foundSurface); + + const auto SURFACELOCAL = mouseCoords - surfacePos; + g_pSeatManager->setPointerFocus(foundSurface, SURFACELOCAL); + g_pSeatManager->sendPointerMotion(time, SURFACELOCAL); + return; + } + + PHLWINDOW forcedFocus = m_pForcedFocus.lock(); + + if (!forcedFocus) + forcedFocus = g_pCompositor->getForceFocus(); + + if (forcedFocus) { + pFoundWindow = forcedFocus; + surfacePos = pFoundWindow->m_vRealPosition.value(); + foundSurface = pFoundWindow->m_pWLSurface->resource(); + } + // if we are holding a pointer button, // and we're not dnd-ing, don't refocus. Keep focus on last surface. if (!PROTO::data->dndActive() && !m_lCurrentlyHeldButtons.empty() && g_pCompositor->m_pLastFocus && g_pSeatManager->state.pointerFocus && !m_bHardInput) { @@ -258,19 +273,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal()); - if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) - g_pCompositor->setActiveMonitor(PMONITOR); - - if (g_pSessionLockManager->isSessionLocked()) { - pSessionLock = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; - - if (!pSessionLock) - return; - - foundSurface = pSessionLock->surface->surface(); - surfacePos = PMONITOR->vecPosition; - } - if (!foundSurface) foundSurface = g_pCompositor->vectorToLayerPopupSurface(mouseCoords, PMONITOR, &surfaceCoords, &pFoundLayerSurface); @@ -460,9 +462,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { restoreCursorIconToApp(); } - if (pSessionLock != nullptr) - g_pCompositor->focusSurface(foundSurface); - else if (pFoundWindow) { + if (pFoundWindow) { // change cursor icon if hovering over border if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (!pFoundWindow->isFullscreen() && !pFoundWindow->hasPopupAt(mouseCoords)) { From bd6d6e7f3378c08fe48c179ba4ec3517fe10ae3f Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:26:46 -0500 Subject: [PATCH 0579/2393] xwayland: add option to enable/disable xwayland (#7633) * config: add xwayland enabled option to config * xwayland: use DISPLAY env variable for enable/disable of new launches * xwayland: close X11 windows when turning of XWayland * clang: format fix * config: add better description for xwayland:enabled * xwayland: close X11 windows on disable without crashes * xwayland: better method of informing CXWayland if xwayland enabled * xwayland: prevent closing non-xwayland windows on disable * misc: loop formatting --- src/Compositor.cpp | 2 +- src/Compositor.hpp | 1 + src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 25 +++++++++++++++++++++++++ src/xwayland/Server.cpp | 3 ++- src/xwayland/XWM.cpp | 4 ++++ src/xwayland/XWayland.cpp | 9 +++++++-- src/xwayland/XWayland.hpp | 4 ++-- 8 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ba9ff96b..da659654 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -615,7 +615,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pCursorManager = std::make_unique(); Debug::log(LOG, "Starting XWayland"); - g_pXWayland = std::make_unique(); + g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); } break; default: UNREACHABLE(); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index bb986f5e..f17d86e5 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -92,6 +92,7 @@ class CCompositor { CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; bool m_bDesktopEnvSet = false; + bool m_bEnableXwayland = true; // ------------------------------------------------- // diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 73f3c9a3..00ebde6a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1115,6 +1115,12 @@ inline static const std::vector CONFIG_OPTIONS = { * xwayland: */ + SConfigOptionDescription{ + .value = "xwayland:enabled", + .description = "allow running applications using X11", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "xwayland:use_nearest_neighbor", .description = "uses the nearest neighbor filtering for xwayland apps, making them pixelated rather than blurry", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5940a6fe..740dbbdf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -6,6 +6,7 @@ #include "config/ConfigValue.hpp" #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" +#include "../xwayland/XWayland.hpp" #include #include @@ -523,6 +524,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("gestures:workspace_swipe_touch", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_touch_invert", Hyprlang::INT{0}); + m_pConfig->addConfigValue("xwayland:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); @@ -860,6 +862,29 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { ensureVRR(); } +#ifndef NO_XWAYLAND + const auto PENABLEXWAYLAND = std::any_cast(m_pConfig->getConfigValue("xwayland:enabled")); + // enable/disable xwayland usage + if (!isFirstLaunch) { + bool prevEnabledXwayland = g_pCompositor->m_bEnableXwayland; + if (PENABLEXWAYLAND != prevEnabledXwayland) { + g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; + if (PENABLEXWAYLAND) { + Debug::log(LOG, "xwayland has been enabled"); + } else { + Debug::log(LOG, "xwayland has been disabled, cleaning up..."); + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_pXDGSurface || !w->m_bIsX11) + continue; + g_pCompositor->closeWindow(w); + } + } + g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); + } + } else + g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; +#endif + if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState) refreshGroupBarGradients(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 200bec70..f3bf5768 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -432,7 +432,8 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { pipeSource = nullptr; // start the wm - g_pXWayland->pWM = std::make_unique(); + if (!g_pXWayland->pWM) + g_pXWayland->pWM = std::make_unique(); g_pCursorManager->setXWaylandCursor(); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index cb4d8f4d..e8e2258a 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -890,6 +890,10 @@ CXWM::~CXWM() { if (eventSource) wl_event_source_remove(eventSource); + + for (auto const& sr : surfaces) { + sr->events.destroy.emit(); + } } void CXWM::setActiveWindow(xcb_window_t window) { diff --git a/src/xwayland/XWayland.cpp b/src/xwayland/XWayland.cpp index 8d45fa63..8cdb1fca 100644 --- a/src/xwayland/XWayland.cpp +++ b/src/xwayland/XWayland.cpp @@ -1,12 +1,17 @@ #include "XWayland.hpp" #include "../debug/Log.hpp" -CXWayland::CXWayland() { +CXWayland::CXWayland(const bool enabled) { #ifndef NO_XWAYLAND Debug::log(LOG, "Starting up the XWayland server"); pServer = std::make_unique(); + if (!enabled) { + unsetenv("DISPLAY"); + return; + } + if (!pServer->create()) { Debug::log(ERR, "XWayland failed to start: it will not work."); return; @@ -25,4 +30,4 @@ void CXWayland::setCursor(unsigned char* pixData, uint32_t stride, const Vector2 pWM->setCursor(pixData, stride, size, hotspot); #endif -} \ No newline at end of file +} diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index 40c0ba65..96253d19 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -17,7 +17,7 @@ class CXWM; class CXWayland { public: - CXWayland(); + CXWayland(const bool enabled); #ifndef NO_XWAYLAND std::unique_ptr pServer; @@ -126,4 +126,4 @@ inline std::unordered_map HYPRATOMS = { HYPRATOM("DELETE"), HYPRATOM("TEXT"), HYPRATOM("INCR"), -}; \ No newline at end of file +}; From 4a42c5ed20a6852e5e51c0f3893024f3b5c03500 Mon Sep 17 00:00:00 2001 From: Parola Marco Date: Thu, 5 Sep 2024 18:29:33 +0200 Subject: [PATCH 0580/2393] config: Add a variable to prevent groups from merging after being dragged (#7650) * config: Add a variable to prevent groups from merging after being dragged * Fixed code style for [f777f028] --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 6 +++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 00ebde6a..44b5ee4a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -742,6 +742,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:merge_groups_on_drag", + .description = "whether window groups can be dragged into other groups", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "general:col.border_active", .description = "border color for inactive windows", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 740dbbdf..b16b7747 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -362,6 +362,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index a9e389a6..cc5b48af 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -951,12 +951,16 @@ int CWindow::getGroupSize() { } bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) { + static auto ALLOWGROUPMERGE = CConfigValue("group:merge_groups_on_drag"); + bool isGroup = m_sGroupData.pNextWindow; + bool disallowDragIntoGroup = g_pInputManager->m_bWasDraggingWindow && isGroup && !bool(*ALLOWGROUPMERGE); return !g_pKeybindManager->m_bGroupsLocked // global group lock disengaged && ((m_eGroupRules & GROUP_INVADE && m_bFirstMap) // window ignore local group locks, or || (!pWindow->getGroupHead()->m_sGroupData.locked // target unlocked && !(m_sGroupData.pNextWindow.lock() && getGroupHead()->m_sGroupData.locked))) // source unlocked or isn't group && !m_sGroupData.deny // source is not denied entry - && !(m_eGroupRules & GROUP_BARRED && m_bFirstMap); // group rule doesn't prevent adding window + && !(m_eGroupRules & GROUP_BARRED && m_bFirstMap) // group rule doesn't prevent adding window + && !disallowDragIntoGroup; // config allows groups to be merged } PHLWINDOW CWindow::getGroupWindowByIndex(int index) { From c80457be02e7b75b590e025708fad38d84c99026 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 21 Jul 2024 20:54:57 +0300 Subject: [PATCH 0581/2393] nix: add COMMITS var --- nix/default.nix | 3 ++- nix/overlays.nix | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index e1a348b0..1c6a0113 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -39,6 +39,7 @@ wrapRuntimeDeps ? true, version ? "git", commit, + revCount, date, # deprecated flags enableNvidiaPatches ? false, @@ -73,7 +74,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov sed -i "s#@PREFIX@/##g" hyprland.pc.in ''; - COMMITS = commit; + COMMITS = revCount; DATE = date; DIRTY = lib.optionalString (commit == "") "dirty"; HASH = commit; diff --git a/nix/overlays.nix b/nix/overlays.nix index 36206f46..d6e078fa 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -34,6 +34,7 @@ in { stdenv = final.gcc14Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; + revCount = self.sourceInfo.revCount or ""; inherit date; }; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; From 727f1b54cd1ba48774092a5d54acc0e55f3ffe0f Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 6 Sep 2024 04:04:23 +0900 Subject: [PATCH 0582/2393] textinput: fix ime activation in some edge cases (#7660) * textinput: clear ti3 state when focused surface gets destroyed * textinput: send enter to newly created ti in focus --- src/managers/input/TextInput.cpp | 46 +++++++++++++++++++++++--------- src/protocols/TextInputV3.cpp | 13 +++++---- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index de14f1ab..4c2e326a 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -23,10 +23,15 @@ void CTextInput::initCallbacks() { listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); g_pInputManager->m_sIMERelay.removeTextInput(this); if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); }); + + if (!g_pCompositor->m_pLastFocus.expired() && g_pCompositor->m_pLastFocus->client() == INPUT->client()) + enter(g_pCompositor->m_pLastFocus.lock()); } else { const auto INPUT = pV1Input.lock(); @@ -72,15 +77,19 @@ void CTextInput::onDisabled() { return; } - if (!focusedSurface()) - return; - if (!isV3()) leave(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + if (!focusedSurface()) + return; + + const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput(); + if (!PFOCUSEDTI || PFOCUSEDTI != this) + return; + g_pInputManager->m_sIMERelay.deactivateIME(this); } @@ -104,12 +113,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface = pSurface; - listeners.surfaceUnmap.reset(); - listeners.surfaceDestroy.reset(); - if (!pSurface) return; + listeners.surfaceUnmap.reset(); + listeners.surfaceDestroy.reset(); + listeners.surfaceUnmap = pSurface->events.unmap.registerListener([this](std::any d) { Debug::log(LOG, "Unmap TI owner1"); @@ -118,6 +127,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface.reset(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) + pV3Input->current.enabled = false; + + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); listeners.surfaceDestroy = pSurface->events.destroy.registerListener([this](std::any d) { @@ -128,6 +143,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { pFocusedSurface.reset(); listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); + + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) + pV3Input->current.enabled = false; + + if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) + g_pInputManager->m_sIMERelay.deactivateIME(this); }); } @@ -142,10 +163,8 @@ void CTextInput::enter(SP pSurface) { if (pSurface == focusedSurface()) return; - if (focusedSurface()) { + if (focusedSurface()) leave(); - setFocusedSurface(nullptr); - } enterLocks++; if (enterLocks != 1) { @@ -173,11 +192,14 @@ void CTextInput::leave() { enterLocks = 0; } - if (isV3() && focusedSurface()) + if (isV3()) { pV3Input->leave(focusedSurface()); - else if (focusedSurface() && pV1Input) { + if (pV3Input->current.enabled) { + pV3Input->current.enabled = false; + onDisabled(); + } + } else pV1Input->leave(); - } setFocusedSurface(nullptr); diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 99d799f3..42dc659e 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -24,10 +24,9 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) current = pending; serial++; - if (wasEnabled && !current.enabled) { - current.reset(); + if (wasEnabled && !current.enabled) events.disable.emit(); - } else if (!wasEnabled && current.enabled) + else if (!wasEnabled && current.enabled) events.enable.emit(); else events.onCommit.emit(); @@ -53,12 +52,12 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) pending.box.cursorBox = {x, y, w, h}; }); - resource->setEnable([this](CZwpTextInputV3* r) { pending.enabled = true; }); - - resource->setDisable([this](CZwpTextInputV3* r) { - pending.enabled = false; + resource->setEnable([this](CZwpTextInputV3* r) { pending.reset(); + pending.enabled = true; }); + + resource->setDisable([this](CZwpTextInputV3* r) { pending.enabled = false; }); } CTextInputV3::~CTextInputV3() { From 0fad7a0bb03d4181901952a0df620d42ab6bbe4d Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 6 Sep 2024 08:54:01 +0900 Subject: [PATCH 0583/2393] workspacerules: fix on-created-empty window focus (#7657) --- src/desktop/Workspace.cpp | 2 +- src/managers/KeybindManager.cpp | 32 ++++++++++++++++++++------------ src/managers/KeybindManager.hpp | 3 ++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 35fc5727..2d92659c 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -51,7 +51,7 @@ void CWorkspace::init(PHLWORKSPACE self) { if (self->m_bWasCreatedEmpty) if (auto cmd = WORKSPACERULE.onCreatedEmptyRunCmd) - g_pKeybindManager->spawn(*cmd); + g_pKeybindManager->spawnWithRules(*cmd, self); g_pEventManager->postEvent({"createworkspace", m_szName}); g_pEventManager->postEvent({"createworkspacev2", std::format("{},{}", m_iID, m_szName)}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7ee5ae7e..2db9f375 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -34,7 +34,7 @@ using namespace Hyprutils::String; #include #endif -static std::vector> getHyprlandLaunchEnv() { +static std::vector> getHyprlandLaunchEnv(PHLWORKSPACE pInitialWorkspace) { static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); if (!*PINITIALWSTRACKING || g_pConfigManager->isLaunchingExecOnce) @@ -46,11 +46,15 @@ static std::vector> getHyprlandLaunchEnv() { std::vector> result; - result.push_back(std::make_pair<>( - "HL_INITIAL_WORKSPACE_TOKEN", - g_pTokenManager->registerNewToken( - SInitialWorkspaceToken{{}, PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace->getConfigName() : PMONITOR->activeWorkspace->getConfigName()}, - std::chrono::months(1337)))); + if (!pInitialWorkspace) { + if (PMONITOR->activeSpecialWorkspace) + pInitialWorkspace = PMONITOR->activeSpecialWorkspace; + else + pInitialWorkspace = PMONITOR->activeWorkspace; + } + + result.push_back(std::make_pair<>("HL_INITIAL_WORKSPACE_TOKEN", + g_pTokenManager->registerNewToken(SInitialWorkspaceToken{{}, pInitialWorkspace->getConfigName()}, std::chrono::months(1337)))); return result; } @@ -846,8 +850,12 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { } // Dispatchers - SDispatchResult CKeybindManager::spawn(std::string args) { + const uint64_t PROC = spawnWithRules(args, nullptr); + return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; +} + +uint64_t CKeybindManager::spawnWithRules(std::string args, PHLWORKSPACE pInitialWorkspace) { args = trim(args); @@ -859,7 +867,7 @@ SDispatchResult CKeybindManager::spawn(std::string args) { args = args.substr(args.find_first_of(']') + 1); } - const uint64_t PROC = spawnRawProc(args); + const uint64_t PROC = spawnRawProc(args, pInitialWorkspace); if (!RULES.empty()) { const auto RULESLIST = CVarList(RULES, 0, ';'); @@ -871,18 +879,18 @@ SDispatchResult CKeybindManager::spawn(std::string args) { Debug::log(LOG, "Applied {} rule arguments for exec.", RULESLIST.size()); } - return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; + return PROC; } SDispatchResult CKeybindManager::spawnRaw(std::string args) { - const uint64_t PROC = spawnRawProc(args); + const uint64_t PROC = spawnRawProc(args, nullptr); return {.success = PROC > 0, .error = std::format("Failed to start process {}", args)}; } -uint64_t CKeybindManager::spawnRawProc(std::string args) { +uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWorkspace) { Debug::log(LOG, "Executing {}", args); - const auto HLENV = getHyprlandLaunchEnv(); + const auto HLENV = getHyprlandLaunchEnv(pInitialWorkspace); int socket[2]; if (pipe(socket) != 0) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index d1f26c2c..bf3b049f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -149,7 +149,8 @@ class CKeybindManager { static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); - static uint64_t spawnRawProc(std::string); + static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace); + static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); // -------------- Dispatchers -------------- // static SDispatchResult killActive(std::string); From 4988e00b1d72edb8ca8e87eecdbed8c2ecc6a7dc Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:58:57 +0000 Subject: [PATCH 0584/2393] input: move idle notify to input handlers (#7659) * Revert "input: don't emit idle activity when calling simulateMouseMovement (#7649)" This reverts commit ea10592ad3c861ff2ce73ad7785bcb5a45a9e400. * input: move idle notify calls to input event listeners * input: don't post idle activity when keyboard is not enabled --- src/managers/PointerManager.cpp | 39 +++++++++++++++++++++++++++++ src/managers/input/InputManager.cpp | 19 ++++++-------- src/managers/input/InputManager.hpp | 2 +- src/managers/input/Tablets.cpp | 9 ------- src/managers/input/Touch.cpp | 3 --- 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index f0f74428..ce9ea4a4 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/IdleNotify.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Seat.hpp" #include "eventLoop/EventLoopManager.hpp" @@ -833,24 +834,32 @@ void CPointerManager::attachPointer(SP pointer) { auto E = std::any_cast(e); g_pInputManager->onMouseMoved(E); + + PROTO::idle->onActivity(); }); listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseWarp(E); + + PROTO::idle->onActivity(); }); listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseButton(E); + + PROTO::idle->onActivity(); }); listener->axis = pointer->pointerEvents.axis.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onMouseWheel(E); + + PROTO::idle->onActivity(); }); listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { @@ -861,48 +870,64 @@ void CPointerManager::attachPointer(SP pointer) { auto E = std::any_cast(e); g_pInputManager->onSwipeBegin(E); + + PROTO::idle->onActivity(); }); listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onSwipeEnd(E); + + PROTO::idle->onActivity(); }); listener->swipeUpdate = pointer->pointerEvents.swipeUpdate.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onSwipeUpdate(E); + + PROTO::idle->onActivity(); }); listener->pinchBegin = pointer->pointerEvents.pinchBegin.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); + + PROTO::idle->onActivity(); }); listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchEnd(E.timeMs, E.cancelled); + + PROTO::idle->onActivity(); }); listener->pinchUpdate = pointer->pointerEvents.pinchUpdate.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->pinchUpdate(E.timeMs, E.delta, E.scale, E.rotation); + + PROTO::idle->onActivity(); }); listener->holdBegin = pointer->pointerEvents.holdBegin.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->holdBegin(E.timeMs, E.fingers); + + PROTO::idle->onActivity(); }); listener->holdEnd = pointer->pointerEvents.holdEnd.registerListener([this] (std::any e) { auto E = std::any_cast(e); PROTO::pointerGestures->holdEnd(E.timeMs, E.cancelled); + + PROTO::idle->onActivity(); }); // clang-format on @@ -926,18 +951,24 @@ void CPointerManager::attachTouch(SP touch) { auto E = std::any_cast(e); g_pInputManager->onTouchDown(E); + + PROTO::idle->onActivity(); }); listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTouchUp(E); + + PROTO::idle->onActivity(); }); listener->motion = touch->touchEvents.motion.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTouchMove(E); + + PROTO::idle->onActivity(); }); listener->cancel = touch->touchEvents.cancel.registerListener([this] (std::any e) { @@ -969,24 +1000,32 @@ void CPointerManager::attachTablet(SP tablet) { auto E = std::any_cast(e); g_pInputManager->onTabletAxis(E); + + PROTO::idle->onActivity(); }); listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletProximity(E); + + PROTO::idle->onActivity(); }); listener->tip = tablet->tabletEvents.tip.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletTip(E); + + PROTO::idle->onActivity(); }); listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { auto E = std::any_cast(e); g_pInputManager->onTabletButton(E); + + PROTO::idle->onActivity(); }); // clang-format on diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index cdf7d615..66ca4eb2 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -111,7 +111,7 @@ void CInputManager::simulateMouseMovement() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); m_vLastCursorPosFloored = m_vLastCursorPosFloored - Vector2D(1, 1); // hack: force the mouseMoveUnified to report without making this a refocus. - mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000, false, true); + mouseMoveUnified(now.tv_sec * 1000 + now.tv_nsec / 10000000); } void CInputManager::sendMotionEventsToFocused() { @@ -132,7 +132,7 @@ void CInputManager::sendMotionEventsToFocused() { g_pSeatManager->setPointerFocus(g_pCompositor->m_pLastFocus.lock(), LOCAL); } -void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { +void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); @@ -170,9 +170,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED); - if (time && !silent) - PROTO::idle->onActivity(); - m_vLastCursorPosFloored = MOUSECOORDSFLOORED; const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); @@ -531,8 +528,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool silent) { void CInputManager::onMouseButton(IPointer::SButtonEvent e) { EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e); - PROTO::idle->onActivity(); - m_tmrLastCursorMovement.reset(); if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { @@ -767,8 +762,6 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { bool passEvent = g_pKeybindManager->onAxisEvent(e); - PROTO::idle->onActivity(); - if (!passEvent) return; @@ -883,6 +876,9 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); onKeyboardKey(data, PKEEB); + + if (PKEEB->enabled) + PROTO::idle->onActivity(); }, keeb.get()); @@ -891,6 +887,9 @@ void CInputManager::setupKeyboard(SP keeb) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); onKeyboardMod(PKEEB); + + if (PKEEB->enabled) + PROTO::idle->onActivity(); }, keeb.get()); @@ -1292,8 +1291,6 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { auto e = std::any_cast(event); - PROTO::idle->onActivity(); - if (passEvent) { const auto IME = m_sIMERelay.m_pIME.lock(); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 70e4d40f..ebf00b2d 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -237,7 +237,7 @@ class CInputManager { uint32_t m_uiCapabilities = 0; - void mouseMoveUnified(uint32_t, bool refocus = false, bool silent = false); + void mouseMoveUnified(uint32_t, bool refocus = false); SP ensureTabletToolPresent(SP); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index f33937e8..9f80726e 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -1,6 +1,5 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" -#include "../../protocols/IdleNotify.hpp" #include "../../protocols/Tablet.hpp" #include "../../devices/Tablet.hpp" #include "../../managers/PointerManager.hpp" @@ -155,8 +154,6 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { if (e.updatedAxes & (CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_X | CTablet::eTabletToolAxes::HID_TABLET_TOOL_AXIS_TILT_Y)) PROTO::tablet->tilt(PTOOL, PTOOL->tilt); - - PROTO::idle->onActivity(); } void CInputManager::onTabletTip(CTablet::STipEvent e) { @@ -171,8 +168,6 @@ void CInputManager::onTabletTip(CTablet::STipEvent e) { PROTO::tablet->up(PTOOL); PTOOL->isDown = e.in; - - PROTO::idle->onActivity(); } void CInputManager::onTabletButton(CTablet::SButtonEvent e) { @@ -184,8 +179,6 @@ void CInputManager::onTabletButton(CTablet::SButtonEvent e) { PTOOL->buttonsDown.push_back(e.button); else std::erase(PTOOL->buttonsDown, e.button); - - PROTO::idle->onActivity(); } void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { @@ -201,8 +194,6 @@ void CInputManager::onTabletProximity(CTablet::SProximityEvent e) { simulateMouseMovement(); refocusTablet(PTAB, PTOOL); } - - PROTO::idle->onActivity(); } void CInputManager::newTablet(SP pDevice) { diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 40af4b1e..9b03168e 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -1,7 +1,6 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" -#include "../../protocols/IdleNotify.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" @@ -78,8 +77,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { return; // oops, nothing found. g_pSeatManager->sendTouchDown(m_sTouchData.touchFocusSurface.lock(), e.timeMs, e.touchID, local); - - PROTO::idle->onActivity(); } void CInputManager::onTouchUp(ITouch::SUpEvent e) { From b0fca6eaf00a2c5061f499c76ec8d60772b6a719 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 5 Sep 2024 17:03:12 -0700 Subject: [PATCH 0585/2393] input: kb focus mouse focused window if unset (#7666) Normally it shouldn't be possible to have mouse focus with no kb focus, but it does happen, and when it does this makes it considerably less annoying. --- src/managers/input/InputManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 66ca4eb2..f1035c82 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -505,6 +505,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } } + if (g_pSeatManager->state.keyboardFocus == nullptr) + g_pCompositor->focusWindow(pFoundWindow, foundSurface); + m_bLastFocusOnLS = false; } else { if (*PRESIZEONBORDER && *PRESIZECURSORICON && m_eBorderIconDirection != BORDERICON_NONE) { From 0500213086f8402ccbdb2acb4748dbc6d22e21f6 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Fri, 6 Sep 2024 17:06:55 -0700 Subject: [PATCH 0586/2393] input: try to refocus a focusable window when seat grabs are reset (#7669) --- src/desktop/Popup.cpp | 7 +++++++ src/desktop/Popup.hpp | 23 ++++++++++++----------- src/managers/SeatManager.cpp | 31 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index a4952ef7..9e254fa6 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -202,6 +202,13 @@ void CPopup::reposition() { m_pResource->applyPositioning(box, COORDS); } +SP CPopup::getT1Owner() { + if (m_pWindowOwner) + return m_pWindowOwner->m_pWLSurface; + else + return m_pLayerOwner->surface; +} + Vector2D CPopup::coordsRelativeToParent() { Vector2D offset; diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index eea3fb84..04996612 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -18,21 +18,22 @@ class CPopup { ~CPopup(); - Vector2D coordsRelativeToParent(); - Vector2D coordsGlobal(); + SP getT1Owner(); + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); - Vector2D size(); + Vector2D size(); - void onNewPopup(SP popup); - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(bool ignoreSiblings = false); - void onReposition(); + void onNewPopup(SP popup); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(bool ignoreSiblings = false); + void onReposition(); - void recheckTree(); + void recheckTree(); - bool visible(); + bool visible(); // will also loop over this node void breadthfirst(std::function fn, void* data); diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 3e4063f4..b40d6cad 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -6,6 +6,7 @@ #include "../protocols/core/Compositor.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" +#include "wlr-layer-shell-unstable-v1.hpp" #include #include @@ -584,6 +585,36 @@ void CSeatManager::setGrab(SP grab) { auto oldGrab = seatGrab; seatGrab.reset(); g_pInputManager->refocus(); + + auto currentFocus = state.keyboardFocus.lock(); + auto refocus = !currentFocus; + + SP surf; + PHLLS layer; + + if (!refocus) { + surf = CWLSurface::fromResource(currentFocus); + layer = surf->getLayer(); + } + + if (!refocus && !layer) { + auto popup = surf->getPopup(); + if (popup) { + auto parent = popup->getT1Owner(); + layer = parent->getLayer(); + } + } + + if (!refocus && layer) + refocus = layer->interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE; + + if (refocus) { + auto candidate = g_pCompositor->m_pLastWindow.lock(); + + if (candidate) + g_pCompositor->focusWindow(candidate); + } + if (oldGrab->onEnd) oldGrab->onEnd(); } From 5ca48231287d67e75a3f21dbdbc47d6dc65752c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Darth=20=C5=A0=C4=8C!?= Date: Sat, 7 Sep 2024 17:14:23 +0200 Subject: [PATCH 0587/2393] config: Added default button mapping for xf86 keys (#7672) * Added default button mapping for laptop multimedia keys for volume and brightness * Added default button mapping for laptop multimedia keys for volume and brightness into example config --- example/hyprland.conf | 8 ++++++++ src/config/defaultConfig.hpp | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/example/hyprland.conf b/example/hyprland.conf index d55d25fd..76e5bcdb 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -228,6 +228,14 @@ bind = $mainMod, mouse_up, workspace, e-1 bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- + ############################## ### WINDOWS AND WORKSPACES ### diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 59265fee..b8d215d1 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -241,6 +241,13 @@ bind = $mainMod, mouse_up, workspace, e-1 bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow +# Laptop multimedia keys for volume and LCD brightness +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- +bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle +bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle +bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ +bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- ############################## ### WINDOWS AND WORKSPACES ### From 70add904c40924a761059e4009a8c0f1e43d76a3 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sat, 7 Sep 2024 14:54:33 -0500 Subject: [PATCH 0588/2393] config: add exec-shutdown for running commands on shutdown (#7683) * config: add exec-shutdown for running commands on shutdown * compositor: delay stopping until after exec-shutdown --- src/Compositor.hpp | 1 + src/config/ConfigManager.cpp | 42 +++++++++++++++++++++++++++++++++ src/config/ConfigManager.hpp | 3 +++ src/managers/KeybindManager.cpp | 5 ++++ 4 files changed, 51 insertions(+) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f17d86e5..a57450f1 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -91,6 +91,7 @@ class CCompositor { bool m_bNextIsUnsafe = false; CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state bool m_bIsShuttingDown = false; + bool m_bFinalRequests = false; bool m_bDesktopEnvSet = false; bool m_bEnableXwayland = true; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b16b7747..852994a7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -141,6 +141,18 @@ static Hyprlang::CParseResult handleExecOnce(const char* c, const char* v) { return result; } +static Hyprlang::CParseResult handleExecShutdown(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleExecShutdown(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} + static Hyprlang::CParseResult handleMonitor(const char* c, const char* v) { const std::string VALUE = v; const std::string COMMAND = c; @@ -609,6 +621,7 @@ CConfigManager::CConfigManager() { // keywords m_pConfig->registerHandler(&::handleRawExec, "exec", {false}); m_pConfig->registerHandler(&::handleExecOnce, "exec-once", {false}); + m_pConfig->registerHandler(&::handleExecShutdown, "exec-shutdown", {false}); m_pConfig->registerHandler(&::handleMonitor, "monitor", {false}); m_pConfig->registerHandler(&::handleBind, "bind", {true}); m_pConfig->registerHandler(&::handleUnbind, "unbind", {false}); @@ -801,6 +814,7 @@ std::optional CConfigManager::resetHLConfig() { m_vDeclaredPlugins.clear(); m_dLayerRules.clear(); m_vFailedPluginConfigValues.clear(); + finalExecRequests.clear(); // paths configPaths.clear(); @@ -1398,6 +1412,24 @@ void CConfigManager::dispatchExecOnce() { g_pCompositor->performUserChecks(); } +void CConfigManager::dispatchExecShutdown() { + if (finalExecRequests.empty()) { + g_pCompositor->m_bFinalRequests = false; + return; + } + + g_pCompositor->m_bFinalRequests = true; + + for (auto const& c : finalExecRequests) { + handleExecShutdown("", c); + } + + finalExecRequests.clear(); + + // Actually exit now + handleExecShutdown("", "hyprctl dispatch exit"); +} + void CConfigManager::appendMonitorRule(const SMonitorRule& r) { m_dMonitorRules.emplace_back(r); } @@ -1700,6 +1732,16 @@ std::optional CConfigManager::handleExecOnce(const std::string& com return {}; } +std::optional CConfigManager::handleExecShutdown(const std::string& command, const std::string& args) { + if (g_pCompositor->m_bFinalRequests) { + g_pKeybindManager->spawn(args); + return {}; + } + + finalExecRequests.push_back(args); + return {}; +} + static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { auto args = CVarList(modeline, 0, 's'); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 4d087753..da450e39 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -192,6 +192,7 @@ class CConfigManager { // no-op when done. void dispatchExecOnce(); + void dispatchExecShutdown(); void performMonitorReload(); void appendMonitorRule(const SMonitorRule&); @@ -213,6 +214,7 @@ class CConfigManager { // keywords std::optional handleRawExec(const std::string&, const std::string&); std::optional handleExecOnce(const std::string&, const std::string&); + std::optional handleExecShutdown(const std::string&, const std::string&); std::optional handleMonitor(const std::string&, const std::string&); std::optional handleBind(const std::string&, const std::string&); std::optional handleUnbind(const std::string&, const std::string&); @@ -289,6 +291,7 @@ class CConfigManager { bool firstExecDispatched = false; bool m_bManualCrashInitiated = false; std::deque firstExecRequests; + std::deque finalExecRequests; std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins std::string m_szConfigErrors = ""; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2db9f375..2f593d74 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1781,6 +1781,11 @@ SDispatchResult CKeybindManager::renameWorkspace(std::string args) { } SDispatchResult CKeybindManager::exitHyprland(std::string argz) { + g_pConfigManager->dispatchExecShutdown(); + + if (g_pCompositor->m_bFinalRequests) + return {}; // Exiting deferred until requests complete + g_pCompositor->stopCompositor(); return {}; } From 312411fc7073143a8bf1fc3ba23ef403b7d15eee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 8 Sep 2024 00:46:16 +0100 Subject: [PATCH 0589/2393] windows: support size with pseudo tiled fixes #7690 --- src/events/Windows.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 034920a2..544483b1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -344,7 +344,8 @@ void Events::listener_mapWindow(void* owner, void* data) { Debug::log(LOG, "Rule size, applying to {}", PWINDOW); - PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); + PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal(); g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); PWINDOW->setHidden(false); @@ -449,8 +450,36 @@ void Events::listener_mapWindow(void* owner, void* data) { } else { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); - // Set the pseudo size here too so that it doesnt end up being 0x0 - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); + bool setPseudo = false; + + for (auto const& r : PWINDOW->m_vMatchedRules) { + if (r.szRule.starts_with("size")) { + try { + const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); + const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); + const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); + + const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + + const auto SIZEX = SIZEXSTR == "max" ? + std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : + (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x); + const auto SIZEY = SIZEYSTR == "max" ? + std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : + (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y); + + Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); + + setPseudo = true; + PWINDOW->m_vPseudoSize = Vector2D(SIZEX, SIZEY); + + PWINDOW->setHidden(false); + } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); } + } + } + + if (!setPseudo) + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); } const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); From 0f594732b063a90d44df8c5d402d658f27471dfe Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 8 Sep 2024 17:48:21 +0100 Subject: [PATCH 0590/2393] props: bump version to 0.43.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 787ffc30..8298bb08 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.42.0 +0.43.0 From 07a21fdfa9e4d3827457dc3f08a4910703fedd35 Mon Sep 17 00:00:00 2001 From: diniamo <55629891+diniamo@users.noreply.github.com> Date: Sun, 8 Sep 2024 20:20:45 +0200 Subject: [PATCH 0591/2393] github(nix-build): switch to better nix installer, attempt at fixing hash mismatch (#7701) * github(nix-build): switch to DeterminateSystems/nix-installer-action * github(nix-build): switch to a direct git reference instead of cloning * github(nix-ci): attempt to fix CI for pull requests --- .github/workflows/nix-build.yml | 11 +++-------- .github/workflows/nix-ci.yml | 3 +-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index ed0c2ae1..50823629 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -16,17 +16,12 @@ jobs: runs-on: ubuntu-latest steps: - - name: Clone repository - uses: actions/checkout@v4 - with: - ref: ${{ github.ref }} - submodules: recursive - - - uses: cachix/install-nix-action@v27 + - uses: DeterminateSystems/nix-installer-action@main - uses: DeterminateSystems/magic-nix-cache-action@main + - uses: cachix/cachix-action@v15 with: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index 2f35337d..75c19790 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -9,7 +9,6 @@ jobs: secrets: inherit build: - if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) && !contains(needs.*.result, 'failure') - needs: update-inputs + if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) uses: ./.github/workflows/nix-build.yml secrets: inherit From 05b48d48d9074041fd7987c36f04bdc1dafa575c Mon Sep 17 00:00:00 2001 From: Davide Conti Date: Sun, 8 Sep 2024 20:36:33 +0200 Subject: [PATCH 0592/2393] config: Limit max volume to 100% --- example/hyprland.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 76e5bcdb..1179a274 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -229,7 +229,7 @@ bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow # Laptop multimedia keys for volume and LCD brightness -bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle From 6179b17903647d7659749f9f7c79bb9aff97a806 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sun, 8 Sep 2024 22:12:01 +0200 Subject: [PATCH 0593/2393] github: improve issue template (#7699) * github: improve issue template Require to check that you have searched through open and closed issues before committing. * fix yaml syntax * clarify text * validation * revert validation * markdown * done --- .github/ISSUE_TEMPLATE/bug.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index e3e97bef..7d402904 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -2,12 +2,13 @@ name: Bug Report description: Something is not working right labels: ["bug"] body: - - type: markdown + - type: checkboxes attributes: - value: | - ## Before opening a new issue, please take a moment to search through the current open and closed issues to check if it already exists. - - --- + label: Already reported ? * + description: Before opening a new bug report, please take a moment to search through the current open and closed issues to check if it already exists. + options: + - label: I have searched the existing open and closed issues. + required: true - type: dropdown id: type From 7c4c402bd7f24241c096d809cc80408a469f15cb Mon Sep 17 00:00:00 2001 From: Richard Ayotte Date: Sun, 8 Sep 2024 17:04:07 -0400 Subject: [PATCH 0594/2393] config: include XF86Audio* key bindings to default cfg (#7695) --- example/hyprland.conf | 13 +++++++++---- src/config/defaultConfig.hpp | 14 ++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 1179a274..4adc2d40 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -59,7 +59,7 @@ env = HYPRCURSOR_SIZE,24 # Refer to https://wiki.hyprland.org/Configuring/Variables/ # https://wiki.hyprland.org/Configuring/Variables/#general -general { +general { gaps_in = 5 gaps_out = 20 @@ -70,7 +70,7 @@ general { col.inactive_border = rgba(595959aa) # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = false + resize_on_border = false # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = false @@ -96,7 +96,7 @@ decoration { enabled = true size = 3 passes = 1 - + vibrancy = 0.1696 } } @@ -129,7 +129,7 @@ master { } # https://wiki.hyprland.org/Configuring/Variables/#misc -misc { +misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( } @@ -236,6 +236,11 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous ############################## ### WINDOWS AND WORKSPACES ### diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index b8d215d1..5843caa3 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -72,7 +72,7 @@ env = HYPRCURSOR_SIZE,24 # Refer to https://wiki.hyprland.org/Configuring/Variables/ # https://wiki.hyprland.org/Configuring/Variables/#general -general { +general { gaps_in = 5 gaps_out = 20 @@ -83,7 +83,7 @@ general { col.inactive_border = rgba(595959aa) # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = false + resize_on_border = false # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on allow_tearing = false @@ -109,7 +109,7 @@ decoration { enabled = true size = 3 passes = 1 - + vibrancy = 0.1696 } } @@ -142,7 +142,7 @@ master { } # https://wiki.hyprland.org/Configuring/Variables/#misc -misc { +misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( } @@ -249,6 +249,12 @@ bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle bindel = ,XF86MonBrightnessUp, exec, brightnessctl s 10%+ bindel = ,XF86MonBrightnessDown, exec, brightnessctl s 10%- +# Requires playerctl +bindl = , XF86AudioNext, exec, playerctl next +bindl = , XF86AudioPause, exec, playerctl play-pause +bindl = , XF86AudioPlay, exec, playerctl play-pause +bindl = , XF86AudioPrev, exec, playerctl previous + ############################## ### WINDOWS AND WORKSPACES ### ############################## From e1448732b3a463fc3aafc162d456a3db593253c8 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 9 Sep 2024 17:58:44 +0900 Subject: [PATCH 0595/2393] tiv1: fix deleting first character (#7716) --- src/managers/input/TextInput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 4c2e326a..d488f173 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -264,7 +264,7 @@ void CTextInput::updateIMEState(SP ime) { INPUT->preeditStyling(0, std::string(ime->current.preeditString.string).length(), ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditString(pV1Input->serial, ime->current.preeditString.string.c_str(), ""); } else { - INPUT->preeditCursor(ime->current.preeditString.begin); + INPUT->preeditCursor(0); INPUT->preeditStyling(0, 0, ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT); INPUT->preeditString(pV1Input->serial, "", ""); } From 43e1415e715bb6c6c4ea722ba839210938ac2b07 Mon Sep 17 00:00:00 2001 From: davc0n Date: Mon, 9 Sep 2024 11:01:26 +0200 Subject: [PATCH 0596/2393] assets: Remove execute permission from lockdead.png (#7715) --- assets/install/lockdead.png | Bin 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 assets/install/lockdead.png diff --git a/assets/install/lockdead.png b/assets/install/lockdead.png old mode 100755 new mode 100644 From 04421063af2941c6e27e6dca2bdc2c387778a3a5 Mon Sep 17 00:00:00 2001 From: darkwater Date: Mon, 9 Sep 2024 11:10:08 +0200 Subject: [PATCH 0597/2393] config: add order rule for layers (#7697) --- src/config/ConfigManager.cpp | 2 +- src/desktop/LayerSurface.cpp | 5 +++++ src/desktop/LayerSurface.hpp | 1 + src/render/Renderer.cpp | 4 ++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 852994a7..57cd2350 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2239,7 +2239,7 @@ bool windowRuleValid(const std::string& RULE) { bool layerRuleValid(const std::string& RULE) { static const auto rules = std::unordered_set{"noanim", "blur", "blurpopups", "dimaround"}; - static const auto rulesPrefix = std::vector{"ignorealpha", "ignorezero", "xray", "animation"}; + static const auto rulesPrefix = std::vector{"ignorealpha", "ignorezero", "xray", "animation", "order"}; return rules.contains(RULE) || std::any_of(rulesPrefix.begin(), rulesPrefix.end(), [&RULE](auto prefix) { return RULE.starts_with(prefix); }); } diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 155a2605..0e7e71b6 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -394,6 +394,11 @@ void CLayerSurface::applyRules() { } else if (rule.rule.starts_with("animation")) { CVarList vars{rule.rule, 2, 's'}; animationStyle = vars[1]; + } else if (rule.rule.starts_with("order")) { + CVarList vars{rule.rule, 2, 's'}; + try { + order = std::stoi(vars[1]); + } catch (...) { Debug::log(ERR, "Invalid value passed to order"); } } } } diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 84935b34..e0f17039 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -55,6 +55,7 @@ class CLayerSurface { bool ignoreAlpha = false; float ignoreAlphaValue = 0.f; bool dimAround = false; + int64_t order = 0; std::optional animationStyle; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 27fde129..08bf76cb 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1742,6 +1742,10 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { + std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->order > b->order; }); + } + for (auto const& la : PMONITOR->m_aLayerSurfaceLayers) arrangeLayerArray(PMONITOR, la, true, &usableArea); From 9609b04ff9e63d16f9b2b9ecfdc732c2c7ebbf2f Mon Sep 17 00:00:00 2001 From: justmessingaround <69480361+DemonKingSwarn@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:49:17 +0530 Subject: [PATCH 0598/2393] man: Fixed the man page to show the new information (#7713) * Update Hyprland.1.rst * Update Hyprland.1 --- docs/Hyprland.1 | 4 ++-- docs/Hyprland.1.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 92061da2..465671e1 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. .SH DESCRIPTION .PP -\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on -wlroots that doesn\[aq]t sacrifice on its looks. +\f[B]Hyprland\f[R] is an independent, highly customizable, +dynamic tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. .PP You can launch Hyprland by either going into a TTY and executing \f[B]Hyprland\f[R], or with a login manager. diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst index c73b4343..e10d9c6a 100644 --- a/docs/Hyprland.1.rst +++ b/docs/Hyprland.1.rst @@ -14,8 +14,8 @@ SYNOPSIS DESCRIPTION =========== -**Hyprland** is a dynamic tiling Wayland compositor based on -wlroots that doesn't sacrifice on its looks. +**Hyprland** is an independent, highly customizable, +dynamic tiling Wayland compositor that doesn't sacrifice on its looks. You can launch Hyprland by either going into a TTY and executing **Hyprland**, or with a login manager. From 85da1a17d831e2b5db9c1c1e4ce6427d63563562 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 9 Sep 2024 15:19:44 +0000 Subject: [PATCH 0599/2393] [gha] build man pages --- docs/Hyprland.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Hyprland.1 b/docs/Hyprland.1 index 465671e1..2d6e1444 100644 --- a/docs/Hyprland.1 +++ b/docs/Hyprland.1 @@ -10,8 +10,8 @@ Hyprland - Dynamic tiling Wayland compositor \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]]. .SH DESCRIPTION .PP -\f[B]Hyprland\f[R] is an independent, highly customizable, -dynamic tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. +\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic +tiling Wayland compositor that doesn\[aq]t sacrifice on its looks. .PP You can launch Hyprland by either going into a TTY and executing \f[B]Hyprland\f[R], or with a login manager. From 8237d7e1a4994f70636b2e91584775308f24a584 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:29:00 +0000 Subject: [PATCH 0600/2393] input: move dmps activation to input listeners (#7721) --- src/managers/KeybindManager.hpp | 1 + src/managers/PointerManager.cpp | 30 +++++++++++++++++++++++++++++ src/managers/input/InputManager.cpp | 21 +++++++++----------- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index bf3b049f..096cd4f9 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -221,6 +221,7 @@ class CKeybindManager { friend class CInputManager; friend class CConfigManager; friend class CWorkspace; + friend class CPointerManager; }; inline std::unique_ptr g_pKeybindManager; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ce9ea4a4..e48c77d5 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -821,6 +821,9 @@ void CPointerManager::attachPointer(SP pointer) { if (!pointer) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = pointerListeners.emplace_back(makeShared()); listener->pointer = pointer; @@ -836,6 +839,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onMouseMoved(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) { @@ -844,6 +850,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onMouseWarp(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) { @@ -872,6 +881,9 @@ void CPointerManager::attachPointer(SP pointer) { g_pInputManager->onSwipeBegin(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) { @@ -896,6 +908,9 @@ void CPointerManager::attachPointer(SP pointer) { PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) { @@ -938,6 +953,9 @@ void CPointerManager::attachTouch(SP touch) { if (!touch) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = touchListeners.emplace_back(makeShared()); listener->touch = touch; @@ -953,6 +971,9 @@ void CPointerManager::attachTouch(SP touch) { g_pInputManager->onTouchDown(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->up = touch->touchEvents.up.registerListener([this] (std::any e) { @@ -987,6 +1008,9 @@ void CPointerManager::attachTablet(SP tablet) { if (!tablet) return; + static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); + + // auto listener = tabletListeners.emplace_back(makeShared()); listener->tablet = tablet; @@ -1002,6 +1026,9 @@ void CPointerManager::attachTablet(SP tablet) { g_pInputManager->onTabletAxis(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->proximity = tablet->tabletEvents.proximity.registerListener([this] (std::any e) { @@ -1018,6 +1045,9 @@ void CPointerManager::attachTablet(SP tablet) { g_pInputManager->onTabletTip(E); PROTO::idle->onActivity(); + + if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) + g_pKeybindManager->dpms("on"); }); listener->button = tablet->tabletEvents.button.registerListener([this] (std::any e) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f1035c82..03c72919 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -28,6 +28,7 @@ #include "../../managers/PointerManager.hpp" #include "../../managers/SeatManager.hpp" +#include "../../managers/KeybindManager.hpp" #include @@ -135,7 +136,6 @@ void CInputManager::sendMotionEventsToFocused() { void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); - static auto PMOUSEDPMS = CConfigValue("misc:mouse_move_enables_dpms"); static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); @@ -157,11 +157,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; - if (!g_pCompositor->m_bDPMSStateON && *PMOUSEDPMS) { - // enable dpms - g_pKeybindManager->dpms("on"); - } - Vector2D mouseCoords = getMouseCoordsInternal(); const auto MOUSECOORDSFLOORED = mouseCoords.floor(); @@ -854,6 +849,8 @@ void CInputManager::newVirtualKeyboard(SP keyboard) } void CInputManager::setupKeyboard(SP keeb) { + static auto PDPMS = CConfigValue("misc:key_press_enables_dpms"); + m_vHIDs.push_back(keeb); try { @@ -882,6 +879,9 @@ void CInputManager::setupKeyboard(SP keeb) { if (PKEEB->enabled) PROTO::idle->onActivity(); + + if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON) + g_pKeybindManager->dpms("on"); }, keeb.get()); @@ -893,6 +893,9 @@ void CInputManager::setupKeyboard(SP keeb) { if (PKEEB->enabled) PROTO::idle->onActivity(); + + if (PKEEB->enabled && *PDPMS && !g_pCompositor->m_bDPMSStateON) + g_pKeybindManager->dpms("on"); }, keeb.get()); @@ -1284,12 +1287,6 @@ void CInputManager::onKeyboardKey(std::any event, SP pKeyboard) { const auto EMAP = std::unordered_map{{"keyboard", pKeyboard}, {"event", event}}; EMIT_HOOK_EVENT_CANCELLABLE("keyPress", EMAP); - static auto PDPMS = CConfigValue("misc:key_press_enables_dpms"); - if (*PDPMS && !g_pCompositor->m_bDPMSStateON) { - // enable dpms - g_pKeybindManager->dpms("on"); - } - bool passEvent = DISALLOWACTION || g_pKeybindManager->onKeyEvent(event, pKeyboard); auto e = std::any_cast(event); From c67b257e51133a2aaeec050fc4d283e2eaea6375 Mon Sep 17 00:00:00 2001 From: davc0n Date: Tue, 10 Sep 2024 12:06:37 +0200 Subject: [PATCH 0601/2393] build: Set cmake_minimum_required to version 3.30 (#7709) * build: Set cmake_minimum_required to version 3.30 * Nix: add patch for CMake min ver --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- nix/cmake-version.patch | 10 ++++++++++ nix/default.nix | 2 ++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 nix/cmake-version.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index d8424d91..6fdf98db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.27) +cmake_minimum_required(VERSION 3.30) # Get version file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/cmake-version.patch b/nix/cmake-version.patch new file mode 100644 index 00000000..ccc9c738 --- /dev/null +++ b/nix/cmake-version.patch @@ -0,0 +1,10 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 6fdf98db..d8424d91 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,4 +1,4 @@ +-cmake_minimum_required(VERSION 3.30) ++cmake_minimum_required(VERSION 3.27) + + # Get version + file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/default.nix b/nix/default.nix index 1c6a0113..985a4cbb 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -64,6 +64,8 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov patches = [ # forces GCC to use -std=c++26 ./stdcxx.patch + # Nix does not have CMake 3.30 yet, so override the minimum version + ./cmake-version.patch ]; postPatch = '' From 13f90bb87a697866f1bbbacd1473d04f33ec2aa7 Mon Sep 17 00:00:00 2001 From: Alexandre Acebedo Date: Sun, 8 Sep 2024 20:54:12 +0200 Subject: [PATCH 0602/2393] update xdph commit in flake.lock --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 99a544e2..239ec219 100644 --- a/flake.lock +++ b/flake.lock @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725203932, - "narHash": "sha256-VLULC/OnI+6R9KEP2OIGk+uLJJsfRlaLouZ5gyFd2+Y=", + "lastModified": 1725228143, + "narHash": "sha256-kbSiPA5oXiz1+1eVoRslMi5wylHD6SDT8dS9eZAxXAM=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "2425e8f541525fa7409d9f26a8ffaf92a3767251", + "rev": "11e15b437e7efc39e452f36e15a183225d6bfa39", "type": "github" }, "original": { From 155d44016d0cb11332c454db73d59030cdbd7b13 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Tue, 10 Sep 2024 22:49:10 +0900 Subject: [PATCH 0603/2393] textinput: handle IME resetting (#7731) --- src/managers/input/InputMethodRelay.cpp | 10 ++++++---- src/managers/input/InputMethodRelay.hpp | 4 ++-- src/managers/input/TextInput.cpp | 24 +++++++++++++++++------- src/managers/input/TextInput.hpp | 2 ++ src/protocols/TextInputV1.cpp | 1 + src/protocols/TextInputV1.hpp | 1 + src/protocols/TextInputV3.cpp | 19 ++++++++++++++----- src/protocols/TextInputV3.hpp | 7 ++++++- 8 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 1608e123..5ef7f331 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -106,20 +106,22 @@ void CInputMethodRelay::updateAllPopups() { } } -void CInputMethodRelay::activateIME(CTextInput* pInput) { +void CInputMethodRelay::activateIME(CTextInput* pInput, bool shouldCommit) { if (m_pIME.expired()) return; m_pIME->activate(); - commitIMEState(pInput); + if (shouldCommit) + commitIMEState(pInput); } -void CInputMethodRelay::deactivateIME(CTextInput* pInput) { +void CInputMethodRelay::deactivateIME(CTextInput* pInput, bool shouldCommit) { if (m_pIME.expired()) return; m_pIME->deactivate(); - commitIMEState(pInput); + if (shouldCommit) + commitIMEState(pInput); } void CInputMethodRelay::commitIMEState(CTextInput* pInput) { diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 5ecc11a2..3d706563 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -21,8 +21,8 @@ class CInputMethodRelay { void onNewTextInput(WP tiv3); void onNewTextInput(WP pTIV1); - void activateIME(CTextInput* pInput); - void deactivateIME(CTextInput* pInput); + void activateIME(CTextInput* pInput, bool shouldCommit = true); + void deactivateIME(CTextInput* pInput, bool shouldCommit = true); void commitIMEState(CTextInput* pInput); void removeTextInput(CTextInput* pInput); diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index d488f173..2769fad0 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -22,6 +22,7 @@ void CTextInput::initCallbacks() { listeners.enable = INPUT->events.enable.registerListener([this](std::any p) { onEnabled(); }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); + listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); @@ -41,6 +42,7 @@ void CTextInput::initCallbacks() { }); listeners.disable = INPUT->events.disable.registerListener([this](std::any p) { onDisabled(); }); listeners.commit = INPUT->events.onCommit.registerListener([this](std::any p) { onCommit(); }); + listeners.reset = INPUT->events.reset.registerListener([this](std::any p) { onReset(); }); listeners.destroy = INPUT->events.destroy.registerListener([this](std::any p) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); @@ -93,13 +95,21 @@ void CTextInput::onDisabled() { g_pInputManager->m_sIMERelay.deactivateIME(this); } +void CTextInput::onReset() { + if (g_pInputManager->m_sIMERelay.m_pIME.expired()) + return; + + g_pInputManager->m_sIMERelay.deactivateIME(this, false); + g_pInputManager->m_sIMERelay.activateIME(this); +} + void CTextInput::onCommit() { if (g_pInputManager->m_sIMERelay.m_pIME.expired()) { // Debug::log(WARN, "Committing TextInput on no IME!"); return; } - if (!(isV3() ? pV3Input->current.enabled : pV1Input->active)) { + if (!(isV3() ? pV3Input->current.enabled.value : pV1Input->active)) { Debug::log(WARN, "Disabled TextInput commit?"); return; } @@ -128,8 +138,8 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) - pV3Input->current.enabled = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) + pV3Input->current.enabled.value = false; if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -144,8 +154,8 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled) - pV3Input->current.enabled = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) + pV3Input->current.enabled.value = false; if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -194,8 +204,8 @@ void CTextInput::leave() { if (isV3()) { pV3Input->leave(focusedSurface()); - if (pV3Input->current.enabled) { - pV3Input->current.enabled = false; + if (pV3Input->current.enabled.value) { + pV3Input->current.enabled.value = false; onDisabled(); } } else diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 0f69866e..f920adc7 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -29,6 +29,7 @@ class CTextInput { void onEnabled(SP surfV1 = nullptr); void onDisabled(); void onCommit(); + void onReset(); bool hasCursorRectangle(); CBox cursorBox(); @@ -47,6 +48,7 @@ class CTextInput { struct { CHyprSignalListener enable; CHyprSignalListener disable; + CHyprSignalListener reset; CHyprSignalListener commit; CHyprSignalListener destroy; CHyprSignalListener surfaceUnmap; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index f25f5aca..dad74b53 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -31,6 +31,7 @@ CTextInputV1::CTextInputV1(SP resource_) : resource(resource_) resource->setReset([this](CZwpTextInputV1* pMgr) { pendingSurrounding.isPending = false; pendingContentType.isPending = false; + events.reset.emit(); }); resource->setSetSurroundingText( diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index c85a1f31..9bee452c 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -37,6 +37,7 @@ class CTextInputV1 { CSignal onCommit; CSignal enable; CSignal disable; + CSignal reset; CSignal destroy; } events; diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 42dc659e..30374104 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -19,17 +19,22 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) resource->setOnDestroy([this](CZwpTextInputV3* r) { PROTO::textInputV3->destroyTextInput(this); }); resource->setCommit([this](CZwpTextInputV3* r) { - bool wasEnabled = current.enabled; + bool wasEnabled = current.enabled.value; current = pending; serial++; - if (wasEnabled && !current.enabled) + if (wasEnabled && !current.enabled.value) events.disable.emit(); - else if (!wasEnabled && current.enabled) + else if (!wasEnabled && current.enabled.value) events.enable.emit(); + else if (current.enabled.value && current.enabled.isEnablePending && current.enabled.isDisablePending) + events.reset.emit(); else events.onCommit.emit(); + + pending.enabled.isEnablePending = false; + pending.enabled.isDisablePending = false; }); resource->setSetSurroundingText([this](CZwpTextInputV3* r, const char* text, int32_t cursor, int32_t anchor) { @@ -54,10 +59,14 @@ CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) resource->setEnable([this](CZwpTextInputV3* r) { pending.reset(); - pending.enabled = true; + pending.enabled.value = true; + pending.enabled.isEnablePending = true; }); - resource->setDisable([this](CZwpTextInputV3* r) { pending.enabled = false; }); + resource->setDisable([this](CZwpTextInputV3* r) { + pending.enabled.value = false; + pending.enabled.isDisablePending = true; + }); } CTextInputV3::~CTextInputV3() { diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index 9f6284dc..ba8b75e6 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -31,6 +31,7 @@ class CTextInputV3 { CSignal onCommit; CSignal enable; CSignal disable; + CSignal reset; CSignal destroy; } events; @@ -53,7 +54,11 @@ class CTextInputV3 { CBox cursorBox; } box; - bool enabled = false; + struct { + bool isEnablePending = false; + bool isDisablePending = false; + bool value = false; + } enabled; zwpTextInputV3ChangeCause cause = ZWP_TEXT_INPUT_V3_CHANGE_CAUSE_INPUT_METHOD; From 518399a95bada8bad8a4c29514da9962ce442307 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 11 Sep 2024 09:30:21 +0100 Subject: [PATCH 0604/2393] pointermgr: avoid derefing null outputs --- src/managers/PointerManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index e48c77d5..6b2a40f5 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -675,7 +675,7 @@ void CPointerManager::damageIfSoftware() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); for (auto const& mw : monitorStates) { - if (mw->monitor.expired()) + if (mw->monitor.expired() || !mw->monitor->output) continue; if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { @@ -789,7 +789,7 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { void CPointerManager::onMonitorLayoutChange() { currentMonitorLayout.monitorBoxes.clear(); for (auto const& m : g_pCompositor->m_vMonitors) { - if (m->isMirror() || !m->m_bEnabled) + if (m->isMirror() || !m->m_bEnabled || !m->output) continue; currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize}); From 7a8c013edcbc59804a98fffa0436efcb268e1cda Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 11 Sep 2024 18:50:59 +0300 Subject: [PATCH 0605/2393] Meson: fix protocols, clean up --- protocols/meson.build | 147 ++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 77 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index de650230..d686bacd 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,77 +1,75 @@ -wayland_protos = dependency('wayland-protocols', +wayland_protos = dependency( + 'wayland-protocols', version: '>=1.32', fallback: 'wayland-protocols', default_options: ['tests=false'], ) -hyprland_protos = dependency('hyprland-protocols', +hyprland_protos = dependency( + 'hyprland-protocols', version: '>=0.2', - fallback: 'hyprland-protocols', + fallback: 'hyprland-protocols', ) -wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') -hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir') +wayland_protocol_dir = wayland_protos.get_variable('pkgdatadir') +hyprland_protocol_dir = hyprland_protos.get_variable('pkgdatadir') -hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.8', native: true) +hyprwayland_scanner_dep = dependency('hyprwayland-scanner', version: '>=0.3.10', native: true) hyprwayland_scanner = find_program( hyprwayland_scanner_dep.get_variable('hyprwayland_scanner'), native: true, ) -new_protocols = [ - ['wlr-gamma-control-unstable-v1.xml'], - ['wlr-foreign-toplevel-management-unstable-v1.xml'], - ['wlr-output-power-management-unstable-v1.xml'], - ['input-method-unstable-v2.xml'], - ['virtual-keyboard-unstable-v1.xml'], - ['wlr-virtual-pointer-unstable-v1.xml'], - ['wlr-output-management-unstable-v1.xml'], - ['kde-server-decoration.xml'], - ['wlr-layer-shell-unstable-v1.xml'], - ['wayland-drm.xml'], - ['wlr-data-control-unstable-v1.xml'], - ['wlr-screencopy-unstable-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'], - [hl_protocol_dir, 'protocols/hyprland-focus-grab-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'], - [wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'], - [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'], - [wl_protocol_dir, 'staging/alpha-modifier/alpha-modifier-v1.xml'], - [wl_protocol_dir, 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml'], - [wl_protocol_dir, 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'], - [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], - [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'], - [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'], - [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], - [wl_protocol_dir, 'stable/tablet/tablet-v2.xml'], - [wl_protocol_dir, 'stable/presentation-time/presentation-time.xml'], - [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], - [wl_protocol_dir, 'unstable/primary-selection/primary-selection-unstable-v1.xml'], - [wl_protocol_dir, 'staging/xwayland-shell/xwayland-shell-v1.xml'], - [wl_protocol_dir, 'stable/viewporter/viewporter.xml'], - [wl_protocol_dir, 'stable/linux-dmabuf/linux-dmabuf-v1.xml'], - [wl_protocol_dir, 'staging/drm-lease/drm-lease-v1.xml'], - [wl_protocol_dir, 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml'], - [wl_protocol_dir, 'staging/xdg-dialog/xdg-dialog-v1.xml'], +protocols = [ + 'wlr-gamma-control-unstable-v1.xml', + 'wlr-foreign-toplevel-management-unstable-v1.xml', + 'wlr-output-power-management-unstable-v1.xml', + 'input-method-unstable-v2.xml', + 'virtual-keyboard-unstable-v1.xml', + 'wlr-virtual-pointer-unstable-v1.xml', + 'wlr-output-management-unstable-v1.xml', + 'kde-server-decoration.xml', + 'wlr-layer-shell-unstable-v1.xml', + 'wayland-drm.xml', + 'wlr-data-control-unstable-v1.xml', + 'wlr-screencopy-unstable-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', + wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', + wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', + wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', + wayland_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', + wayland_protocol_dir / 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml', + wayland_protocol_dir / 'unstable/relative-pointer/relative-pointer-unstable-v1.xml', + wayland_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml', + wayland_protocol_dir / 'staging/alpha-modifier/alpha-modifier-v1.xml', + wayland_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', + wayland_protocol_dir / 'unstable/pointer-gestures/pointer-gestures-unstable-v1.xml', + wayland_protocol_dir / 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml', + wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml', + wayland_protocol_dir / 'unstable/text-input/text-input-unstable-v1.xml', + wayland_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', + wayland_protocol_dir / 'staging/xdg-activation/xdg-activation-v1.xml', + wayland_protocol_dir / 'staging/ext-idle-notify/ext-idle-notify-v1.xml', + wayland_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', + wayland_protocol_dir / 'stable/tablet/tablet-v2.xml', + wayland_protocol_dir / 'stable/presentation-time/presentation-time.xml', + wayland_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', + wayland_protocol_dir / 'unstable/primary-selection/primary-selection-unstable-v1.xml', + wayland_protocol_dir / 'staging/xwayland-shell/xwayland-shell-v1.xml', + wayland_protocol_dir / 'stable/viewporter/viewporter.xml', + wayland_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml', + wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', + wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', + wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', ] -wl_protos_src = [] -wl_protos_headers = [] - -new_wl_protos = [] -foreach p : new_protocols - xml = join_paths(p) - new_wl_protos += custom_target( - xml.underscorify(), - input: xml, +wl_protocols = [] +foreach protocol : protocols + wl_protocols += custom_target( + protocol.underscorify(), + input: protocol, install: true, install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], @@ -79,31 +77,26 @@ foreach p : new_protocols ) endforeach -wayland_server_dep = dependency('wayland-server', version: '>=1.20.0') -wayland_server_dir = wayland_server_dep.get_variable('pkgdatadir') +# wayland.xml generation +wayland_scanner = dependency('wayland-scanner') +wayland_scanner_datadir = wayland_scanner.get_variable('pkgdatadir') -wl_server_protos = [ - wayland_server_dir / 'wayland.xml' -] -wl_server_protos_gen = [] -foreach p : wl_server_protos - wl_server_protos_gen += custom_target( - p.underscorify(), - input: p, - install: true, - install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], - output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], - command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], - ) -endforeach +wayland_xml = wayland_scanner_datadir / 'wayland.xml' +wayland_protocol = custom_target( + wayland_xml.underscorify(), + input: wayland_xml, + install: true, + install_dir: [false, join_paths(get_option('includedir'), 'hyprland/protocols')], + output: ['@BASENAME@.cpp', '@BASENAME@.hpp'], + command: [hyprwayland_scanner, '--wayland-enums', '@INPUT@', '@OUTDIR@'], +) lib_server_protos = static_library( 'server_protos', - wl_protos_src + wl_protos_headers + new_wl_protos + wl_server_protos_gen, - dependencies: wayland_server_dep.partial_dependency(compile_args: true), + wl_protocols + wayland_protocol, ) server_protos = declare_dependency( link_with: lib_server_protos, - sources: wl_protos_headers + new_wl_protos, + sources: wl_protocols + wayland_protocol, ) From e01da1fd7a50ab0baeaba074f2a14c826b05bf1c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 11 Sep 2024 19:00:47 +0300 Subject: [PATCH 0606/2393] Meson: format --- assets/install/meson.build | 6 +++++- assets/meson.build | 7 ++++++- docs/meson.build | 4 ++-- example/meson.build | 12 ++++++++++-- hyprctl/meson.build | 26 +++++++++++++++++++++----- hyprpm/src/meson.build | 28 ++++++++++++++++++++++------ meson.build | 26 +++++++++++++++++--------- src/meson.build | 6 ++++-- 8 files changed, 87 insertions(+), 28 deletions(-) diff --git a/assets/install/meson.build b/assets/install/meson.build index 1d4fb917..45076469 100644 --- a/assets/install/meson.build +++ b/assets/install/meson.build @@ -2,5 +2,9 @@ globber = run_command('sh', '-c', 'find . -type f -not -name "*.build"', check: files = globber.stdout().strip().split('\n') foreach file : files - install_data(file, install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') + install_data( + file, + install_dir: join_paths(get_option('datadir'), 'hypr'), + install_tag: 'runtime', + ) endforeach diff --git a/assets/meson.build b/assets/meson.build index 0648037a..2a28121d 100644 --- a/assets/meson.build +++ b/assets/meson.build @@ -1,2 +1,7 @@ -install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime') +install_data( + 'hyprland-portals.conf', + install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), + install_tag: 'runtime', +) + subdir('install') diff --git a/docs/meson.build b/docs/meson.build index a5d7e737..6ff51d1a 100644 --- a/docs/meson.build +++ b/docs/meson.build @@ -1,2 +1,2 @@ -install_man ('Hyprland.1') -install_man ('hyprctl.1') +install_man('Hyprland.1') +install_man('hyprctl.1') diff --git a/example/meson.build b/example/meson.build index 2fb3a35e..a338644e 100644 --- a/example/meson.build +++ b/example/meson.build @@ -1,2 +1,10 @@ -install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hypr'), install_tag: 'runtime') -install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime') +install_data( + 'hyprland.conf', + install_dir: join_paths(get_option('datadir'), 'hypr'), + install_tag: 'runtime', +) +install_data( + 'hyprland.desktop', + install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), + install_tag: 'runtime', +) diff --git a/hyprctl/meson.build b/hyprctl/meson.build index 5488845f..455f5739 100644 --- a/hyprctl/meson.build +++ b/hyprctl/meson.build @@ -1,10 +1,26 @@ -executable('hyprctl', 'main.cpp', +executable( + 'hyprctl', + 'main.cpp', dependencies: [ dependency('hyprutils', version: '>= 0.1.1'), ], - install: true + install: true, ) -install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl') -install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') -install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl') +install_data( + 'hyprctl.bash', + install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), + install_tag: 'runtime', + rename: 'hyprctl', +) +install_data( + 'hyprctl.fish', + install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), + install_tag: 'runtime', +) +install_data( + 'hyprctl.zsh', + install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), + install_tag: 'runtime', + rename: '_hyprctl', +) diff --git a/hyprpm/src/meson.build b/hyprpm/src/meson.build index e2c512a5..2ef6c323 100644 --- a/hyprpm/src/meson.build +++ b/hyprpm/src/meson.build @@ -1,15 +1,31 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') -executable('hyprpm', src, +executable( + 'hyprpm', + src, dependencies: [ dependency('hyprutils', version: '>= 0.1.1'), dependency('threads'), - dependency('tomlplusplus') + dependency('tomlplusplus'), ], - install : true + install: true, ) -install_data('../hyprpm.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprpm') -install_data('../hyprpm.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime') -install_data('../hyprpm.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprpm') +install_data( + '../hyprpm.bash', + install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), + install_tag: 'runtime', + rename: 'hyprpm', +) +install_data( + '../hyprpm.fish', + install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), + install_tag: 'runtime', +) +install_data( + '../hyprpm.zsh', + install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), + install_tag: 'runtime', + rename: '_hyprpm', +) diff --git a/meson.build b/meson.build index 6a9b7ac5..123c31ae 100644 --- a/meson.build +++ b/meson.build @@ -1,13 +1,17 @@ -project('Hyprland', 'cpp', 'c', - version : run_command('cat', join_paths(meson.source_root(), 'VERSION'), check: true).stdout().strip(), - default_options : [ +project( + 'Hyprland', + 'cpp', + 'c', + version: run_command('cat', join_paths(meson.project_source_root(), 'VERSION'), check: true).stdout().strip(), + default_options: [ 'warning_level=2', 'default_library=static', 'optimization=3', 'buildtype=release', 'debug=false', 'cpp_std=c++26', - ]) + ], +) datarootdir = '-DDATAROOTDIR="' + get_option('prefix') / get_option('datadir') + '"' add_project_arguments( @@ -16,10 +20,10 @@ add_project_arguments( '-Wno-unused-value', '-Wno-missing-field-initializers', '-Wno-narrowing', - '-Wno-pointer-arith', - datarootdir, + '-Wno-pointer-arith', datarootdir, ], - language: 'cpp') + language: 'cpp', +) cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.check_header('execinfo.h') @@ -34,7 +38,7 @@ xcb_render_dep = dependency('xcb-render', required: get_option('xwayland')) xcb_res_dep = dependency('xcb-res', required: get_option('xwayland')) xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) -gio_dep = dependency('gio-2.0', required:true) +gio_dep = dependency('gio-2.0', required: true) cmake = import('cmake') udis = cmake.subproject('udis86') @@ -47,6 +51,7 @@ endif backtrace_dep = cpp_compiler.find_library('execinfo', required: false) epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs +# Handle options if get_option('systemd').enabled() add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') endif @@ -59,8 +64,10 @@ if get_option('buildtype') == 'debug' add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp') endif -version_h = run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) +# Generate hyprland version and populate version.h +run_command('sh', '-c', 'scripts/generateVersion.sh', check: true) +# Install headers globber = run_command('find', 'src', '-name', '*.h*', check: true) headers = globber.stdout().strip().split('\n') foreach file : headers @@ -75,6 +82,7 @@ subdir('assets') subdir('example') subdir('docs') +# Generate hyprland.pc pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') import('pkgconfig').generate( diff --git a/src/meson.build b/src/meson.build index 475ecc24..3821bd60 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,7 +1,9 @@ globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true) src = globber.stdout().strip().split('\n') -executable('Hyprland', src, +executable( + 'Hyprland', + src, link_args: '-rdynamic', cpp_pch: 'pch/pch.hpp', dependencies: [ @@ -38,5 +40,5 @@ executable('Hyprland', src, dependency('pangocairo'), dependency('uuid'), ], - install : true + install: true, ) From 8b9e385943d1a9fd0f8c6070fa1eae507ae26145 Mon Sep 17 00:00:00 2001 From: fufexan Date: Wed, 11 Sep 2024 16:10:51 +0000 Subject: [PATCH 0607/2393] [gha] Nix: update inputs --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 239ec219..55dc6939 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725199881, - "narHash": "sha256-jsmipf/u1GFZE5tBUkr56CHMN6VpUWCAjfLIhvQijU0=", + "lastModified": 1725753098, + "narHash": "sha256-/NO/h/qD/eJXAQr/fHA4mdDgYsNT9thHQ+oT6KPi2ac=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "f8a687dd29ff019657498f1bd14da2fbbf0e604b", + "rev": "e4a13203112a036fc7f437d391c7810f3dd5ab52", "type": "github" }, "original": { @@ -93,11 +93,11 @@ ] }, "locked": { - "lastModified": 1725188252, - "narHash": "sha256-yBH8c4GDaEAtBrh+BqIlrx5vp6gG/Gu8fQQK63KAQgs=", + "lastModified": 1725997860, + "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "c12ab785ce1982f82594aff03b3104c598186ddd", + "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725103162, - "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", + "lastModified": 1725983898, + "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", + "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", "type": "github" }, "original": { @@ -209,11 +209,11 @@ ] }, "locked": { - "lastModified": 1725228143, - "narHash": "sha256-kbSiPA5oXiz1+1eVoRslMi5wylHD6SDT8dS9eZAxXAM=", + "lastModified": 1726046979, + "narHash": "sha256-6SEsjurq9cdTkITA6d49ncAJe4O/8CgRG5/F//s6Xh8=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "11e15b437e7efc39e452f36e15a183225d6bfa39", + "rev": "e695669fd8e1d1be9eaae40f35e00f8bd8b64c18", "type": "github" }, "original": { From 73b9756b8d7ee06fc1c9f072f2a41f2dd1aeb2c9 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Thu, 12 Sep 2024 04:15:01 -0500 Subject: [PATCH 0608/2393] xwayland: remove extra x11 deactivation (#7755) --- src/managers/XWaylandManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 144343f8..fad7e451 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -46,11 +46,8 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool PWINDOW->m_pXWaylandSurface->restackToTop(); } PWINDOW->m_pXWaylandSurface->activate(activate); - } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) { + } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) PWINDOW->m_pXDGSurface->toplevel->setActive(activate); - if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastWindow && g_pCompositor->m_pLastWindow->m_bIsX11) - activateSurface(g_pCompositor->m_pLastFocus.lock(), false); - } } void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { From 118be4dea048df88fd21b84580fe62950c868c8f Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Fri, 13 Sep 2024 01:41:24 +0900 Subject: [PATCH 0609/2393] textinput: fix tiv3 leave (#7761) --- src/managers/input/TextInput.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index 2769fad0..e601ad9a 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -138,8 +138,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) - pV3Input->current.enabled.value = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) { + pV3Input->pending.enabled.value = false; + pV3Input->pending.enabled.isDisablePending = false; + pV3Input->pending.enabled.isEnablePending = false; + pV3Input->current.enabled.value = false; + } if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -154,8 +158,12 @@ void CTextInput::setFocusedSurface(SP pSurface) { listeners.surfaceUnmap.reset(); listeners.surfaceDestroy.reset(); - if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) - pV3Input->current.enabled.value = false; + if (isV3() && !pV3Input.expired() && pV3Input->current.enabled.value) { + pV3Input->pending.enabled.value = false; + pV3Input->pending.enabled.isDisablePending = false; + pV3Input->pending.enabled.isEnablePending = false; + pV3Input->current.enabled.value = false; + } if (!g_pInputManager->m_sIMERelay.getFocusedTextInput()) g_pInputManager->m_sIMERelay.deactivateIME(this); @@ -202,13 +210,9 @@ void CTextInput::leave() { enterLocks = 0; } - if (isV3()) { + if (isV3()) pV3Input->leave(focusedSurface()); - if (pV3Input->current.enabled.value) { - pV3Input->current.enabled.value = false; - onDisabled(); - } - } else + else pV1Input->leave(); setFocusedSurface(nullptr); From d505b3366533b71d57156469c926e8b2b75afb89 Mon Sep 17 00:00:00 2001 From: diniamo Date: Fri, 13 Sep 2024 16:21:33 +0200 Subject: [PATCH 0610/2393] nix: use meson --- nix/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nix/default.nix b/nix/default.nix index 985a4cbb..d3c7dd5f 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -4,6 +4,7 @@ pkg-config, pkgconf, makeWrapper, + meson, cmake, ninja, aquamarine, @@ -89,6 +90,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov hyprwayland-scanner jq makeWrapper + meson cmake ninja pkg-config From c35ed8363f321bb9925bc5e6f5ff03a903593802 Mon Sep 17 00:00:00 2001 From: diniamo Date: Fri, 13 Sep 2024 17:29:41 +0200 Subject: [PATCH 0611/2393] nix: adapt cmake options --- nix/cmake-version.patch | 10 ---------- nix/default.nix | 21 +++++++-------------- nix/stdcxx.patch | 12 ------------ 3 files changed, 7 insertions(+), 36 deletions(-) delete mode 100644 nix/cmake-version.patch delete mode 100644 nix/stdcxx.patch diff --git a/nix/cmake-version.patch b/nix/cmake-version.patch deleted file mode 100644 index ccc9c738..00000000 --- a/nix/cmake-version.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 6fdf98db..d8424d91 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -1,4 +1,4 @@ --cmake_minimum_required(VERSION 3.30) -+cmake_minimum_required(VERSION 3.27) - - # Get version - file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW) diff --git a/nix/default.nix b/nix/default.nix index d3c7dd5f..8d912fe6 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -62,13 +62,6 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov src = lib.cleanSource ../.; }; - patches = [ - # forces GCC to use -std=c++26 - ./stdcxx.patch - # Nix does not have CMake 3.30 yet, so override the minimum version - ./cmake-version.patch - ]; - postPatch = '' # Fix hardcoded paths to /usr installation sed -i "s#/usr#$out#" src/render/OpenGL.cpp @@ -144,18 +137,18 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.optionals withSystemd [systemd]) ]; - cmakeBuildType = + mesonBuildType = if debug - then "Debug" - else "RelWithDebInfo"; + then "debug" + else "release"; # we want as much debug info as possible dontStrip = debug; - cmakeFlags = [ - (lib.cmakeBool "NO_XWAYLAND" (!enableXWayland)) - (lib.cmakeBool "LEGACY_RENDERER" legacyRenderer) - (lib.cmakeBool "NO_SYSTEMD" (!withSystemd)) + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + (lib.mesonEnable "legacy_renderer" legacyRenderer) + (lib.mesonEnable "systemd" withSystemd) ]; postInstall = '' diff --git a/nix/stdcxx.patch b/nix/stdcxx.patch deleted file mode 100644 index 032e494d..00000000 --- a/nix/stdcxx.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index cfbd431f..73e8e0c2 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -64,6 +64,7 @@ endif() - include_directories(. "src/" "subprojects/udis86/" "protocols/") - set(CMAKE_CXX_STANDARD 26) - add_compile_options( -+ -std=c++26 - -Wall - -Wextra - -Wno-unused-parameter From d35e70a8c6599bb058cf86eb87c783ce1cf72471 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 13 Sep 2024 17:56:39 +0100 Subject: [PATCH 0612/2393] cmake: drop ninja dep --- Makefile | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index bc7b750b..59efc0ef 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,24 @@ PREFIX = /usr/local legacyrenderer: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` legacyrendererdebug: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` release: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` debug: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja - cmake --build ./build --config Debug --target all - chmod -R 777 ./build + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build + cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` nopch: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja - cmake --build ./build --config Release --target all + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build + cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` clear: rm -rf build From 5ee4b19691f413072f6877940ed709774333f84b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 14 Sep 2024 23:35:45 +0100 Subject: [PATCH 0613/2393] data-device: send clock time in motion events remove hack --- src/protocols/core/DataDevice.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 8c1a48d8..43a63949 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -513,7 +513,10 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource if (!box.has_value()) return; - dnd.focusedDevice->sendMotion(0 /* this is a hack */, V - box->pos()); + timespec timeNow; + clock_gettime(CLOCK_MONOTONIC, &timeNow); + + dnd.focusedDevice->sendMotion(timeNow.tv_sec * 1000 + timeNow.tv_nsec / 1000000, V - box->pos()); LOGM(LOG, "Drag motion {}", V - box->pos()); } }); From 4dbdb556fe441506ec5cf129c65b14e514dbcc5a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 14 Sep 2024 23:36:06 +0100 Subject: [PATCH 0614/2393] data-device: don't send default action of move gtk doesn't like it? --- src/protocols/core/DataDevice.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 43a63949..eac80a83 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -82,10 +82,8 @@ void CWLDataOfferResource::sendData() { if (!source) return; - if (resource->version() >= 3) { + if (resource->version() >= 3) resource->sendSourceActions(7); - resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); - } for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); From e74efd87e5aa38f9cf84cb3848ee1ab26e5e4bcb Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sat, 14 Sep 2024 17:37:18 -0500 Subject: [PATCH 0615/2393] internal: fix initial cursor warping (#7793) --- src/Compositor.cpp | 34 ++++++++++++++++++++++++++++ src/managers/PointerManager.cpp | 40 +-------------------------------- src/managers/PointerManager.hpp | 1 - 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index da659654..8e1b11b0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2943,6 +2943,38 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } +static void checkDefaultCursorWarp(SP monitor) { + static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); + static bool cursorDefaultDone = false; + static bool firstLaunch = true; + + const auto POS = monitor->middle(); + + // by default, cursor should be set to first monitor detected + // this is needed as a default if the monitor given in config above doesn't exist + if (firstLaunch) { + firstLaunch = false; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + + if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { + if (*PCURSORMONITOR == monitor->szName) { + cursorDefaultDone = true; + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + return; + } + } + + // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. + if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { + g_pCompositor->warpCursorTo(POS, true); + g_pInputManager->refocus(); + } +} + void CCompositor::onNewMonitor(SP output) { // add it to real auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared(output)); @@ -2977,6 +3009,8 @@ void CCompositor::onNewMonitor(SP output) { g_pConfigManager->m_bWantsMonitorReload = true; g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); + checkDefaultCursorWarp(PNEWMONITOR); + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_iMonitorID == PNEWMONITOR->ID) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 6b2a40f5..5a192e13 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -18,13 +18,7 @@ CPointerManager::CPointerManager() { onMonitorLayoutChange(); PMONITOR->events.modeChanged.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { - g_pEventLoopManager->doLater([this, PMONITOR]() { - onMonitorLayoutChange(); - checkDefaultCursorWarp(PMONITOR, PMONITOR->output->name); - }); - }, - nullptr); + [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.disconnect.registerStaticListener( [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( @@ -44,38 +38,6 @@ CPointerManager::CPointerManager() { }); } -void CPointerManager::checkDefaultCursorWarp(SP monitor, std::string monitorName) { - static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); - static bool cursorDefaultDone = false; - static bool firstLaunch = true; - - const auto POS = monitor->middle(); - - // by default, cursor should be set to first monitor detected - // this is needed as a default if the monitor given in config above doesn't exist - if (firstLaunch) { - firstLaunch = false; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - return; - } - - if (!cursorDefaultDone && *PCURSORMONITOR != STRVAL_EMPTY) { - if (*PCURSORMONITOR == monitorName) { - cursorDefaultDone = true; - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - return; - } - } - - // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. - if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { - g_pCompositor->warpCursorTo(POS, true); - g_pInputManager->refocus(); - } -} - void CPointerManager::lockSoftwareAll() { for (auto const& state : monitorStates) state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 082855b5..4a4c4f61 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -26,7 +26,6 @@ class CPointerManager { public: CPointerManager(); - void checkDefaultCursorWarp(SP monitor, std::string monitorName); void attachPointer(SP pointer); void attachTouch(SP touch); void attachTablet(SP tablet); From eb97d949aa31b900d9735bcb8ead47acddc1f339 Mon Sep 17 00:00:00 2001 From: Sungyoon Cho Date: Mon, 16 Sep 2024 01:31:38 +0900 Subject: [PATCH 0616/2393] textinput: don't reset if ti isn't enabled (#7798) --- src/managers/input/TextInput.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/managers/input/TextInput.cpp b/src/managers/input/TextInput.cpp index e601ad9a..f7a6a350 100644 --- a/src/managers/input/TextInput.cpp +++ b/src/managers/input/TextInput.cpp @@ -99,6 +99,13 @@ void CTextInput::onReset() { if (g_pInputManager->m_sIMERelay.m_pIME.expired()) return; + if (!focusedSurface()) + return; + + const auto PFOCUSEDTI = g_pInputManager->m_sIMERelay.getFocusedTextInput(); + if (!PFOCUSEDTI || PFOCUSEDTI != this) + return; + g_pInputManager->m_sIMERelay.deactivateIME(this, false); g_pInputManager->m_sIMERelay.activateIME(this); } From e87758529e9d2dc70f318346c66a9d895d4503ce Mon Sep 17 00:00:00 2001 From: AlvinaNancy <152092635+AlvinaNancy@users.noreply.github.com> Date: Sun, 15 Sep 2024 17:25:06 +0000 Subject: [PATCH 0617/2393] internal: Fix change group current fullscreen state query (#7802) --- src/desktop/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index cc5b48af..feced807 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -991,7 +991,7 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { const auto PCURRENT = getGroupCurrent(); const bool FULLSCREEN = PCURRENT->isFullscreen(); const auto WORKSPACE = PCURRENT->m_pWorkspace; - const auto MODE = PCURRENT->m_sFullscreenState.client; + const auto MODE = PCURRENT->m_sFullscreenState.internal; const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); From 9e356562446f44c471ae38a80506a9df039305d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leiser=20Fern=C3=A1ndez=20Gallo?= Date: Sun, 15 Sep 2024 22:03:42 +0200 Subject: [PATCH 0618/2393] internal: Delay monitor events/hooks (#7797) * Delay monitor messages * Format --- src/helpers/Monitor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5b01d651..708a5cc8 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -192,10 +192,6 @@ void CMonitor::onConnect(bool noRule) { if (!activeMonitorRule.mirrorOf.empty()) setMirror(activeMonitorRule.mirrorOf); - g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); - EMIT_HOOK_EVENT("monitorAdded", this); - if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet g_pCompositor->setActiveMonitor(this); @@ -224,6 +220,10 @@ void CMonitor::onConnect(bool noRule) { PROTO::gamma->applyGammaToState(this); events.connect.emit(); + + g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); + g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); + EMIT_HOOK_EVENT("monitorAdded", this); } void CMonitor::onDisconnect(bool destroy) { @@ -281,9 +281,6 @@ void CMonitor::onDisconnect(bool destroy) { Debug::log(LOG, "Removed monitor {}!", szName); - g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); - EMIT_HOOK_EVENT("monitorRemoved", this); - if (!BACKUPMON) { Debug::log(WARN, "Unplugged last monitor, entering an unsafe state. Good luck my friend."); g_pCompositor->enterUnsafeState(); @@ -342,6 +339,9 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); + + g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); + EMIT_HOOK_EVENT("monitorRemoved", this); } void CMonitor::addDamage(const pixman_region32_t* rg) { From e72ae6b25fe019404df31e783ae980f80d3eaa3c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 17 Sep 2024 11:24:54 +0100 Subject: [PATCH 0619/2393] hyprctl: allow parsing empty value fixes #7821 --- src/debug/HyprCtl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 683665be..3d4d8092 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -987,9 +987,9 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { const auto COMMAND = in.substr(0, secondSpacePos); const auto VALUE = in.substr(secondSpacePos + 1); - // If either COMMAND or VALUE is empty, handle accordingly - if (COMMAND.empty() || VALUE.empty()) - return "Invalid input: command or value is empty"; + // If COMMAND is empty, handle accordingly + if (COMMAND.empty()) + return "Invalid input: command is empty"; std::string retval = g_pConfigManager->parseKeyword(COMMAND, VALUE); From 581f6659f8541476da82ebd819a564780b3a969e Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 17 Sep 2024 12:55:48 +0100 Subject: [PATCH 0620/2393] data-device: conform to reported source actions fixes #7815 --- src/protocols/core/DataDevice.cpp | 21 ++++++++++++++++++--- src/protocols/core/DataDevice.hpp | 3 ++- src/protocols/types/DataDevice.cpp | 4 ++++ src/protocols/types/DataDevice.hpp | 1 + 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index eac80a83..5644f243 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -82,8 +82,19 @@ void CWLDataOfferResource::sendData() { if (!source) return; - if (resource->version() >= 3) - resource->sendSourceActions(7); + const auto SOURCEACTIONS = source->actions(); + + if (resource->version() >= 3 && SOURCEACTIONS > 0) { + resource->sendSourceActions(SOURCEACTIONS); + if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + else if (SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + else { + LOGM(ERR, "Client bug? dnd source has no action move or copy. Sending move, f this."); + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + } + } for (auto const& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); @@ -111,7 +122,7 @@ CWLDataSourceResource::CWLDataSourceResource(SP resource_, SPsetOffer([this](CWlDataSource* r, const char* mime) { mimeTypes.push_back(mime); }); resource->setSetActions([this](CWlDataSource* r, uint32_t a) { LOGM(LOG, "DataSource {:x} actions {}", (uintptr_t)this, a); - actions = (wl_data_device_manager_dnd_action)a; + supportedActions = a; }); } @@ -193,6 +204,10 @@ void CWLDataSourceResource::sendDndAction(wl_data_device_manager_dnd_action a) { resource->sendAction(a); } +uint32_t CWLDataSourceResource::actions() { + return supportedActions; +} + CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 8aaf46be..50e9ac61 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -65,6 +65,7 @@ class CWLDataSourceResource : public IDataSource { virtual bool dndDone(); virtual void error(uint32_t code, const std::string& msg); virtual void sendDndFinished(); + virtual uint32_t actions(); // wl_data_device_manager.dnd_action void sendDndDropPerformed(); void sendDndAction(wl_data_device_manager_dnd_action a); @@ -78,7 +79,7 @@ class CWLDataSourceResource : public IDataSource { WP self; std::vector mimeTypes; - uint32_t actions = 0; + uint32_t supportedActions = 0; private: SP resource; diff --git a/src/protocols/types/DataDevice.cpp b/src/protocols/types/DataDevice.cpp index e95f1c76..36a7a157 100644 --- a/src/protocols/types/DataDevice.cpp +++ b/src/protocols/types/DataDevice.cpp @@ -23,3 +23,7 @@ eDataSourceType IDataSource::type() { void IDataSource::sendDndFinished() { ; } + +uint32_t IDataSource::actions() { + return 7; // all +} diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index f6757e1c..a62cc35e 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -26,6 +26,7 @@ class IDataSource { virtual void markUsed(); virtual void error(uint32_t code, const std::string& msg) = 0; virtual eDataSourceType type(); + virtual uint32_t actions(); // wl_data_device_manager.dnd_action struct { CSignal destroy; From 3c9716acfd00c6ea1b7bcd1dc63f97b51cc09998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Silva?= <123550+andresilva@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:37:20 +0100 Subject: [PATCH 0621/2393] gammactrl: fix potential crash on monitor removed (#7828) --- src/protocols/GammaControl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index d7992981..077d6e2f 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -19,7 +19,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out pMonitor = OUTPUTRES->monitor; - if (!pMonitor) { + if (!pMonitor || !pMonitor->output) { LOGM(ERR, "No CMonitor"); resource->sendFailed(); return; From 0564b46a5e9afbf2fb51a7198452342e43ba4637 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 18 Sep 2024 12:05:17 +0200 Subject: [PATCH 0622/2393] dispatchers: allow moveintogroup when floating (#7818) This allows to use the moveintogroup dispatcher when windows are floating. I don't know why was this disabled in the first place though. Cheers! --- src/managers/KeybindManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2f593d74..dd35bc19 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2730,7 +2730,7 @@ SDispatchResult CKeybindManager::moveIntoGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || PWINDOW->m_bIsFloating || PWINDOW->m_sGroupData.deny) + if (!PWINDOW || PWINDOW->m_sGroupData.deny) return {}; auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, arg); From 883d01084c52fdc5da0e6bfff7fd0f5cf0f62352 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 18 Sep 2024 11:22:07 +0100 Subject: [PATCH 0623/2393] userchecks: add an xdg_current_desktop check ref https://github.com/hyprwm/xdg-desktop-portal-hyprland/issues/251 if the XDG_CURRENT_DESKTOP is externally managed (e.g. DE, DM, etc) Hyprland will not overwrite it. In those cases, if that's undesired, portals and other apps depending on it might break. --- src/Compositor.cpp | 12 +++++++++++- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8e1b11b0..232ba4a6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2696,7 +2696,17 @@ WORKSPACEID CCompositor::getNewSpecialID() { } void CCompositor::performUserChecks() { - ; // intentional + static auto PNOCHECKXDG = CConfigValue("misc:disable_xdg_env_checks"); + + if (!*PNOCHECKXDG) { + const auto CURRENT_DESKTOP_ENV = getenv("XDG_CURRENT_DESKTOP"); + if (!CURRENT_DESKTOP_ENV || std::string{CURRENT_DESKTOP_ENV} != "Hyprland") { + g_pHyprNotificationOverlay->addNotification( + std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.", + CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"), + CColor{}, 15000, ICON_WARNING); + } + } } void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) { diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 44b5ee4a..84ac1a41 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1049,6 +1049,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{15, 1, 120}, }, + SConfigOptionDescription{ + .value = "misc:disable_xdg_env_checks", + .description = "disable the warning if XDG environment is externally managed", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 57cd2350..27e8fdb0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -371,6 +371,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:initial_workspace_tracking", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); + m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); From d936eb437b5d33cda21e1502a96dc7d83446aca5 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 17:26:51 +0300 Subject: [PATCH 0624/2393] flake.lock: update aquamarine --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 55dc6939..35974921 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1725753098, - "narHash": "sha256-/NO/h/qD/eJXAQr/fHA4mdDgYsNT9thHQ+oT6KPi2ac=", + "lastModified": 1726665257, + "narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "e4a13203112a036fc7f437d391c7810f3dd5ab52", + "rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", "type": "github" }, "original": { From 6b6554adb8c2fba5d89554af6fc467dcd15cedc0 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 14 Sep 2024 00:06:43 +0300 Subject: [PATCH 0625/2393] flake.nix: inherit stdenv from package Means we no longer have to change the base stdenv in two places. --- flake.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 9e1e3ab4..ef914627 100644 --- a/flake.nix +++ b/flake.nix @@ -95,13 +95,9 @@ devShells = eachSystem (system: { default = pkgsFor.${system}.mkShell.override { - stdenv = pkgsFor.${system}.gcc14Stdenv; + inherit (self.packages.${system}.default) stdenv; } { name = "hyprland-shell"; - nativeBuildInputs = with pkgsFor.${system}; [ - expat - libxml2 - ]; hardeningDisable = ["fortify"]; inputsFrom = [pkgsFor.${system}.hyprland]; packages = [pkgsFor.${system}.clang-tools]; From cbc0ff6ec0670e904758069c3844b05086bb15d3 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 18:54:00 +0300 Subject: [PATCH 0626/2393] Nix: disable PCH --- nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/default.nix b/nix/default.nix index 8d912fe6..b167a4df 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -149,6 +149,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.mesonEnable "xwayland" enableXWayland) (lib.mesonEnable "legacy_renderer" legacyRenderer) (lib.mesonEnable "systemd" withSystemd) + (lib.mesonEnable "b_pch" false) ]; postInstall = '' From b248d59713d99a8338d25f4765fd2f564069f98b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 18 Sep 2024 19:43:56 +0300 Subject: [PATCH 0627/2393] Nix: fix meson PCH flag --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index b167a4df..11e18e6c 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -149,7 +149,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov (lib.mesonEnable "xwayland" enableXWayland) (lib.mesonEnable "legacy_renderer" legacyRenderer) (lib.mesonEnable "systemd" withSystemd) - (lib.mesonEnable "b_pch" false) + "-Db_pch=false" ]; postInstall = '' From 94140e886ea8c4ac34478d290c212f0f5454ab2e Mon Sep 17 00:00:00 2001 From: Jasson Date: Wed, 18 Sep 2024 13:12:26 -0400 Subject: [PATCH 0628/2393] xwayland: Some readability improvements (#7807) * Readability improvements xwayland server * Made requested changes * removed braces * fix * Ok this time is fixed * Formatting --- src/xwayland/Server.cpp | 194 ++++++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 89 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index f3bf5768..97caf9e3 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -1,105 +1,115 @@ +#include #ifndef NO_XWAYLAND -#include "Server.hpp" -#include "../defines.hpp" -#include "../Compositor.hpp" -#include "../managers/CursorManager.hpp" -#include "XWayland.hpp" - +#include +#include #include #include +#include +#include #include #include #include -#include #include -#include -#include -#include #include #include +#include #include -#include +#include +#include +#include -// TODO: cleanup -static bool set_cloexec(int fd, bool cloexec) { +#include "Server.hpp" +#include "XWayland.hpp" +#include "debug/Log.hpp" +#include "../defines.hpp" +#include "../Compositor.hpp" +#include "../managers/CursorManager.hpp" + +// Constants +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 044; + +static bool setCloseOnExec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD); if (flags == -1) { Debug::log(ERR, "fcntl failed"); return false; } - if (cloexec) { + + if (cloexec) flags = flags | FD_CLOEXEC; - } else { + else flags = flags & ~FD_CLOEXEC; - } + if (fcntl(fd, F_SETFD, flags) == -1) { Debug::log(ERR, "fcntl failed"); return false; } + return true; } -static int openSocket(struct sockaddr_un* addr, size_t path_size) { - int fd, rc; - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; +void cleanUpSocket(int fd, const char* path) { + close(fd); + if (path[0]) + unlink(path); +} - fd = socket(AF_UNIX, SOCK_STREAM, 0); +static int createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - Debug::log(ERR, "failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); return -1; } - if (!set_cloexec(fd, true)) { + + if (!setCloseOnExec(fd, true)) { close(fd); return -1; } - if (addr->sun_path[0]) { + if (addr->sun_path[0]) unlink(addr->sun_path); - } + if (bind(fd, (struct sockaddr*)addr, size) < 0) { - rc = errno; - Debug::log(ERR, "failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - goto cleanup; + Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + cleanUpSocket(fd, addr->sun_path); + return -1; } - if (listen(fd, 1) < 0) { - rc = errno; - Debug::log(ERR, "failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - goto cleanup; + + if (listen(fd, SOCKET_BACKLOG) < 0) { + Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + cleanUpSocket(fd, addr->sun_path); + return -1; } return fd; - -cleanup: - close(fd); - if (addr->sun_path[0]) { - unlink(addr->sun_path); - } - errno = rc; - return -1; } static bool checkPermissionsForSocketDir(void) { struct stat buf; if (lstat("/tmp/.X11-unix", &buf)) { - Debug::log(ERR, "Failed statting X11 socket dir"); + Debug::log(ERR, "Failed to stat X11 socket dir"); return false; } if (!(buf.st_mode & S_IFDIR)) { - Debug::log(ERR, "X11 socket dir is not a dir"); + Debug::log(ERR, "X11 socket dir is not a directory"); return false; } if (!((buf.st_uid == 0) || (buf.st_uid == getuid()))) { - Debug::log(ERR, "X11 socket dir is not ours"); + Debug::log(ERR, "X11 socket dir is not owned by root or current user"); return false; } if (!(buf.st_mode & S_ISVTX)) { if ((buf.st_mode & (S_IWGRP | S_IWOTH))) { - Debug::log(ERR, "X11 socket dir is sticky by others"); + Debug::log(ERR, "X11 socket dir is writable by others"); return false; } } @@ -107,38 +117,51 @@ static bool checkPermissionsForSocketDir(void) { return true; } -static bool openSockets(std::array& sockets, int display) { - auto ret = mkdir("/tmp/.X11-unix", 755); - - if (ret != 0) { - if (errno == EEXIST) { - if (!checkPermissionsForSocketDir()) - return false; - } else { - Debug::log(ERR, "XWayland: couldn't create socket dir"); +static bool ensureSocketDirExists() { + if (mkdir("/tmp/.X11-unix", SOCKET_DIR_PERMISSIONS) != 0) { + if (errno == EEXIST) + return checkPermissionsForSocketDir(); + else { + Debug::log(ERR, "XWayland: Couldn't create socket dir"); return false; } } - std::string path; + return true; +} + +static std::string getSocketPath(int display, bool isLinux) { + if (isLinux) + return std::format("/tmp/.X11-unix{}", display); + + return std::format("/tmp/.X11-unix{}_", display); +} + +static bool openSockets(std::array& sockets, int display) { + if (!ensureSocketDirExists()) + return false; + sockaddr_un addr = {.sun_family = AF_UNIX}; + std::string path; #ifdef __linux__ // cursed... addr.sun_path[0] = 0; - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1); #else - path = std::format("/tmp/.X11-unix/X{}_", display); + path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); #endif - sockets[0] = openSocket(&addr, path.length()); + + sockets[0] = createSocket(&addr, path.length()); if (sockets[0] < 0) return false; - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = openSocket(&addr, path.length()); + + sockets[1] = createSocket(&addr, path.length()); if (sockets[1] < 0) { close(sockets[0]); sockets[0] = -1; @@ -160,39 +183,37 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) { static bool safeRemove(const std::string& path) { try { return std::filesystem::remove(path); - } catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); } - + } catch (const std::exception& e) { Debug::log(ERR, "[XWayland] Failed to remove {}", path); } return false; } bool CXWaylandServer::tryOpenSockets() { - for (size_t i = 0; i <= 32; ++i) { - auto LOCK = std::format("/tmp/.X{}-lock", i); + for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { + std::string lockPath = std::format("/tmp/.X{}-lock", i); - if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { + int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); + if (fd >= 0) { // we managed to open the lock if (!openSockets(xFDs, i)) { - safeRemove(LOCK); + safeRemove(lockPath); close(fd); continue; } - const auto PIDSTR = std::format("{}", getpid()); - - if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { - safeRemove(LOCK); + const std::string pidStr = std::to_string(getpid()); + if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + safeRemove(lockPath); close(fd); continue; } close(fd); - display = i; displayName = std::format(":{}", display); break; } - int fd = open(LOCK.c_str(), O_RDONLY | O_CLOEXEC); + fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); if (fd < 0) continue; @@ -201,21 +222,20 @@ bool CXWaylandServer::tryOpenSockets() { read(fd, pidstr, sizeof(pidstr) - 1); close(fd); - uint64_t pid = 0; + int32_t pid = 0; try { pid = std::stoi(std::string{pidstr, 11}); } catch (...) { continue; } if (kill(pid, 0) != 0 && errno == ESRCH) { - if (!safeRemove(LOCK)) + if (!safeRemove(lockPath)) continue; - i--; } } if (display < 0) { - Debug::log(ERR, "Failed to find a suitable socket for xwayland"); + Debug::log(ERR, "Failed to find a suitable socket for XWayland"); return false; } @@ -232,19 +252,17 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - if (xFDs[0]) - close(xFDs[0]); - if (xFDs[1]) - close(xFDs[1]); + close(xFDs[0]); + close(xFDs[1]); - auto LOCK = std::format("/tmp/.X{}-lock", display); - safeRemove(LOCK); + std::string lockPath = std::format("/tmp/.X{}-lock", display); + safeRemove(lockPath); std::string path; #ifdef __linux__ - path = std::format("/tmp/.X11-unix/X{}", display); + path = getSocketPath(display, true); #else - path = std::format("/tmp/.X11-unix/X{}_", display); + path = getSocketPath(display, false); #endif safeRemove(path); } @@ -256,7 +274,6 @@ void CXWaylandServer::die() { if (xFDReadEvents[0]) { wl_event_source_remove(xFDReadEvents[0]); wl_event_source_remove(xFDReadEvents[1]); - xFDReadEvents = {nullptr, nullptr}; } @@ -298,7 +315,7 @@ bool CXWaylandServer::create() { } void CXWaylandServer::runXWayland(int notifyFD) { - if (!set_cloexec(xFDs[0], false) || !set_cloexec(xFDs[1], false) || !set_cloexec(waylandFDs[1], false) || !set_cloexec(xwmFDs[1], false)) { + if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } @@ -325,7 +342,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(waylandFDs[0], true) || !set_cloexec(waylandFDs[1], true)) { + if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; @@ -337,7 +354,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(xwmFDs[0], true) || !set_cloexec(xwmFDs[1], true)) { + if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; @@ -359,7 +376,7 @@ bool CXWaylandServer::start() { return false; } - if (!set_cloexec(notify[0], true)) { + if (!setCloseOnExec(notify[0], true)) { Debug::log(ERR, "set_cloexec failed (3)"); close(notify[0]); close(notify[1]); @@ -382,9 +399,8 @@ bool CXWaylandServer::start() { if (pid < 0) { Debug::log(ERR, "second fork failed"); _exit(1); - } else if (pid == 0) { + } else if (pid == 0) runXWayland(notify[1]); - } _exit(0); } From e6cf643f5ab1c1545fb858ab1fd9d7538ef9e0f3 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:47:53 +0100 Subject: [PATCH 0629/2393] pointermgr: Hide hardware cursor on leave (#7806) --- src/managers/PointerManager.cpp | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 5a192e13..3dcee431 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -208,9 +208,8 @@ void CPointerManager::recheckEnteredOutputs() { // if we are using hw cursors, prevent // the cursor from being stuck at the last point. - // if we are leaving it, move it to narnia. if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)) - s->monitor->output->moveCursor({-1337, -420}); + setHWCursorBuffer(s, nullptr); if (!currentCursorImage.surface) continue; @@ -269,6 +268,8 @@ void CPointerManager::resetCursorImage(bool apply) { void CPointerManager::updateCursorBackend() { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + const auto CURSORBOX = getCursorBoxGlobal(); + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); @@ -277,6 +278,15 @@ void CPointerManager::updateCursorBackend() { continue; } + auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); + + if (!CROSSES) { + if (state->cursorFrontBuffer) + setHWCursorBuffer(state, nullptr); + + continue; + } + if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); @@ -297,17 +307,34 @@ void CPointerManager::onCursorMoved() { if (!hasCursor()) return; + const auto CURSORBOX = getCursorBoxGlobal(); + bool recalc = false; + for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); + auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); + + if (!CROSSES && state->cursorFrontBuffer) { + Debug::log(TRACE, "onCursorMoved for output {}: cursor left the viewport, removing it from the backend", m->szName); + setHWCursorBuffer(state, nullptr); + continue; + } else if (CROSSES && !state->cursorFrontBuffer) { + Debug::log(TRACE, "onCursorMoved for output {}: cursor entered the output, but no front buffer, forcing recalc", m->szName); + recalc = true; + } + if (state->hardwareFailed || !state->entered) continue; const auto CURSORPOS = getCursorPosForMonitor(m); m->output->moveCursor(CURSORPOS); } + + if (recalc) + updateCursorBackend(); } bool CPointerManager::attemptHardwareCursor(SP state) { From 1bc05b1f9fd55f2a7371082e6914622e4584ed54 Mon Sep 17 00:00:00 2001 From: Arisa Snowbell Date: Thu, 19 Sep 2024 12:08:02 +0200 Subject: [PATCH 0630/2393] xwayland: use proper path for the XWayland sockets (#7852) fixes #7849 --- src/xwayland/Server.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 97caf9e3..5ad9ff23 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -132,9 +132,9 @@ static bool ensureSocketDirExists() { static std::string getSocketPath(int display, bool isLinux) { if (isLinux) - return std::format("/tmp/.X11-unix{}", display); + return std::format("/tmp/.X11-unix/X{}", display); - return std::format("/tmp/.X11-unix{}_", display); + return std::format("/tmp/.X11-unix/X{}_", display); } static bool openSockets(std::array& sockets, int display) { From 71963972bff15acccd9abd0dfd3e70504609b7cc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 19 Sep 2024 11:25:58 +0100 Subject: [PATCH 0631/2393] args: add --version to binary args --- src/main.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 820a248c..525ad4ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,9 @@ #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include +using namespace Hyprutils::String; + #include #include #include @@ -20,6 +23,7 @@ void help() { std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; + std::cout << " --version -v - Print this binary's version\n"; } int main(int argc, char** argv) { @@ -109,6 +113,24 @@ int main(int argc, char** argv) { } else if (it->compare("-h") == 0 || it->compare("--help") == 0) { help(); + return 0; + } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { + auto commitMsg = trim(GIT_COMMIT_MESSAGE); + std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); + std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + +#ifdef LEGACY_RENDERER + result += "legacyrenderer\n"; +#endif +#ifndef ISDEBUG + result += "debug\n"; +#endif +#ifdef NO_XWAYLAND + result += "no xwayland\n"; +#endif + + std::cout << result; return 0; } else { std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; From 92df6b0dce1b81b130c2b0e46d206c8c3dbb2971 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 19 Sep 2024 11:39:54 +0100 Subject: [PATCH 0632/2393] version: log build aquamarine version log the built against aq version, might be useful when it's mismatched to identify the problem --- CMakeLists.txt | 7 +++++-- src/debug/HyprCtl.cpp | 7 +++++-- src/main.cpp | 3 ++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fdf98db..b6ac8efc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,11 +91,14 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine) + +add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") + pkg_check_modules( deps REQUIRED IMPORTED_TARGET - aquamarine xkbcommon uuid wayland-server @@ -220,7 +223,7 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::deps) +target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3d4d8092..9faefe26 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -858,7 +858,8 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + + "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; @@ -881,8 +882,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "commit_date": "{}", "tag": "{}", "commits": "{}", + "buildAquamarine": "{}", "flags": [)#", - GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS); + GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, + AQUAMARINE_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; diff --git a/src/main.cpp b/src/main.cpp index 525ad4ff..ba6fe505 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,7 +118,8 @@ int main(int argc, char** argv) { auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + "\n\nflags: (if any)\n"; + ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + + "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; From dfa1bd0cd48253a446fbe455a46f0f4d23368c02 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 19 Sep 2024 13:48:31 +0000 Subject: [PATCH 0633/2393] Meson: pass AQUAMARINE_VERSION argument --- meson.build | 3 +++ src/meson.build | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 123c31ae..9449c241 100644 --- a/meson.build +++ b/meson.build @@ -30,6 +30,9 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif +aquamarine = dependency('aquamarine') +add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') + xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) xcb_errors_dep = dependency('xcb-errors', required: get_option('xwayland')) diff --git a/src/meson.build b/src/meson.build index 3821bd60..928cd5a7 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,7 +8,7 @@ executable( cpp_pch: 'pch/pch.hpp', dependencies: [ server_protos, - dependency('aquamarine'), + aquamarine, dependency('gbm'), dependency('xcursor'), dependency('wayland-server'), From 9856378384539e35cd943604e6a4d696a9d25447 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 19 Sep 2024 18:53:34 +0300 Subject: [PATCH 0634/2393] Nix: use mold linker --- nix/default.nix | 237 +++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 115 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 11e18e6c..3d621db6 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -1,6 +1,7 @@ { lib, stdenv, + stdenvAdapters, pkg-config, pkgconf, makeWrapper, @@ -46,130 +47,136 @@ enableNvidiaPatches ? false, nvidiaPatches ? false, hidpiXWayland ? false, -}: -assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; -assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; -assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; - stdenv.mkDerivation { - pname = "hyprland${lib.optionalString debug "-debug"}"; - inherit version; +}: let + adapters = lib.flatten [ + stdenvAdapters.useMoldLinker + ]; - src = lib.cleanSourceWith { - filter = name: type: let - baseName = baseNameOf (toString name); - in - ! (lib.hasSuffix ".nix" baseName); - src = lib.cleanSource ../.; - }; + customStdenv = builtins.foldl' (acc: adapter: adapter acc) stdenv adapters; +in + assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; + assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; + assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; + customStdenv.mkDerivation { + pname = "hyprland${lib.optionalString debug "-debug"}"; + inherit version; - postPatch = '' - # Fix hardcoded paths to /usr installation - sed -i "s#/usr#$out#" src/render/OpenGL.cpp + src = lib.cleanSourceWith { + filter = name: type: let + baseName = baseNameOf (toString name); + in + ! (lib.hasSuffix ".nix" baseName); + src = lib.cleanSource ../.; + }; - # Remove extra @PREFIX@ to fix pkg-config paths - sed -i "s#@PREFIX@/##g" hyprland.pc.in - ''; + postPatch = '' + # Fix hardcoded paths to /usr installation + sed -i "s#/usr#$out#" src/render/OpenGL.cpp - COMMITS = revCount; - DATE = date; - DIRTY = lib.optionalString (commit == "") "dirty"; - HASH = commit; + # Remove extra @PREFIX@ to fix pkg-config paths + sed -i "s#@PREFIX@/##g" hyprland.pc.in + ''; - depsBuildBuild = [ - pkg-config - ]; + COMMITS = revCount; + DATE = date; + DIRTY = lib.optionalString (commit == "") "dirty"; + HASH = commit; - nativeBuildInputs = [ - hyprwayland-scanner - jq - makeWrapper - meson - cmake - ninja - pkg-config - python3 # for udis86 - wayland-scanner - ]; + depsBuildBuild = [ + pkg-config + ]; - outputs = [ - "out" - "man" - "dev" - ]; + nativeBuildInputs = [ + hyprwayland-scanner + jq + makeWrapper + meson + cmake + ninja + pkg-config + python3 # for udis86 + wayland-scanner + ]; - buildInputs = lib.concatLists [ - [ - aquamarine - cairo - # expat - # fribidi - git - hyprcursor - hyprlang - hyprutils - # libdatrie - libdrm - libGL - libinput - # libselinux - # libsepol - # libthai - libuuid - libxkbcommon - mesa - pango - pciutils - # pcre2 - tomlplusplus - wayland - wayland-protocols - xorg.libXcursor - ] - (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) - (lib.optionals enableXWayland [ - xorg.libxcb - xorg.libXdmcp - xorg.xcbutilerrors - xorg.xcbutilrenderutil - xorg.xcbutilwm - xwayland - ]) - (lib.optionals withSystemd [systemd]) - ]; + outputs = [ + "out" + "man" + "dev" + ]; - mesonBuildType = - if debug - then "debug" - else "release"; - - # we want as much debug info as possible - dontStrip = debug; - - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) - (lib.mesonEnable "legacy_renderer" legacyRenderer) - (lib.mesonEnable "systemd" withSystemd) - "-Db_pch=false" - ]; - - postInstall = '' - ${lib.optionalString wrapRuntimeDeps '' - wrapProgram $out/bin/Hyprland \ - --suffix PATH : ${lib.makeBinPath [ - binutils + buildInputs = lib.concatLists [ + [ + aquamarine + cairo + # expat + # fribidi + git + hyprcursor + hyprlang + hyprutils + # libdatrie + libdrm + libGL + libinput + # libselinux + # libsepol + # libthai + libuuid + libxkbcommon + mesa + pango pciutils - pkgconf - ]} - ''} - ''; + # pcre2 + tomlplusplus + wayland + wayland-protocols + xorg.libXcursor + ] + (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) + (lib.optionals enableXWayland [ + xorg.libxcb + xorg.libXdmcp + xorg.xcbutilerrors + xorg.xcbutilrenderutil + xorg.xcbutilwm + xwayland + ]) + (lib.optionals withSystemd [systemd]) + ]; - passthru.providedSessions = ["hyprland"]; + mesonBuildType = + if debug + then "debug" + else "release"; - meta = { - homepage = "https://github.com/hyprwm/Hyprland"; - description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; - license = lib.licenses.bsd3; - platforms = lib.platforms.linux; - mainProgram = "Hyprland"; - }; - } + # we want as much debug info as possible + dontStrip = debug; + + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + (lib.mesonEnable "legacy_renderer" legacyRenderer) + (lib.mesonEnable "systemd" withSystemd) + "-Db_pch=false" + ]; + + postInstall = '' + ${lib.optionalString wrapRuntimeDeps '' + wrapProgram $out/bin/Hyprland \ + --suffix PATH : ${lib.makeBinPath [ + binutils + pciutils + pkgconf + ]} + ''} + ''; + + passthru.providedSessions = ["hyprland"]; + + meta = { + homepage = "https://github.com/hyprwm/Hyprland"; + description = "Dynamic tiling Wayland compositor that doesn't sacrifice on its looks"; + license = lib.licenses.bsd3; + platforms = lib.platforms.linux; + mainProgram = "Hyprland"; + }; + } From 9e98fb0167f8bc6c5eb4510a65b42aaa3b743421 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 20 Sep 2024 10:47:34 +0100 Subject: [PATCH 0635/2393] dmabuffer: attempt importing failed dmabufs as implicit don't ask me why, vulkan doesn't like this. funny note, broken on wlroots :P fixes #7037 --- src/protocols/types/DMABuffer.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 63a26c76..a8c7248e 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -16,8 +16,15 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); - if (!eglImage) - return; + if (!eglImage) { + Debug::log(ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit"); + attrs.modifier = DRM_FORMAT_MOD_INVALID; + eglImage = g_pHyprOpenGL->createEGLImage(attrs); + if (!eglImage) { + Debug::log(ERR, "CDMABuffer: failed to import EGLImage"); + return; + } + } texture = makeShared(attrs, eglImage); // texture takes ownership of the eglImage opaque = FormatUtils::isFormatOpaque(attrs.format); From 4414cd07e257a57362e73d1f6efe1df692ae3762 Mon Sep 17 00:00:00 2001 From: Jasson Date: Fri, 20 Sep 2024 07:32:04 -0400 Subject: [PATCH 0636/2393] xwm: Minor cleanup, add wrappers for basic types (#7856) --- src/xwayland/XDataSource.cpp | 2 +- src/xwayland/XSurface.cpp | 13 ++++---- src/xwayland/XWM.cpp | 37 +++++++++------------ src/xwayland/XWM.hpp | 62 ++++++++++++++++++++++++++++++------ 4 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index f4059ee1..c6495435 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -1,8 +1,8 @@ #ifndef NO_XWAYLAND -#include "XDataSource.hpp" #include "XWayland.hpp" #include "../defines.hpp" +#include "XDataSource.hpp" #include diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 02fe2b3b..e734c153 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -5,8 +5,8 @@ #ifndef NO_XWAYLAND -#include "../Compositor.hpp" #include +#include "../Compositor.hpp" CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { xcb_res_query_client_ids_cookie_t client_id_cookie = {0}; @@ -196,12 +196,11 @@ void CXWaylandSurface::restackToTop() { xcb_configure_window(g_pXWayland->pWM->connection, xID, XCB_CONFIG_WINDOW_STACK_MODE, values); - for (auto it = g_pXWayland->pWM->mappedSurfacesStacking.begin(); it != g_pXWayland->pWM->mappedSurfacesStacking.end(); ++it) { - if (*it == self) { - std::rotate(it, it + 1, g_pXWayland->pWM->mappedSurfacesStacking.end()); - break; - } - } + auto& stack = g_pXWayland->pWM->mappedSurfacesStacking; + auto it = std::find(stack.begin(), stack.end(), self); + + if (it != stack.end()) + std::rotate(it, it + 1, stack.end()); g_pXWayland->pWM->updateClientList(); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index e8e2258a..dcb22eae 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1,20 +1,21 @@ #include "helpers/math/Math.hpp" +#include #ifndef NO_XWAYLAND +#include +#include +#include +#include +#include +#include + #include "XWayland.hpp" #include "../defines.hpp" -#include #include "../Compositor.hpp" +#include "../protocols/core/Seat.hpp" +#include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" -#include "../managers/SeatManager.hpp" -#include "../protocols/core/Seat.hpp" -#include -#include -#include -#include - -#include #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -830,15 +831,15 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() { - connection = xcb_connect_to_fd(g_pXWayland->pServer->xwmFDs[0], nullptr); +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { - if (int ret = xcb_connection_has_error(connection); ret) { - Debug::log(ERR, "[xwm] Couldn't start, error {}", ret); + if (connection.hasError()) { + Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); return; } - if (xcb_errors_context_new(connection, &errors)) { + CXCBErrorContext xcbErrCtx(connection); + if (!xcbErrCtx.isValid()) { Debug::log(ERR, "[xwm] Couldn't allocate errors context"); return; } @@ -867,10 +868,7 @@ CXWM::CXWM() { }; xcb_change_property(connection, XCB_PROP_MODE_REPLACE, screen->root, HYPRATOMS["_NET_SUPPORTED"], XCB_ATOM_ATOM, 32, sizeof(supported) / sizeof(*supported), supported); - xcb_flush(connection); - setActiveWindow(XCB_WINDOW_NONE); - initSelection(); listeners.newWLSurface = PROTO::compositor->events.newSurface.registerListener([this](std::any d) { onNewSurface(std::any_cast>(d)); }); @@ -882,11 +880,6 @@ CXWM::CXWM() { } CXWM::~CXWM() { - if (errors) - xcb_errors_context_free(errors); - - if (connection) - xcb_disconnect(connection); if (eventSource) wl_event_source_remove(eventSource); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 59695720..ba00dd8d 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,17 +1,16 @@ #pragma once -#include "../helpers/signal/Signal.hpp" -#include "../helpers/memory/Memory.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" - #include "XDataSource.hpp" +#include "../helpers/WLListener.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/signal/Signal.hpp" #include -#include -#include -#include #include +#include +#include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -58,6 +57,49 @@ struct SXSelection { std::unique_ptr transfer; }; +class CXCBConnection { + public: + CXCBConnection(int fd) { + connection = xcb_connect_to_fd(fd, nullptr); + } + + ~CXCBConnection() { + if (connection) + xcb_disconnect(connection); + } + + bool hasError() const { + return xcb_connection_has_error(connection); + } + + operator xcb_connection_t*() const { + return connection; + } + + private: + xcb_connection_t* connection = nullptr; +}; + +class CXCBErrorContext { + public: + explicit CXCBErrorContext(xcb_connection_t* connection) { + if (xcb_errors_context_new(connection, &errors) != 0) + errors = nullptr; + } + + ~CXCBErrorContext() { + if (errors) + xcb_errors_context_free(errors); + } + + bool isValid() const { + return errors != nullptr; + } + + private: + xcb_errors_context_t* errors = nullptr; +}; + class CXWM { public: CXWM(); @@ -123,9 +165,9 @@ class CXWM { void readProp(SP XSURF, uint32_t atom, xcb_get_property_reply_t* reply); // - xcb_connection_t* connection = nullptr; - xcb_errors_context_t* errors = nullptr; - xcb_screen_t* screen = nullptr; + CXCBConnection connection; + xcb_errors_context_t* errors = nullptr; + xcb_screen_t* screen = nullptr; xcb_window_t wmWindow; From 278583b8a1ab66272a4c437ed1acd7936a6a5c36 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 20 Sep 2024 20:16:13 +0300 Subject: [PATCH 0637/2393] flake.lock: update --- flake.lock | 24 +++++++++++++++--------- flake.nix | 2 ++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 35974921..608c5bbb 100644 --- a/flake.lock +++ b/flake.lock @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1721324119, - "narHash": "sha256-SOOqIT27/X792+vsLSeFdrNTF+OSRp5qXv6Te+fb2Qg=", + "lastModified": 1726840673, + "narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "a048a6cb015340bd82f97c1f40a4b595ca85cc30", + "rev": "b68dab23fc922eae99306988133ee80a40b39ca5", "type": "github" }, "original": { @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1725983898, - "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", + "lastModified": 1726755586, + "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", + "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", "type": "github" }, "original": { @@ -201,6 +201,12 @@ "hyprlang": [ "hyprlang" ], + "hyprutils": [ + "hyprutils" + ], + "hyprwayland-scanner": [ + "hyprwayland-scanner" + ], "nixpkgs": [ "nixpkgs" ], @@ -209,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726046979, - "narHash": "sha256-6SEsjurq9cdTkITA6d49ncAJe4O/8CgRG5/F//s6Xh8=", + "lastModified": 1726851729, + "narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "e695669fd8e1d1be9eaae40f35e00f8bd8b64c18", + "rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index ef914627..ef48b2d1 100644 --- a/flake.nix +++ b/flake.nix @@ -46,6 +46,8 @@ inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; inputs.hyprlang.follows = "hyprlang"; + inputs.hyprutils.follows = "hyprutils"; + inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; }; }; From db0b764a5ac22e752d8557cc1e1e5a42ac58c7e4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 20 Sep 2024 22:56:10 +0100 Subject: [PATCH 0638/2393] shm: send a static list of shm formats fixes #7733 --- src/protocols/core/Shm.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index b09326bd..a8c98bb0 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -193,11 +193,8 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, }; - for (auto const& fmt : g_pHyprOpenGL->getDRMFormats()) { - if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) - continue; - - shmFormats.push_back(fmt.drmFormat); + for (auto const& fmt : supportedShmFourccFormats) { + shmFormats.push_back(fmt); } } From 9232bc2c00a57b99ac876b43fdfedfa25c2de774 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 21 Sep 2024 00:33:48 +0100 Subject: [PATCH 0639/2393] internal: move to hyprutils' scopeguard bumps hyprutils dep to 0.2.2 --- CMakeLists.txt | 2 +- flake.lock | 6 +++--- src/helpers/Monitor.cpp | 3 ++- src/helpers/ScopeGuard.cpp | 10 ---------- src/helpers/ScopeGuard.hpp | 13 ------------- src/render/Renderer.cpp | 4 +++- 6 files changed, 9 insertions(+), 29 deletions(-) delete mode 100644 src/helpers/ScopeGuard.cpp delete mode 100644 src/helpers/ScopeGuard.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b6ac8efc..e1718b2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ pkg_check_modules( gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 - hyprutils>=0.2.1) + hyprutils>=0.2.2) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index 608c5bbb..024bcf50 100644 --- a/flake.lock +++ b/flake.lock @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1724966483, - "narHash": "sha256-WXDgKIbzjYKczxSZOsJplCS1i1yrTUpsDPuJV/xpYLo=", + "lastModified": 1726874949, + "narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8976e3f6a5357da953a09511d0c7f6a890fb6ec2", + "rev": "d97af4f6bd068c03a518b597675e598f57ea2291", "type": "github" }, "original": { diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 708a5cc8..223a3f94 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -2,7 +2,6 @@ #include "MiscFunctions.hpp" #include "math/Math.hpp" #include "sync/SyncReleaser.hpp" -#include "ScopeGuard.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/GammaControl.hpp" @@ -17,7 +16,9 @@ #include "sync/SyncTimeline.hpp" #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::Utils; int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); diff --git a/src/helpers/ScopeGuard.cpp b/src/helpers/ScopeGuard.cpp deleted file mode 100644 index 319255cd..00000000 --- a/src/helpers/ScopeGuard.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "ScopeGuard.hpp" - -CScopeGuard::CScopeGuard(const std::function& fn_) : fn(fn_) { - ; -} - -CScopeGuard::~CScopeGuard() { - if (fn) - fn(); -} diff --git a/src/helpers/ScopeGuard.hpp b/src/helpers/ScopeGuard.hpp deleted file mode 100644 index 8a1468eb..00000000 --- a/src/helpers/ScopeGuard.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -// calls a function when it goes out of scope -class CScopeGuard { - public: - CScopeGuard(const std::function& fn_); - ~CScopeGuard(); - - private: - std::function fn; -}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 08bf76cb..417a3ff8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,7 +1,6 @@ #include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" -#include "../helpers/ScopeGuard.hpp" #include "../helpers/sync/SyncReleaser.hpp" #include #include @@ -23,6 +22,9 @@ #include "../helpers/sync/SyncTimeline.hpp" #include "debug/Log.hpp" +#include +using namespace Hyprutils::Utils; + extern "C" { #include } From 8579066c7a1ceb745499ea4e11d5d420b1387ec0 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 21 Sep 2024 14:27:13 +0300 Subject: [PATCH 0640/2393] Nix: clean up derivation --- nix/default.nix | 58 +++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 3d621db6..40675d9a 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -48,25 +48,32 @@ nvidiaPatches ? false, hidpiXWayland ? false, }: let - adapters = lib.flatten [ + inherit (builtins) baseNameOf foldl'; + inherit (lib.asserts) assertMsg; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.lists) flatten concatLists optional optionals; + inherit (lib.sources) cleanSourceWith cleanSource; + inherit (lib.strings) hasSuffix makeBinPath optionalString mesonBool mesonEnable; + + adapters = flatten [ stdenvAdapters.useMoldLinker ]; - customStdenv = builtins.foldl' (acc: adapter: adapter acc) stdenv adapters; + customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; in - assert lib.assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; - assert lib.assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; - assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; + assert assertMsg (!nvidiaPatches) "The option `nvidiaPatches` has been removed."; + assert assertMsg (!enableNvidiaPatches) "The option `enableNvidiaPatches` has been removed."; + assert assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been removed. Please refer https://wiki.hyprland.org/Configuring/XWayland"; customStdenv.mkDerivation { - pname = "hyprland${lib.optionalString debug "-debug"}"; + pname = "hyprland${optionalString debug "-debug"}"; inherit version; - src = lib.cleanSourceWith { + src = cleanSourceWith { filter = name: type: let baseName = baseNameOf (toString name); in - ! (lib.hasSuffix ".nix" baseName); - src = lib.cleanSource ../.; + ! (hasSuffix ".nix" baseName); + src = cleanSource ../.; }; postPatch = '' @@ -79,7 +86,7 @@ in COMMITS = revCount; DATE = date; - DIRTY = lib.optionalString (commit == "") "dirty"; + DIRTY = optionalString (commit == "") "dirty"; HASH = commit; depsBuildBuild = [ @@ -104,36 +111,29 @@ in "dev" ]; - buildInputs = lib.concatLists [ + buildInputs = concatLists [ [ aquamarine cairo - # expat - # fribidi git hyprcursor hyprlang hyprutils - # libdatrie libdrm libGL libinput - # libselinux - # libsepol - # libthai libuuid libxkbcommon mesa pango pciutils - # pcre2 tomlplusplus wayland wayland-protocols xorg.libXcursor ] - (lib.optionals stdenv.hostPlatform.isMusl [libexecinfo]) - (lib.optionals enableXWayland [ + (optionals customStdenv.hostPlatform.isMusl [libexecinfo]) + (optionals enableXWayland [ xorg.libxcb xorg.libXdmcp xorg.xcbutilerrors @@ -141,7 +141,7 @@ in xorg.xcbutilwm xwayland ]) - (lib.optionals withSystemd [systemd]) + (optional withSystemd systemd) ]; mesonBuildType = @@ -152,17 +152,19 @@ in # we want as much debug info as possible dontStrip = debug; - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) - (lib.mesonEnable "legacy_renderer" legacyRenderer) - (lib.mesonEnable "systemd" withSystemd) - "-Db_pch=false" + mesonFlags = flatten [ + (mapAttrsToList mesonEnable { + "xwayland" = enableXWayland; + "legacy_renderer" = legacyRenderer; + "systemd" = withSystemd; + }) + (mesonBool "b_pch" false) ]; postInstall = '' - ${lib.optionalString wrapRuntimeDeps '' + ${optionalString wrapRuntimeDeps '' wrapProgram $out/bin/Hyprland \ - --suffix PATH : ${lib.makeBinPath [ + --suffix PATH : ${makeBinPath [ binutils pciutils pkgconf From e5ff19ac0f2c8d53a0c847d06a17676e636d6447 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sat, 21 Sep 2024 16:52:11 +0200 Subject: [PATCH 0641/2393] flake: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 024bcf50..76351cc9 100644 --- a/flake.lock +++ b/flake.lock @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726851729, - "narHash": "sha256-1z0esr5lBeUMlrPZ9gZmqZT8oTQekxJi53HAW4cH0Ms=", + "lastModified": 1726933538, + "narHash": "sha256-xTqnMoJsEojuvqJLuM+U7EZ7q71efaj3pbvjutq4TXc=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "73b8c4f1150040644cf678aa8bbf2cec48a433cf", + "rev": "4880c50146d0c2a3152d2b02f79253810c330c11", "type": "github" }, "original": { From 508bde1f61b1264c9621b937657088f09f318ce0 Mon Sep 17 00:00:00 2001 From: Artur Manuel Date: Mon, 23 Sep 2024 16:40:19 +0100 Subject: [PATCH 0642/2393] core: add HYPRLAND_CONFIG environment variable (#7851) --- src/config/ConfigManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 27e8fdb0..21a3a21e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -683,6 +683,10 @@ std::string CConfigManager::getMainConfigPath() { if (!g_pCompositor->explicitConfigPath.empty()) return g_pCompositor->explicitConfigPath; + if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV) + return CFG_ENV; + Debug::log(TRACE, "Seems as if HYPRLAND_CONFIG isn't set, let's see what we can do with HOME."); + static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); if (paths.first.has_value()) { return paths.first.value(); From f79497087bdea3ea2706606362ba99cfe7a956a0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 23 Sep 2024 17:59:35 +0100 Subject: [PATCH 0643/2393] internal: nuke wlsignal and related old semi-wrappers for wl_signal, they are no longer used --- src/defines.hpp | 1 - src/desktop/Subsurface.cpp | 8 +--- src/desktop/Subsurface.hpp | 4 -- src/devices/IKeyboard.hpp | 1 - src/devices/IPointer.hpp | 1 - src/devices/ITouch.hpp | 1 - src/devices/Tablet.hpp | 1 - src/helpers/WLListener.cpp | 62 ------------------------- src/helpers/WLListener.hpp | 39 ---------------- src/managers/SeatManager.hpp | 1 - src/managers/input/InputMethodPopup.hpp | 1 - src/managers/input/TextInput.hpp | 1 - src/protocols/FocusGrab.hpp | 3 -- src/protocols/PresentationTime.hpp | 2 - src/render/Renderbuffer.hpp | 1 - src/xwayland/XSurface.hpp | 1 - src/xwayland/XWM.hpp | 1 - 17 files changed, 1 insertion(+), 128 deletions(-) delete mode 100644 src/helpers/WLListener.cpp delete mode 100644 src/helpers/WLListener.hpp diff --git a/src/defines.hpp b/src/defines.hpp index 0b2c0e0c..41ee4502 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,6 +1,5 @@ #include "includes.hpp" #include "debug/Log.hpp" -#include "helpers/WLListener.hpp" #include "helpers/Color.hpp" #include "macros.hpp" #include "desktop/DesktopTypes.hpp" diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 64dd7cf5..893411bd 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -30,13 +30,7 @@ CSubsurface::CSubsurface(SP pSubsurface, CPopup* pOwner) } CSubsurface::~CSubsurface() { - hyprListener_newSubsurface.removeCallback(); - - if (!m_pSubsurface) - return; - - hyprListener_commitSubsurface.removeCallback(); - hyprListener_destroySubsurface.removeCallback(); + ; } void CSubsurface::initSignals() { diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index 101f4f19..7829c489 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -35,10 +35,6 @@ class CSubsurface { void recheckDamageForSubsurfaces(); private: - DYNLISTENER(destroySubsurface); - DYNLISTENER(commitSubsurface); - DYNLISTENER(newSubsurface); - struct { CHyprSignalListener destroySubsurface; CHyprSignalListener commitSubsurface; diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index ad8eaf7e..759b2f58 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index 760ec8dc..f38ef55a 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index cb8a6e90..bf969b2f 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index 0efbe796..01901721 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -1,7 +1,6 @@ #pragma once #include "IHID.hpp" -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/helpers/WLListener.cpp b/src/helpers/WLListener.cpp deleted file mode 100644 index 2ea5c0b6..00000000 --- a/src/helpers/WLListener.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "WLListener.hpp" -#include "MiscFunctions.hpp" -#include -#include "../debug/Log.hpp" -#include "Watchdog.hpp" - -void handleWrapped(wl_listener* listener, void* data) { - CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener); - - if (g_pWatchdog) - g_pWatchdog->startWatching(); - - try { - pWrap->m_pSelf->emit(data); - } catch (std::exception& e) { Debug::log(ERR, "Listener {} threw or timed out and was killed by Watchdog!!! This is bad. what(): {}", (uintptr_t)listener, e.what()); } - - if (g_pWatchdog) - g_pWatchdog->endWatching(); -} - -CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function const& callback, void* pOwner) { - initCallback(pSignal, callback, pOwner); -} - -CHyprWLListener::CHyprWLListener() { - m_swWrapper.m_pSelf = this; - m_swWrapper.m_sListener.notify = &handleWrapped; - wl_list_init(&m_swWrapper.m_sListener.link); -} - -CHyprWLListener::~CHyprWLListener() { - removeCallback(); -} - -void CHyprWLListener::removeCallback() { - if (isConnected()) { - Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor); - wl_list_remove(&m_swWrapper.m_sListener.link); - wl_list_init(&m_swWrapper.m_sListener.link); - } -} - -bool CHyprWLListener::isConnected() { - return !wl_list_empty(&m_swWrapper.m_sListener.link); -} - -void CHyprWLListener::initCallback(wl_signal* pSignal, std::function const& callback, void* pOwner, std::string author) { - if (isConnected()) { - Debug::log(ERR, "Tried to connect a listener twice?!"); - return; - } - - m_pOwner = pOwner; - m_pCallback = callback; - m_szAuthor = author; - - addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor); -} - -void CHyprWLListener::emit(void* data) { - m_pCallback(m_pOwner, data); -} diff --git a/src/helpers/WLListener.hpp b/src/helpers/WLListener.hpp deleted file mode 100644 index 621458e6..00000000 --- a/src/helpers/WLListener.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include - -class CHyprWLListener { - public: - CHyprWLListener(wl_signal*, std::function const&, void* owner); - CHyprWLListener(); - ~CHyprWLListener(); - - CHyprWLListener(const CHyprWLListener&) = delete; - CHyprWLListener(CHyprWLListener&&) = delete; - CHyprWLListener& operator=(const CHyprWLListener&) = delete; - CHyprWLListener& operator=(CHyprWLListener&&) = delete; - - void initCallback(wl_signal*, std::function const&, void* owner, std::string author = ""); - - void removeCallback(); - - bool isConnected(); - - struct SWrapper { - wl_listener m_sListener; - CHyprWLListener* m_pSelf; - }; - - void emit(void*); - - private: - SWrapper m_swWrapper; - - void* m_pOwner = nullptr; - - std::function m_pCallback = nullptr; - - std::string m_szAuthor = ""; -}; \ No newline at end of file diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 43ebe8b5..5cc7eee0 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -2,7 +2,6 @@ #include #include -#include "../helpers/WLListener.hpp" #include "../macros.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index f8e4b962..53c11cff 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../helpers/WLListener.hpp" #include "../../desktop/WLSurface.hpp" #include "../../macros.hpp" #include "../../helpers/math/Math.hpp" diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index f920adc7..3cf07006 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../../helpers/WLListener.hpp" #include "../../macros.hpp" #include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index a2d545c5..6fe8780f 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -53,9 +53,6 @@ class CFocusGrab { bool m_bGrabActive = false; - DYNLISTENER(pointerGrabStarted); - DYNLISTENER(keyboardGrabStarted); - DYNLISTENER(touchGrabStarted); friend class CFocusGrabSurfaceState; }; diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 06c71c9a..421bb838 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -27,8 +27,6 @@ class CQueuedPresentationData { WP pMonitor; WP surface; - DYNLISTENER(destroySurface); - friend class CPresentationFeedback; friend class CPresentationProtocol; }; diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp index e6bfa909..ff06bd5a 100644 --- a/src/render/Renderbuffer.hpp +++ b/src/render/Renderbuffer.hpp @@ -2,7 +2,6 @@ #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" -#include "../helpers/WLListener.hpp" #include "Framebuffer.hpp" #include diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 61eee984..7584354e 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../helpers/WLListener.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/math/Math.hpp" diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index ba00dd8d..37c61416 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -2,7 +2,6 @@ #include "../macros.hpp" #include "XDataSource.hpp" -#include "../helpers/WLListener.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" From 6c78b03bb7810e074d21d5c41f088bd317c28906 Mon Sep 17 00:00:00 2001 From: diniamo Date: Mon, 23 Sep 2024 18:52:30 +0200 Subject: [PATCH 0644/2393] flake: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 76351cc9..68bb0ed2 100644 --- a/flake.lock +++ b/flake.lock @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1726933538, - "narHash": "sha256-xTqnMoJsEojuvqJLuM+U7EZ7q71efaj3pbvjutq4TXc=", + "lastModified": 1727109343, + "narHash": "sha256-1PFckA8Im7wMSl26okwOKqBZeCFLD3LvZZFaxswDhbY=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "4880c50146d0c2a3152d2b02f79253810c330c11", + "rev": "4adb6c4c41ee5014bfe608123bfeddb26e5f5cea", "type": "github" }, "original": { From d279d7c4c6fe27c1944d8e9b51c4730612c8a9ae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 24 Sep 2024 00:49:29 +0100 Subject: [PATCH 0645/2393] eventloop: dispatch pending in session on start fixes #7855 #7391 --- src/managers/eventLoop/EventLoopManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index e9b0fa3e..081268c3 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -50,6 +50,10 @@ void CEventLoopManager::enterLoop() { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); } + // if we have a session, dispatch it to get the pending input devices + if (g_pCompositor->m_pAqBackend->hasSession()) + g_pCompositor->m_pAqBackend->session->dispatchPendingEventsAsync(); + wl_display_run(m_sWayland.display); Debug::log(LOG, "Kicked off the event loop! :("); From 0a211f29f5952322925b9f982cbf9b0326d45f0f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 24 Sep 2024 01:19:05 +0100 Subject: [PATCH 0646/2393] hyprctl: add defaultName to workspacerules fixes #7886 --- src/debug/HyprCtl.cpp | 67 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 9faefe26..4de9143d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -320,45 +320,48 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form static std::string getWorkspaceRuleData(const SWorkspaceRule& r, eHyprCtlOutputFormat format) { const auto boolToString = [](const bool b) -> std::string { return b ? "true" : "false"; }; if (format == eHyprCtlOutputFormat::FORMAT_JSON) { - const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor)); - const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : ""; - const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : ""; - const std::string gapsIn = (bool)(r.gapsIn) ? - std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) : + const std::string monitor = r.monitor.empty() ? "" : std::format(",\n \"monitor\": \"{}\"", escapeJSONStrings(r.monitor)); + const std::string default_ = (bool)(r.isDefault) ? std::format(",\n \"default\": {}", boolToString(r.isDefault)) : ""; + const std::string persistent = (bool)(r.isPersistent) ? std::format(",\n \"persistent\": {}", boolToString(r.isPersistent)) : ""; + const std::string gapsIn = (bool)(r.gapsIn) ? + std::format(",\n \"gapsIn\": [{}, {}, {}, {}]", r.gapsIn.value().top, r.gapsIn.value().right, r.gapsIn.value().bottom, r.gapsIn.value().left) : + ""; + const std::string gapsOut = (bool)(r.gapsOut) ? + std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : ""; - const std::string gapsOut = (bool)(r.gapsOut) ? - std::format(",\n \"gapsOut\": [{}, {}, {}, {}]", r.gapsOut.value().top, r.gapsOut.value().right, r.gapsOut.value().bottom, r.gapsOut.value().left) : - ""; - const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; - const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; - const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; - const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; - const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; + const std::string borderSize = (bool)(r.borderSize) ? std::format(",\n \"borderSize\": {}", r.borderSize.value()) : ""; + const std::string border = (bool)(r.noBorder) ? std::format(",\n \"border\": {}", boolToString(!r.noBorder.value())) : ""; + const std::string rounding = (bool)(r.noRounding) ? std::format(",\n \"rounding\": {}", boolToString(!r.noRounding.value())) : ""; + const std::string decorate = (bool)(r.decorate) ? std::format(",\n \"decorate\": {}", boolToString(r.decorate.value())) : ""; + const std::string shadow = (bool)(r.noShadow) ? std::format(",\n \"shadow\": {}", boolToString(!r.noShadow.value())) : ""; + const std::string defaultName = r.defaultName.has_value() ? std::format(",\n \"defaultName\": \"{}\"", escapeJSONStrings(r.defaultName.value())) : ""; - std::string result = std::format(R"#({{ - "workspaceString": "{}"{}{}{}{}{}{}{}{} + std::string result = + std::format(R"#({{ + "workspaceString": "{}"{}{}{}{}{}{}{}{}{}{}{} }})#", - escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow); + escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, borderSize, border, rounding, decorate, shadow, defaultName); return result; } else { - const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "" : escapeJSONStrings(r.monitor)); - const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : ""); - const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : ""); - const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right), - std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) : - std::format("\tgapsIn: \n"); - const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right), - std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : - std::format("\tgapsOut: \n"); - const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : ""); - const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : ""); - const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : ""); - const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : ""); - const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : ""); + const std::string monitor = std::format("\tmonitor: {}\n", r.monitor.empty() ? "" : escapeJSONStrings(r.monitor)); + const std::string default_ = std::format("\tdefault: {}\n", (bool)(r.isDefault) ? boolToString(r.isDefault) : ""); + const std::string persistent = std::format("\tpersistent: {}\n", (bool)(r.isPersistent) ? boolToString(r.isPersistent) : ""); + const std::string gapsIn = (bool)(r.gapsIn) ? std::format("\tgapsIn: {} {} {} {}\n", std::to_string(r.gapsIn.value().top), std::to_string(r.gapsIn.value().right), + std::to_string(r.gapsIn.value().bottom), std::to_string(r.gapsIn.value().left)) : + std::format("\tgapsIn: \n"); + const std::string gapsOut = (bool)(r.gapsOut) ? std::format("\tgapsOut: {} {} {} {}\n", std::to_string(r.gapsOut.value().top), std::to_string(r.gapsOut.value().right), + std::to_string(r.gapsOut.value().bottom), std::to_string(r.gapsOut.value().left)) : + std::format("\tgapsOut: \n"); + const std::string borderSize = std::format("\tborderSize: {}\n", (bool)(r.borderSize) ? std::to_string(r.borderSize.value()) : ""); + const std::string border = std::format("\tborder: {}\n", (bool)(r.noBorder) ? boolToString(!r.noBorder.value()) : ""); + const std::string rounding = std::format("\trounding: {}\n", (bool)(r.noRounding) ? boolToString(!r.noRounding.value()) : ""); + const std::string decorate = std::format("\tdecorate: {}\n", (bool)(r.decorate) ? boolToString(r.decorate.value()) : ""); + const std::string shadow = std::format("\tshadow: {}\n", (bool)(r.noShadow) ? boolToString(!r.noShadow.value()) : ""); + const std::string defaultName = std::format("\tdefaultName: {}\n", r.defaultName.value_or("")); - std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, - borderSize, border, rounding, decorate, shadow); + std::string result = std::format("Workspace rule {}:\n{}{}{}{}{}{}{}{}{}{}{}\n", escapeJSONStrings(r.workspaceString), monitor, default_, persistent, gapsIn, gapsOut, + borderSize, border, rounding, decorate, shadow, defaultName); return result; } From 00c862686354d139a53222d41a1c80d698a50c43 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 24 Sep 2024 11:25:05 +0100 Subject: [PATCH 0647/2393] hyprctl: add submap request fixes #7898 --- src/debug/HyprCtl.cpp | 9 +++++++++ src/managers/KeybindManager.cpp | 4 ++++ src/managers/KeybindManager.hpp | 1 + 3 files changed, 14 insertions(+) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 4de9143d..87e071d7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1627,6 +1627,14 @@ std::string getDescriptions(eHyprCtlOutputFormat format, std::string request) { return json; } +std::string submapRequest(eHyprCtlOutputFormat format, std::string request) { + std::string submap = g_pKeybindManager->getCurrentSubmap(); + if (submap.empty()) + submap = "default"; + + return format == FORMAT_JSON ? std::format("{{\"{}\"}}\n", escapeJSONStrings(submap)) : (submap + "\n"); +} + CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"workspaces", true, workspacesRequest}); registerCommand(SHyprCtlCommand{"workspacerules", true, workspaceRulesRequest}); @@ -1648,6 +1656,7 @@ CHyprCtl::CHyprCtl() { registerCommand(SHyprCtlCommand{"configerrors", true, configErrorsRequest}); registerCommand(SHyprCtlCommand{"locked", true, getIsLocked}); registerCommand(SHyprCtlCommand{"descriptions", true, getDescriptions}); + registerCommand(SHyprCtlCommand{"submap", true, submapRequest}); registerCommand(SHyprCtlCommand{"monitors", false, monitorsRequest}); registerCommand(SHyprCtlCommand{"reload", false, reloadRequest}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index dd35bc19..02e2f5e7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -594,6 +594,10 @@ eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); } +std::string CKeybindManager::getCurrentSubmap() { + return m_szCurrentSelectedSubmap; +} + SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); bool found = false; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 096cd4f9..c81ca86f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -96,6 +96,7 @@ class CKeybindManager { uint32_t keycodeToModifier(xkb_keycode_t); void clearKeybinds(); void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); + std::string getCurrentSubmap(); std::unordered_map> m_mDispatchers; From 8f5188269b7d58a90c569fd150435b4330dff7df Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 09:59:18 +0100 Subject: [PATCH 0648/2393] hyprctl: add solitary field to hyprctl monitors --- src/debug/HyprCtl.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 87e071d7..178e9ba8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -103,6 +103,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer "focused": {}, "dpmsStatus": {}, "vrr": {}, + "solitary": "{:x}", "activelyTearing": {}, "disabled": {}, "currentFormat": "{}", @@ -114,19 +115,20 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), - (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"), - (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), + (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), + availableModesForOutput(m.get(), format)); } else { result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, - (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing, - !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); } return result; From 2320b2241c0713b8d81e8f467cb99bd4179ad23b Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:01:13 +0100 Subject: [PATCH 0649/2393] Internal: move to Mat3x3 from hyprutils (#7902) * Meson: require hyprutils >= 0.2.3 * flake.lock: update hyprutils --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- flake.lock | 6 +- src/helpers/MiscFunctions.cpp | 21 ----- src/helpers/MiscFunctions.hpp | 1 - src/helpers/Monitor.cpp | 9 +-- src/helpers/Monitor.hpp | 2 +- src/helpers/math/Math.cpp | 120 ---------------------------- src/helpers/math/Math.hpp | 10 +-- src/meson.build | 2 +- src/render/OpenGL.cpp | 142 ++++++++++++++-------------------- src/render/OpenGL.hpp | 46 +++++------ 11 files changed, 93 insertions(+), 268 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1718b2d..8055271e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ pkg_check_modules( gio-2.0 hyprlang>=0.3.2 hyprcursor>=0.1.7 - hyprutils>=0.2.2) + hyprutils>=0.2.3) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index 68bb0ed2..a1f0d88d 100644 --- a/flake.lock +++ b/flake.lock @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1726874949, - "narHash": "sha256-PNnIpwGqpTvMU3N2r0wMQwK1E+t4Bb5fbJwblQvr+80=", + "lastModified": 1727219120, + "narHash": "sha256-wmT+JpnDk6EjgASU2VGfS0nnu6oKA4Cw25o5fzpDD/Q=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "d97af4f6bd068c03a518b597675e598f57ea2291", + "rev": "db956287d3aa194dda91d05c8eb286de2a569edf", "type": "github" }, "original": { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b9970399..20c79a2b 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -628,27 +628,6 @@ void logSystemInfo() { Debug::log(NONE, "{}", execAndGet("cat /etc/os-release")); } -void matrixProjection(float mat[9], int w, int h, wl_output_transform tr) { - memset(mat, 0, sizeof(*mat) * 9); - - const float* t = transforms[tr]; - float x = 2.0f / w; - float y = 2.0f / h; - - // Rotation + reflection - mat[0] = x * t[0]; - mat[1] = x * t[1]; - mat[3] = y * t[3]; - mat[4] = y * t[4]; - - // Translation - mat[2] = -copysign(1.0f, mat[0] + mat[1]); - mat[5] = -copysign(1.0f, mat[3] + mat[4]); - - // Identity - mat[8] = 1.0f; -} - int64_t getPPIDof(int64_t pid) { #if defined(KERN_PROC_PID) int mib[] = { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 8b2ea0d1..f696fc5d 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -34,7 +34,6 @@ int64_t getPPIDof(int64_t pid); int64_t configStringToInt(const std::string&); Vector2D configStringToVector2D(const std::string&); std::optional getPlusMinusKeywordResult(std::string in, float relative); -void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 223a3f94..a2d4c504 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -772,12 +772,9 @@ Vector2D CMonitor::middle() { } void CMonitor::updateMatrix() { - matrixIdentity(projMatrix.data()); - if (transform != WL_OUTPUT_TRANSFORM_NORMAL) { - matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0); - matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform)); - matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0); - } + projMatrix = Mat3x3::identity(); + if (transform != WL_OUTPUT_TRANSFORM_NORMAL) + projMatrix.translate(vecPixelSize / 2.0).transform(wlTransformToHyprutils(transform)).translate(-vecTransformedSize / 2.0); } WORKSPACEID CMonitor::activeWorkspaceID() { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 203cac90..97d9f8ab 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -96,7 +96,7 @@ class CMonitor { bool scheduledRecalc = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; float xwaylandScale = 1.f; - std::array projMatrix = {0}; + Mat3x3 projMatrix; std::optional forceSize; SP currentMode; SP cursorSwapchain; diff --git a/src/helpers/math/Math.cpp b/src/helpers/math/Math.cpp index fccfd636..d111690e 100644 --- a/src/helpers/math/Math.cpp +++ b/src/helpers/math/Math.cpp @@ -1,6 +1,4 @@ #include "Math.hpp" -#include -#include Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { switch (t) { @@ -17,124 +15,6 @@ Hyprutils::Math::eTransform wlTransformToHyprutils(wl_output_transform t) { return Hyprutils::Math::eTransform::HYPRUTILS_TRANSFORM_NORMAL; } -void matrixIdentity(float mat[9]) { - static const float identity[9] = { - 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - }; - memcpy(mat, identity, sizeof(identity)); -} - -void matrixMultiply(float mat[9], const float a[9], const float b[9]) { - float product[9]; - - product[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; - product[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7]; - product[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8]; - - product[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6]; - product[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7]; - product[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8]; - - product[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6]; - product[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7]; - product[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8]; - - memcpy(mat, product, sizeof(product)); -} - -void matrixTranspose(float mat[9], const float a[9]) { - float transposition[9] = { - a[0], a[3], a[6], a[1], a[4], a[7], a[2], a[5], a[8], - }; - memcpy(mat, transposition, sizeof(transposition)); -} - -void matrixTranslate(float mat[9], float x, float y) { - float translate[9] = { - 1.0f, 0.0f, x, 0.0f, 1.0f, y, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, translate); -} - -void matrixScale(float mat[9], float x, float y) { - float scale[9] = { - x, 0.0f, 0.0f, 0.0f, y, 0.0f, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, scale); -} - -void matrixRotate(float mat[9], float rad) { - float rotate[9] = { - cos(rad), -sin(rad), 0.0f, sin(rad), cos(rad), 0.0f, 0.0f, 0.0f, 1.0f, - }; - matrixMultiply(mat, mat, rotate); -} - -const std::unordered_map>& getTransforms() { - static std::unordered_map> transforms = { - {HYPRUTILS_TRANSFORM_NORMAL, {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_90, {0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_180, {-1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_270, {0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED, {-1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_90, {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_180, {1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - {HYPRUTILS_TRANSFORM_FLIPPED_270, {0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}, - }; - return transforms; -} - -void matrixTransform(float mat[9], eTransform transform) { - matrixMultiply(mat, mat, getTransforms().at(transform).data()); -} - -void matrixProjection(float mat[9], int width, int height, eTransform transform) { - memset(mat, 0, sizeof(*mat) * 9); - - const float* t = getTransforms().at(transform).data(); - float x = 2.0f / width; - float y = 2.0f / height; - - // Rotation + reflection - mat[0] = x * t[0]; - mat[1] = x * t[1]; - mat[3] = y * -t[3]; - mat[4] = y * -t[4]; - - // Translation - mat[2] = -copysign(1.0f, mat[0] + mat[1]); - mat[5] = -copysign(1.0f, mat[3] + mat[4]); - - // Identity - mat[8] = 1.0f; -} - -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]) { - double x = box.x; - double y = box.y; - double width = box.width; - double height = box.height; - - matrixIdentity(mat); - matrixTranslate(mat, x, y); - - if (rotation != 0) { - matrixTranslate(mat, width / 2, height / 2); - matrixRotate(mat, rotation); - matrixTranslate(mat, -width / 2, -height / 2); - } - - matrixScale(mat, width, height); - - if (transform != HYPRUTILS_TRANSFORM_NORMAL) { - matrixTranslate(mat, 0.5, 0.5); - matrixTransform(mat, transform); - matrixTranslate(mat, -0.5, -0.5); - } - - matrixMultiply(mat, projection, mat); -} - wl_output_transform invertTransform(wl_output_transform tr) { if ((tr & WL_OUTPUT_TRANSFORM_90) && !(tr & WL_OUTPUT_TRANSFORM_FLIPPED)) tr = (wl_output_transform)(tr ^ (int)WL_OUTPUT_TRANSFORM_180); diff --git a/src/helpers/math/Math.hpp b/src/helpers/math/Math.hpp index f57cef93..9b73a20f 100644 --- a/src/helpers/math/Math.hpp +++ b/src/helpers/math/Math.hpp @@ -4,17 +4,9 @@ // includes box and vector as well #include +#include using namespace Hyprutils::Math; eTransform wlTransformToHyprutils(wl_output_transform t); -void projectBox(float mat[9], CBox& box, eTransform transform, float rotation, const float projection[9]); -void matrixProjection(float mat[9], int width, int height, eTransform transform); -void matrixTransform(float mat[9], eTransform transform); -void matrixRotate(float mat[9], float rad); -void matrixScale(float mat[9], float x, float y); -void matrixTranslate(float mat[9], float x, float y); -void matrixTranspose(float mat[9], const float a[9]); -void matrixMultiply(float mat[9], const float a[9], const float b[9]); -void matrixIdentity(float mat[9]); wl_output_transform invertTransform(wl_output_transform tr); diff --git a/src/meson.build b/src/meson.build index 928cd5a7..da46c38c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,7 +16,7 @@ executable( dependency('cairo'), dependency('hyprcursor', version: '>=0.1.7'), dependency('hyprlang', version: '>= 0.3.2'), - dependency('hyprutils', version: '>= 0.2.1'), + dependency('hyprutils', version: '>= 0.2.3'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 74d3d3cd..ff3d52e4 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -755,14 +755,12 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP< glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL); - matrixIdentity(m_RenderData.monitorProjection.data()); + m_RenderData.monitorProjection = Mat3x3::identity(); if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) { const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize; - matrixTranslate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(pMonitor->transform)); - matrixTranslate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0); + m_RenderData.monitorProjection.translate(FBO->m_vSize / 2.0).transform(wlTransformToHyprutils(pMonitor->transform)).translate(-tfmd / 2.0); } m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; @@ -809,7 +807,7 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + m_RenderData.projection = Mat3x3::outputProjection(pMonitor->vecPixelSize, HYPRUTILS_TRANSFORM_NORMAL); m_RenderData.monitorProjection = pMonitor->projMatrix; @@ -1289,20 +1287,17 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion box = &newBox; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); glUseProgram(m_RenderData.pCurrentMonData->m_shQUAD.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shQUAD.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif // premultiply the color as well as we don't work with straight alpha @@ -1386,11 +1381,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB if (m_bEndFrame || TRANSFORMS_MATCH) TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Debug::log(LOG, "internal:\nmat: {},\nglmat: {}", matrix.toString(), glMatrix.toString()); if (waitTimeline != nullptr) { if (!waitForTimelinePoint(waitTimeline, waitPoint)) { @@ -1442,10 +1436,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); @@ -1556,13 +1550,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { // get transform const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); - - CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; + CShader* shader = &m_RenderData.pCurrentMonData->m_shPASSTHRURGBA; glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); @@ -1570,10 +1561,10 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); @@ -1610,21 +1601,18 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf // get transform const auto TRANSFORM = wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)); - float matrix[9]; - projectBox(matrix, newBox, TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data()); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); - - CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; + CShader* shader = &m_RenderData.pCurrentMonData->m_shMATTE; glUseProgram(shader->program); #ifndef GLES2 - glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(shader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1i(shader->tex, 0); glUniform1i(shader->alphaMatte, 1); @@ -1667,13 +1655,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glDisable(GL_STENCIL_TEST); // get transforms for the full monitor - const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - float matrix[9]; + const auto TRANSFORM = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - projectBox(matrix, MONITORBOX, TRANSFORM, 0, m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(MONITORBOX, TRANSFORM); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); // get the config settings static auto PBLURSIZE = CConfigValue("decoration:blur:size"); @@ -1710,10 +1695,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURPREPARE.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.contrast, *PBLURCONTRAST); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURPREPARE.brightness, *PBLURBRIGHTNESS); @@ -1755,10 +1740,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // prep two shaders #ifndef GLES2 - glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(pShader->proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(pShader->radius, *PBLURSIZE * a); // this makes the blursize change with a if (pShader == &m_RenderData.pCurrentMonData->m_shBLUR1) { @@ -1832,10 +1817,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBLURFINISH.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.noise, *PBLURNOISE); glUniform1f(m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness, *PBLURBRIGHTNESS); @@ -2165,12 +2150,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in round += round == 0 ? 0 : scaledBorderSize; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); const auto BLEND = m_bBlend; blend(true); @@ -2178,10 +2160,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail @@ -2471,22 +2453,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const const auto col = color; - float matrix[9]; - projectBox(matrix, newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot, - m_RenderData.monitorProjection.data()); - - float glMatrix[9]; - matrixMultiply(glMatrix, m_RenderData.projection, matrix); + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); glEnable(GL_BLEND); glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); #ifndef GLES2 - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); #else - matrixTranspose(glMatrix, glMatrix); - glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix); + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); @@ -2565,11 +2544,11 @@ void CHyprOpenGLImpl::renderMirrored() { return; // replace monitor projection to undo the mirrored monitor's projection - matrixIdentity(m_RenderData.monitorProjection.data()); - matrixTranslate(m_RenderData.monitorProjection.data(), monitor->vecPixelSize.x / 2.0, monitor->vecPixelSize.y / 2.0); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(monitor->transform)); - matrixTransform(m_RenderData.monitorProjection.data(), wlTransformToHyprutils(invertTransform(mirrored->transform))); - matrixTranslate(m_RenderData.monitorProjection.data(), -monitor->vecTransformedSize.x / 2.0, -monitor->vecTransformedSize.y / 2.0); + m_RenderData.monitorProjection = Mat3x3::identity() + .translate(monitor->vecPixelSize / 2.0) + .transform(wlTransformToHyprutils(monitor->transform)) + .transform(wlTransformToHyprutils(invertTransform(mirrored->transform))) + .translate(-monitor->vecTransformedSize / 2.0); // clear stuff outside of mirrored area (e.g. when changing to mirrored) clear(CColor(0, 0, 0, 0)); @@ -2920,16 +2899,15 @@ void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { } void CHyprOpenGLImpl::saveMatrix() { - memcpy(m_RenderData.savedProjection, m_RenderData.projection, 9 * sizeof(float)); + m_RenderData.savedProjection = m_RenderData.projection; } void CHyprOpenGLImpl::setMatrixScaleTranslate(const Vector2D& translate, const float& scale) { - matrixScale(m_RenderData.projection, scale, scale); - matrixTranslate(m_RenderData.projection, translate.x, translate.y); + m_RenderData.projection.scale(scale).translate(translate); } void CHyprOpenGLImpl::restoreMatrix() { - memcpy(m_RenderData.projection, m_RenderData.savedProjection, 9 * sizeof(float)); + m_RenderData.projection = m_RenderData.savedProjection; } void CHyprOpenGLImpl::bindOffMain() { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 06078a00..0d1c267b 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -94,35 +94,35 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - CMonitor* pMonitor = nullptr; - PHLWORKSPACE pWorkspace = nullptr; - float projection[9]; - float savedProjection[9]; - std::array monitorProjection; + CMonitor* pMonitor = nullptr; + PHLWORKSPACE pWorkspace = nullptr; + Mat3x3 projection; + Mat3x3 savedProjection; + Mat3x3 monitorProjection; - SMonitorRenderData* pCurrentMonData = nullptr; - CFramebuffer* currentFB = nullptr; // current rendering to - CFramebuffer* mainFB = nullptr; // main to render to - CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) + SMonitorRenderData* pCurrentMonData = nullptr; + CFramebuffer* currentFB = nullptr; // current rendering to + CFramebuffer* mainFB = nullptr; // main to render to + CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc) - CRegion damage; - CRegion finalDamage; // damage used for funal off -> main + CRegion damage; + CRegion finalDamage; // damage used for funal off -> main - SRenderModifData renderModif; - float mouseZoomFactor = 1.f; - bool mouseZoomUseMouse = true; // true by default - bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() - bool blockScreenShader = false; - bool simplePass = false; + SRenderModifData renderModif; + float mouseZoomFactor = 1.f; + bool mouseZoomUseMouse = true; // true by default + bool useNearestNeighbor = false; + bool forceIntrospection = false; // cleaned in ::end() + bool blockScreenShader = false; + bool simplePass = false; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); + Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); - CBox clipBox = {}; // scaled coordinates + CBox clipBox = {}; // scaled coordinates - uint32_t discardMode = DISCARD_OPAQUE; - float discardOpacity = 0.f; + uint32_t discardMode = DISCARD_OPAQUE; + float discardOpacity = 0.f; }; class CEGLSync { From 2a052c69f36a71fb473262f57039b8ac81518ad3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 10:36:43 +0100 Subject: [PATCH 0650/2393] core: add a --systeminfo parameter to gather systeminfo without running --- src/debug/HyprCtl.cpp | 11 +++++++---- src/debug/HyprCtl.hpp | 3 +++ src/main.cpp | 5 +++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 178e9ba8..0229a803 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -943,11 +943,14 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; result += "plugins:\n"; - for (auto const& pl : g_pPluginSystem->getAllPlugins()) { - result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); - } + if (g_pPluginSystem) { + for (auto const& pl : g_pPluginSystem->getAllPlugins()) { + result += std::format(" {} by {} ver {}\n", pl->name, pl->author, pl->version); + } + } else + result += "\tunknown: not runtime\n"; - if (g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { + if (g_pHyprCtl && g_pHyprCtl->m_sCurrentRequestParams.sysInfoConfig) { result += "\n======Config-Start======\n"; result += g_pConfigManager->getConfigString(); result += "\n======Config-End========\n"; diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index cbacd7cb..d68bf14f 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -5,6 +5,9 @@ #include "../helpers/MiscFunctions.hpp" #include +// exposed for main.cpp +std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); + class CHyprCtl { public: CHyprCtl(); diff --git a/src/main.cpp b/src/main.cpp index ba6fe505..279e1ce1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,7 @@ #include "Compositor.hpp" #include "config/ConfigManager.hpp" #include "init/initHelpers.hpp" +#include "debug/HyprCtl.hpp" #include using namespace Hyprutils::String; @@ -133,6 +134,10 @@ int main(int argc, char** argv) { std::cout << result; return 0; + } else if (it->compare("--systeminfo") == 0) { + const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); + std::cout << SYSINFO << "\n"; + return 0; } else { std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; help(); From 8b86ee8bf08eaf8b57d0a7f12af876216323cc3d Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 25 Sep 2024 10:37:58 +0100 Subject: [PATCH 0651/2393] github: encourage usage of --systeminfo if Hyprland won't launch --- .github/ISSUE_TEMPLATE/bug.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 7d402904..ce6d9d3e 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -29,10 +29,10 @@ body: attributes: label: System Info and Version description: | - Paste the output of `hyprctl systeminfo -c` here (If you are on a - version that shows you help menu, omit the `-c` and attach config files - to the issue). If you have configs outside of the main config shown - here, please attach. + Paste the output of `hyprctl systeminfo -c` here. If you can't + launch Hyprland, paste the output of `Hyprland --systeminfo`. + If `Hyprland --systeminfo` errors out (added in 0.44.0), find + and paste the Hyprland version manually. value: "
System/Version info From 49713fab045f7bd41466ddedd83ad5cb81142853 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 25 Sep 2024 23:15:36 +0100 Subject: [PATCH 0652/2393] pointermgr: avoid hogging CMonitor refs --- src/managers/PointerManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 3dcee431..736b629c 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -17,10 +17,8 @@ CPointerManager::CPointerManager() { onMonitorLayoutChange(); - PMONITOR->events.modeChanged.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); - PMONITOR->events.disconnect.registerStaticListener( - [this, PMONITOR](void* owner, std::any data) { g_pEventLoopManager->doLater([this, PMONITOR]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); + PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { g_pEventLoopManager->doLater([this]() { onMonitorLayoutChange(); }); }, nullptr); PMONITOR->events.destroy.registerStaticListener( [this](void* owner, std::any data) { if (g_pCompositor && !g_pCompositor->m_bIsShuttingDown) From 22746b304614b313a78d740f4536e809a4df90e2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 25 Sep 2024 23:38:11 +0100 Subject: [PATCH 0653/2393] hyprctl: use the getMonitorData helper everywhere --- src/debug/HyprCtl.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 0229a803..d9274727 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -160,16 +160,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) { if (!m->output || m->ID == -1) continue; - result += std::format( - "Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" - "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: A {} H {}\n\tavailableModes: {}\n\n", - m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, - m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), - m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, - (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), - (int)m->dpmsStatus, (int)(m->output->state ? m->output->state->state().adaptiveSync : false), m->tearingState.activelyTearing, !m->m_bEnabled, - formatToString(m->output->state->state().drmFormat), formatToString(m->drmFormat), availableModesForOutput(m.get(), format)); + result += CHyprCtl::getMonitorData(m, format); } } From b1ad2d806634edff656cb5ddc9850ae2c73324e8 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Thu, 26 Sep 2024 04:08:50 +0500 Subject: [PATCH 0654/2393] dispatchers: fixup dpms toggle (#7875) now toggles every monitor individually --- src/managers/KeybindManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 02e2f5e7..48c4517a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2403,9 +2403,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { bool enable = arg.starts_with("on"); std::string port = ""; - if (arg.starts_with("toggle")) - enable = !std::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](const auto& other) { return !other->dpmsStatus; }); // enable if any is off - + bool isToggle = arg.starts_with("toggle"); if (arg.find_first_of(' ') != std::string::npos) port = arg.substr(arg.find_first_of(' ') + 1); @@ -2414,6 +2412,9 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { if (!port.empty() && m->szName != port) continue; + if (isToggle) + enable = !m->dpmsStatus; + m->output->state->resetExplicitFences(); m->output->state->setEnabled(enable); From caaa9b11e4763ed0367f81bf97ceaad5175806fc Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:10:53 +0100 Subject: [PATCH 0655/2393] wlr-output-configuration: Improve output configuration (#7571) --- src/config/ConfigManager.cpp | 66 ++++++++++++++--- src/config/ConfigManager.hpp | 2 +- src/helpers/Monitor.cpp | 4 +- src/managers/KeybindManager.cpp | 2 +- src/protocols/OutputManagement.cpp | 115 +++++++++++++++++++---------- src/protocols/OutputManagement.hpp | 69 +++++++++++------ 6 files changed, 181 insertions(+), 77 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 21a3a21e..ab5905c2 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -7,6 +7,7 @@ #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" #include "../xwayland/XWayland.hpp" +#include "../protocols/OutputManagement.hpp" #include #include @@ -1079,28 +1080,69 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s return VAL; } -SMonitorRule CConfigManager::getMonitorRuleFor(const CMonitor& PMONITOR) { +SMonitorRule CConfigManager::getMonitorRuleFor(const SP PMONITOR) { + auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule { + const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR); + + if (!CONFIG) + return rule; + + Debug::log(LOG, "CConfigManager::getMonitorRuleFor: found a wlr_output_manager override for {}", PMONITOR->szName); + + Debug::log(LOG, " > overriding enabled: {} -> {}", !rule.disabled, !CONFIG->enabled); + rule.disabled = !CONFIG->enabled; + + if ((CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_MODE) || (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE)) { + Debug::log(LOG, " > overriding mode: {:.0f}x{:.0f}@{:.2f}Hz -> {:.0f}x{:.0f}@{:.2f}Hz", rule.resolution.x, rule.resolution.y, rule.refreshRate, CONFIG->resolution.x, + CONFIG->resolution.y, CONFIG->refresh / 1000.F); + rule.resolution = CONFIG->resolution; + rule.refreshRate = CONFIG->refresh / 1000.F; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_POSITION) { + Debug::log(LOG, " > overriding offset: {:.0f}, {:.0f} -> {:.0f}, {:.0f}", rule.offset.x, rule.offset.y, CONFIG->position.x, CONFIG->position.y); + rule.offset = CONFIG->position; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM) { + Debug::log(LOG, " > overriding transform: {} -> {}", (uint8_t)rule.transform, (uint8_t)CONFIG->transform); + rule.transform = CONFIG->transform; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_SCALE) { + Debug::log(LOG, " > overriding scale: {} -> {}", (uint8_t)rule.scale, (uint8_t)CONFIG->scale); + rule.scale = CONFIG->scale; + } + + if (CONFIG->committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) { + Debug::log(LOG, " > overriding vrr: {} -> {}", rule.vrr.value_or(0), CONFIG->adaptiveSync); + rule.vrr = (int)CONFIG->adaptiveSync; + } + + return rule; + }; + for (auto const& r : m_dMonitorRules | std::views::reverse) { - if (PMONITOR.matchesStaticSelector(r.name)) { - return r; + if (PMONITOR->matchesStaticSelector(r.name)) { + return applyWlrOutputConfig(r); } } - Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR.szName); + Debug::log(WARN, "No rule found for {}, trying to use the first.", PMONITOR->szName); for (auto const& r : m_dMonitorRules) { if (r.name.empty()) { - return r; + return applyWlrOutputConfig(r); } } Debug::log(WARN, "No rules configured. Using the default hardcoded one."); - return SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, - .name = "", - .resolution = Vector2D(0, 0), - .offset = Vector2D(-INT32_MAX, -INT32_MAX), - .scale = -1}; // 0, 0 is preferred and -1, -1 is auto + return applyWlrOutputConfig(SMonitorRule{.autoDir = eAutoDirs::DIR_AUTO_RIGHT, + .name = "", + .resolution = Vector2D(0, 0), + .offset = Vector2D(-INT32_MAX, -INT32_MAX), + .scale = -1}); // 0, 0 is preferred and -1, -1 is auto } SWorkspaceRule CConfigManager::getWorkspaceRuleFor(PHLWORKSPACE pWorkspace) { @@ -1459,7 +1501,7 @@ void CConfigManager::performMonitorReload() { if (!m->output || m->isUnsafeFallback) continue; - auto rule = getMonitorRuleFor(*m); + auto rule = getMonitorRuleFor(m); if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { overAgain = true; @@ -1516,7 +1558,7 @@ void CConfigManager::ensureMonitorStatus() { if (!rm->output || rm->isUnsafeFallback) continue; - auto rule = getMonitorRuleFor(*rm); + auto rule = getMonitorRuleFor(rm); if (rule.disabled == rm->m_bEnabled) g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index da450e39..2134acf4 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -169,7 +169,7 @@ class CConfigManager { static std::string getMainConfigPath(); const std::string getConfigString(); - SMonitorRule getMonitorRuleFor(const CMonitor&); + SMonitorRule getMonitorRuleFor(const SP); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); std::string getDefaultWorkspaceFor(const std::string&); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a2d4c504..a9569699 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -114,7 +114,7 @@ void CMonitor::onConnect(bool noRule) { createdByUser = true; // should be true. WL and Headless backends should be addable / removable // get monitor rule that matches - SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this); + SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(self.lock()); // if it's disabled, disable and ignore if (monitorRule.disabled) { @@ -489,7 +489,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { pMirrorOf = nullptr; // set rule - const auto RULE = g_pConfigManager->getMonitorRuleFor(*this); + const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock()); vecPosition = RULE.offset; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 48c4517a..cd47bf71 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1943,7 +1943,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { if (!m->output) continue; - auto rule = g_pConfigManager->getMonitorRuleFor(*m); + auto rule = g_pConfigManager->getMonitorRuleFor(m); if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { overAgain = true; break; diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 09552b19..dcc7a62d 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -307,10 +307,15 @@ COutputConfiguration::COutputConfiguration(SP resour LOGM(LOG, "disableHead on {}", PMONITOR->szName); - PMONITOR->activeMonitorRule.disabled = true; - if (!g_pConfigManager->replaceMonitorRule(PMONITOR->activeMonitorRule)) - g_pConfigManager->appendMonitorRule(PMONITOR->activeMonitorRule); - g_pHyprRenderer->applyMonitorRule(PMONITOR, &PMONITOR->activeMonitorRule, false); + SWlrManagerSavedOutputState newState; + if (owner->monitorStates.contains(PMONITOR->szName)) + newState = owner->monitorStates.at(PMONITOR->szName); + + newState.enabled = false; + + g_pConfigManager->m_bWantsMonitorReload = true; + + owner->monitorStates[PMONITOR->szName] = newState; }); resource->setTest([this](CZwlrOutputConfigurationV1* r) { @@ -346,6 +351,11 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { LOGM(LOG, "Applying configuration"); + if (!owner) { + LOGM(ERR, "applyTestConfiguration: no owner?!"); + return false; + } + for (auto const& headw : heads) { auto head = headw.lock(); @@ -357,41 +367,59 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { if (!PMONITOR) continue; - LOGM(LOG, "Applying config for monitor {}", PMONITOR->szName); + LOGM(LOG, "Saving config for monitor {}", PMONITOR->szName); - SMonitorRule newRule = PMONITOR->activeMonitorRule; - newRule.name = PMONITOR->szName; - newRule.disabled = false; + SWlrManagerSavedOutputState newState; + if (owner->monitorStates.contains(PMONITOR->szName)) + newState = owner->monitorStates.at(PMONITOR->szName); - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = head->state.mode->getMode()->pixelSize; - newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; - } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { - newRule.resolution = head->state.customMode.size; - newRule.refreshRate = head->state.customMode.refresh / 1000.F; + newState.enabled = true; + + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { + newState.resolution = head->state.mode->getMode()->pixelSize; + newState.refresh = head->state.mode->getMode()->refreshRate; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE; + LOGM(LOG, " > Mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh); + } else if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { + newState.resolution = head->state.customMode.size; + newState.refresh = head->state.customMode.refresh; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE; + LOGM(LOG, " > Custom mode: {:.0f}x{:.0f}@{}mHz", newState.resolution.x, newState.resolution.y, newState.refresh); } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) - newRule.offset = head->state.position; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION) { + newState.position = head->state.position; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_POSITION; + LOGM(LOG, " > Position: {:.0f}, {:.0f}", head->state.position.x, head->state.position.y); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) - newRule.vrr = head->state.adaptiveSync; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC) { + newState.adaptiveSync = head->state.adaptiveSync; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC; + LOGM(LOG, " > vrr: {}", newState.adaptiveSync); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) - newRule.scale = head->state.scale; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE) { + newState.scale = head->state.scale; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_SCALE; + LOGM(LOG, " > scale: {:.2f}", newState.scale); + } - if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) - newRule.transform = head->state.transform; + if (head->state.committedProperties & eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM) { + newState.transform = head->state.transform; + newState.committedProperties |= eWlrOutputCommittedProperties::OUTPUT_HEAD_COMMITTED_TRANSFORM; + LOGM(LOG, " > transform: {}", (uint8_t)newState.transform); + } // reset properties for next set. - head->committedProperties = 0; + head->state.committedProperties = 0; - if (!g_pConfigManager->replaceMonitorRule(newRule)) - g_pConfigManager->appendMonitorRule(newRule); g_pConfigManager->m_bWantsMonitorReload = true; + + owner->monitorStates[PMONITOR->szName] = newState; } - LOGM(LOG, "Applied configuration"); + LOGM(LOG, "Saved configuration"); return true; } @@ -417,12 +445,12 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } - committedProperties |= OUTPUT_HEAD_COMMITTED_MODE; + state.committedProperties |= OUTPUT_HEAD_COMMITTED_MODE; state.mode = MODE; LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); @@ -434,7 +462,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -444,7 +472,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, w, h, refresh); @@ -456,12 +484,12 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } - committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION; + state.committedProperties |= OUTPUT_HEAD_COMMITTED_POSITION; state.position = {x, y}; LOGM(LOG, " | configHead for {}: set pos to {}, {}", pMonitor->szName, x, y); @@ -473,7 +501,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -483,7 +511,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, transform); @@ -495,7 +523,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -507,7 +535,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, scale); @@ -519,7 +547,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET, "Property already set"); return; } @@ -529,7 +557,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, as); @@ -601,3 +629,14 @@ SP COutputManagementProtocol::modeFromResource(wl_resource* r) { return nullptr; } + +SP COutputManagementProtocol::getOutputStateFor(SP pMonitor) { + for (auto const& m : m_vManagers) { + if (!m->monitorStates.contains(pMonitor->szName)) + continue; + + return makeShared(m->monitorStates.at(pMonitor->szName)); + } + + return nullptr; +} diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 36478d0b..f4a84475 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" @@ -13,6 +14,43 @@ class CMonitor; class COutputHead; class COutputMode; +struct SMonitorRule; + +enum eWlrOutputCommittedProperties : uint32_t { + OUTPUT_HEAD_COMMITTED_MODE = (1 << 0), + OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1), + OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2), + OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3), + OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4), + OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5), +}; + +struct SWlrManagerOutputState { + uint32_t committedProperties = 0; + + WP mode; + struct { + Vector2D size; + uint32_t refresh = 0; + } customMode; + Vector2D position; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float scale = 1.F; + bool adaptiveSync = false; + bool enabled = true; +}; + +struct SWlrManagerSavedOutputState { + uint32_t committedProperties = 0; + Vector2D resolution; + uint32_t refresh = 0; + Vector2D position; + wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; + float scale = 1.F; + bool adaptiveSync = false; + bool enabled = true; +}; + class COutputManager { public: COutputManager(SP resource_); @@ -21,6 +59,9 @@ class COutputManager { void ensureMonitorSent(CMonitor* pMonitor); void sendDone(); + // holds the states for this manager. + std::unordered_map monitorStates; + private: SP resource; bool stopped = false; @@ -80,30 +121,9 @@ class COutputConfigurationHead { public: COutputConfigurationHead(SP resource_, CMonitor* pMonitor_); - bool good(); + bool good(); - enum eCommittedProperties : uint32_t { - OUTPUT_HEAD_COMMITTED_MODE = (1 << 0), - OUTPUT_HEAD_COMMITTED_CUSTOM_MODE = (1 << 1), - OUTPUT_HEAD_COMMITTED_POSITION = (1 << 2), - OUTPUT_HEAD_COMMITTED_TRANSFORM = (1 << 3), - OUTPUT_HEAD_COMMITTED_SCALE = (1 << 4), - OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC = (1 << 5), - }; - - uint32_t committedProperties = 0; - - struct { - WP mode; - struct { - Vector2D size; - uint32_t refresh = 0; - } customMode; - Vector2D position; - wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; - float scale = 1.F; - bool adaptiveSync = false; - } state; + SWlrManagerOutputState state; private: SP resource; @@ -136,6 +156,9 @@ class COutputManagementProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + // doesn't have to return one + SP getOutputStateFor(SP pMonitor); + private: void destroyResource(COutputManager* resource); void destroyResource(COutputHead* resource); From 32a8caf7e7a0609629eb08c91de9f9b23a10c455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 6 Jun 2024 10:07:53 +0200 Subject: [PATCH 0656/2393] Nix: also test cross build --- flake.nix | 10 ++++++++++ nix/default.nix | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index ef48b2d1..eca45675 100644 --- a/flake.nix +++ b/flake.nix @@ -67,6 +67,15 @@ hyprland-extras ]; }); + pkgsCrossFor = eachSystem (system: crossSystem: + import nixpkgs { + localSystem = system; + crossSystem = crossSystem; + overlays = with self.overlays; [ + hyprland-packages + hyprland-extras + ]; + }); in { overlays = import ./nix/overlays.nix {inherit self lib inputs;}; @@ -92,6 +101,7 @@ xdg-desktop-portal-hyprland ; + hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland; }); devShells = eachSystem (system: { diff --git a/nix/default.nix b/nix/default.nix index 40675d9a..be7394e4 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -102,7 +102,6 @@ in ninja pkg-config python3 # for udis86 - wayland-scanner ]; outputs = [ @@ -130,6 +129,7 @@ in tomlplusplus wayland wayland-protocols + wayland-scanner xorg.libXcursor ] (optionals customStdenv.hostPlatform.isMusl [libexecinfo]) From 7b56ce6521e5ad3b0a2dab6f79a045e79c7aeb82 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Tue, 11 Jun 2024 18:49:12 +0300 Subject: [PATCH 0657/2393] CI/Nix: add cross build --- .github/workflows/nix-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 50823629..6351216f 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -12,6 +12,7 @@ jobs: matrix: package: - hyprland + - hyprland-cross - xdg-desktop-portal-hyprland runs-on: ubuntu-latest From 77f2a01304f33a2dc7c9002ca9fb20a7653e6ae1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 26 Sep 2024 16:52:02 +0300 Subject: [PATCH 0658/2393] flake.lock: update nixpkgs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index a1f0d88d..4ebdc734 100644 --- a/flake.lock +++ b/flake.lock @@ -154,11 +154,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1726755586, - "narHash": "sha256-PmUr/2GQGvFTIJ6/Tvsins7Q43KTMvMFhvG6oaYK+Wk=", + "lastModified": 1727122398, + "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c04d5652cfa9742b1d519688f65d1bbccea9eb7e", + "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", "type": "github" }, "original": { From 14942bca60cc7d85e8238a151bd444112601ebe6 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 21:19:09 +0300 Subject: [PATCH 0659/2393] Nix: re-add hyprland-protocols --- flake.lock | 26 +++++++++++++++++++++++++- flake.nix | 6 ++++++ nix/default.nix | 2 ++ nix/overlays.nix | 1 + 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/flake.lock b/flake.lock index 4ebdc734..7e0f093e 100644 --- a/flake.lock +++ b/flake.lock @@ -56,6 +56,29 @@ } }, "hyprland-protocols": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1721326555, + "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", + "owner": "hyprwm", + "repo": "hyprland-protocols", + "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-protocols", + "type": "github" + } + }, + "hyprland-protocols_2": { "inputs": { "nixpkgs": [ "xdph", @@ -172,6 +195,7 @@ "inputs": { "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", + "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", @@ -197,7 +221,7 @@ }, "xdph": { "inputs": { - "hyprland-protocols": "hyprland-protocols", + "hyprland-protocols": "hyprland-protocols_2", "hyprlang": [ "hyprlang" ], diff --git a/flake.nix b/flake.nix index eca45675..ee5af6a1 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,12 @@ inputs.hyprlang.follows = "hyprlang"; }; + hyprland-protocols = { + url = "github:hyprwm/hyprland-protocols"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + }; + hyprlang = { url = "github:hyprwm/hyprlang"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/nix/default.nix b/nix/default.nix index be7394e4..85a3105d 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,6 +13,7 @@ cairo, git, hyprcursor, + hyprland-protocols, hyprlang, hyprutils, hyprwayland-scanner, @@ -116,6 +117,7 @@ in cairo git hyprcursor + hyprland-protocols hyprlang hyprutils libdrm diff --git a/nix/overlays.nix b/nix/overlays.nix index d6e078fa..71b5f59f 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -22,6 +22,7 @@ in { # Dependencies inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default + inputs.hyprland-protocols.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default From 27211c71e92e1bacf111d8a815e958f80969ce6e Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 21:20:35 +0300 Subject: [PATCH 0660/2393] Meson: try to find udis86 through pkgconfig, fallback to subproject Only the fork provides a .pc file, so there's no risk of linking the wrong lib version. If pkg-config can't find it (most cases), fall back to using the subproject through the wrap file. --- meson.build | 4 ---- nix/default.nix | 8 ++------ nix/overlays.nix | 17 +++++++++++++++++ src/meson.build | 6 +++++- subprojects/udis86.wrap | 5 +++++ 5 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 subprojects/udis86.wrap diff --git a/meson.build b/meson.build index 9449c241..42ed519d 100644 --- a/meson.build +++ b/meson.build @@ -43,10 +43,6 @@ xcb_xfixes_dep = dependency('xcb-xfixes', required: get_option('xwayland')) gio_dep = dependency('gio-2.0', required: true) -cmake = import('cmake') -udis = cmake.subproject('udis86') -udis86 = udis.dependency('libudis86') - if not xcb_dep.found() add_project_arguments('-DNO_XWAYLAND', language: 'cpp') endif diff --git a/nix/default.nix b/nix/default.nix index 85a3105d..df270f28 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -6,7 +6,6 @@ pkgconf, makeWrapper, meson, - cmake, ninja, aquamarine, binutils, @@ -17,7 +16,6 @@ hyprlang, hyprutils, hyprwayland-scanner, - jq, libGL, libdrm, libexecinfo, @@ -27,9 +25,9 @@ mesa, pango, pciutils, - python3, systemd, tomlplusplus, + udis86-hyprland, wayland, wayland-protocols, wayland-scanner, @@ -96,13 +94,10 @@ in nativeBuildInputs = [ hyprwayland-scanner - jq makeWrapper meson - cmake ninja pkg-config - python3 # for udis86 ]; outputs = [ @@ -129,6 +124,7 @@ in pango pciutils tomlplusplus + udis86-hyprland wayland wayland-protocols wayland-scanner diff --git a/nix/overlays.nix b/nix/overlays.nix index 71b5f59f..2b2788e7 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -26,6 +26,7 @@ in { inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default + self.overlays.udis86 # Hyprland packages themselves (final: prev: let @@ -64,4 +65,20 @@ in { hyprland-extras = lib.composeManyExtensions [ inputs.xdph.overlays.xdg-desktop-portal-hyprland ]; + + # udis86 from nixpkgs is too old, and also does not provide a .pc file + # this version is the one used in the git submodule, and allows us to + # fetch the source without '?submodules=1' + udis86 = final: prev: { + udis86-hyprland = prev.udis86.overrideAttrs (self: super: { + src = final.fetchFromGitHub { + owner = "canihavesomecoffee"; + repo = "udis86"; + rev = "5336633af70f3917760a6d441ff02d93477b0c86"; + hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g="; + }; + + patches = []; + }); + }; } diff --git a/src/meson.build b/src/meson.build index da46c38c..7c71a735 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,7 +31,11 @@ executable( backtrace_dep, epoll_dep, gio_dep, - udis86, + + # Try to find canihavesomecoffee's udis86 using pkgconfig + # vmt/udis86 does not provide a .pc file and won't be detected this way + # Falls back to using the subproject through udis86.wrap + dependency('udis86'), dependency('pixman-1'), dependency('gl', 'opengl'), diff --git a/subprojects/udis86.wrap b/subprojects/udis86.wrap new file mode 100644 index 00000000..dfb63984 --- /dev/null +++ b/subprojects/udis86.wrap @@ -0,0 +1,5 @@ +[wrap-file] +method = cmake + +[provide] +udis86 = libudis86_dep From 89d945aabe632387f113ac500bfee573d51cc4f7 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 18:00:02 +0300 Subject: [PATCH 0661/2393] CMake: use hyprland-protocols from pkg-config, fallback to subproject protocolnew: fix external path, which may not be in $CMAKE_SOURCE_DIR --- CMakeLists.txt | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8055271e..08eb93cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -230,7 +230,7 @@ add_custom_target(generate-protocol-headers) function(protocolnew protoPath protoName external) if(external) - set(path ${CMAKE_SOURCE_DIR}/${protoPath}) + set(path ${protoPath}) else() set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath}) endif() @@ -261,11 +261,20 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads libudis86) -protocolnew("subprojects/hyprland-protocols/protocols" - "hyprland-global-shortcuts-v1" true) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) +if(hyprland_protocols_dep_FOUND) + pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) + message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") +else() + set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols") + message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}") +endif() + +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1" + true) protocolnew("unstable/text-input" "text-input-unstable-v1" false) -protocolnew("subprojects/hyprland-protocols/protocols" - "hyprland-toplevel-export-v1" true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1" + true) protocolnew("protocols" "wlr-screencopy-unstable-v1" true) protocolnew("protocols" "wlr-gamma-control-unstable-v1" true) protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true) @@ -276,8 +285,7 @@ protocolnew("protocols" "input-method-unstable-v2" true) protocolnew("protocols" "wlr-output-management-unstable-v1" true) protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true) -protocolnew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" - true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("staging/tearing-control" "tearing-control-v1" false) From be96787ed086f751455cf713739296b5c6e3a235 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 18:01:44 +0300 Subject: [PATCH 0662/2393] CMake: use udis86 from pkg-config, fallback to subproject Only canihavesomecoffee's fork (the one the subproject uses) provides a .pc file, so we either find the correct version or we use the subproject. --- CMakeLists.txt | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08eb93cf..8115d01c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,18 @@ message(STATUS "Gathering git info") execute_process(COMMAND ./scripts/generateVersion.sh WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) -# udis -add_subdirectory("subprojects/udis86") +find_package(PkgConfig REQUIRED) + +# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not +# provide a .pc file and won't be detected this way +pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2) + +# Fallback to subproject +if(NOT udis_dep_FOUND) + add_subdirectory("subprojects/udis86") + include_directories("subprojects/udis86") + message(STATUS "udis86 dependency not found, falling back to subproject") +endif() if(CMAKE_BUILD_TYPE) string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER) @@ -47,8 +57,6 @@ else() set(BUILDTYPE_LOWER "release") endif() -find_package(PkgConfig REQUIRED) - pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir) message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}") pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir) @@ -63,7 +71,8 @@ else() message(STATUS "Configuring Hyprland in Release with CMake") endif() -include_directories(. "src/" "subprojects/udis86/" "protocols/") +include_directories(. "src/" "protocols/") + set(CMAKE_CXX_STANDARD 26) add_compile_options( -Wall @@ -224,6 +233,11 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) +if(udis_dep_FOUND) + target_link_libraries(Hyprland PkgConfig::udis_dep) +else() + target_link_libraries(Hyprland libudis86) +endif() # used by `make installheaders`, to ensure the headers are generated add_custom_target(generate-protocol-headers) @@ -258,8 +272,7 @@ function(protocolWayland) PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp) endfunction() -target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads - libudis86) +target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) if(hyprland_protocols_dep_FOUND) From f75f8efb1be227e586cc0ba2ce6153ce56e04314 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sun, 22 Sep 2024 20:53:34 +0300 Subject: [PATCH 0663/2393] Meson: add tracy dependency --- meson.build | 6 ++++++ meson_options.txt | 1 + nix/default.nix | 7 +++++-- src/meson.build | 1 + subprojects/tracy.wrap | 1 + 5 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 subprojects/tracy.wrap diff --git a/meson.build b/meson.build index 42ed519d..3545f46a 100644 --- a/meson.build +++ b/meson.build @@ -73,6 +73,12 @@ foreach file : headers install_headers(file, subdir: 'hyprland', preserve_path: true) endforeach +tracy = dependency('tracy', static: true, required: get_option('tracy_enable')) + +if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized' + warning('Profiling builds should set -- buildtype = debugoptimized') +endif + subdir('protocols') subdir('src') subdir('hyprctl') diff --git a/meson_options.txt b/meson_options.txt index 16a34a54..d8c9d5e6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,4 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') +option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') diff --git a/nix/default.nix b/nix/default.nix index df270f28..6f086ccc 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -144,7 +144,7 @@ in mesonBuildType = if debug - then "debug" + then "debugoptimized" else "release"; # we want as much debug info as possible @@ -156,7 +156,10 @@ in "legacy_renderer" = legacyRenderer; "systemd" = withSystemd; }) - (mesonBool "b_pch" false) + (mapAttrsToList mesonBool { + "b_pch" = false; + "tracy_enable" = false; + }) ]; postInstall = '' diff --git a/src/meson.build b/src/meson.build index 7c71a735..2dbe2f44 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,6 +31,7 @@ executable( backtrace_dep, epoll_dep, gio_dep, + tracy, # Try to find canihavesomecoffee's udis86 using pkgconfig # vmt/udis86 does not provide a .pc file and won't be detected this way diff --git a/subprojects/tracy.wrap b/subprojects/tracy.wrap new file mode 100644 index 00000000..11b21787 --- /dev/null +++ b/subprojects/tracy.wrap @@ -0,0 +1 @@ +[wrap-file] From b2143a98e2719012f8c36211a066f8ebccc950b8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 26 Sep 2024 23:00:20 +0300 Subject: [PATCH 0664/2393] CI/Nix: no longer build with submodules --- .github/workflows/nix-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 6351216f..73adb497 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -25,4 +25,4 @@ jobs: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}&submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" From e20aef7d53fcde1470e8d7672e6a03d814fca97f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 26 Sep 2024 22:34:33 +0100 Subject: [PATCH 0665/2393] opengl: remove debug log --- src/render/OpenGL.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ff3d52e4..4f22d6aa 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1384,8 +1384,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB Mat3x3 matrix = m_RenderData.monitorProjection.projectBox(newBox, TRANSFORM, newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - Debug::log(LOG, "internal:\nmat: {},\nglmat: {}", matrix.toString(), glMatrix.toString()); - if (waitTimeline != nullptr) { if (!waitForTimelinePoint(waitTimeline, waitPoint)) { Debug::log(ERR, "renderTextureInternalWithDamage: failed to wait for explicit sync point {}", waitPoint); From 58669fef77ac17ea205ce3570f48e17de736111f Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 27 Sep 2024 18:35:29 +0300 Subject: [PATCH 0666/2393] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 7e0f093e..5adaa350 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1726665257, - "narHash": "sha256-rEzEZtd3iyVo5RJ1OGujOlnywNf3gsrOnjAn1NLciD4=", + "lastModified": 1727261104, + "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "752d0fbd141fabb5a1e7f865199b80e6e76f8d8e", + "rev": "b82fdaff917582a9d568969e15e61b398c71e990", "type": "github" }, "original": { @@ -65,11 +65,11 @@ ] }, "locked": { - "lastModified": 1721326555, - "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", + "lastModified": 1727451107, + "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", + "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3", "type": "github" }, "original": { @@ -139,11 +139,11 @@ ] }, "locked": { - "lastModified": 1727219120, - "narHash": "sha256-wmT+JpnDk6EjgASU2VGfS0nnu6oKA4Cw25o5fzpDD/Q=", + "lastModified": 1727300645, + "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "db956287d3aa194dda91d05c8eb286de2a569edf", + "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", "type": "github" }, "original": { @@ -162,11 +162,11 @@ ] }, "locked": { - "lastModified": 1726840673, - "narHash": "sha256-HIPEXyRRVZoqD6U+lFS1B0tsIU7p83FaB9m7KT/x6mQ=", + "lastModified": 1726874836, + "narHash": "sha256-VKR0sf0PSNCB0wPHVKSAn41mCNVCnegWmgkrneKDhHM=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "b68dab23fc922eae99306988133ee80a40b39ca5", + "rev": "500c81a9e1a76760371049a8d99e008ea77aa59e", "type": "github" }, "original": { From 2cf6e7862a844ad96aa060d63f6774df7e2234a6 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Fri, 27 Sep 2024 20:49:40 -0400 Subject: [PATCH 0667/2393] dwindle: add config option `split_bias` (#7920) If `default_split_ratio` is greater than 1.0, `split_bias` will give the bigger half to a specific window: 0 - positional (default) 1 - current window 2 - opening window --- src/config/ConfigManager.cpp | 1 + src/layout/DwindleLayout.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ab5905c2..ad6e1871 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -446,6 +446,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); + m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:smart_resizing", Hyprlang::INT{1}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index c936d59c..69b044b4 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -1,7 +1,7 @@ #include "DwindleLayout.hpp" -#include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "../render/decorations/CHyprGroupBarDecoration.hpp" void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { if (children[0]) { @@ -459,6 +459,12 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir } } + // split in favor of a specific window + const auto first = NEWPARENT->children[0]; + static auto PSPLITBIAS = CConfigValue("dwindle:split_bias"); + if ((*PSPLITBIAS == 1 && first == PNODE) || (*PSPLITBIAS == 2 && first == OPENINGON)) + NEWPARENT->splitRatio = 2.f - NEWPARENT->splitRatio; + // and update the previous parent if it exists if (OPENINGON->pParent) { if (OPENINGON->pParent->children[0] == OPENINGON) { From 6f313de952311282e82461a342c74ea702d9f13a Mon Sep 17 00:00:00 2001 From: bivsk <141476105+bivsk@users.noreply.github.com> Date: Sat, 28 Sep 2024 08:46:31 -0400 Subject: [PATCH 0668/2393] core: Fix Musl builds (#7934) Musl does not include the internal type `__time_t`. Use `time_t` instead. --- src/protocols/PresentationTime.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index e1ff52cd..71f74cd5 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -58,8 +58,8 @@ void CPresentationFeedback::sendQueued(SP data, timespe if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; - __time_t tv_sec = 0; - if (sizeof(__time_t) > 4) + time_t tv_sec = 0; + if (sizeof(time_t) > 4) tv_sec = when->tv_sec >> 32; if (data->wasPresented) From d73c14751ad40fd54d93baac2226f550142b0e74 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 28 Sep 2024 21:53:08 +0300 Subject: [PATCH 0669/2393] CI/Nix: git+https -> github --- .github/workflows/nix-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index 73adb497..d1f47ee4 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -25,4 +25,4 @@ jobs: name: hyprland authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - run: nix build 'git+https://github.com/hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" + - run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" From 9e418671e12549156d0735a6b23732f66d5647c7 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Sun, 29 Sep 2024 09:42:10 -0400 Subject: [PATCH 0670/2393] config: add descriptions for dwindle and master layout options (#7933) --- src/config/ConfigDescriptions.hpp | 160 ++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 84ac1a41..3a91a808 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1372,4 +1372,164 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + + /* + * dwindle: + */ + + SConfigOptionDescription{ + .value = "dwindle:pseudotile", + .description = "enable pseudotiling. Pseudotiled windows retain their floating size when tiled.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:force_split", + .description = "0 -> split follows mouse, 1 -> always split to the left (new = left or top) 2 -> always split to the right (new = right or bottom)", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "follow mouse,left or top,right or bottom"}, + }, + SConfigOptionDescription{ + .value = "dwindle:preserve_split", + .description = "if enabled, the split (side/top) will not change regardless of what happens to the container.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:smart_split", + .description = "if enabled, allows a more precise control over the window split direction based on the cursor's position. The window is conceptually divided into four " + "triangles, and cursor's triangle determines the split direction. This feature also turns on preserve_split.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:smart_resizing", + .description = + "if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "dwindle:permanent_direction_override", + .description = "if enabled, makes the preselect direction persist until either this mode is turned off, another direction is specified, or a non-direction is specified " + "(anything other than l,r,u/t,d/b)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "dwindle:special_scale_factor", + .description = "specifies the scale factor of windows on the special workspace [0 - 1]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "dwindle:split_width_multiplier", + .description = "specifies the auto-split width multiplier", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0.1, 3}, + }, + SConfigOptionDescription{ + .value = "dwindle:no_gaps_when_only", + .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, + }, + SConfigOptionDescription{ + .value = "dwindle:use_active_for_splits", + .description = "whether to prefer the active window or the mouse position for splits", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "dwindle:default_split_ratio", + .description = "the default split ratio on window open. 1 means even 50/50 split. [0.1 - 1.9]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0.1, 1.9}, + }, + SConfigOptionDescription{ + .value = "dwindle:split_bias", + .description = "specifies which window will receive the larger half of a split. positional - 0, current window - 1, opening window - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"}, + }, + + /* + * master: + */ + + SConfigOptionDescription{ + .value = "master:allow_small_split", + .description = "enable adding additional master windows in a horizontal split style", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:special_scale_factor", + .description = "the scale of the special workspace windows. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{1, 0, 1}, + }, + SConfigOptionDescription{ + .value = "master:mfact", + .description = + "the size as a percentage of the master window, for example `mfact = 0.70` would mean 70% of the screen will be the master window, and 30% the slave [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.55, 0, 1}, + }, + SConfigOptionDescription{ + .value = "master:new_status", + .description = "`master`: new window becomes master; `slave`: new windows are added to slave stack; `inherit`: inherit from focused window", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"slave"}, + }, + SConfigOptionDescription{ + .value = "master:new_on_top", + .description = "whether a newly open window should be on the top of the stack", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:new_on_active", + .description = "`before`, `after`: place new window relative to the focused window; `none`: place new window according to the value of `new_on_top`. ", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"none"}, + }, + SConfigOptionDescription{ + .value = "master:no_gaps_when_only", + .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, + }, + SConfigOptionDescription{ + .value = "master:orientation", + .description = "default placement of the master area, can be left, right, top, bottom or center", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"left"}, + }, + SConfigOptionDescription{ + .value = "master:inherit_fullscreen", + .description = "inherit fullscreen status when cycling/swapping to another window (e.g. monocle layout)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "master:always_center_master", + .description = "when using orientation=center, keep the master window centered, even when it is the only window in the workspace.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "master:smart_resizing", + .description = + "if enabled, resizing direction will be determined by the mouse's position on the window (nearest to which corner). Else, it is based on the window's tiling position.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "master:drop_at_cursor", + .description = "when enabled, dragging and dropping windows will put them at the cursor position. Otherwise, when dropped at the stack side, they will go to the " + "top/bottom of the stack depending on new_on_top.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, }; From 4b00cba319dc44294567d06df7c378cf5e4e5338 Mon Sep 17 00:00:00 2001 From: Luke Chen <3363954+LukeXuan@users.noreply.github.com> Date: Sun, 29 Sep 2024 09:47:59 -0400 Subject: [PATCH 0671/2393] dwindle: add movetoroot method to layout messages (#7903) --- src/layout/DwindleLayout.cpp | 42 ++++++++++++++++++++++++++++++++++++ src/layout/DwindleLayout.hpp | 1 + 2 files changed, 43 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 69b044b4..ed47fa44 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -998,6 +998,10 @@ std::any CHyprDwindleLayout::layoutMessage(SLayoutMessageHeader header, std::str toggleSplit(header.pWindow); } else if (ARGS[0] == "swapsplit") { swapSplit(header.pWindow); + } else if (ARGS[0] == "movetoroot") { + const auto WINDOW = ARGS[1].empty() ? header.pWindow : g_pCompositor->getWindowByRegex(ARGS[1]); + const auto STABLE = ARGS[2].empty() || ARGS[2] != "unstable"; + moveToRoot(WINDOW, STABLE); } else if (ARGS[0] == "preselect") { std::string direction = ARGS[1]; @@ -1065,6 +1069,44 @@ void CHyprDwindleLayout::swapSplit(PHLWINDOW pWindow) { PNODE->pParent->recalcSizePosRecursive(); } +// goal: maximize the chosen window within current dwindle layout +// impl: swap the selected window with the other sub-tree below root +void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) { + const auto PNODE = getNodeFromWindow(pWindow); + + if (!PNODE || !PNODE->pParent) + return; + + if (pWindow->isFullscreen()) + return; + + // already at root + if (!PNODE->pParent->pParent) + return; + + auto& pNode = PNODE->pParent->children[0] == PNODE ? PNODE->pParent->children[0] : PNODE->pParent->children[1]; + + // instead of [getMasterNodeOnWorkspace], we walk back to root since we need + // to know which children of root is our ancestor + auto pAncestor = PNODE, pRoot = PNODE->pParent; + while (pRoot->pParent) { + pAncestor = pRoot; + pRoot = pRoot->pParent; + } + + auto& pSwap = pRoot->children[0] == pAncestor ? pRoot->children[1] : pRoot->children[0]; + std::swap(pNode, pSwap); + std::swap(pNode->pParent, pSwap->pParent); + + // [stable] in that the focused window occupies same side of screen + if (stable) + std::swap(pRoot->children[0], pRoot->children[1]); + + // if the workspace is visible, recalculate layout + if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + pRoot->recalcSizePosRecursive(); +} + void CHyprDwindleLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { const auto PNODE = getNodeFromWindow(from); diff --git a/src/layout/DwindleLayout.hpp b/src/layout/DwindleLayout.hpp index bbd511c2..953ba3a2 100644 --- a/src/layout/DwindleLayout.hpp +++ b/src/layout/DwindleLayout.hpp @@ -87,6 +87,7 @@ class CHyprDwindleLayout : public IHyprLayout { void toggleSplit(PHLWINDOW); void swapSplit(PHLWINDOW); + void moveToRoot(PHLWINDOW, bool stable = true); eDirection overrideDirection = DIRECTION_DEFAULT; From 6649255d54f45a7e2fedd9b4be85fe5d11229c04 Mon Sep 17 00:00:00 2001 From: Gliczy <129636582+Gliczy@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:45:19 +0200 Subject: [PATCH 0672/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 5adaa350..2579dd11 100644 --- a/flake.lock +++ b/flake.lock @@ -42,11 +42,11 @@ ] }, "locked": { - "lastModified": 1722623071, - "narHash": "sha256-sLADpVgebpCBFXkA1FlCXtvEPu1tdEsTfqK1hfeHySE=", + "lastModified": 1727532803, + "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "912d56025f03d41b1ad29510c423757b4379eb1c", + "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f", "type": "github" }, "original": { @@ -177,11 +177,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727122398, - "narHash": "sha256-o8VBeCWHBxGd4kVMceIayf5GApqTavJbTa44Xcg5Rrk=", + "lastModified": 1727348695, + "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "30439d93eb8b19861ccbe3e581abf97bdc91b093", + "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", "type": "github" }, "original": { @@ -239,11 +239,11 @@ ] }, "locked": { - "lastModified": 1727109343, - "narHash": "sha256-1PFckA8Im7wMSl26okwOKqBZeCFLD3LvZZFaxswDhbY=", + "lastModified": 1727524473, + "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "4adb6c4c41ee5014bfe608123bfeddb26e5f5cea", + "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26", "type": "github" }, "original": { From 488efab63654a643d76df4997cd932d6fddd8faf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 00:57:51 +0100 Subject: [PATCH 0673/2393] single-pixel-buffer: new protocol impl fixes #6624 --- CMakeLists.txt | 1 + src/helpers/Color.hpp | 3 +- src/managers/ProtocolManager.cpp | 2 + src/protocols/SinglePixel.cpp | 125 +++++++++++++++++++++++++++++++ src/protocols/SinglePixel.hpp | 79 +++++++++++++++++++ 5 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/protocols/SinglePixel.cpp create mode 100644 src/protocols/SinglePixel.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8115d01c..ee9cd2e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,6 +330,7 @@ protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false) protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) +protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolwayland() diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 8abfe748..32ed39ee 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -8,8 +8,9 @@ class CColor { CColor(float r, float g, float b, float a); CColor(uint64_t); - float r = 0, g = 0, b = 0, a = 1.f; + float r = 0, g = 0, b = 0, a = 1.f; + // AR32 uint32_t getAsHex() const; CColor operator-(const CColor& c2) const { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6b6d5acf..8bcc857a 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -44,6 +44,7 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/XDGDialog.hpp" +#include "../protocols/SinglePixel.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -152,6 +153,7 @@ CProtocolManager::CProtocolManager() { PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); + PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp new file mode 100644 index 00000000..7dd3748f --- /dev/null +++ b/src/protocols/SinglePixel.cpp @@ -0,0 +1,125 @@ +#include "SinglePixel.hpp" +#include + +CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) { + LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex()); + + color = col_.getAsHex(); + + g_pHyprRenderer->makeEGLCurrent(); + + opaque = col_.a >= 1.F; + + texture = makeShared(DRM_FORMAT_ARGB8888, (uint8_t*)&color, 4, Vector2D{1, 1}); + + resource = CWLBufferResource::create(makeShared(client, 1, id)); + + success = texture->m_iTexID; + + if (!success) + Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); +} + +CSinglePixelBuffer::~CSinglePixelBuffer() { + ; +} + +Aquamarine::eBufferCapability CSinglePixelBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; +} + +Aquamarine::eBufferType CSinglePixelBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; +} + +bool CSinglePixelBuffer::isSynchronous() { + return true; +} + +void CSinglePixelBuffer::update(const CRegion& damage) { + ; +} + +Aquamarine::SDMABUFAttrs CSinglePixelBuffer::dmabuf() { + return {.success = false}; +} + +std::tuple CSinglePixelBuffer::beginDataPtr(uint32_t flags) { + return {(uint8_t*)&color, DRM_FORMAT_ARGB8888, 4}; +} + +void CSinglePixelBuffer::endDataPtr() { + ; +} + +bool CSinglePixelBuffer::good() { + return resource->good(); +} + +CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) { + buffer = makeShared(id, client, color); + + if (!buffer->good()) + return; + + buffer->resource->buffer = buffer; + + listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) { + listeners.bufferResourceDestroy.reset(); + PROTO::singlePixel->destroyResource(this); + }); +} + +CSinglePixelBufferResource::~CSinglePixelBufferResource() { + ; +} + +bool CSinglePixelBufferResource::good() { + return buffer->good(); +} + +CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); + resource->setOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); + + resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) { + CColor color{r / (float)std::numeric_limits::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), + a / (float)std::numeric_limits::max()}; + const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared(id, resource->client(), color)); + + if (!RESOURCE->good()) { + res->noMemory(); + PROTO::singlePixel->m_vBuffers.pop_back(); + return; + } + }); +} + +bool CSinglePixelBufferManagerResource::good() { + return resource->resource(); +} + +CSinglePixelProtocol::CSinglePixelProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CSinglePixelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CSinglePixelProtocol::destroyResource(CSinglePixelBufferManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CSinglePixelProtocol::destroyResource(CSinglePixelBufferResource* surf) { + std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == surf; }); +} diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp new file mode 100644 index 00000000..ab74825c --- /dev/null +++ b/src/protocols/SinglePixel.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "single-pixel-buffer-v1.hpp" +#include "types/Buffer.hpp" + +class CSinglePixelBuffer : public IHLBuffer { + public: + CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col); + virtual ~CSinglePixelBuffer(); + + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); + virtual bool isSynchronous(); + virtual void update(const CRegion& damage); + virtual Aquamarine::SDMABUFAttrs dmabuf(); + virtual std::tuple beginDataPtr(uint32_t flags); + virtual void endDataPtr(); + // + bool good(); + bool success = false; + + private: + uint32_t color = 0x00000000; + + struct { + CHyprSignalListener resourceDestroy; + } listeners; +}; + +class CSinglePixelBufferResource { + public: + CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color); + ~CSinglePixelBufferResource(); + + bool good(); + + private: + SP buffer; + + struct { + CHyprSignalListener bufferResourceDestroy; + } listeners; +}; + +class CSinglePixelBufferManagerResource { + public: + CSinglePixelBufferManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CSinglePixelProtocol : public IWaylandProtocol { + public: + CSinglePixelProtocol(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); + + private: + void destroyResource(CSinglePixelBufferManagerResource* resource); + void destroyResource(CSinglePixelBufferResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vBuffers; + + friend class CSinglePixelBufferManagerResource; + friend class CSinglePixelBufferResource; +}; + +namespace PROTO { + inline UP singlePixel; +}; \ No newline at end of file From 968f6a6013409a6e6eab1545b28cd5e0cc49ce87 Mon Sep 17 00:00:00 2001 From: Trianta <56975502+Trimutex@users.noreply.github.com> Date: Sun, 29 Sep 2024 23:52:58 -0500 Subject: [PATCH 0674/2393] meson: fix arch build with new protocol --- protocols/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/meson.build b/protocols/meson.build index d686bacd..6990b5a7 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -63,6 +63,7 @@ protocols = [ wayland_protocol_dir / 'staging/drm-lease/drm-lease-v1.xml', wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', + wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', ] wl_protocols = [] From f6387536f62454f82039b42f641cd8c44153ad47 Mon Sep 17 00:00:00 2001 From: Trianta <56975502+Trimutex@users.noreply.github.com> Date: Mon, 30 Sep 2024 00:15:25 -0500 Subject: [PATCH 0675/2393] protocol: fix missing include --- src/protocols/SinglePixel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 7dd3748f..0595cce5 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -1,5 +1,6 @@ #include "SinglePixel.hpp" #include +#include "render/Renderer.hpp" CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) { LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex()); From 3ddb16bd5bb7146d125a7d68e4e9f3b54c381a20 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:25:39 +0100 Subject: [PATCH 0676/2393] compositor/wayland: up the max buffer size to avoid disconnects when app hangs --- CMakeLists.txt | 2 +- src/Compositor.cpp | 4 +++ src/helpers/ByteOperations.hpp | 52 ++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/helpers/ByteOperations.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ee9cd2e2..3440af4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ pkg_check_modules( IMPORTED_TARGET xkbcommon uuid - wayland-server + wayland-server>=1.22.90 wayland-protocols cairo pango diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 232ba4a6..25d73db0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -28,6 +28,7 @@ #include "desktop/LayerSurface.hpp" #include "render/Renderer.hpp" #include "xwayland/XWayland.hpp" +#include "helpers/ByteOperations.hpp" #include #include @@ -229,6 +230,9 @@ void CCompositor::initServer(std::string socketName, int socketFd) { if (envEnabled("HYPRLAND_TRACE")) Debug::trace = true; + // set the buffer size to 1MB to avoid disconnects due to an app hanging for a short while + wl_display_set_default_max_buffer_size(m_sWLDisplay, 1_MB); + Aquamarine::SBackendOptions options; options.logFunction = aqLog; diff --git a/src/helpers/ByteOperations.hpp b/src/helpers/ByteOperations.hpp new file mode 100644 index 00000000..6d9507ff --- /dev/null +++ b/src/helpers/ByteOperations.hpp @@ -0,0 +1,52 @@ +#pragma once + +#define ULL unsigned long long +#define LD long double + +constexpr ULL operator""_kB(const ULL BYTES) { + return BYTES * 1024; +} +constexpr ULL operator""_MB(const ULL BYTES) { + return BYTES * 1024 * 1024; +} +constexpr ULL operator""_GB(const ULL BYTES) { + return BYTES * 1024 * 1024 * 1024; +} +constexpr ULL operator""_TB(const ULL BYTES) { + return BYTES * 1024 * 1024 * 1024 * 1024; +} +constexpr LD operator""_kB(const LD BYTES) { + return BYTES * 1024; +} +constexpr LD operator""_MB(const LD BYTES) { + return BYTES * 1024 * 1024; +} +constexpr LD operator""_GB(const LD BYTES) { + return BYTES * 1024 * 1024 * 1024; +} +constexpr LD operator""_TB(const LD BYTES) { + return BYTES * 1024 * 1024 * 1024 * 1024; +} + +template +using __acceptable_byte_operation_type = typename std::enable_if::value || std::is_trivially_constructible::value>::type; + +template > +constexpr X kBtoBytes(const X kB) { + return kB * 1024; +} +template > +constexpr X MBtoBytes(const X MB) { + return MB * 1024 * 1024; +} +template > +constexpr X GBtoBytes(const X GB) { + return GB * 1024 * 1024 * 1024; +} +template > +constexpr X TBtoBytes(const X TB) { + return TB * 1024 * 1024 * 1024 * 1024; +} + +#undef ULL +#undef LD \ No newline at end of file From 68fd32c81013541f237e2046779185b41db1538e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:27:10 +0100 Subject: [PATCH 0677/2393] byteoperations: add missing header --- src/helpers/ByteOperations.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/ByteOperations.hpp b/src/helpers/ByteOperations.hpp index 6d9507ff..13e98500 100644 --- a/src/helpers/ByteOperations.hpp +++ b/src/helpers/ByteOperations.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #define ULL unsigned long long #define LD long double From 6bd339714160505ab1c4aade659eca6fe426fea5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:40:38 +0100 Subject: [PATCH 0678/2393] wlr-output-management: accept 0 refresh rates fixes #7879 --- src/protocols/OutputManagement.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index dcc7a62d..3fd0cf6c 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -467,11 +467,16 @@ COutputConfigurationHead::COutputConfigurationHead(SPerror(ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE, "Invalid mode"); return; } + if (refresh == 0) { + LOGM(LOG, " | configHead for {}: refreshRate 0, using old refresh rate of {:.2f}Hz", pMonitor->szName, pMonitor->refreshRate); + refresh = std::round(pMonitor->refreshRate * 1000.F); + } + state.committedProperties |= OUTPUT_HEAD_COMMITTED_CUSTOM_MODE; state.customMode = {{w, h}, (uint32_t)refresh}; From 5c6c300abfea2539ffad9bcbf857325eec5ab765 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 30 Sep 2024 17:42:36 +0100 Subject: [PATCH 0679/2393] wayland/output: send geometry in updateState --- src/protocols/core/Output.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 394dc8e2..7b88e0a8 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -21,8 +21,6 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni PROTO::outputs.at(monitor->szName)->destroyResource(this); }); - resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), - monitor->output->model.c_str(), monitor->transform); if (resource->version() >= 4) { resource->sendName(monitor->szName.c_str()); resource->sendDescription(monitor->szDescription.c_str()); @@ -57,6 +55,9 @@ void CWLOutputResource::updateState() { resource->sendMode((wl_output_mode)(WL_OUTPUT_MODE_CURRENT), monitor->vecPixelSize.x, monitor->vecPixelSize.y, monitor->refreshRate * 1000.0); + resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), + monitor->output->model.c_str(), monitor->transform); + if (resource->version() >= 2) resource->sendDone(); } From e2426942e5716a742ea353d2a1de7d7760fbbb41 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 2 Oct 2024 11:22:19 +0200 Subject: [PATCH 0680/2393] layout: add auto_group to control default grouping (#7883) --- src/config/ConfigDescriptions.hpp | 6 +++ src/config/ConfigManager.cpp | 1 + src/events/Windows.cpp | 2 +- src/layout/DwindleLayout.cpp | 21 +-------- src/layout/IHyprLayout.cpp | 73 ++++++++++++++++++++++++------- src/layout/IHyprLayout.hpp | 1 + src/layout/MasterLayout.cpp | 20 --------- 7 files changed, 68 insertions(+), 56 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 3a91a808..385d4e59 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -772,6 +772,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_GRADIENT, .data = SConfigOptionDescription::SGradientData{"0x66775500"}, }, + SConfigOptionDescription{ + .value = "group:auto_group", + .description = "automatically group new windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ad6e1871..2ce07ff0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -377,6 +377,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 544483b1..1c2c7cfa 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -322,7 +322,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->updateWindowData(); if (PWINDOW->m_bIsFloating) { - g_pLayoutManager->getCurrentLayout()->onWindowCreatedFloating(PWINDOW); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); PWINDOW->m_bCreatedOverFullscreen = true; // size and move rules diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index ed47fa44..04cbf21d 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -340,26 +340,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir return; } - // if it's a group, add the window - if (OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group - && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock()) && !m_vOverrideFocalPoint) { // we are not moving window - m_lDwindleNodesData.remove(*PNODE); - - static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - - OPENINGON->pWindow->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); - pWindow->updateWindowDecos(); - recalculateWindow(pWindow); - - if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); - - return; - } - - // If it's not, get the node under our cursor + // get the node under our cursor m_lDwindleNodesData.push_back(SDwindleNodeData()); const auto NEWPARENT = &m_lDwindleNodesData.back(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index c5a5373c..0fb78d02 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -9,23 +9,25 @@ #include "../xwayland/XSurface.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { - if (pWindow->m_bIsFloating) { + CBox desiredGeometry = {}; + g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); + + if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; + } else + pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + + pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; + + bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow); + if (autoGrouped) + return; + + if (pWindow->m_bIsFloating) onWindowCreatedFloating(pWindow); - } else { - CBox desiredGeometry = {}; - g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); - - if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; - } else { - pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); - } - - pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; - + else onWindowCreatedTiling(pWindow, direction); - } } void IHyprLayout::onWindowRemoved(PHLWINDOW pWindow) { @@ -178,6 +180,47 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } } +bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { + static auto AUTOGROUP = CConfigValue("group:auto_group"); + if ((*AUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. + && g_pCompositor->m_pLastWindow.lock() // check if a focused window exists. + && g_pCompositor->m_pLastWindow != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && g_pCompositor->m_pLastWindow->m_pWorkspace == + pWindow + ->m_pWorkspace // fix for multimonitor: when there is a focused group in monitor 1 and monitor 2 is empty, this enables adding the first window of monitor 2 when using the mouse to focus it. + && g_pCompositor->m_pLastWindow->m_sGroupData.pNextWindow.lock() // check if the focused window is a group + && pWindow->canBeGroupedInto(g_pCompositor->m_pLastWindow.lock()) // check if the new window can be grouped into the focused group + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + + switch (pWindow->m_bIsFloating) { + case false: + if (g_pCompositor->m_pLastWindow->m_bIsFloating) + pWindow->m_bIsFloating = true; + break; + + case true: + if (!g_pCompositor->m_pLastWindow->m_bIsFloating) + pWindow->m_bIsFloating = false; + break; + } + + static auto USECURRPOS = CConfigValue("group:insert_after_current"); + (*USECURRPOS ? g_pCompositor->m_pLastWindow : g_pCompositor->m_pLastWindow->getGroupTail())->insertWindowToGroup(pWindow); + + g_pCompositor->m_pLastWindow->setGroupCurrent(pWindow); + pWindow->applyGroupRules(); + pWindow->updateWindowDecos(); + recalculateWindow(pWindow); + + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); + + return true; + } + + return false; +} + void IHyprLayout::onBeginDragWindow() { const auto DRAGGINGWINDOW = g_pInputManager->currentlyDraggedWindow.lock(); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index 7e0d5704..f9e2de0d 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -47,6 +47,7 @@ class IHyprLayout { virtual void onWindowCreated(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT); virtual void onWindowCreatedTiling(PHLWINDOW, eDirection direction = DIRECTION_DEFAULT) = 0; virtual void onWindowCreatedFloating(PHLWINDOW); + virtual bool onWindowCreatedAutoGroup(PHLWINDOW); /* Return tiled status diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 8fa324b0..04a6ea29 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -116,26 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire return; } - // if it's a group, add the window - if (OPENINGON && OPENINGON != PNODE && OPENINGON->pWindow->m_sGroupData.pNextWindow.lock() // target is group - && pWindow->canBeGroupedInto(OPENINGON->pWindow.lock())) { - - m_lMasterNodesData.remove(*PNODE); - - static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? OPENINGON->pWindow.lock() : OPENINGON->pWindow->getGroupTail())->insertWindowToGroup(pWindow); - - OPENINGON->pWindow->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); - pWindow->updateWindowDecos(); - recalculateWindow(pWindow); - - if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); - - return; - } - pWindow->applyGroupRules(); static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); From de68e065fe861d7ca01eca267df4c305bc6e73c2 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 2 Oct 2024 22:25:25 +0200 Subject: [PATCH 0681/2393] layout: fix dragging a window into a group after e242694 (#7976) --- src/layout/IHyprLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 0fb78d02..4b5c9d4f 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -552,10 +552,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vLastFloatingSize = PSAVEDSIZE; - // move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back. + // move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back. pWindow->m_vPosition = Vector2D(-999999, -999999); - onWindowCreatedTiling(pWindow); + onWindowCreated(pWindow); pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealSize.setValue(PSAVEDSIZE); From aed529f695bc62f5fa45dc94c545275ebb49bc48 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 3 Oct 2024 22:00:44 +0000 Subject: [PATCH 0682/2393] renderer: fix uvBR calculation (#7975) --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 417a3ff8..b081fd81 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1134,7 +1134,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPcurrent.size.y; const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); - uvBR = uvBR - Vector2D(1.0 - WPERC * (uvBR.x - uvTL.x), 1.0 - HPERC * (uvBR.y - uvTL.y)); + uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); uvTL = uvTL + TOADDTL; // TODO: make this passed to the func. Might break in the future. From 1ed925b69c2854a3f345cbeb7dca29a6286ca926 Mon Sep 17 00:00:00 2001 From: Theo Paris Date: Fri, 4 Oct 2024 01:41:27 -0700 Subject: [PATCH 0683/2393] internal: fix missing include directive (#7984) This should fix building with clang. --- src/helpers/SdDaemon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 48c23e6b..80944794 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace Systemd { From 8e237b006fa7dd348a58c85f1aa46a8a835533c2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:43:59 +0100 Subject: [PATCH 0684/2393] xdg-output: minor cleanups --- src/protocols/XDGOutput.cpp | 32 ++++++++++++++------------------ src/protocols/XDGOutput.hpp | 6 +++--- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 5d620667..0cdadd43 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -29,29 +29,20 @@ void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver return; } - RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); - RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); - RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { this->onManagerGetXDGOutput(mgr, id, output); }); + RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); }); + RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { onManagerResourceDestroy(res->resource()); }); + RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { onManagerGetXDGOutput(mgr, id, output); }); } CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorLayoutChanged", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); static auto P2 = g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); - static auto P3 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - const auto PMONITOR = std::any_cast(param); - for (auto const& o : m_vXDGOutputs) { - if (o->monitor == PMONITOR) - o->monitor = nullptr; - } - }); } void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { - const auto OUTPUT = CWLOutputResource::fromResource(outputResource); - - const auto PMONITOR = OUTPUT->monitor.get(); - - const auto CLIENT = mgr->client(); + const auto OUTPUT = CWLOutputResource::fromResource(outputResource); + const auto PMONITOR = OUTPUT->monitor.lock(); + const auto CLIENT = mgr->client(); CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); #ifndef NO_XWAYLAND @@ -66,8 +57,12 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 return; } - if (!PMONITOR) + if (!PMONITOR) { + LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland"); return; + } + + LOGM(LOG, "New xdg_output for {}: client {:x} ({})", PMONITOR->szName, (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland"); const auto XDGVER = pXDGOutput->resource->version(); @@ -84,8 +79,9 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 } void CXDGOutputProtocol::updateAllOutputs() { - for (auto const& o : m_vXDGOutputs) { + LOGM(LOG, "updating all xdg_output heads"); + for (auto const& o : m_vXDGOutputs) { if (!o->monitor) continue; @@ -97,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() { // -CXDGOutput::CXDGOutput(SP resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) { +CXDGOutput::CXDGOutput(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { if (!resource->resource()) return; diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 73e7d53e..15d86cc7 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -9,12 +9,12 @@ class CXDGOutputProtocol; class CXDGOutput { public: - CXDGOutput(SP resource, CMonitor* monitor_); + CXDGOutput(SP resource, SP monitor_); void sendDetails(); private: - CMonitor* monitor = nullptr; + WP monitor; SP resource; std::optional overridePosition; @@ -30,12 +30,12 @@ class CXDGOutputProtocol : public IWaylandProtocol { CXDGOutputProtocol(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); + void updateAllOutputs(); private: void onManagerResourceDestroy(wl_resource* res); void onOutputResourceDestroy(wl_resource* res); void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource); - void updateAllOutputs(); // std::vector> m_vManagerResources; From 3a5052a714e2a6a2b002dddcac1204960b298f8b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:44:16 +0100 Subject: [PATCH 0685/2393] compositor: update all xdg outputs on arrange --- src/Compositor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 25d73db0..b4d10c88 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -23,6 +23,7 @@ #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" +#include "protocols/XDGOutput.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -2869,6 +2870,8 @@ void CCompositor::arrangeMonitors() { else m->xwaylandScale = 1.f; } + + PROTO::xdgOutput->updateAllOutputs(); } void CCompositor::enterUnsafeState() { From a815b14bf1b69b92f82bd09f6845fbdbb2fbe516 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 00:44:30 +0100 Subject: [PATCH 0686/2393] monitor: cleanup and modernize scheduleDone --- src/helpers/Monitor.cpp | 25 ++++++++++++++----------- src/helpers/Monitor.hpp | 6 +++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a9569699..03a1d92b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -12,6 +12,7 @@ #include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Output.hpp" #include "../managers/PointerManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../protocols/core/Compositor.hpp" #include "sync/SyncTimeline.hpp" #include @@ -789,20 +790,22 @@ CBox CMonitor::logicalBox() { return {vecPosition, vecSize}; } -static void onDoneSource(void* data) { - auto pMonitor = (CMonitor*)data; - - if (!PROTO::outputs.contains(pMonitor->szName)) - return; - - PROTO::outputs.at(pMonitor->szName)->sendDone(); -} - void CMonitor::scheduleDone() { - if (doneSource) + if (doneScheduled) return; - doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this); + doneScheduled = true; + + g_pEventLoopManager->doLater([M = self] { + if (!M) // if M is gone, we got destroyed, doesn't matter. + return; + + if (!PROTO::outputs.contains(M->szName)) + return; + + PROTO::outputs.at(M->szName)->sendDone(); + M->doneScheduled = false; + }); } bool CMonitor::attemptDirectScanout() { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 97d9f8ab..2a2edab6 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -190,10 +190,10 @@ class CMonitor { } private: - void setupDefaultWS(const SMonitorRule&); - WORKSPACEID findAvailableDefaultWS(); + void setupDefaultWS(const SMonitorRule&); + WORKSPACEID findAvailableDefaultWS(); - wl_event_source* doneSource = nullptr; + bool doneScheduled = false; struct { CHyprSignalListener frame; From 595eb89f6e16df0e19916e3c02bf5ceac5a61c57 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:52:53 +0100 Subject: [PATCH 0687/2393] renderer: Fix resize artifacts (stretching, bumps) (#7499) --- src/desktop/WLSurface.cpp | 2 +- src/render/OpenGL.cpp | 3 +++ src/render/Renderer.cpp | 42 +++++++++++++++++++++++---------------- src/render/Renderer.hpp | 33 +++++++++++++++--------------- 4 files changed, 46 insertions(+), 34 deletions(-) diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 45050e35..5e88f507 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -62,7 +62,7 @@ bool CWLSurface::small() const { const auto O = m_pWindowOwner.lock(); - return O->m_vReportedSize.x > m_pResource->current.bufferSize.x + 1 || O->m_vReportedSize.y > m_pResource->current.bufferSize.y + 1; + return O->m_vReportedSize.x > m_pResource->current.size.x + 1 || O->m_vReportedSize.y > m_pResource->current.size.y + 1; } Vector2D CWLSurface::correctSmallVec() const { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 4f22d6aa..a16c2d62 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1423,6 +1423,9 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, 0x2900 /* GL_CLAMP */); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, 0x2900); + if (m_RenderData.useNearestNeighbor) { glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(tex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b081fd81..310d45af 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -150,7 +150,7 @@ static void renderSurface(SP surface, int x, int y, void* da const auto& TEXTURE = surface->current.texture; const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow.lock() == RDATA->pWindow && g_pInputManager->dragMode == MBIND_RESIZE; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; // this is bad, probably has been logged elsewhere. Means the texture failed // uploading to the GPU. @@ -180,6 +180,7 @@ static void renderSurface(SP surface, int x, int y, void* da // however, if surface buffer w / h < box, we need to adjust them const auto PWINDOW = PSURFACE ? PSURFACE->getWindow() : nullptr; + // center the surface if it's smaller than the viewport we assign it if (PSURFACE && !PSURFACE->m_bFillIgnoreSmall && PSURFACE->small() /* guarantees PWINDOW */) { const auto CORRECT = PSURFACE->correctSmallVec(); const auto SIZE = PSURFACE->getViewporterCorrectedSize(); @@ -195,17 +196,6 @@ static void renderSurface(SP surface, int x, int y, void* da } } - if (!INTERACTIVERESIZEINPROGRESS && PSURFACE && PWINDOW && PWINDOW->m_vRealSize.goal().floor() > PWINDOW->m_vReportedSize && PWINDOW->m_vReportedSize > Vector2D{1, 1}) { - Vector2D size = - Vector2D{windowBox.w * (PWINDOW->m_vReportedSize.x / PWINDOW->m_vRealSize.value().x), windowBox.h * (PWINDOW->m_vReportedSize.y / PWINDOW->m_vRealSize.value().y)}; - Vector2D correct = Vector2D{windowBox.w, windowBox.h} - size; - - windowBox.translate(correct / 2.0); - - windowBox.w = size.x; - windowBox.h = size.y; - } - } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + RDATA->x + x, (int)outputY + RDATA->y + y, std::max((float)surface->current.size.x, 2.F), std::max((float)surface->current.size.y, 2.F)}; if (RDATA->pWindow && RDATA->pWindow->m_vRealSize.isBeingAnimated() && RDATA->surface && RDATA->surface != surface && RDATA->squishOversized /* subsurface */) { @@ -231,6 +221,8 @@ static void renderSurface(SP surface, int x, int y, void* da return; // invisible } + const auto PROJSIZEUNSCALED = windowBox.size(); + windowBox.scale(RDATA->pMonitor->scale); windowBox.round(); @@ -239,7 +231,7 @@ static void renderSurface(SP surface, int x, int y, void* da DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; - g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->surface == surface, windowBox.size(), MISALIGNEDFSV1); + g_pHyprRenderer->calculateUVForSurface(RDATA->pWindow, surface, RDATA->pMonitor->self.lock(), RDATA->surface == surface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size // in those cases it's better to just force nearest neighbor @@ -1083,7 +1075,8 @@ void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, bool main, const Vector2D& projSize, bool fixMisalignedFSV1) { +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, SP pMonitor, bool main, const Vector2D& projSize, + const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; Vector2D uvBR = Vector2D(1, 1); @@ -1112,6 +1105,22 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPscale); + const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination; + const auto EXPECTED_SIZE = + ((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale) + .round(); + if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) { + // this will not work with shm AFAIK, idk why. + // NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much + const auto FIX = projSize / EXPECTED_SIZE; + uvBR = uvBR * FIX; + } + g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = uvBR; @@ -1127,7 +1136,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_pXDGSurface->current.geometry; // ignore X and Y, adjust uv - if (geom.x != 0 || geom.y != 0 || geom.width > pWindow->m_vRealSize.value().x || geom.height > pWindow->m_vRealSize.value().y) { + if (geom.x != 0 || geom.y != 0 || geom.width > projSizeUnscaled.x || geom.height > projSizeUnscaled.y) { const auto XPERC = (double)geom.x / (double)pSurface->current.size.x; const auto YPERC = (double)geom.y / (double)pSurface->current.size.y; const auto WPERC = (double)(geom.x + geom.width) / (double)pSurface->current.size.x; @@ -1137,8 +1146,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_vRealSize.value(); + auto maxSize = projSizeUnscaled; if (pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall) maxSize = pWindow->m_pWLSurface->getViewporterCorrectedSize(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index b730d589..7d1ae4b1 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,22 +49,23 @@ class CHyprRenderer { CHyprRenderer(); ~CHyprRenderer(); - void renderMonitor(CMonitor* pMonitor); - void arrangeLayersForMonitor(const MONITORID&); - void damageSurface(SP, double, double, double scale = 1.0); - void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*, bool skipFrameSchedule = false); - void damageBox(const int& x, const int& y, const int& w, const int& h); - void damageRegion(const CRegion&); - void damageMonitor(CMonitor*); - void damageMirrorsWith(CMonitor*, const CRegion&); - bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); - bool shouldRenderWindow(PHLWINDOW, CMonitor*); - bool shouldRenderWindow(PHLWINDOW); - void ensureCursorRenderingMode(); - bool shouldRenderCursor(); - void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, SP, bool main = false, const Vector2D& projSize = {}, bool fixMisalignedFSV1 = false); + void renderMonitor(CMonitor* pMonitor); + void arrangeLayersForMonitor(const MONITORID&); + void damageSurface(SP, double, double, double scale = 1.0); + void damageWindow(PHLWINDOW, bool forceFull = false); + void damageBox(CBox*, bool skipFrameSchedule = false); + void damageBox(const int& x, const int& y, const int& w, const int& h); + void damageRegion(const CRegion&); + void damageMonitor(CMonitor*); + void damageMirrorsWith(CMonitor*, const CRegion&); + bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); + bool shouldRenderWindow(PHLWINDOW, CMonitor*); + bool shouldRenderWindow(PHLWINDOW); + void ensureCursorRenderingMode(); + bool shouldRenderCursor(); + void setCursorHidden(bool hide); + void calculateUVForSurface(PHLWINDOW, SP, SP pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, + bool fixMisalignedFSV1 = false); std::tuple getRenderTimes(CMonitor* pMonitor); // avg max min void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); From 46bf87c8d1f053284a266d5f0b470073a48a92f6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:37:12 +0100 Subject: [PATCH 0688/2393] monitor: use a scope guard for disconnect events --- src/helpers/Monitor.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 03a1d92b..f105ea66 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -229,6 +229,12 @@ void CMonitor::onConnect(bool noRule) { } void CMonitor::onDisconnect(bool destroy) { + CScopeGuard x = {[this]() { + if (g_pCompositor->m_bIsShuttingDown) + return; + g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); + EMIT_HOOK_EVENT("monitorRemoved", this); + }}; if (renderTimer) { wl_event_source_remove(renderTimer); @@ -341,9 +347,6 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); - - g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); - EMIT_HOOK_EVENT("monitorRemoved", this); } void CMonitor::addDamage(const pixman_region32_t* rg) { From 6fbfeefc7119ff86411b765aa26b4bffbaa825ec Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:40:03 +0100 Subject: [PATCH 0689/2393] protocolmgr: don't expose the fallback output --- src/managers/ProtocolManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 8bcc857a..157fa76c 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -86,7 +86,8 @@ CProtocolManager::CProtocolManager() { // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after // this event is emitted iirc. - if (M->isMirror()) + // also ignore the fallback + if (M->isMirror() || M == g_pCompositor->m_pUnsafeOutput) return; if (PROTO::outputs.contains(M->szName)) From 52c09196219313aec2ec1d3d543669bff834d746 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:41:44 +0100 Subject: [PATCH 0690/2393] monitor: arrange monitors on connect and disconnect --- src/helpers/Monitor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f105ea66..c6cef41f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -36,6 +36,7 @@ CMonitor::~CMonitor() { } void CMonitor::onConnect(bool noRule) { + CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }}; if (output->supportsExplicit) { inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); @@ -234,6 +235,7 @@ void CMonitor::onDisconnect(bool destroy) { return; g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); EMIT_HOOK_EVENT("monitorRemoved", this); + g_pCompositor->arrangeMonitors(); }}; if (renderTimer) { From 3ca699debffbb97085888835a33f20d0c542128d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 14:57:18 +0100 Subject: [PATCH 0691/2393] opengl: use GL_CLAMP_TO_EDGE instead of GL_CLAMP avoid error spam on select hw --- src/render/OpenGL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index a16c2d62..833e2ccb 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1423,8 +1423,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_iTarget, tex->m_iTexID); - glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, 0x2900 /* GL_CLAMP */); - glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, 0x2900); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->m_iTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (m_RenderData.useNearestNeighbor) { glTexParameteri(tex->m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); From 0ec6072a290051a03ab66cfb9bc616b2f5540e64 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 5 Oct 2024 16:36:57 +0100 Subject: [PATCH 0692/2393] single-pixel: set buffer size to 1,1 --- src/protocols/SinglePixel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 0595cce5..d800539d 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -17,6 +17,8 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor co success = texture->m_iTexID; + size = {1, 1}; + if (!success) Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); } From 0c7a7e2d569eeed9d6025f3eef4ea0690d90845d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 12:04:13 +0100 Subject: [PATCH 0693/2393] version: bump to 0.44.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8298bb08..a8ab6c96 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.43.0 +0.44.0 From da86aac0f5c5c3604351961b901f62cdf7186a10 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 14:07:07 +0100 Subject: [PATCH 0694/2393] security-context: implement protocol fixes #7318 --- CMakeLists.txt | 1 + protocols/meson.build | 1 + src/Compositor.cpp | 12 ++ src/managers/ProtocolManager.cpp | 55 ++++++++ src/managers/ProtocolManager.hpp | 2 + src/protocols/SecurityContext.cpp | 214 ++++++++++++++++++++++++++++++ src/protocols/SecurityContext.hpp | 83 ++++++++++++ src/protocols/TextInputV1.hpp | 2 +- src/protocols/WaylandProtocol.cpp | 4 + src/protocols/WaylandProtocol.hpp | 1 + 10 files changed, 374 insertions(+), 1 deletion(-) create mode 100644 src/protocols/SecurityContext.cpp create mode 100644 src/protocols/SecurityContext.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3440af4a..1bac29ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,6 +331,7 @@ protocolnew("staging/drm-lease" "drm-lease-v1" false) protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) +protocolnew("staging/security-context" "security-context-v1" false) protocolwayland() diff --git a/protocols/meson.build b/protocols/meson.build index 6990b5a7..3fa2ef2f 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -64,6 +64,7 @@ protocols = [ wayland_protocol_dir / 'staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml', wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', + wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', ] wl_protocols = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b4d10c88..f00e1e34 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -24,6 +24,7 @@ #include "protocols/LayerShell.hpp" #include "protocols/XDGShell.hpp" #include "protocols/XDGOutput.hpp" +#include "protocols/SecurityContext.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -210,11 +211,22 @@ void CCompositor::setRandomSplash() { static std::vector> pendingOutputs; +// + +static bool filterGlobals(const wl_client* client, const wl_global* global, void* data) { + if (!PROTO::securityContext->isClientSandboxed(client)) + return true; + + return !g_pProtocolManager || !g_pProtocolManager->isGlobalPrivileged(global); +} + // void CCompositor::initServer(std::string socketName, int socketFd) { m_sWLDisplay = wl_display_create(); + wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr); + m_sWLEventLoop = wl_display_get_event_loop(m_sWLDisplay); // register crit signal handler diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 157fa76c..6366eefe 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -45,6 +45,7 @@ #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/XDGDialog.hpp" #include "../protocols/SinglePixel.hpp" +#include "../protocols/SecurityContext.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -155,6 +156,7 @@ CProtocolManager::CProtocolManager() { PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); + PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -225,9 +227,62 @@ CProtocolManager::~CProtocolManager() { PROTO::toplevelExport.reset(); PROTO::globalShortcuts.reset(); PROTO::xdgDialog.reset(); + PROTO::singlePixel.reset(); + PROTO::securityContext.reset(); PROTO::lease.reset(); PROTO::sync.reset(); PROTO::mesaDRM.reset(); PROTO::linuxDma.reset(); } + +bool CProtocolManager::isGlobalPrivileged(const wl_global* global) { + if (!global) + return false; + + for (auto& [k, v] : PROTO::outputs) { + if (global == v->getGlobal()) + return false; + } + + // this is a static whitelist of allowed protocols, + // outputs are dynamic so we checked them above + // clang-format off + static const std::vector ALLOWED_WHITELIST = { + PROTO::seat->getGlobal(), + PROTO::data->getGlobal(), + PROTO::compositor->getGlobal(), + PROTO::subcompositor->getGlobal(), + PROTO::shm->getGlobal(), + PROTO::viewport->getGlobal(), + PROTO::tearing->getGlobal(), + PROTO::fractional->getGlobal(), + PROTO::cursorShape->getGlobal(), + PROTO::idleInhibit->getGlobal(), + PROTO::relativePointer->getGlobal(), + PROTO::xdgDecoration->getGlobal(), + PROTO::alphaModifier->getGlobal(), + PROTO::pointerGestures->getGlobal(), + PROTO::shortcutsInhibit->getGlobal(), + PROTO::textInputV1->getGlobal(), + PROTO::textInputV3->getGlobal(), + PROTO::constraints->getGlobal(), + PROTO::activation->getGlobal(), + PROTO::idle->getGlobal(), + PROTO::ime->getGlobal(), + PROTO::virtualKeyboard->getGlobal(), + PROTO::virtualPointer->getGlobal(), + PROTO::serverDecorationKDE->getGlobal(), + PROTO::tablet->getGlobal(), + PROTO::presentation->getGlobal(), + PROTO::xdgShell->getGlobal(), + PROTO::xdgDialog->getGlobal(), + PROTO::singlePixel->getGlobal(), + PROTO::sync ? PROTO::sync->getGlobal() : nullptr, + PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr, + PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr, + }; + // clang-format on + + return std::find(ALLOWED_WHITELIST.begin(), ALLOWED_WHITELIST.end(), global) == ALLOWED_WHITELIST.end(); +} diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 1b6d31b6..d5629e9e 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -11,6 +11,8 @@ class CProtocolManager { CProtocolManager(); ~CProtocolManager(); + bool isGlobalPrivileged(const wl_global* global); + private: std::unordered_map m_mModeChangeListeners; diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp new file mode 100644 index 00000000..b93ef448 --- /dev/null +++ b/src/protocols/SecurityContext.cpp @@ -0,0 +1,214 @@ +#include "SecurityContext.hpp" +#include "../Compositor.hpp" +#include + +static int onListenFdEvent(int fd, uint32_t mask, void* data) { + auto sc = (CSecurityContext*)data; + sc->onListen(mask); + return 0; +} + +static int onCloseFdEvent(int fd, uint32_t mask, void* data) { + auto sc = (CSecurityContext*)data; + sc->onClose(mask); + return 0; +} + +SP CSecurityContextSandboxedClient::create(int clientFD) { + auto p = SP(new CSecurityContextSandboxedClient(clientFD)); + if (!p->client) + return nullptr; + return p; +} + +static void onSecurityContextClientDestroy(wl_listener* l, void* d) { + CSecurityContextSandboxedClient* client = wl_container_of(l, client, destroyListener); + client->onDestroy(); +} + +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); + if (!client) + return; + + destroyListener.notify = ::onSecurityContextClientDestroy; + wl_client_add_destroy_late_listener(client, &destroyListener); +} + +CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { + wl_list_remove(&destroyListener.link); +} + +void CSecurityContextSandboxedClient::onDestroy() { + std::erase_if(PROTO::securityContext->m_vSandboxedClients, [this](const auto& e) { return e.get() == this; }); +} + +CSecurityContext::CSecurityContext(SP resource_, int listenFD_, int closeFD_) : listenFD(listenFD_), closeFD(closeFD_), resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSecurityContextV1* r) { + LOGM(LOG, "security_context at 0x{:x}: resource destroyed, keeping context until fd hangup", (uintptr_t)this); + resource = nullptr; + }); + resource->setOnDestroy([this](CWpSecurityContextV1* r) { + LOGM(LOG, "security_context at 0x{:x}: resource destroyed, keeping context until fd hangup", (uintptr_t)this); + resource = nullptr; + }); + + LOGM(LOG, "New security_context at 0x{:x}", (uintptr_t)this); + + resource->setSetSandboxEngine([this](CWpSecurityContextV1* r, const char* engine) { + if (!sandboxEngine.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox engine already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + sandboxEngine = engine ? engine : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets engine to {}", (uintptr_t)this, sandboxEngine); + }); + + resource->setSetAppId([this](CWpSecurityContextV1* r, const char* appid) { + if (!appID.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox appid already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + appID = appid ? appid : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets appid to {}", (uintptr_t)this, appID); + }); + + resource->setSetInstanceId([this](CWpSecurityContextV1* r, const char* instance) { + if (!instanceID.empty()) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox instance already set"); + return; + } + + if (committed) { + r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); + return; + } + + instanceID = instance ? instance : "(null)"; + LOGM(LOG, "security_context at 0x{:x} sets instance to {}", (uintptr_t)this, instanceID); + }); + + resource->setCommit([this](CWpSecurityContextV1* r) { + committed = true; + + LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); + + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + + if (!listenSource || !closeSource) { + r->noMemory(); + return; + } + }); +} + +CSecurityContext::~CSecurityContext() { + if (listenSource) + wl_event_source_remove(listenSource); + if (closeSource) + wl_event_source_remove(closeSource); +} + +bool CSecurityContext::good() { + return resource->resource(); +} + +void CSecurityContext::onListen(uint32_t mask) { + if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { + LOGM(ERR, "security_context at 0x{:x} got an error in listen", (uintptr_t)this); + PROTO::securityContext->destroyContext(this); + return; + } + + if (!(mask & WL_EVENT_READABLE)) + return; + + int clientFD = accept(listenFD, nullptr, nullptr); + if (clientFD < 0) { + LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); + return; + } + + auto newClient = CSecurityContextSandboxedClient::create(clientFD); + if (!newClient) { + LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); + close(clientFD); + return; + } + + PROTO::securityContext->m_vSandboxedClients.emplace_back(newClient); + + LOGM(LOG, "security_context at 0x{:x} got a new wl_client 0x{:x}", (uintptr_t)this, (uintptr_t)newClient->client); +} + +void CSecurityContext::onClose(uint32_t mask) { + if (!(mask & (WL_EVENT_ERROR | WL_EVENT_HANGUP))) + return; + + PROTO::securityContext->destroyContext(this); +} + +CSecurityContextManagerResource::CSecurityContextManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CWpSecurityContextManagerV1* r) { PROTO::securityContext->destroyResource(this); }); + resource->setOnDestroy([this](CWpSecurityContextManagerV1* r) { PROTO::securityContext->destroyResource(this); }); + + resource->setCreateListener([](CWpSecurityContextManagerV1* r, uint32_t id, int32_t lfd, int32_t cfd) { + const auto RESOURCE = + PROTO::securityContext->m_vContexts.emplace_back(makeShared(makeShared(r->client(), r->version(), id), lfd, cfd)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::securityContext->m_vContexts.pop_back(); + return; + } + }); +} + +bool CSecurityContextManagerResource::good() { + return resource->resource(); +} + +CSecurityContextProtocol::CSecurityContextProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CSecurityContextProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CSecurityContextProtocol::destroyResource(CSecurityContextManagerResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CSecurityContextProtocol::destroyContext(CSecurityContext* context) { + std::erase_if(m_vContexts, [&](const auto& other) { return other.get() == context; }); +} + +bool CSecurityContextProtocol::isClientSandboxed(const wl_client* client) { + return std::find_if(m_vSandboxedClients.begin(), m_vSandboxedClients.end(), [client](const auto& e) { return e->client == client; }) != m_vSandboxedClients.end(); +} diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp new file mode 100644 index 00000000..bcbb69b2 --- /dev/null +++ b/src/protocols/SecurityContext.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "security-context-v1.hpp" + +class CSecurityContext { + public: + CSecurityContext(SP resource_, int listenFD_, int closeFD_); + ~CSecurityContext(); + + bool good(); + + std::string sandboxEngine, appID, instanceID; + int listenFD = -1, closeFD = -1; + + void onListen(uint32_t mask); + void onClose(uint32_t mask); + + private: + SP resource; + + wl_event_source * listenSource = nullptr, *closeSource = nullptr; + + bool committed = false; +}; + +class CSecurityContextManagerResource { + public: + CSecurityContextManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CSecurityContextSandboxedClient { + public: + static SP create(int clientFD); + ~CSecurityContextSandboxedClient(); + + void onDestroy(); + + wl_listener destroyListener; + + private: + CSecurityContextSandboxedClient(int clientFD); + + wl_client* client = nullptr; + + friend class CSecurityContextProtocol; + friend class CSecurityContext; +}; + +class CSecurityContextProtocol : public IWaylandProtocol { + public: + CSecurityContextProtocol(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); + + bool isClientSandboxed(const wl_client* client); + + private: + void destroyResource(CSecurityContextManagerResource* resource); + + void destroyContext(CSecurityContext* context); + + // + std::vector> m_vManagers; + std::vector> m_vContexts; + std::vector> m_vSandboxedClients; + + friend class CSecurityContextManagerResource; + friend class CSecurityContext; + friend class CSecurityContextSandboxedClient; +}; + +namespace PROTO { + inline UP securityContext; +}; \ No newline at end of file diff --git a/src/protocols/TextInputV1.hpp b/src/protocols/TextInputV1.hpp index 9bee452c..d3b0d71b 100644 --- a/src/protocols/TextInputV1.hpp +++ b/src/protocols/TextInputV1.hpp @@ -60,7 +60,7 @@ class CTextInputV1 { friend class CTextInputV1Protocol; }; -class CTextInputV1Protocol : IWaylandProtocol { +class CTextInputV1Protocol : public IWaylandProtocol { public: CTextInputV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 0782d323..00b112b0 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -40,3 +40,7 @@ IWaylandProtocol::~IWaylandProtocol() { void IWaylandProtocol::removeGlobal() { wl_global_remove(m_pGlobal); } + +wl_global* IWaylandProtocol::getGlobal() { + return m_pGlobal; +} diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index 87c75ed8..056322ac 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -53,6 +53,7 @@ class IWaylandProtocol { virtual void onDisplayDestroy(); virtual void removeGlobal(); + virtual wl_global* getGlobal(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) = 0; From 4e41cda27ed4176005082436cb35878335e63fae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 6 Oct 2024 15:08:26 +0100 Subject: [PATCH 0695/2393] security-context: close client fds after disconnect --- src/protocols/SecurityContext.cpp | 7 ++++--- src/protocols/SecurityContext.hpp | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index b93ef448..b42c3a97 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -14,8 +14,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD)); +SP CSecurityContextSandboxedClient::create(int clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); if (!p->client) return nullptr; return p; @@ -26,7 +26,7 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); if (!client) return; @@ -37,6 +37,7 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD) { CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.link); + close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index bcbb69b2..76313bcf 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -47,9 +47,10 @@ class CSecurityContextSandboxedClient { wl_listener destroyListener; private: - CSecurityContextSandboxedClient(int clientFD); + CSecurityContextSandboxedClient(int clientFD_); - wl_client* client = nullptr; + wl_client* client = nullptr; + int clientFD = -1; friend class CSecurityContextProtocol; friend class CSecurityContext; From 97444ed7a8a83406970fcc05907db1110435b59b Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 7 Oct 2024 14:22:55 +0200 Subject: [PATCH 0696/2393] layout: fix auto group when opening a new window in a non-focused workspace using window rules (#8006) --- src/layout/IHyprLayout.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 4b5c9d4f..f090e87d 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -181,33 +181,34 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { - static auto AUTOGROUP = CConfigValue("group:auto_group"); - if ((*AUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. - && g_pCompositor->m_pLastWindow.lock() // check if a focused window exists. - && g_pCompositor->m_pLastWindow != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && g_pCompositor->m_pLastWindow->m_pWorkspace == - pWindow - ->m_pWorkspace // fix for multimonitor: when there is a focused group in monitor 1 and monitor 2 is empty, this enables adding the first window of monitor 2 when using the mouse to focus it. - && g_pCompositor->m_pLastWindow->m_sGroupData.pNextWindow.lock() // check if the focused window is a group - && pWindow->canBeGroupedInto(g_pCompositor->m_pLastWindow.lock()) // check if the new window can be grouped into the focused group - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + static auto PAUTOGROUP = CConfigValue("group:auto_group"); + PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? + g_pCompositor->m_pLastWindow.lock() : + g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + + if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. switch (pWindow->m_bIsFloating) { case false: - if (g_pCompositor->m_pLastWindow->m_bIsFloating) + if (OPENINGON->m_bIsFloating) pWindow->m_bIsFloating = true; break; case true: - if (!g_pCompositor->m_pLastWindow->m_bIsFloating) + if (!OPENINGON->m_bIsFloating) pWindow->m_bIsFloating = false; break; } static auto USECURRPOS = CConfigValue("group:insert_after_current"); - (*USECURRPOS ? g_pCompositor->m_pLastWindow : g_pCompositor->m_pLastWindow->getGroupTail())->insertWindowToGroup(pWindow); + (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); - g_pCompositor->m_pLastWindow->setGroupCurrent(pWindow); + OPENINGON->setGroupCurrent(pWindow); pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); From 5bf7b1e1fadf743f41ec765f7545370e3d7ccf96 Mon Sep 17 00:00:00 2001 From: Timon Schelling Date: Mon, 7 Oct 2024 15:44:03 +0000 Subject: [PATCH 0697/2393] flake.nix: add xdph follows fixes a duplicate hyprland-protocols instance sometimes being created due to xdph not following hyprlands instance --- flake.lock | 29 +++-------------------------- flake.nix | 5 +++-- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/flake.lock b/flake.lock index 2579dd11..2f9fbbc6 100644 --- a/flake.lock +++ b/flake.lock @@ -78,31 +78,6 @@ "type": "github" } }, - "hyprland-protocols_2": { - "inputs": { - "nixpkgs": [ - "xdph", - "nixpkgs" - ], - "systems": [ - "xdph", - "systems" - ] - }, - "locked": { - "lastModified": 1721326555, - "narHash": "sha256-zCu4R0CSHEactW9JqYki26gy8h9f6rHmSwj4XJmlHgg=", - "owner": "hyprwm", - "repo": "hyprland-protocols", - "rev": "5a11232266bf1a1f5952d5b179c3f4b2facaaa84", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-protocols", - "type": "github" - } - }, "hyprlang": { "inputs": { "hyprutils": [ @@ -221,7 +196,9 @@ }, "xdph": { "inputs": { - "hyprland-protocols": "hyprland-protocols_2", + "hyprland-protocols": [ + "hyprland-protocols" + ], "hyprlang": [ "hyprlang" ], diff --git a/flake.nix b/flake.nix index ee5af6a1..cfd003f8 100644 --- a/flake.nix +++ b/flake.nix @@ -51,6 +51,7 @@ url = "github:hyprwm/xdg-desktop-portal-hyprland"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; + inputs.hyprland-protocols.follows = "hyprland-protocols"; inputs.hyprlang.follows = "hyprlang"; inputs.hyprutils.follows = "hyprutils"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; @@ -98,13 +99,13 @@ inherit (pkgsFor.${system}) # hyprland-packages - + hyprland hyprland-debug hyprland-legacy-renderer hyprland-unwrapped # hyprland-extras - + xdg-desktop-portal-hyprland ; hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland; From 46d990f1b632dc52a667d876a32cffb24ef72bd8 Mon Sep 17 00:00:00 2001 From: Artur Manuel Date: Mon, 7 Oct 2024 19:49:19 +0100 Subject: [PATCH 0698/2393] feat: add a custom made treewide formatter (#7992) --- .gitignore | 4 +++ flake.lock | 77 +++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 22 ++++++++++++-- nix/default.nix | 2 +- nix/formatter.nix | 64 +++++++++++++++++++++++++++++++++++++++ nix/overlays.nix | 4 +-- 6 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 nix/formatter.nix diff --git a/.gitignore b/.gitignore index 2e158a4e..a7934790 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ _deps build/ result* +/.pre-commit-config.yaml /.vscode/ /.idea/ .envrc @@ -39,3 +40,6 @@ PKGBUILD src/version.h hyprpm/Makefile hyprctl/Makefile + +**/.#*.* +**/#*.*# diff --git a/flake.lock b/flake.lock index 2f9fbbc6..85069a74 100644 --- a/flake.lock +++ b/flake.lock @@ -29,6 +29,43 @@ "type": "github" } }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, "hyprcursor": { "inputs": { "hyprlang": [ @@ -166,6 +203,45 @@ "type": "github" } }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1728092656, + "narHash": "sha256-eMeCTJZ5xBeQ0f9Os7K8DThNVSo9gy4umZLDfF5q6OM=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "1211305a5b237771e13fcca0c51e60ad47326a9a", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "aquamarine": "aquamarine", @@ -175,6 +251,7 @@ "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks", "systems": "systems", "xdph": "xdph" } diff --git a/flake.nix b/flake.nix index cfd003f8..e3419ef8 100644 --- a/flake.nix +++ b/flake.nix @@ -56,6 +56,11 @@ inputs.hyprutils.follows = "hyprutils"; inputs.hyprwayland-scanner.follows = "hyprwayland-scanner"; }; + + pre-commit-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs @ { @@ -77,7 +82,7 @@ pkgsCrossFor = eachSystem (system: crossSystem: import nixpkgs { localSystem = system; - crossSystem = crossSystem; + inherit crossSystem; overlays = with self.overlays; [ hyprland-packages hyprland-extras @@ -92,6 +97,18 @@ self.packages.${system}) // { inherit (self.packages.${system}) xdg-desktop-portal-hyprland; + pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run { + src = ./.; + hooks = { + hyprland-treewide-formatter = { + enable = true; + entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter"; + pass_filenames = false; + excludes = ["subprojects"]; + always_run = true; + }; + }; + }; }); packages = eachSystem (system: { @@ -120,10 +137,11 @@ hardeningDisable = ["fortify"]; inputsFrom = [pkgsFor.${system}.hyprland]; packages = [pkgsFor.${system}.clang-tools]; + inherit (self.checks.${system}.pre-commit-check) shellHook; }; }); - formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra); + formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix {}); nixosModules.default = import ./nix/module.nix inputs; homeManagerModules.default = import ./nix/hm-module.nix self; diff --git a/nix/default.nix b/nix/default.nix index 6f086ccc..d463e271 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -68,7 +68,7 @@ in inherit version; src = cleanSourceWith { - filter = name: type: let + filter = name: _type: let baseName = baseNameOf (toString name); in ! (hasSuffix ".nix" baseName); diff --git a/nix/formatter.nix b/nix/formatter.nix new file mode 100644 index 00000000..66721c2c --- /dev/null +++ b/nix/formatter.nix @@ -0,0 +1,64 @@ +{ + writeShellApplication, + deadnix, + statix, + alejandra, + llvmPackages_19, + fd, +}: +writeShellApplication { + name = "hyprland-treewide-formatter"; + runtimeInputs = [ + deadnix + statix + alejandra + llvmPackages_19.clang-tools + fd + ]; + text = '' + # shellcheck disable=SC2148 + + # common excludes + excludes="subprojects" + + nix_format() { + if [ "$*" = 0 ]; then + fd '.*\.nix' . -E "$excludes" -x statix fix -- {} \; + fd '.*\.nix' . -E "$excludes" -X deadnix -e -- {} \; -X alejandra {} \; + elif [ -d "$1" ]; then + fd '.*\.nix' "$1" -E "$excludes" -i -x statix fix -- {} \; + fd '.*\.nix' "$1" -E "$excludes" -i -X deadnix -e -- {} \; -X alejandra {} \; + else + statix fix -- "$1" + deadnix -e "$1" + alejandra "$1" + fi + } + + cpp_format() { + if [ "$*" = 0 ] || [ "$1" = "." ]; then + fd '.*\.cpp' . -E "$excludes" | xargs clang-format --verbose -i + elif [ -d "$1" ]; then + fd '.*\.cpp' "$1" -E "$excludes" | xargs clang-format --verbose -i + else + clang-format --verbose -i "$1" + fi + } + + for i in "$@"; do + case ''${i##*.} in + "nix") + nix_format "$i" + ;; + "cpp") + cpp_format "$i" + ;; + *) + nix_format "$i" + cpp_format "$i" + ;; + esac + + done + ''; +} diff --git a/nix/overlays.nix b/nix/overlays.nix index 2b2788e7..a78f3003 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -29,7 +29,7 @@ in { self.overlays.udis86 # Hyprland packages themselves - (final: prev: let + (final: _prev: let date = mkDate (self.lastModifiedDate or "19700101"); in { hyprland = final.callPackage ./default.nix { @@ -70,7 +70,7 @@ in { # this version is the one used in the git submodule, and allows us to # fetch the source without '?submodules=1' udis86 = final: prev: { - udis86-hyprland = prev.udis86.overrideAttrs (self: super: { + udis86-hyprland = prev.udis86.overrideAttrs (_self: _super: { src = final.fetchFromGitHub { owner = "canihavesomecoffee"; repo = "udis86"; From a364df4c9e9a73f0460665463028539e3abe4a8b Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Mon, 7 Oct 2024 18:52:49 +0000 Subject: [PATCH 0699/2393] internal: use clampWindowSize to unify min/maxsize handling (#8014) modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp --- src/desktop/Window.cpp | 20 ++++++++++++++------ src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 22 ++-------------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index feced807..fa85dc07 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -736,9 +736,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } m_sWindowData.maxSize = CWindowOverridableVar(VEC, priority); - m_vRealSize = - Vector2D(std::min((double)m_sWindowData.maxSize.value().x, m_vRealSize.goal().x), std::min((double)m_sWindowData.maxSize.value().y, m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); + clampWindowSize(std::nullopt, m_sWindowData.maxSize.value()); + } catch (std::exception& e) { Debug::log(ERR, "maxsize rule \"{}\" failed with: {}", r.szRule, e.what()); } } else if (r.szRule.starts_with("minsize")) { try { @@ -751,9 +750,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } m_sWindowData.minSize = CWindowOverridableVar(VEC, priority); - m_vRealSize = - Vector2D(std::max((double)m_sWindowData.minSize.value().x, m_vRealSize.goal().x), std::max((double)m_sWindowData.minSize.value().y, m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal()); + clampWindowSize(m_sWindowData.minSize.value(), std::nullopt); + if (m_sGroupData.pNextWindow.expired()) setHidden(false); } catch (std::exception& e) { Debug::log(ERR, "minsize rule \"{}\" failed with: {}", r.szRule, e.what()); } @@ -1253,6 +1251,16 @@ int CWindow::surfacesCount() { return no; } +void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { + const Vector2D REALSIZE = m_vRealSize.goal(); + const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{0.f, 0.f}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); + const Vector2D DELTA = REALSIZE - NEWSIZE; + + m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0; + m_vRealSize = NEWSIZE; + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE); +} + bool CWindow::isFullscreen() { return m_sFullscreenState.internal != FSMODE_NONE; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d14248c5..9baf57c4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -429,6 +429,7 @@ class CWindow { bool onSpecialWorkspace(); void activate(bool force = false); int surfacesCount(); + void clampWindowSize(const std::optional minSize, const std::optional maxSize); bool isFullscreen(); bool isEffectiveInternalFSMode(const eFullscreenMode); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 1c2c7cfa..37f29130 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -751,26 +751,8 @@ void Events::listener_commitWindow(void* owner, void* data) { const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; - if (MAXSIZE > Vector2D{1, 1}) { - const auto REALSIZE = PWINDOW->m_vRealSize.goal(); - Vector2D newSize = REALSIZE; - - if (MAXSIZE.x < newSize.x) - newSize.x = MAXSIZE.x; - if (MAXSIZE.y < newSize.y) - newSize.y = MAXSIZE.y; - if (MINSIZE.x > newSize.x) - newSize.x = MINSIZE.x; - if (MINSIZE.y > newSize.y) - newSize.y = MINSIZE.y; - - const Vector2D DELTA = REALSIZE - newSize; - - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + DELTA / 2.0; - PWINDOW->m_vRealSize = newSize; - g_pXWaylandManager->setWindowSize(PWINDOW, newSize); - g_pHyprRenderer->damageWindow(PWINDOW); - } + PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional{MAXSIZE} : std::nullopt); + g_pHyprRenderer->damageWindow(PWINDOW); } if (!PWINDOW->m_pWorkspace->m_bVisible) From 0d70c442538ba0d1efc63558c859c184367c95ad Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:23:48 -0500 Subject: [PATCH 0700/2393] screencopy: fix screencopy frames not being cleaned up (#8017) --------- Co-authored-by: Vaxry --- src/protocols/Screencopy.cpp | 13 ++++++++----- src/protocols/Screencopy.hpp | 4 ++-- src/protocols/ToplevelExport.cpp | 16 +++++++++++----- src/protocols/ToplevelExport.hpp | 4 ++-- subprojects/hyprland-protocols | 2 +- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 63024541..1b06a1fa 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -394,12 +394,12 @@ void CScreencopyProtocol::bindManager(wl_client* client, void* data, uint32_t ve void CScreencopyProtocol::destroyResource(CScreencopyClient* client) { std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; }); } void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) { std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { @@ -412,8 +412,11 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { + if (!f) + continue; + if (!f->pMonitor || !f->buffer) { - framesToRemove.push_back(f); + framesToRemove.emplace_back(f); continue; } @@ -425,10 +428,10 @@ void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { f->client->lastFrame.reset(); ++f->client->frameCounter; - framesToRemove.push_back(f); + framesToRemove.emplace_back(f); } for (auto const& f : framesToRemove) { - destroyResource(f.get()); + std::erase(m_vFramesAwaitingWrite, f); } } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index cbc56edb..e121d0fd 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -54,7 +54,7 @@ class CScreencopyFrame { bool good(); - SP self; + WP self; WP client; private: @@ -92,7 +92,7 @@ class CScreencopyProtocol : public IWaylandProtocol { private: std::vector> m_vFrames; - std::vector> m_vFramesAwaitingWrite; + std::vector> m_vFramesAwaitingWrite; std::vector> m_vClients; SP m_pSoftwareCursorTimer; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index b28a827a..66df5926 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -354,12 +354,12 @@ void CToplevelExportProtocol::bindManager(wl_client* client, void* data, uint32_ void CToplevelExportProtocol::destroyResource(CToplevelExportClient* client) { std::erase_if(m_vClients, [&](const auto& other) { return other.get() == client; }); std::erase_if(m_vFrames, [&](const auto& other) { return other->client.get() == client; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other->client.get() == client; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other->client.get() == client; }); } void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) { std::erase_if(m_vFrames, [&](const auto& other) { return other.get() == frame; }); - std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other.get() == frame; }); + std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { @@ -370,11 +370,17 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { - if (!f->pWindow || !validMapped(f->pWindow)) { - framesToRemove.push_back(f); + if (!f) + continue; + + if (!validMapped(f->pWindow)) { + framesToRemove.emplace_back(f); continue; } + if (!f->pWindow) + continue; + const auto PWINDOW = f->pWindow; if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) @@ -394,7 +400,7 @@ void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { } for (auto const& f : framesToRemove) { - destroyResource(f.get()); + std::erase(m_vFramesAwaitingWrite, f); } } diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 638b69f0..9686431b 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -45,7 +45,7 @@ class CToplevelExportFrame { bool good(); - SP self; + WP self; WP client; private: @@ -85,7 +85,7 @@ class CToplevelExportProtocol : IWaylandProtocol { private: std::vector> m_vClients; std::vector> m_vFrames; - std::vector> m_vFramesAwaitingWrite; + std::vector> m_vFramesAwaitingWrite; void shareFrame(CToplevelExportFrame* frame); bool copyFrameDmabuf(CToplevelExportFrame* frame, timespec* now); diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index e06482e0..c7c3f4cd 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit e06482e0e611130cd1929f75e8c1cf679e57d161 +Subproject commit c7c3f4cd0faed21fc90ba6bd06fe4f3e0e057ea8 From 4711796d3800f1a6673eccbd50e8e8a02bb0fd85 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 09:54:25 +0100 Subject: [PATCH 0701/2393] config: give simple help for super+q not working only on default config :P --- src/config/ConfigManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 2ce07ff0..018deaa7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -867,8 +867,10 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { if (result.error && !std::any_cast(m_pConfig->getConfigValue("debug:suppress_errors"))) g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) - g_pHyprError->queueCreate("Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty\nSUPER+M -> exit Hyprland", - CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); + g_pHyprError->queueCreate( + "Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + + " )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland", + CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); else if (*PENABLEEXPLICIT != prevEnabledExplicit) g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); else From 45e82199fb29f422ebbbfe06ce03022dfb6d645e Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 8 Oct 2024 12:20:41 +0200 Subject: [PATCH 0702/2393] layout: add drag_into_group to control merging dragging windows (#8004) --- src/config/ConfigDescriptions.hpp | 6 ++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 65 +++++++++++++------ .../decorations/CHyprGroupBarDecoration.cpp | 16 +++-- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 385d4e59..2ca230be 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -778,6 +778,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:drag_into_group", + .description = "whether dragging a window into a unlocked group will merge them. Options: 0 (disabled), 1 (enabled), 2 (only when dragging into the groupbar)", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 018deaa7..9a5283fa 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -378,6 +378,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f090e87d..f249d2b5 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -193,17 +193,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. - switch (pWindow->m_bIsFloating) { - case false: - if (OPENINGON->m_bIsFloating) - pWindow->m_bIsFloating = true; - break; - - case true: - if (!OPENINGON->m_bIsFloating) - pWindow->m_bIsFloating = false; - break; - } + pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); @@ -335,21 +325,47 @@ void IHyprLayout::onEndDragWindow() { g_pInputManager->currentlyDraggedWindow.reset(); g_pInputManager->m_bWasDraggingWindow = true; - if (DRAGGINGWINDOW->m_bDraggingTiled) { - DRAGGINGWINDOW->m_bIsFloating = false; - g_pInputManager->refocus(); - changeWindowFloatingMode(DRAGGINGWINDOW); - DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; - } else if (g_pInputManager->dragMode == MBIND_MOVE) { + if (g_pInputManager->dragMode == MBIND_MOVE) { g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); - PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING | FLOATING_ONLY, DRAGGINGWINDOW); + PHLWINDOW pWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, DRAGGINGWINDOW); if (pWindow) { if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW)) return; - if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow)) { + bool denied = false; + if (!pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled) + denied = true; + + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !denied) { + if (DRAGGINGWINDOW->m_bDraggingTiled) { + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; + DRAGGINGWINDOW->m_bDraggingTiled = false; + } + + if (DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock()) { + std::vector members; + PHLWINDOW curr = DRAGGINGWINDOW->getGroupHead(); + do { + members.push_back(curr); + curr = curr->m_sGroupData.pNextWindow.lock(); + } while (curr != members[0]); + + for (auto it = members.begin(); it != members.end(); ++it) { + (*it)->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members + if (pWindow->m_bIsFloating) + (*it)->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members + } + } + + DRAGGINGWINDOW->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of the window + + if (pWindow->m_bIsFloating) + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window + static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW); @@ -361,6 +377,13 @@ void IHyprLayout::onEndDragWindow() { } } + if (DRAGGINGWINDOW->m_bDraggingTiled) { + DRAGGINGWINDOW->m_bIsFloating = false; + g_pInputManager->refocus(); + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; + } + g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); g_pCompositor->focusWindow(DRAGGINGWINDOW); @@ -553,10 +576,10 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vLastFloatingSize = PSAVEDSIZE; - // move to narnia because we don't wanna find our own node. onWindowCreated should apply the coords back. + // move to narnia because we don't wanna find our own node. onWindowCreatedTiling should apply the coords back. pWindow->m_vPosition = Vector2D(-999999, -999999); - onWindowCreated(pWindow); + onWindowCreatedTiling(pWindow); pWindow->m_vRealPosition.setValue(PSAVEDPOS); pWindow->m_vRealSize.setValue(PSAVEDSIZE); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4cdb9043..ef6c81e6 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -402,8 +402,9 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { } bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) { - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock())) + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2)) return false; const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; @@ -435,6 +436,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND // restores the group for (auto it = members.begin(); it != members.end(); ++it) { + (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members + if (pWindowInsertAfter->m_bIsFloating) + (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members if (std::next(it) != members.end()) (*it)->m_sGroupData.pNextWindow = *std::next(it); else @@ -442,9 +446,13 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND } members[0]->m_sGroupData.head = true; members[0]->m_sGroupData.locked = WASLOCKED; - } else { + } else g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pDraggedWindow); - } + + pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window + + if (pWindowInsertAfter->m_bIsFloating) + g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize.goal()); // match the size of the window pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); From b3a7e3109bf2b7b4422424471130197dc08baeb1 Mon Sep 17 00:00:00 2001 From: davc0n Date: Tue, 8 Oct 2024 12:42:51 +0200 Subject: [PATCH 0703/2393] misc: refactor version command (#8027) Fixes a minor spacing issue if git status is not dirty. Additionally now should be easier to extend it eventually. --- src/main.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 279e1ce1..57bb5507 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -116,11 +116,20 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { + auto result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH; + auto dirty = std::string(GIT_DIRTY); + if (!dirty.empty()) + result += " " + dirty; + auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); - std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + - "\n\nflags: (if any)\n"; + result += " (" + commitMsg + ")."; + + result += "\nDate: " + std::string(GIT_COMMIT_DATE); + result += "\nTag: " + std::string(GIT_TAG) + ", commits: " + std::string(GIT_COMMITS); + result += "\nbuilt against aquamarine " + std::string(AQUAMARINE_VERSION); + + result += "\n\nflags: (if any)\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; From e0cfbec66b97edb2957508152f32e77a1b181afc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 8 Oct 2024 13:15:53 +0100 Subject: [PATCH 0704/2393] keybinds: fixup xkb_states for resolve_by_sym fixes #7750 --- src/devices/IKeyboard.cpp | 10 ++++++++++ src/devices/IKeyboard.hpp | 5 +++-- src/managers/KeybindManager.cpp | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 13440169..3300f252 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -178,13 +178,18 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { if (xkbState) xkb_state_unref(xkbState); + if (xkbSymState) + xkb_state_unref(xkbSymState); + xkbState = nullptr; xkbStaticState = nullptr; + xkbSymState = nullptr; if (keymap) { Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this); xkbStaticState = xkb_state_new(keymap); xkbState = xkb_state_new(keymap); + xkbSymState = xkb_state_new(keymap); return; } @@ -230,6 +235,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { xkbState = xkb_state_new(KEYMAP); xkbStaticState = xkb_state_new(KEYMAP); + xkbSymState = xkb_state_new(KEYMAP); xkb_keymap_unref(KEYMAP); xkb_context_unref(PCONTEXT); @@ -252,6 +258,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { xkbState = xkb_state_new(NEWKEYMAP); xkbStaticState = xkb_state_new(NEWKEYMAP); + xkbSymState = xkb_state_new(NEWKEYMAP); xkb_keymap_unref(NEWKEYMAP); xkb_context_unref(PCONTEXT); @@ -332,6 +339,9 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group); + if (xkbSymState) + xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, group); + if (!updateModifiersState()) return; diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 759b2f58..76d2c31b 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -82,8 +82,9 @@ class IKeyboard : public IHID { bool keymapOverridden = false; xkb_layout_index_t activeLayout = 0; - xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr; - xkb_keymap* xkbKeymap = nullptr; + xkb_state * xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr, + *xkbSymState = nullptr /* Same as static but gets layouts */; + xkb_keymap* xkbKeymap = nullptr; struct { uint32_t depressed = 0, latched = 0, locked = 0, group = 0; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index cd47bf71..d893e258 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -376,7 +376,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput - const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbState : m_pXKBTranslationState, KEYCODE); + const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); if (handleInternalKeybinds(internalKeysym)) From 1bf63dfdcd76c09137b4647f9af2c5ebc9fc6e34 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:59:15 +0100 Subject: [PATCH 0705/2393] protocols: Add support for hyprland-ctm-control-v1 (#8023) * initial ctm support * flake.lock: update * Meson: bump required versions and add ctm proto --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 6 ++- flake.lock | 36 ++++++------- meson.build | 2 +- protocols/meson.build | 3 +- src/helpers/Monitor.cpp | 6 +++ src/helpers/Monitor.hpp | 5 ++ src/managers/ProtocolManager.cpp | 3 ++ src/protocols/CTMControl.cpp | 86 ++++++++++++++++++++++++++++++++ src/protocols/CTMControl.hpp | 44 ++++++++++++++++ src/render/Renderer.cpp | 5 ++ 10 files changed, 174 insertions(+), 22 deletions(-) create mode 100644 src/protocols/CTMControl.cpp create mode 100644 src/protocols/CTMControl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bac29ab..4de449dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) -pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") @@ -274,7 +274,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) -pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0) if(hyprland_protocols_dep_FOUND) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") @@ -301,6 +301,8 @@ protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) protocolnew("protocols" "wayland-drm" true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) + protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false) diff --git a/flake.lock b/flake.lock index 85069a74..de9a4dce 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1727261104, - "narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=", + "lastModified": 1728326504, + "narHash": "sha256-dQXAj+4d6neY7ldCiH6gNym3upP49PVxRzEPxXlD9Aw=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "b82fdaff917582a9d568969e15e61b398c71e990", + "rev": "65dd97b5d21e917295159bbef1d52e06963f4eb0", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1727532803, - "narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=", + "lastModified": 1727821604, + "narHash": "sha256-hNw5J6xatedqytYowx0mJKgctjA4lQARZFdgnzM2RpM=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f", + "rev": "d60e1e01e6e6633ef1c87148b9137cc1dd39263d", "type": "github" }, "original": { @@ -102,11 +102,11 @@ ] }, "locked": { - "lastModified": 1727451107, - "narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=", + "lastModified": 1728345020, + "narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3", + "rev": "a7c183800e74f337753de186522b9017a07a8cee", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1725997860, - "narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=", + "lastModified": 1728168612, + "narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876", + "rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1727348695, - "narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=", + "lastModified": 1728018373, + "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784", + "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", "type": "github" }, "original": { @@ -293,11 +293,11 @@ ] }, "locked": { - "lastModified": 1727524473, - "narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=", + "lastModified": 1728166987, + "narHash": "sha256-w6dVTguAn9zJ+7aPOhBQgDz8bn6YZ7b56cY8Kg5HJRI=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26", + "rev": "fb9c8d665af0588bb087f97d0f673ddf0d501787", "type": "github" }, "original": { diff --git a/meson.build b/meson.build index 3545f46a..e9bbb99d 100644 --- a/meson.build +++ b/meson.build @@ -30,7 +30,7 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -aquamarine = dependency('aquamarine') +aquamarine = dependency('aquamarine', version: '>=0.4.2') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') xcb_dep = dependency('xcb', required: get_option('xwayland')) diff --git a/protocols/meson.build b/protocols/meson.build index 3fa2ef2f..2c0d06d1 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,7 +7,7 @@ wayland_protos = dependency( hyprland_protos = dependency( 'hyprland-protocols', - version: '>=0.2', + version: '>=0.4', fallback: 'hyprland-protocols', ) @@ -36,6 +36,7 @@ protocols = [ hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index c6cef41f..f3e7de4e 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -813,6 +813,12 @@ void CMonitor::scheduleDone() { }); } +void CMonitor::setCTM(const Mat3x3& ctm_) { + ctm = ctm_; + ctmUpdated = true; + g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME); +} + bool CMonitor::attemptDirectScanout() { if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked) return false; // do not DS if this monitor is being mirrored. Will break the functionality. diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2a2edab6..f5068dba 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -131,6 +131,10 @@ class CMonitor { CMonitor* pMirrorOf = nullptr; std::vector mirrors; + // ctm + Mat3x3 ctm = Mat3x3::identity(); + bool ctmUpdated = false; + // for tearing PHLWINDOWREF solitaryClient; @@ -179,6 +183,7 @@ class CMonitor { CBox logicalBox(); void scheduleDone(); bool attemptDirectScanout(); + void setCTM(const Mat3x3& ctm); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6366eefe..25a34657 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -46,6 +46,7 @@ #include "../protocols/XDGDialog.hpp" #include "../protocols/SinglePixel.hpp" #include "../protocols/SecurityContext.hpp" +#include "../protocols/CTMControl.hpp" #include "../protocols/core/Seat.hpp" #include "../protocols/core/DataDevice.hpp" @@ -157,6 +158,7 @@ CProtocolManager::CProtocolManager() { PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); + PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) @@ -229,6 +231,7 @@ CProtocolManager::~CProtocolManager() { PROTO::xdgDialog.reset(); PROTO::singlePixel.reset(); PROTO::securityContext.reset(); + PROTO::ctm.reset(); PROTO::lease.reset(); PROTO::sync.reset(); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp new file mode 100644 index 00000000..f2a54c6f --- /dev/null +++ b/src/protocols/CTMControl.cpp @@ -0,0 +1,86 @@ +#include "CTMControl.hpp" +#include "../Compositor.hpp" +#include "core/Output.hpp" + +CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); }); + resource->setOnDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); }); + + resource->setSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4, + wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) { + const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output); + + if (!OUTPUTRESOURCE) + return; // ?! + + const auto PMONITOR = OUTPUTRESOURCE->monitor.lock(); + + if (!PMONITOR) + return; // ?!?! + + const std::array MAT = {wl_fixed_to_double(mat0), wl_fixed_to_double(mat1), wl_fixed_to_double(mat2), wl_fixed_to_double(mat3), wl_fixed_to_double(mat4), + wl_fixed_to_double(mat5), wl_fixed_to_double(mat6), wl_fixed_to_double(mat7), wl_fixed_to_double(mat8)}; + + for (auto& el : MAT) { + if (el < 0.F) { + resource->error(HYPRLAND_CTM_CONTROL_MANAGER_V1_ERROR_INVALID_MATRIX, "a matrix component was < 0"); + return; + } + } + + ctms[PMONITOR->szName] = MAT; + + LOGM(LOG, "CTM set for output {}: {}", PMONITOR->szName, ctms.at(PMONITOR->szName).toString()); + }); + + resource->setCommit([this](CHyprlandCtmControlManagerV1* r) { + LOGM(LOG, "Committing ctms to outputs"); + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!ctms.contains(m->szName)) { + PROTO::ctm->setCTM(m, Mat3x3::identity()); + continue; + } + + PROTO::ctm->setCTM(m, ctms.at(m->szName)); + } + }); +} + +CHyprlandCTMControlResource::~CHyprlandCTMControlResource() { + for (auto& m : g_pCompositor->m_vMonitors) { + PROTO::ctm->setCTM(m, Mat3x3::identity()); + } +} + +bool CHyprlandCTMControlResource::good() { + return resource->resource(); +} + +CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get()); +} + +void CHyprlandCTMControlProtocol::destroyResource(CHyprlandCTMControlResource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); +} + +void CHyprlandCTMControlProtocol::setCTM(SP monitor, const Mat3x3& ctm) { + monitor->setCTM(ctm); +} diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp new file mode 100644 index 00000000..08f1b0e8 --- /dev/null +++ b/src/protocols/CTMControl.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "hyprland-ctm-control-v1.hpp" +#include + +class CMonitor; + +class CHyprlandCTMControlResource { + public: + CHyprlandCTMControlResource(SP resource_); + ~CHyprlandCTMControlResource(); + + bool good(); + + private: + SP resource; + + std::unordered_map ctms; +}; + +class CHyprlandCTMControlProtocol : public IWaylandProtocol { + public: + CHyprlandCTMControlProtocol(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); + + private: + void destroyResource(CHyprlandCTMControlResource* resource); + + void setCTM(SP monitor, const Mat3x3& ctm); + + // + std::vector> m_vManagers; + + friend class CHyprlandCTMControlResource; +}; + +namespace PROTO { + inline UP ctm; +}; \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 310d45af..f388ec37 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1498,6 +1498,11 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + if (pMonitor->ctmUpdated) { + pMonitor->ctmUpdated = false; + pMonitor->output->state->setCTM(pMonitor->ctm); + } + bool ok = pMonitor->state.commit(); if (!ok) { if (inFD >= 0) { From 57b632ead88b4558a53e52aa9c098d48362ee768 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 17:02:55 +0100 Subject: [PATCH 0706/2393] pointer: expand sw cursor damage box fixes #8031 just a bit, rounding errors I guess --- src/managers/PointerManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 736b629c..cc9deec7 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -657,7 +657,7 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { } void CPointerManager::damageIfSoftware() { - auto b = getCursorBoxGlobal(); + auto b = getCursorBoxGlobal().expand(4); static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); From e4a26f4f1d9d30569b9e7e6c265fccfd42fa5d72 Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:50:06 +0100 Subject: [PATCH 0707/2393] dispatchers: allow leading whitespace in window parameter (#8016) --- src/Compositor.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f00e1e34..459aca11 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2445,13 +2445,31 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleF pMonitor->output->scheduleFrame(reason); } -PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { +PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) { + auto regexp = trim(regexp_); + if (regexp.starts_with("active")) return m_pLastWindow.lock(); + else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) { + // first floating on the current ws + if (!valid(m_pLastWindow)) + return nullptr; + + const bool FLOAT = regexp.starts_with("floating"); + + for (auto const& w : m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) + continue; + + return w; + } + + return nullptr; + } eFocusWindowMode mode = MODE_CLASS_REGEX; - std::regex regexCheck(regexp); + std::regex regexCheck(regexp_); std::string matchCheck; if (regexp.starts_with("class:")) { regexCheck = std::regex(regexp.substr(6)); @@ -2470,21 +2488,6 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) { } else if (regexp.starts_with("pid:")) { mode = MODE_PID; matchCheck = regexp.substr(4); - } else if (regexp.starts_with("floating") || regexp.starts_with("tiled")) { - // first floating on the current ws - if (!valid(m_pLastWindow)) - return nullptr; - - const bool FLOAT = regexp.starts_with("floating"); - - for (auto const& w : m_vWindows) { - if (!w->m_bIsMapped || w->m_bIsFloating != FLOAT || w->m_pWorkspace != m_pLastWindow->m_pWorkspace || w->isHidden()) - continue; - - return w; - } - - return nullptr; } for (auto const& w : g_pCompositor->m_vWindows) { From 613eac4603f4a15868c88a47a8ee8dcb84ee2dd3 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 8 Oct 2024 20:31:15 +0200 Subject: [PATCH 0708/2393] layout: remove unnecessary check after 45e8219 (#8037) --- src/layout/IHyprLayout.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f249d2b5..24ee13f4 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -186,12 +186,12 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { g_pCompositor->m_pLastWindow.lock() : g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); - if ((*PAUTOGROUP || g_pInputManager->m_bWasDraggingWindow) // check if auto_group is enabled, or, if the user is manually dragging the window into the group. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group - && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + if (*PAUTOGROUP // check if auto_group is enabled. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON + && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state From 60308a2bb576413cbc787d4bde4f8d0e3fa3c9d6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 20:28:30 +0100 Subject: [PATCH 0709/2393] defaultConfig: add a nofocus rule for weird X windows ref #6543 --- example/hyprland.conf | 6 +++++- src/config/defaultConfig.hpp | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 4adc2d40..3478bcff 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -255,4 +255,8 @@ bindl = , XF86AudioPrev, exec, playerctl previous # Example windowrule v2 # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ -windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. +# Ignore maximize requests from apps. You'll probably like this. +windowrulev2 = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 5843caa3..54ce6642 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -268,5 +268,9 @@ bindl = , XF86AudioPrev, exec, playerctl previous # Example windowrule v2 # windowrulev2 = float,class:^(kitty)$,title:^(kitty)$ -windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. +# Ignore maximize requests from apps. You'll probably like this. +windowrulev2 = suppressevent maximize, class:.* + +# Fix some dragging issues with XWayland +windowrulev2 = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 )#"; From 91299f7039d80b25b3f0296d3d0f4d2059d41869 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:20:25 +0100 Subject: [PATCH 0710/2393] hyprerror: make hyprerror reserve space (#8040) --- src/hyprerror/HyprError.cpp | 20 ++++++++++++++++++++ src/hyprerror/HyprError.hpp | 12 ++++++++---- src/render/Renderer.cpp | 17 +++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index bbc3a006..5f63de24 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -3,6 +3,9 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include +using namespace Hyprutils::Utils; + CHyprError::CHyprError() { m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); m_fFadeOpacity.registerVar(); @@ -130,6 +133,8 @@ void CHyprError::createQueued() { } m_szQueued = ""; + m_fLastHeight = yoffset + PAD + 1; + pango_font_description_free(pangoFD); g_object_unref(layoutText); @@ -158,6 +163,8 @@ void CHyprError::createQueued() { m_cQueued = CColor(); g_pHyprRenderer->damageMonitor(PMONITOR); + + g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); } void CHyprError::draw() { @@ -174,6 +181,11 @@ void CHyprError::draw() { m_pTexture->destroyTexture(); m_bIsCreated = false; m_szQueued = ""; + + for (auto& m : g_pCompositor->m_vMonitors) { + g_pHyprRenderer->arrangeLayersForMonitor(m->ID); + } + return; } else { m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); @@ -203,3 +215,11 @@ void CHyprError::destroy() { else m_szQueued = ""; } + +bool CHyprError::active() { + return m_bIsCreated; +} + +float CHyprError::height() { + return m_fLastHeight; +} diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 8dbb4521..a553614c 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -11,9 +11,12 @@ class CHyprError { CHyprError(); ~CHyprError(); - void queueCreate(std::string message, const CColor& color); - void draw(); - void destroy(); + void queueCreate(std::string message, const CColor& color); + void draw(); + void destroy(); + + bool active(); + float height(); // logical private: void createQueued(); @@ -23,7 +26,8 @@ class CHyprError { bool m_bIsCreated = false; SP m_pTexture; CAnimatedVariable m_fFadeOpacity; - CBox m_bDamageBox = {0, 0, 0, 0}; + CBox m_bDamageBox = {0, 0, 0, 0}; + float m_fLastHeight = 0.F; bool m_bMonitorChanged = false; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f388ec37..61f94014 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -97,6 +97,16 @@ CHyprRenderer::CHyprRenderer() { ensureCursorRenderingMode(); }); + static auto P3 = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { + g_pEventLoopManager->doLater([this]() { + if (!g_pHyprError->active()) + return; + for (auto& m : g_pCompositor->m_vMonitors) { + arrangeLayersForMonitor(m->ID); + } + }); + }); + m_pCursorTicker = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, cursorTicker, nullptr); wl_event_source_timer_update(m_pCursorTicker, 500); @@ -1757,6 +1767,13 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; + if (g_pHyprError->active() && g_pCompositor->m_pLastMonitor == PMONITOR->self) { + const auto HEIGHT = g_pHyprError->height(); + PMONITOR->vecReservedTopLeft.y = HEIGHT; + usableArea.y += HEIGHT; + usableArea.h -= HEIGHT; + } + for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->order > b->order; }); } From 8cced091f53c92bc8de97b9d3dac20b31980af70 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 21:58:40 +0100 Subject: [PATCH 0711/2393] renderer: reserve space for error at the bottom if that's set ref #8040 --- src/render/Renderer.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 61f94014..bc95abc6 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1756,7 +1756,9 @@ void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vectorgetMonitorFromID(monitor); + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitor); + + static auto BAR_POSITION = CConfigValue("debug:error_position"); if (!PMONITOR) return; @@ -1768,10 +1770,15 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { CBox usableArea = {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; if (g_pHyprError->active() && g_pCompositor->m_pLastMonitor == PMONITOR->self) { - const auto HEIGHT = g_pHyprError->height(); - PMONITOR->vecReservedTopLeft.y = HEIGHT; - usableArea.y += HEIGHT; - usableArea.h -= HEIGHT; + const auto HEIGHT = g_pHyprError->height(); + if (*BAR_POSITION == 0) { + PMONITOR->vecReservedTopLeft.y = HEIGHT; + usableArea.y += HEIGHT; + usableArea.h -= HEIGHT; + } else { + PMONITOR->vecReservedBottomRight.y = HEIGHT; + usableArea.h -= HEIGHT; + } } for (auto& la : PMONITOR->m_aLayerSurfaceLayers) { From ac658500fbebe607f2db83f11c37f0a3a05ef734 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 8 Oct 2024 23:33:10 +0100 Subject: [PATCH 0712/2393] keyboard: update group state on change for the sym resolve state fixes #8038 --- src/devices/IKeyboard.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 3300f252..d1119772 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -392,6 +392,9 @@ void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); if (updateModifiersState()) { + if (xkbSymState) + xkb_state_update_mask(xkbSymState, 0, 0, 0, 0, 0, modifiersState.group); + keyboardEvents.modifiers.emit(SModifiersEvent{ .depressed = modifiersState.depressed, .latched = modifiersState.latched, From bc299928ad5571300180eb8edb6742ed3bbf0282 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 9 Oct 2024 00:26:40 +0100 Subject: [PATCH 0713/2393] output/xdg-output: avoid sending events to released globals ref #6835 --- src/protocols/XDGOutput.cpp | 4 +++- src/protocols/XDGOutput.hpp | 2 ++ src/protocols/core/Output.cpp | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 0cdadd43..0598e713 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -51,6 +51,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 #endif pXDGOutput->client = CLIENT; + pXDGOutput->outputProto = OUTPUT->owner; + if (!pXDGOutput->resource->resource()) { m_vXDGOutputs.pop_back(); mgr->noMemory(); @@ -104,7 +106,7 @@ CXDGOutput::CXDGOutput(SP resource_, SP monitor_) : mon void CXDGOutput::sendDetails() { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (!monitor) + if (!monitor || !outputProto || outputProto->isDefunct()) return; const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition; diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 15d86cc7..520f3aaa 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -6,6 +6,7 @@ class CMonitor; class CXDGOutputProtocol; +class CWLOutputProtocol; class CXDGOutput { public: @@ -16,6 +17,7 @@ class CXDGOutput { private: WP monitor; SP resource; + WP outputProto; std::optional overridePosition; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 7b88e0a8..4047774a 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -47,7 +47,7 @@ SP CWLOutputResource::getResource() { } void CWLOutputResource::updateState() { - if (!monitor || (owner && owner->defunct)) + if (!monitor || !owner || owner->defunct) return; if (resource->version() >= 2) @@ -119,6 +119,9 @@ bool CWLOutputProtocol::isDefunct() { } void CWLOutputProtocol::sendDone() { + if (defunct) + return; + for (auto const& r : m_vOutputs) { r->resource->sendDone(); } From 6ce07ee86453e8ef01faa7b4e1eb8f09475f32b7 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 9 Oct 2024 12:00:43 +0300 Subject: [PATCH 0714/2393] CI/release: remove script backup line --- .github/workflows/release.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1f52b4ff..d5ff1aa0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -20,7 +20,6 @@ jobs: run: | git fetch --unshallow || echo "failed unshallowing" bash -c scripts/generateVersion.sh - mv scripts/generateVersion.sh scripts/generateVersion.sh.bak - name: Create tarball with submodules id: tar From 223dcc8bac7fee90aa6aa7596d9379e56b526e62 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Wed, 9 Oct 2024 04:24:05 -0500 Subject: [PATCH 0715/2393] output: update state even if no owner exists (#8044) --- src/protocols/core/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 4047774a..3e68937f 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -47,7 +47,7 @@ SP CWLOutputResource::getResource() { } void CWLOutputResource::updateState() { - if (!monitor || !owner || owner->defunct) + if (!monitor || (owner && owner->defunct)) return; if (resource->version() >= 2) From 3d28879c2640cdb6e8426127692240100793bfef Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:24:35 +0100 Subject: [PATCH 0716/2393] hyprerror: fix height calc with bottom bar (#8043) --- src/hyprerror/HyprError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 5f63de24..4044bcc9 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -133,7 +133,7 @@ void CHyprError::createQueued() { } m_szQueued = ""; - m_fLastHeight = yoffset + PAD + 1; + m_fLastHeight = yoffset + PAD + 1 - (TOPBAR ? 0 : Y - PAD); pango_font_description_free(pangoFD); g_object_unref(layoutText); From 6ae89940c761d4ed4317df0af29e8df41d472091 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 9 Oct 2024 11:58:49 +0200 Subject: [PATCH 0717/2393] layout: add merge_floated_into_tiled_on_groupbar (#8042) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/render/decorations/CHyprGroupBarDecoration.cpp | 12 +++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 2ca230be..d684e44a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -784,6 +784,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "disabled,enabled,only when dragging into the groupbar"}, }, + SConfigOptionDescription{ + .value = "group:merge_floated_into_tiled_on_groupbar", + .description = "whether dragging a floating window into a tiled window groupbar will merge them", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 9a5283fa..e973f1ab 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -377,6 +377,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:merge_floated_into_tiled_on_groupbar", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index ef6c81e6..eca3f2cb 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -402,9 +402,15 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { } bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWINDOW pDraggedWindow) { - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); - static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2)) + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + static auto PMERGEFLOATEDINTOTILEDONGROUPBAR = CConfigValue("group:merge_floated_into_tiled_on_groupbar"); + + bool denied = false; + if (!m_pWindow->m_bIsFloating && !pDraggedWindow->m_bDraggingTiled && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) + denied = true; + + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || denied) return false; const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; From c4eb1940336cd88ca65ba65582ce104e49dfc7c9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 9 Oct 2024 22:00:06 +0100 Subject: [PATCH 0718/2393] gammactrl: guard pMonitor in setGamma --- src/protocols/GammaControl.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 077d6e2f..e794e543 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -46,6 +46,13 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + if (!pMonitor) { + LOGM(ERR, "setGamma for a dead monitor"); + resource->sendFailed(); + close(fd); + return; + } + LOGM(LOG, "setGamma for {}", pMonitor->szName); int fdFlags = fcntl(fd, F_GETFL, 0); From b65773bea9b912a41cfcbc789fb2e60a07e3d0c1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 10 Oct 2024 11:01:13 +0100 Subject: [PATCH 0719/2393] hyprpm: disallow shallow on unknown branch --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 669789b4..612995dc 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -436,7 +436,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); - const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow; + const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; // let us give a bit of leg-room for shallowing // due to timezones, etc. From d655a10381f01212635f2eadd69e1f22930f8f06 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:56:19 +0100 Subject: [PATCH 0720/2393] config/layout: nuke no_gaps_when_only (#8072) --- src/config/ConfigDescriptions.hpp | 12 ------------ src/config/ConfigManager.cpp | 2 -- src/layout/DwindleLayout.cpp | 30 ++++-------------------------- src/layout/MasterLayout.cpp | 30 +++++------------------------- src/managers/input/Touch.cpp | 1 - 5 files changed, 9 insertions(+), 66 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index d684e44a..bef5ee53 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1446,12 +1446,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_FLOAT, .data = SConfigOptionDescription::SFloatData{1, 0.1, 3}, }, - SConfigOptionDescription{ - .value = "dwindle:no_gaps_when_only", - .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", - .type = CONFIG_OPTION_CHOICE, - .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, - }, SConfigOptionDescription{ .value = "dwindle:use_active_for_splits", .description = "whether to prefer the active window or the mouse position for splits", @@ -1512,12 +1506,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_STRING_SHORT, .data = SConfigOptionDescription::SStringData{"none"}, }, - SConfigOptionDescription{ - .value = "master:no_gaps_when_only", - .description = "whether to apply gaps when there is only one window on a workspace, aka. smart gaps. (default: disabled - 0) no border - 1, with border - 2 [0/1/2]", - .type = CONFIG_OPTION_CHOICE, - .data = SConfigOptionDescription::SChoiceData{0, "disabled,no border,with border"}, - }, SConfigOptionDescription{ .value = "master:orientation", .description = "default placement of the master area, can be left, right, top, bottom or center", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e973f1ab..6ec63d4c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -446,7 +446,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("dwindle:preserve_split", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:special_scale_factor", {1.f}); m_pConfig->addConfigValue("dwindle:split_width_multiplier", {1.0f}); - m_pConfig->addConfigValue("dwindle:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("dwindle:use_active_for_splits", Hyprlang::INT{1}); m_pConfig->addConfigValue("dwindle:default_split_ratio", {1.f}); m_pConfig->addConfigValue("dwindle:split_bias", Hyprlang::INT{0}); @@ -459,7 +458,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); - m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:orientation", {"left"}); m_pConfig->addConfigValue("master:inherit_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:allow_small_split", Hyprlang::INT{0}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 04cbf21d..76b26af1 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -142,11 +142,10 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - static auto PNOGAPSWHENONLY = CConfigValue("dwindle:no_gaps_when_only"); - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); - auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); + static auto PGAPSINDATA = CConfigValue("general:gaps_in"); + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* const PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); + auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); @@ -156,27 +155,6 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for PWINDOW->m_vSize = nodeBox.size(); PWINDOW->m_vPosition = nodeBox.pos(); - const auto NODESONWORKSPACE = getNodesOnWorkspace(PWINDOW->workspaceID()); - - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (NODESONWORKSPACE == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { - - PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); - - PWINDOW->updateWindowDecos(); - - const auto RESERVED = PWINDOW->getFullWindowReservedArea(); - - PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft; - PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight); - - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - return; - } - PWINDOW->updateWindowDecos(); auto calcPos = PWINDOW->m_vPosition; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 04a6ea29..8fde960d 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -631,12 +631,11 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->unsetWindowData(PRIORITY_LAYOUT); PWINDOW->updateWindowData(); - static auto PNOGAPSWHENONLY = CConfigValue("master:no_gaps_when_only"); - static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); - static auto PGAPSINDATA = CConfigValue("general:gaps_in"); - static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); - auto* PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); - auto* PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); + static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); + static auto PGAPSINDATA = CConfigValue("general:gaps_in"); + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* PGAPSIN = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); + auto* PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN); auto gapsOut = WORKSPACERULE.gapsOut.value_or(*PGAPSOUT); @@ -649,25 +648,6 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { PWINDOW->m_vSize = pNode->size; PWINDOW->m_vPosition = pNode->position; - if (*PNOGAPSWHENONLY && !PWINDOW->onSpecialWorkspace() && (getNodesOnWorkspace(PWINDOW->workspaceID()) == 1 || PWINDOW->isEffectiveInternalFSMode(FSMODE_MAXIMIZED))) { - - PWINDOW->m_sWindowData.decorate = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noBorder = CWindowOverridableVar(*PNOGAPSWHENONLY != 2, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noRounding = CWindowOverridableVar(true, PRIORITY_LAYOUT); - PWINDOW->m_sWindowData.noShadow = CWindowOverridableVar(true, PRIORITY_LAYOUT); - - PWINDOW->updateWindowDecos(); - - const auto RESERVED = PWINDOW->getFullWindowReservedArea(); - - PWINDOW->m_vRealPosition = PWINDOW->m_vPosition + RESERVED.topLeft; - PWINDOW->m_vRealSize = PWINDOW->m_vSize - (RESERVED.topLeft + RESERVED.bottomRight); - - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - return; - } - PWINDOW->updateWindowDecos(); auto calcPos = PWINDOW->m_vPosition; diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 9b03168e..0333648a 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -39,7 +39,6 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - // TODO: support no_gaps_when_only? const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); From 178a300eeaf006fed4c8c9a599657b4530f65559 Mon Sep 17 00:00:00 2001 From: Jasson Date: Fri, 11 Oct 2024 07:07:25 -0400 Subject: [PATCH 0721/2393] xwayland: minor cleanups and fixes (#8076) --- src/managers/XWaylandManager.cpp | 110 +++++++++++++++---------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index fad7e451..8b63d37e 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -5,14 +5,13 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 #define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3 -CHyprXWaylandManager::CHyprXWaylandManager() { - ; -} +CHyprXWaylandManager::CHyprXWaylandManager() = default; CHyprXWaylandManager::~CHyprXWaylandManager() { #ifndef NO_XWAYLAND @@ -21,7 +20,7 @@ CHyprXWaylandManager::~CHyprXWaylandManager() { } SP CHyprXWaylandManager::getWindowSurface(PHLWINDOW pWindow) { - return pWindow->m_pWLSurface->resource(); + return pWindow ? pWindow->m_pWLSurface->resource() : nullptr; } void CHyprXWaylandManager::activateSurface(SP pSurface, bool activate) { @@ -40,27 +39,31 @@ void CHyprXWaylandManager::activateSurface(SP pSurface, bool return; } - if (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface) { - if (activate) { - PWINDOW->m_pXWaylandSurface->setMinimized(false); - PWINDOW->m_pXWaylandSurface->restackToTop(); + if (PWINDOW->m_bIsX11) { + if (PWINDOW->m_pXWaylandSurface) { + if (activate) { + PWINDOW->m_pXWaylandSurface->setMinimized(false); + PWINDOW->m_pXWaylandSurface->restackToTop(); + } + PWINDOW->m_pXWaylandSurface->activate(activate); } - PWINDOW->m_pXWaylandSurface->activate(activate); - } else if (!PWINDOW->m_bIsX11 && PWINDOW->m_pXDGSurface) + } else if (PWINDOW->m_pXDGSurface) PWINDOW->m_pXDGSurface->toplevel->setActive(activate); } void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { - setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos if (activate) { + setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); + if (!pWindow->isX11OverrideRedirect()) pWindow->m_pXWaylandSurface->restackToTop(); } pWindow->m_pXWaylandSurface->activate(activate); + } else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) pWindow->m_pXDGSurface->toplevel->setActive(activate); @@ -74,6 +77,9 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { } void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { + if (!pWindow) + return; + if (pWindow->m_bIsX11) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); @@ -83,7 +89,10 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { pbox->x = pWindow->m_pXWaylandSurface->geometry.x; pbox->y = pWindow->m_pXWaylandSurface->geometry.y; - if ((SIZEHINTS->flags & 0x2 /* ICCCM USSize */) || (SIZEHINTS->flags & 0x8 /* ICCCM PSize */)) { + constexpr int ICCCM_USSize = 0x2; + constexpr int ICCCM_PSize = 0x8; + + if ((SIZEHINTS->flags & ICCCM_USSize) || (SIZEHINTS->flags & ICCCM_PSize)) { pbox->w = SIZEHINTS->base_width; pbox->h = SIZEHINTS->base_height; } else { @@ -117,34 +126,34 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool Vector2D windowPos = pWindow->m_vRealPosition.value(); if (pWindow->m_bIsX11 && PMONITOR) { - windowPos = windowPos - PMONITOR->vecPosition; // normalize to monitor + windowPos -= PMONITOR->vecPosition; // normalize to monitor if (*PXWLFORCESCALEZERO) - windowPos = windowPos * PMONITOR->scale; // scale if applicable - windowPos = windowPos + PMONITOR->vecXWaylandPosition; // move to correct position for xwayland + windowPos *= PMONITOR->scale; // scale if applicable + windowPos += PMONITOR->vecXWaylandPosition; // move to correct position for xwayland } - if (!force && ((pWindow->m_vPendingReportedSize == size && windowPos == pWindow->m_vReportedPosition) || (pWindow->m_vPendingReportedSize == size && !pWindow->m_bIsX11))) + if (!force && pWindow->m_vPendingReportedSize == size && (windowPos == pWindow->m_vReportedPosition || !pWindow->m_bIsX11)) return; pWindow->m_vReportedPosition = windowPos; pWindow->m_vPendingReportedSize = size; - pWindow->m_fX11SurfaceScaledBy = 1.f; + pWindow->m_fX11SurfaceScaledBy = 1.0f; if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) { - size = size * PMONITOR->scale; + size *= PMONITOR->scale; pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale; } if (pWindow->m_bIsX11) pWindow->m_pXWaylandSurface->configure({windowPos, size}); else if (pWindow->m_pXDGSurface->toplevel) - pWindow->m_vPendingSizeAcks.push_back(std::make_pair<>(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor())); + pWindow->m_vPendingSizeAcks.emplace_back(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()); } bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { - for (auto const& a : pWindow->m_pXWaylandSurface->atoms) + for (const auto& a : pWindow->m_pXWaylandSurface->atoms) if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_SPLASH"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLBAR"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_UTILITY"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_TOOLTIP"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_POPUP_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DOCK"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"] || @@ -157,16 +166,8 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { return true; } - if (pWindow->isModal()) - return true; - - if (pWindow->m_pXWaylandSurface->transient) - return true; - - if (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up")) - return true; - - if (pWindow->m_pXWaylandSurface->overrideRedirect) + if (pWindow->isModal() || pWindow->m_pXWaylandSurface->transient || + (pWindow->m_pXWaylandSurface->role.contains("task_dialog") || pWindow->m_pXWaylandSurface->role.contains("pop-up")) || pWindow->m_pXWaylandSurface->overrideRedirect) return true; const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); @@ -203,6 +204,9 @@ void CHyprXWaylandManager::checkBorders(PHLWINDOW pWindow) { } void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscreen) { + if (!pWindow) + return; + if (pWindow->m_bIsX11) pWindow->m_pXWaylandSurface->setFullscreen(fullscreen); else if (pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel) @@ -210,37 +214,33 @@ void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscree } Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { - if (!validMapped(pWindow)) - return Vector2D(99999, 99999); + constexpr int NO_MAX_SIZE_LIMIT = 99999; + if (!validMapped(pWindow) || + ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || + pWindow->m_sWindowData.noMaxSize.valueOrDefault())) + return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT); - if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || - pWindow->m_sWindowData.noMaxSize.valueOrDefault()) - return Vector2D(99999, 99999); + Vector2D maxSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : + pWindow->m_pXDGSurface->toplevel->current.maxSize; - auto MAXSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : - pWindow->m_pXDGSurface->toplevel->current.maxSize; + if (maxSize.x < 5) + maxSize.x = NO_MAX_SIZE_LIMIT; + if (maxSize.y < 5) + maxSize.y = NO_MAX_SIZE_LIMIT; - if (MAXSIZE.x < 5) - MAXSIZE.x = 99999; - if (MAXSIZE.y < 5) - MAXSIZE.y = 99999; - - return MAXSIZE; + return maxSize; } Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) { - if (!validMapped(pWindow)) + if (!validMapped(pWindow) || ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))) return Vector2D(0, 0); - if ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel)) - return Vector2D(0, 0); + Vector2D minSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : + pWindow->m_pXDGSurface->toplevel->current.minSize; - auto MINSIZE = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : - pWindow->m_pXDGSurface->toplevel->current.minSize; + minSize = minSize.clamp({1, 1}); - MINSIZE = MINSIZE.clamp({1, 1}); - - return MINSIZE; + return minSize; } Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { @@ -249,7 +249,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { CMonitor* pMonitor = nullptr; double bestDistance = __FLT_MAX__; - for (auto const& m : g_pCompositor->m_vMonitors) { + for (const auto& m : g_pCompositor->m_vMonitors) { const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize; double distance = @@ -268,9 +268,9 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { Vector2D result = coord - pMonitor->vecXWaylandPosition; // if scaled, unscale if (*PXWLFORCESCALEZERO) - result = result / pMonitor->scale; + result /= pMonitor->scale; // add pos - result = result + pMonitor->vecPosition; + result += pMonitor->vecPosition; return result; -} +} \ No newline at end of file From 7564b26b7d386d248eaa47c1a481c09eefd8e3ca Mon Sep 17 00:00:00 2001 From: Toni500github <88878648+Toni500github@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:19:16 +0200 Subject: [PATCH 0722/2393] internal: improve version query and define HYPRLAND_VERSION (#8034) --- CMakeLists.txt | 2 ++ hyprpm/src/core/PluginManager.cpp | 3 +-- meson.build | 1 + src/debug/HyprCtl.cpp | 23 +++++++++++++-------- src/debug/HyprCtl.hpp | 1 + src/main.cpp | 34 +++++-------------------------- 6 files changed, 25 insertions(+), 39 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4de449dc..df919d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,8 @@ else() message(STATUS "Configuring Hyprland in Release with CMake") endif() +add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}") + include_directories(. "src/" "protocols/") set(CMAKE_CXX_STANDARD 26) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 612995dc..96ec60ad 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -440,8 +440,7 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. - const std::string SHALLOW_DATE = - trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); if (m_bVerbose && bShallow) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); diff --git a/meson.build b/meson.build index e9bbb99d..33e8fdbe 100644 --- a/meson.build +++ b/meson.build @@ -21,6 +21,7 @@ add_project_arguments( '-Wno-missing-field-initializers', '-Wno-narrowing', '-Wno-pointer-arith', datarootdir, + '-DHYPRLAND_VERSION="' + meson.project_version() + '"', ], language: 'cpp', ) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index d9274727..e0bb2b83 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -853,26 +853,33 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - std::string result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH + " " + GIT_DIRTY + " (" + commitMsg + - ").\nDate: " + GIT_COMMIT_DATE + "\nTag: " + GIT_TAG + ", commits: " + GIT_COMMITS + std::string{"\nbuilt against aquamarine "} + AQUAMARINE_VERSION + "\n" + - "\n\nflags: (if any)\n"; + std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" + "Date: {}\n" + "Tag: {}, commits: {}\n" + "built against aquamarine {}\n\n\n", + HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION); +#if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND)) + result += "no flags were set\n"; +#else + result += "flags set:\n"; #ifdef LEGACY_RENDERER result += "legacyrenderer\n"; #endif -#ifndef ISDEBUG +#ifdef ISDEBUG result += "debug\n"; #endif #ifdef NO_XWAYLAND result += "no xwayland\n"; #endif - +#endif return result; } else { std::string result = std::format( R"#({{ "branch": "{}", "commit": "{}", + "version": "{}", "dirty": {}, "commit_message": "{}", "commit_date": "{}", @@ -880,13 +887,13 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "commits": "{}", "buildAquamarine": "{}", "flags": [)#", - GIT_BRANCH, GIT_COMMIT_HASH, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, - AQUAMARINE_VERSION); + GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, + GIT_COMMITS, AQUAMARINE_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; #endif -#ifndef ISDEBUG +#ifdef ISDEBUG result += "\"debug\","; #endif #ifdef NO_XWAYLAND diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index d68bf14f..c1bf51ca 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -7,6 +7,7 @@ // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); +std::string versionRequest(eHyprCtlOutputFormat format, std::string request); class CHyprCtl { public: diff --git a/src/main.cpp b/src/main.cpp index 57bb5507..45f212d3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ void help() { std::cout << " --config FILE -c FILE - Specify config file to use\n"; std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; + std::cout << " --systeminfo - Prints system infos\n"; std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; std::cout << " --version -v - Print this binary's version\n"; } @@ -33,9 +34,9 @@ int main(int argc, char** argv) { throwError("XDG_RUNTIME_DIR is not set!"); // export HYPRLAND_CMD - std::string cmd = ""; - for (auto i = 0; i < argc; ++i) - cmd += std::string(i == 0 ? "" : " ") + argv[i]; + std::string cmd = argv[0]; + for (int i = 1; i < argc; ++i) + cmd += std::string(" ") + argv[i]; setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("XDG_BACKEND", "wayland", 1); @@ -116,32 +117,7 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { - auto result = "Hyprland, built from branch " + std::string(GIT_BRANCH) + " at commit " + GIT_COMMIT_HASH; - auto dirty = std::string(GIT_DIRTY); - if (!dirty.empty()) - result += " " + dirty; - - auto commitMsg = trim(GIT_COMMIT_MESSAGE); - std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); - result += " (" + commitMsg + ")."; - - result += "\nDate: " + std::string(GIT_COMMIT_DATE); - result += "\nTag: " + std::string(GIT_TAG) + ", commits: " + std::string(GIT_COMMITS); - result += "\nbuilt against aquamarine " + std::string(AQUAMARINE_VERSION); - - result += "\n\nflags: (if any)\n"; - -#ifdef LEGACY_RENDERER - result += "legacyrenderer\n"; -#endif -#ifndef ISDEBUG - result += "debug\n"; -#endif -#ifdef NO_XWAYLAND - result += "no xwayland\n"; -#endif - - std::cout << result; + std::cout << versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "") << std::endl; return 0; } else if (it->compare("--systeminfo") == 0) { const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); From f5db4839730643169b7e8b7fb6ae2fbb8743ebe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgars=20C=C4=ABrulis?= Date: Sat, 12 Oct 2024 03:12:07 +0300 Subject: [PATCH 0723/2393] drm-timeline: Add check for conflicting acquire and release points (#8083) Signed-off-by: Edgars Cirulis --- src/protocols/DRMSyncobj.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 4993f1a4..a7f242ee 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -55,8 +55,13 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP= pending.releasePoint) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release"); + surface->pending.rejected = true; + return; + } + } // wait for the acquire timeline to materialize auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); From ee8116ac5dc412dce924a0163074ce7988dd0cfc Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sat, 12 Oct 2024 03:29:51 +0300 Subject: [PATCH 0724/2393] input: Fix VRR for constrained cursors (#6877) --- src/Compositor.cpp | 4 +++ src/events/Windows.cpp | 19 +++++++++++-- src/helpers/Monitor.cpp | 8 +++++- src/helpers/Monitor.hpp | 2 ++ src/helpers/Timer.cpp | 5 ++-- src/helpers/Timer.hpp | 2 +- src/managers/AnimationManager.cpp | 2 +- src/managers/PointerManager.cpp | 43 +++++++++++++++++++++++++---- src/managers/PointerManager.hpp | 7 +++++ src/managers/SeatManager.hpp | 3 ++ src/managers/input/InputManager.cpp | 21 ++++++++++++-- src/managers/input/InputManager.hpp | 1 + 12 files changed, 100 insertions(+), 17 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 459aca11..dcc6422d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,4 +1,5 @@ #include "Compositor.hpp" +#include "debug/Log.hpp" #include "helpers/Splashes.hpp" #include "config/ConfigValue.hpp" #include "managers/CursorManager.hpp" @@ -1380,6 +1381,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { if (!validMapped(pWindow)) return; + if (pWindow == (top ? m_vWindows.back() : m_vWindows.front())) + return; + auto moveToZ = [&](PHLWINDOW pw, bool top) -> void { if (top) { for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 37f29130..e549907e 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,6 +12,7 @@ #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" #include "../xwayland/XSurface.hpp" +#include "managers/PointerManager.hpp" #include using namespace Hyprutils::String; @@ -758,8 +759,21 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_pWorkspace->m_bVisible) return; - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, - PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); + const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + + PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); + if (g_pSeatManager->isPointerFrameCommit) { + g_pSeatManager->isPointerFrameSkipped = false; + g_pSeatManager->isPointerFrameCommit = false; + } else + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); + + if (g_pSeatManager->isPointerFrameSkipped) { + g_pPointerManager->sendStoredMovement(); + g_pSeatManager->sendPointerFrame(); + g_pSeatManager->isPointerFrameCommit = true; + } if (!PWINDOW->m_bIsX11) { PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces(); @@ -767,7 +781,6 @@ void Events::listener_commitWindow(void* owner, void* data) { } // tearing: if solitary, redraw it. This still might be a single surface window - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) { CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f3e7de4e..091745df 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -16,6 +16,7 @@ #include "../protocols/core/Compositor.hpp" #include "sync/SyncTimeline.hpp" #include +#include "debug/Log.hpp" #include #include using namespace Hyprutils::String; @@ -384,7 +385,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; // keep requested minimum refresh rate - if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { + if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { // damage whole screen because some previous cursor box damages were skipped damage.damageEntire(); return false; @@ -933,6 +934,11 @@ bool CMonitor::attemptDirectScanout() { return true; } +void CMonitor::debugLastPresentation(const std::string& message) { + Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(), + lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f); +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index f5068dba..ad8a823b 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -185,6 +185,8 @@ class CMonitor { bool attemptDirectScanout(); void setCTM(const Mat3x3& ctm); + void debugLastPresentation(const std::string& message); + bool m_bEnabled = false; bool m_bRenderingInitPassed = false; diff --git a/src/helpers/Timer.cpp b/src/helpers/Timer.cpp index 7b1726df..e00c5918 100644 --- a/src/helpers/Timer.cpp +++ b/src/helpers/Timer.cpp @@ -1,4 +1,5 @@ #include "Timer.hpp" +#include void CTimer::reset() { m_tpLastReset = std::chrono::steady_clock::now(); @@ -8,8 +9,8 @@ std::chrono::steady_clock::duration CTimer::getDuration() { return std::chrono::steady_clock::now() - m_tpLastReset; } -long CTimer::getMillis() { - return std::chrono::duration_cast(getDuration()).count(); +float CTimer::getMillis() { + return std::chrono::duration_cast(getDuration()).count() / 1000.f; } float CTimer::getSeconds() { diff --git a/src/helpers/Timer.hpp b/src/helpers/Timer.hpp index 827e7625..a58225d0 100644 --- a/src/helpers/Timer.hpp +++ b/src/helpers/Timer.hpp @@ -6,7 +6,7 @@ class CTimer { public: void reset(); float getSeconds(); - long getMillis(); + float getMillis(); const std::chrono::steady_clock::time_point& chrono() const; private: diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 092d9721..0ff94f1f 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -259,7 +259,7 @@ void CAnimationManager::tick() { // manually schedule a frame if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } // do it here, because if this alters the animation vars deque we would be in trouble above. diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index cc9deec7..8c2a1bad 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/PointerGestures.hpp" +#include "../protocols/RelativePointer.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/IdleNotify.hpp" #include "../protocols/core/Compositor.hpp" @@ -328,7 +329,7 @@ void CPointerManager::onCursorMoved() { continue; const auto CURSORPOS = getCursorPosForMonitor(m); - m->output->moveCursor(CURSORPOS); + m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent()); } if (recalc) @@ -342,7 +343,7 @@ bool CPointerManager::attemptHardwareCursor(SPmonitor.lock()); - state->monitor->output->moveCursor(CURSORPOS); + state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent()); auto texture = getCurrentCursorTexture(); @@ -385,7 +386,8 @@ bool CPointerManager::setHWCursorBuffer(SP state, SPcursorFrontBuffer = buf; - g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent()) + g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); return true; } @@ -676,8 +678,11 @@ void CPointerManager::warpTo(const Vector2D& logical) { damageIfSoftware(); pointerPos = closestValid(logical); - recheckEnteredOutputs(); - onCursorMoved(); + + if (!g_pInputManager->isLocked()) { + recheckEnteredOutputs(); + onCursorMoved(); + } damageIfSoftware(); } @@ -859,7 +864,14 @@ void CPointerManager::attachPointer(SP pointer) { }); listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) { - g_pSeatManager->sendPointerFrame(); + bool shouldSkip = false; + if (!g_pSeatManager->mouse.expired() && g_pInputManager->isLocked()) { + auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); + shouldSkip = PMONITOR && PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); + } + g_pSeatManager->isPointerFrameSkipped = shouldSkip; + if (!g_pSeatManager->isPointerFrameSkipped) + g_pSeatManager->sendPointerFrame(); }); listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) { @@ -1080,3 +1092,22 @@ void CPointerManager::damageCursor(SP pMonitor) { Vector2D CPointerManager::cursorSizeLogical() { return currentCursorImage.size / currentCursorImage.scale; } + +void CPointerManager::storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) { + storedTime = time; + storedDelta += delta; + storedUnaccel += deltaUnaccel; +} + +void CPointerManager::setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) { + storedTime = time; + storedDelta = delta; + storedUnaccel = deltaUnaccel; +} + +void CPointerManager::sendStoredMovement() { + PROTO::relativePointer->sendRelativeMotion((uint64_t)storedTime * 1000, storedDelta, storedUnaccel); + storedTime = 0; + storedDelta = Vector2D{}; + storedUnaccel = Vector2D{}; +} diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 4a4c4f61..6b89eb16 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -61,6 +61,9 @@ class CPointerManager { // Vector2D position(); Vector2D cursorSizeLogical(); + void storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel); + void setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel); + void sendStoredMovement(); void recheckEnteredOutputs(); @@ -154,6 +157,10 @@ class CPointerManager { Vector2D pointerPos = {0, 0}; + uint64_t storedTime = 0; + Vector2D storedDelta = {0, 0}; + Vector2D storedUnaccel = {0, 0}; + struct SMonitorPointerState { SMonitorPointerState(SP m) : monitor(m) {} ~SMonitorPointerState() {} diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index 5cc7eee0..e50f123f 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -128,6 +128,9 @@ class CSeatManager { void setGrab(SP grab); // nullptr removes SP seatGrab; + bool isPointerFrameSkipped = false; + bool isPointerFrameCommit = false; + private: struct SSeatResourceContainer { SSeatResourceContainer(SP); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 03c72919..eef5e040 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -87,6 +87,11 @@ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) { const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta; + if (g_pSeatManager->isPointerFrameSkipped) + g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, e.unaccel); + else + g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, e.unaccel); + PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel); g_pPointerManager->move(DELTA); @@ -167,7 +172,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_vLastCursorPosFloored = MOUSECOORDSFLOORED; - const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); + const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.get() : g_pCompositor->getMonitorFromCursor(); // this can happen if there are no displays hooked up to Hyprland if (PMONITOR == nullptr) @@ -184,9 +189,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // constraints if (!g_pSeatManager->mouse.expired() && isConstrained()) { const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); - const auto CONSTRAINT = SURF->constraint(); + const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; - if (SURF && CONSTRAINT) { + if (CONSTRAINT) { if (CONSTRAINT->isLocked()) { const auto HINT = CONSTRAINT->logicPositionHint(); g_pCompositor->warpCursorTo(HINT, true); @@ -1428,6 +1433,16 @@ bool CInputManager::isConstrained() { return false; } +bool CInputManager::isLocked() { + if (!isConstrained()) + return false; + + const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock()); + const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr; + + return CONSTRAINT && CONSTRAINT->isLocked(); +} + void CInputManager::updateCapabilities() { uint32_t caps = 0; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index ebf00b2d..d5634796 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -108,6 +108,7 @@ class CInputManager { void unconstrainMouse(); bool isConstrained(); + bool isLocked(); Vector2D getMouseCoordsInternal(); void refocus(); From c3f7c9bbb52b9ad3d24ccfcc5c552ed16c9985a5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 12 Oct 2024 15:18:34 +0100 Subject: [PATCH 0725/2393] xcursor: don't crash on broken permissions in X themes ref #8079 --- src/managers/XCursorManager.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 1e7ca535..93ee7965 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -117,9 +117,11 @@ void CXCursorManager::loadTheme(std::string const& name, int size, float scale) cursors = loadStandardCursors(themeName, lastLoadSize); } else { for (auto const& p : paths) { - auto dirCursors = loadAllFromDir(p, lastLoadSize); - std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors), - [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + try { + auto dirCursors = loadAllFromDir(p, lastLoadSize); + std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(cursors), + [this](auto const& p) { return std::none_of(cursors.begin(), cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + } catch (std::exception& e) { Debug::log(ERR, "XCursor path {} can't be loaded: threw error {}", p, e.what()); } } } From 1822707c7e7394ce8c7572f2fe890763a307f499 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 12 Oct 2024 17:56:46 +0100 Subject: [PATCH 0726/2393] drm-syncobj: fix crash on missing timelines fixes #8092 --- src/protocols/DRMSyncobj.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index a7f242ee..1da4baaf 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -55,6 +55,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP= pending.releasePoint) { resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release"); From e79d3cd2ef5632e2e6b3b20fd0b5dc4d2843f956 Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:23:33 +0200 Subject: [PATCH 0727/2393] hyprpm: convert std::cout and std::cerr to std::println() --- hyprpm/src/core/DataState.cpp | 6 +- hyprpm/src/core/PluginManager.cpp | 267 ++++++++++++++------------- hyprpm/src/core/PluginManager.hpp | 3 +- hyprpm/src/helpers/StringUtils.hpp | 32 ++++ hyprpm/src/main.cpp | 35 ++-- hyprpm/src/progress/CProgressBar.cpp | 16 +- hyprpm/src/progress/CProgressBar.hpp | 2 +- 7 files changed, 202 insertions(+), 159 deletions(-) create mode 100644 hyprpm/src/helpers/StringUtils.hpp diff --git a/hyprpm/src/core/DataState.cpp b/hyprpm/src/core/DataState.cpp index 05c63f4e..fb8679d6 100644 --- a/hyprpm/src/core/DataState.cpp +++ b/hyprpm/src/core/DataState.cpp @@ -1,6 +1,6 @@ #include "DataState.hpp" #include -#include +#include #include #include #include "PluginManager.hpp" @@ -8,7 +8,7 @@ std::string DataState::getDataStatePath() { const auto HOME = getenv("HOME"); if (!HOME) { - std::cerr << "DataState: no $HOME\n"; + std::println(stderr, "DataState: no $HOME"); throw std::runtime_error("no $HOME"); return ""; } @@ -242,4 +242,4 @@ bool DataState::setPluginEnabled(const std::string& name, bool enabled) { } return false; -} \ No newline at end of file +} diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 96ec60ad..359b2c78 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -1,12 +1,15 @@ #include "PluginManager.hpp" #include "../helpers/Colors.hpp" +#include "../helpers/StringUtils.hpp" #include "../progress/CProgressBar.hpp" #include "Manifest.hpp" #include "DataState.hpp" +#include #include #include #include +#include #include #include #include @@ -31,6 +34,7 @@ static std::string execAndGet(std::string cmd) { if (!pipe) return ""; + result.reserve(buffer.size()); while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } @@ -47,10 +51,10 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() { once = true; const auto HLVERCALL = execAndGet("hyprctl version"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "version returned: " << HLVERCALL << "\n"; + std::println("{}", verboseString("version returned: {}", HLVERCALL)); if (!HLVERCALL.contains("Tag:")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " You don't seem to be running Hyprland."; + std::println(stderr, "\n{}", failureString("You don't seem to be running Hyprland.")); return SHyprlandVersion{}; } @@ -76,7 +80,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() { } catch (...) { ; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "parsed commit " << hlcommit << " at branch " << hlbranch << " on " << hldate << ", commits " << commits << "\n"; + std::println("{}", verboseString("parsed commit {} at branch {} on {}, commits {}", hlcommit, hlbranch, hldate, commits)); ver = SHyprlandVersion{hlbranch, hlcommit, hldate, commits}; return ver; @@ -102,20 +106,21 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); return false; } if (DataState::pluginRepoExists(url)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. Repository already installed.\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Repository already installed.")); return false; } auto GLOBALSTATE = DataState::getGlobalState(); if (!GLOBALSTATE.dontWarnInstall) { - std::cout << Colors::YELLOW << "!" << Colors::RED << " Disclaimer:\n " << Colors::RESET - << "plugins, especially not official, have no guarantee of stability, availablity or security.\n Run them at your own risk.\n " - << "This message will not appear again.\n"; + std::println("{}!{} Disclaimer: {}", Colors::YELLOW, Colors::RED, Colors::RESET); + std::println("plugins, especially not official, have no guarantee of stability, availablity or security.\n" + "Run them at your own risk.\n" + "This message will not appear again."); GLOBALSTATE.dontWarnInstall = true; DataState::updateGlobalState(GLOBALSTATE); } @@ -129,7 +134,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::getline(std::cin, input); if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { - std::cout << "Aborting.\n"; + std::println(stderr, "Aborting."); return false; } @@ -144,7 +149,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::filesystem::create_directory("/tmp/hyprpm"); std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); } else if (!std::filesystem::is_directory("/tmp/hyprpm")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hyprpm\n"; + std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm")); return false; } @@ -153,59 +158,59 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; if (!createSafeDirectory(m_szWorkingPluginDirectory)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for repo\n"; + std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo")); return false; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + url); + progress.printMessageAbove(infoString("Cloning {}", url)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the plugin repository. shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret)); return false; } if (!rev.empty()) { std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + rev); if (ret.compare(0, 6, "fatal:") == 0) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not check out revision " << rev << ". shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not check out revision {}. shell returned:\n{}", rev, ret)); return false; } ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + std::println("{}", verboseString("git submodule update --init returned: {}", ret)); } progress.m_iSteps = 1; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned"); + progress.printMessageAbove(successString("cloned")); progress.m_szCurrentMessage = "Reading the manifest"; progress.print(); std::unique_ptr pManifest; if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest"); + progress.printMessageAbove(successString("found hyprpm manifest")); pManifest = std::make_unique(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest"); + progress.printMessageAbove(successString("found hyprload manifest")); pManifest = std::make_unique(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); } if (!pManifest) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); return false; } if (!pManifest->m_bGood) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); return false; } progress.m_iSteps = 2; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:"); + progress.printMessageAbove(successString("parsed manifest, found " + std::to_string(pManifest->m_vPlugins.size()) + " plugins:")); for (auto const& pl : pManifest->m_vPlugins) { - std::string message = std::string{Colors::RESET} + " → " + pl.name + " by "; + std::string message = "→ " + pl.name + " by "; for (auto const& a : pl.authors) { message += a + ", "; } @@ -220,19 +225,19 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& if (!pManifest->m_sRepository.commitPins.empty()) { // check commit pins - progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); + progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " submodule update --init"); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "git submodule update --init returned: " << ret << "\n"; + std::println("{}", verboseString("git submodule update --init returned: {}", ret)); break; } @@ -244,12 +249,12 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& const auto HEADERSSTATUS = headersValid(); if (HEADERSSTATUS != HEADERS_OK) { - std::cerr << "\n" << headerError(HEADERSSTATUS); + std::println("\n{}", headerError(HEADERSSTATUS)); return false; } progress.m_iSteps = 3; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " Hyprland headers OK"); + progress.printMessageAbove(successString("Hyprland headers OK")); progress.m_szCurrentMessage = "Building plugin(s)"; progress.print(); @@ -257,35 +262,36 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1 /* for --depth 1 clones, we can't check this. */) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); + progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); + progress.printMessageAbove(infoString("Building {}", p.name)); for (auto const& bs : p.buildSteps) { - std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); + const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; + std::println("{}", verboseString("shell returned: " + out)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Plugin " + p.name + " failed to build.\n" + - " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update " - "first.\n Try re-running with -v to see " - "more verbose output.\n"); + progress.printMessageAbove(failureString("Plugin {} failed to build.\n" + " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" + " If you are on -git, update first\n" + " Try re-running with -v to see more verbose output.\n", + p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output); + progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " all plugins built"); + progress.printMessageAbove(successString("all plugins built")); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing repository"; progress.print(); @@ -304,13 +310,13 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& } DataState::addNewPluginRepo(repo); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed repository"); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " you can now enable the plugin(s) with hyprpm enable"); + progress.printMessageAbove(successString("installed repository")); + progress.printMessageAbove(successString("you can now enable the plugin(s) with hyprpm enable")); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); // remove build files std::filesystem::remove_all(m_szWorkingPluginDirectory); @@ -320,7 +326,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& bool CPluginManager::removePluginRepo(const std::string& urlOrName) { if (!DataState::pluginRepoExists(urlOrName)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not remove the repository. Repository is not installed.\n"; + std::println(stderr, "\n{}", failureString("Could not remove the repository. Repository is not installed.")); return false; } @@ -331,7 +337,7 @@ bool CPluginManager::removePluginRepo(const std::string& urlOrName) { std::getline(std::cin, input); if (input.size() > 0 && input[0] != 'Y' && input[0] != 'y') { - std::cout << "Aborting.\n"; + std::println("Aborting."); return false; } @@ -347,15 +353,15 @@ eHeadersErrors CPluginManager::headersValid() { return HEADERS_MISSING; // find headers commit - std::string cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); - auto headers = execAndGet(cmd.c_str()); + const std::string& cmd = std::format("PKG_CONFIG_PATH=\"{}/share/pkgconfig\" pkgconf --cflags --keep-system-cflags hyprland", DataState::getHeadersPath()); + auto headers = execAndGet(cmd.c_str()); if (!headers.contains("-I/")) return HEADERS_MISSING; headers.pop_back(); // pop newline - std::string verHeader = ""; + std::string verHeader; while (!headers.empty()) { const auto PATH = headers.substr(0, headers.find(" -I/", 3)); @@ -406,7 +412,7 @@ bool CPluginManager::updateHeaders(bool force) { const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio\n"; + std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); return false; } @@ -416,7 +422,7 @@ bool CPluginManager::updateHeaders(bool force) { } if (!force && headersValid() == HEADERS_OK) { - std::cout << "\n" << std::string{Colors::GREEN} + "✔" + Colors::RESET + " Headers up to date.\n"; + std::println("\n{}", successString("Headers up to date.")); return true; } @@ -430,11 +436,11 @@ bool CPluginManager::updateHeaders(bool force) { const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME; if (!createSafeDirectory(WORKINGDIR)) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not prepare working dir for hl\n"; + std::println("\n{}", failureString("Could not prepare working dir for hl")); return false; } - progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); + progress.printMessageAbove(statusString("!", Colors::YELLOW, "Cloning https://github.com/hyprwm/Hyprland, this might take a moment.")); const bool bShallow = (HLVER.branch == "main") && !m_bNoShallow; @@ -443,60 +449,60 @@ bool CPluginManager::updateHeaders(bool force) { const std::string SHALLOW_DATE = trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+%a %b %d %H:%M:%S %Y'"); if (m_bVerbose && bShallow) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); + progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); std::string ret = - execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); + execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); if (!std::filesystem::exists(WORKINGDIR)) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Clone failed. Retrying without shallow."); + progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME); } if (!std::filesystem::exists(WORKINGDIR + "/.git")) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not clone the hyprland repository. shell returned:\n" << ret << "\n"; + std::println(stderr, "\n{}", failureString("Could not clone the Hyprland repository. shell returned:\n{}", ret)); return false; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " cloned"); + progress.printMessageAbove(successString("Hyprland cloned")); progress.m_iSteps = 2; progress.m_szCurrentMessage = "Checking out sources"; progress.print(); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will run: " + "cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); + progress.printMessageAbove(verboseString("will run: cd {} && git checkout {} 2>&1", WORKINGDIR, HLVER.hash)); ret = execAndGet("cd " + WORKINGDIR + " && git checkout " + HLVER.hash + " 2>&1"); if (ret.contains("fatal: unable to read tree")) { - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET - << " Could not checkout the running Hyprland commit. If you are on -git, try updating.\nYou can also try re-running hyprpm update with --no-shallow.\n"; + std::println(stderr, "\n{}", + failureString("Could not checkout the running Hyprland commit. If you are on -git, try updating.\n" + "You can also try re-running hyprpm update with --no-shallow.")); return false; } if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (co): " + ret); + progress.printMessageAbove(verboseString("git returned (co): {}", ret)); ret = execAndGet("cd " + WORKINGDIR + " ; git rm subprojects/tracy ; git submodule update --init 2>&1 ; git reset --hard --recurse-submodules " + HLVER.hash); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "git returned (rs): " + ret); + progress.printMessageAbove(verboseString("git returned (rs): {}", ret)); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " checked out to running ver"); + progress.printMessageAbove(successString("checked out to running ver")); progress.m_iSteps = 3; progress.m_szCurrentMessage = "Building Hyprland"; progress.print(); - progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " configuring Hyprland"); + progress.printMessageAbove(statusString("!", Colors::YELLOW, "configuring Hyprland")); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "setting PREFIX for cmake to " + DataState::getHeadersPath()); + progress.printMessageAbove(verboseString("setting PREFIX for cmake to {}", DataState::getHeadersPath())); ret = execAndGet(std::format("cd {} && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=\"{}\" -S . -B ./build -G Ninja", WORKINGDIR, DataState::getHeadersPath())); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); + progress.printMessageAbove(verboseString("cmake returned: {}", ret)); if (ret.contains("CMake Error at")) { // missing deps, let the user know. @@ -505,48 +511,46 @@ bool CPluginManager::updateHeaders(bool force) { missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find_last_of('\n')); - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" - << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n"; + std::println(stderr, "\n{}", + failureString("Could not configure the hyprland source, cmake complained:\n{}\n\n" + "This likely means that you are missing the above dependencies or they are out of date.", + missing)); return false; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " configured Hyprland"); + progress.printMessageAbove(successString("configured Hyprland")); progress.m_iSteps = 4; progress.m_szCurrentMessage = "Installing sources"; progress.print(); - std::string cmd = + const std::string& cmd = std::format("sed -i -e \"s#PREFIX = /usr/local#PREFIX = {}#\" {}/Makefile && cd {} && make installheaders", DataState::getHeadersPath(), WORKINGDIR, WORKINGDIR); if (m_bVerbose) - progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "installation will run: " + cmd); + progress.printMessageAbove(verboseString("installation will run: {}", cmd)); ret = execAndGet(cmd); if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "installer returned: " << ret << "\n"; + std::println("{}", verboseString("installer returned: {}", ret)); // remove build files std::filesystem::remove_all(WORKINGDIR); auto HEADERSVALID = headersValid(); if (HEADERSVALID == HEADERS_OK) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " installed headers"); + progress.printMessageAbove(successString("installed headers")); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); } else { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " failed to install headers with error code " + std::to_string((int)HEADERSVALID) + " (" + - headerErrorShort(HEADERSVALID) + ")"); + progress.printMessageAbove(failureString("failed to install headers with error code {} ({})", (int)HEADERSVALID, headerErrorShort(HEADERSVALID))); progress.m_iSteps = 5; progress.m_szCurrentMessage = "Failed"; progress.print(); - std::cout << "\n"; - - std::cerr << "\n" << headerError(HEADERSVALID); + std::print(stderr, "\n\n{}", headerError(HEADERSVALID)); return false; } @@ -556,14 +560,14 @@ bool CPluginManager::updateHeaders(bool force) { bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (headersValid() != HEADERS_OK) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; + std::println("{}", failureString("headers are not up-to-date, please run hyprpm update.")); return false; } const auto REPOS = DataState::getAllRepositories(); if (REPOS.size() < 1) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " No repos to update.\n"; + std::println("{}", failureString("No repos to update.")); return true; } @@ -585,25 +589,26 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.m_szCurrentMessage = "Updating " + repo.name; progress.print(); - progress.printMessageAbove(std::string{Colors::RESET} + " → checking for updates for " + repo.name); + progress.printMessageAbove(infoString("checking for updates for {}", repo.name)); createSafeDirectory(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::RESET} + " → Cloning " + repo.url); + progress.printMessageAbove(infoString("Cloning {}", repo.url)); std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not clone repo: shell returned:\n" + ret; + std::println("{}", failureString("could not clone repo: shell returned: {}", ret)); return false; } if (!repo.rev.empty()) { - progress.printMessageAbove(std::string{Colors::RESET} + " → Plugin has revision set, resetting: " + repo.rev); + progress.printMessageAbove(infoString("Plugin has revision set, resetting: {}", repo.rev)); std::string ret = execAndGet("git -C " + m_szWorkingPluginDirectory + " reset --hard --recurse-submodules " + repo.rev); if (ret.compare(0, 6, "fatal:") == 0) { - std::cout << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " could not check out revision " + repo.rev + ": shell returned:\n" + ret; + std::println(stderr, "\n{}", failureString("could not check out revision {}: shell returned:\n{}", repo.rev, ret)); + return false; } } @@ -619,7 +624,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { if (!update) { std::filesystem::remove_all(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " is up-to-date."); + progress.printMessageAbove(successString("repository {} is up-to-date.", repo.name)); progress.m_iSteps++; progress.print(); continue; @@ -627,41 +632,41 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { // we need to update - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " repository " + repo.name + " has updates."); - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + repo.name); + progress.printMessageAbove(successString("repository {} has updates.", repo.name)); + progress.printMessageAbove(infoString("Building {}", repo.name)); progress.m_iSteps++; progress.print(); std::unique_ptr pManifest; if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprpm.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprpm manifest"); + progress.printMessageAbove(successString("found hyprpm manifest")); pManifest = std::make_unique(MANIFEST_HYPRPM, m_szWorkingPluginDirectory + "/hyprpm.toml"); } else if (std::filesystem::exists(m_szWorkingPluginDirectory + "/hyprload.toml")) { - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " found hyprload manifest"); + progress.printMessageAbove(successString("found hyprload manifest")); pManifest = std::make_unique(MANIFEST_HYPRLOAD, m_szWorkingPluginDirectory + "/hyprload.toml"); } if (!pManifest) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository does not have a valid manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository does not have a valid manifest")); continue; } if (!pManifest->m_bGood) { - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " The provided plugin repository has a corrupted manifest\n"; + std::println(stderr, "\n{}", failureString("The provided plugin repository has a corrupted manifest")); continue; } if (repo.rev.empty() && !pManifest->m_sRepository.commitPins.empty()) { // check commit pins unless a revision is specified - progress.printMessageAbove(std::string{Colors::RESET} + " → Manifest has " + std::to_string(pManifest->m_sRepository.commitPins.size()) + " pins, checking"); + progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_sRepository.commitPins.size())); for (auto const& [hl, plugin] : pManifest->m_sRepository.commitPins) { if (hl != HLVER.hash) continue; - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " commit pin " + plugin + " matched hl, resetting"); + progress.printMessageAbove(successString("commit pin {} matched hl, resetting", plugin)); execAndGet("cd " + m_szWorkingPluginDirectory + " && git reset --hard --recurse-submodules " + plugin); } @@ -671,32 +676,33 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { std::string out; if (p.since > HLVER.commits && HLVER.commits >= 1000 /* for shallow clones, we can't check this. 1000 is an arbitrary number I chose. */) { - progress.printMessageAbove(std::string{Colors::RED} + "✖" + Colors::RESET + " Not building " + p.name + ": your Hyprland version is too old.\n"); + progress.printMessageAbove(failureString("Not building {}: your Hyprland version is too old.\n", p.name)); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::RESET} + " → Building " + p.name); + progress.printMessageAbove(infoString("Building {}", p.name)); for (auto const& bs : p.buildSteps) { - std::string cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); + const std::string& cmd = std::format("cd {} && PKG_CONFIG_PATH=\"{}/share/pkgconfig\" {}", m_szWorkingPluginDirectory, DataState::getHeadersPath(), bs); out += " -> " + cmd + "\n" + execAndGet(cmd) + "\n"; } if (m_bVerbose) - std::cout << Colors::BLUE << "[v] " << Colors::RESET << "shell returned: " << out << "\n"; + std::println("{}", verboseString("shell returned: {}", out)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { - std::cerr << "\n" - << Colors::RED << "✖" << Colors::RESET << " Plugin " << p.name << " failed to build.\n" - << " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n If you are on -git, update first.\n Try " - "re-running with -v to see more verbose " - "output.\n"; + std::println(stderr, + "\n{}\n" + " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" + "If you are on -git, update first.\n" + "Try re-running with -v to see more verbose output.", + failureString("Plugin {} failed to build.")); p.failed = true; continue; } - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " built " + p.name + " into " + p.output); + progress.printMessageAbove(successString("built {} into {}", p.name, p.output)); } // add repo toml to DataState @@ -717,7 +723,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { std::filesystem::remove_all(m_szWorkingPluginDirectory); - progress.printMessageAbove(std::string{Colors::GREEN} + "✔" + Colors::RESET + " updated " + repo.name); + progress.printMessageAbove(successString("updated {}", repo.name)); } progress.m_iSteps++; @@ -732,7 +738,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.m_szCurrentMessage = "Done!"; progress.print(); - std::cout << "\n"; + std::print("\n"); return true; } @@ -740,27 +746,27 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { bool CPluginManager::enablePlugin(const std::string& name) { bool ret = DataState::setPluginEnabled(name, true); if (ret) - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Enabled " << name << "\n"; + std::println("{}", successString("Enabled {}", name)); return ret; } bool CPluginManager::disablePlugin(const std::string& name) { bool ret = DataState::setPluginEnabled(name, false); if (ret) - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Disabled " << name << "\n"; + std::println("{}", successString("Disabled {}", name)); return ret; } ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { if (headersValid() != HEADERS_OK) { - std::cerr << "\n" << std::string{Colors::RED} + "✖" + Colors::RESET + " headers are not up-to-date, please run hyprpm update.\n"; + std::println(stderr, "\n{}", failureString("headers are not up-to-date, please run hyprpm update.")); return LOADSTATE_HEADERS_OUTDATED; } const auto HOME = getenv("HOME"); const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE"); if (!HOME || !HIS) { - std::cerr << "PluginManager: no $HOME or HIS\n"; + std::println(stderr, "PluginManager: no $HOME or HIS"); return LOADSTATE_FAIL; } const auto HYPRPMPATH = DataState::getDataStatePath() + "/"; @@ -769,14 +775,14 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { std::vector loadedPlugins; - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Ensuring plugin load state\n"; + std::println("{}", successString("Ensuring plugin load state")); // iterate line by line while (!pluginLines.empty()) { - auto plLine = pluginLines.substr(0, pluginLines.find("\n")); + auto plLine = pluginLines.substr(0, pluginLines.find('\n')); - if (pluginLines.find("\n") != std::string::npos) - pluginLines = pluginLines.substr(pluginLines.find("\n") + 1); + if (pluginLines.find('\n') != std::string::npos) + pluginLines = pluginLines.substr(pluginLines.find('\n') + 1); else pluginLines = ""; @@ -819,7 +825,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { if (!enabled(p)) { // unload loadUnloadPlugin(HYPRPMPATH + repoForName(p) + "/" + p + ".so", false); - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Unloaded " << p << "\n"; + std::println("{}", successString("Unloaded {}", p)); } } @@ -833,11 +839,11 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { continue; loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true); - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Loaded " << p.name << "\n"; + std::println("{}", successString("Loaded {}"), p.name); } } - std::cout << Colors::GREEN << "✔" << Colors::RESET << " Plugin load state ensured\n"; + std::println("{}", successString("Plugin load state ensured")); return LOADSTATE_OK; } @@ -855,16 +861,17 @@ void CPluginManager::listAllPlugins() { const auto REPOS = DataState::getAllRepositories(); for (auto const& r : REPOS) { - std::cout << std::string{Colors::RESET} + " → Repository " + r.name + ":\n"; + std::println("{}", infoString("Repository {}:", r.name)); for (auto const& p : r.plugins) { - - std::cout << std::string{Colors::RESET} + " │ Plugin " + p.name; + std::println(" │ Plugin {}", p.name); if (!p.failed) - std::cout << "\n └─ enabled: " << (p.enabled ? Colors::GREEN : Colors::RED) << (p.enabled ? "true" : "false") << Colors::RESET << "\n"; + std::println(" └─ enabled: {}", (p.enabled ? std::string{Colors::GREEN} + "true" : std::string{Colors::RED} + "false")); else - std::cout << "\n └─ enabled: " << Colors::RED << "Plugin failed to build" << Colors::RESET << "\n"; + std::println(" └─ enabled: {}Plugin failed to build", Colors::RED); + + std::println("{}", Colors::RESET); } } } @@ -875,19 +882,19 @@ void CPluginManager::notify(const eNotifyIcons icon, uint32_t color, int duratio std::string CPluginManager::headerError(const eHeadersErrors err) { switch (err) { - case HEADERS_CORRUPTED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers corrupted. Please run hyprpm update to fix those.\n"; - case HEADERS_MISMATCHED: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers version mismatch. Please run hyprpm update to fix those.\n"; - case HEADERS_NOT_HYPRLAND: return std::string{Colors::RED} + "✖" + Colors::RESET + " It doesn't seem you are running on hyprland.\n"; - case HEADERS_MISSING: return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers missing. Please run hyprpm update to fix those.\n"; + case HEADERS_CORRUPTED: return failureString("Headers corrupted. Please run hyprpm update to fix those.\n"); + case HEADERS_MISMATCHED: return failureString("Headers version mismatch. Please run hyprpm update to fix those.\n"); + case HEADERS_NOT_HYPRLAND: return failureString("It doesn't seem you are running on hyprland.\n"); + case HEADERS_MISSING: return failureString("Headers missing. Please run hyprpm update to fix those.\n"); case HEADERS_DUPLICATED: { - return std::string{Colors::RED} + "✖" + Colors::RESET + " Headers duplicated!!! This is a very bad sign.\n" + - " This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" + - " If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"; + return failureString("Headers duplicated!!! This is a very bad sign.\n" + "This could be due to e.g. installing hyprland manually while a system package of hyprland is also installed.\n" + "If the above doesn't apply, check your /usr/include and /usr/local/include directories\n and remove all the hyprland headers.\n"); } default: break; } - return std::string{Colors::RED} + "✖" + Colors::RESET + " Unknown header error. Please run hyprpm update to fix those.\n"; + return failureString("Unknown header error. Please run hyprpm update to fix those.\n"); } std::string CPluginManager::headerErrorShort(const eHeadersErrors err) { diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index c16a9d0f..d4603084 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -2,6 +2,7 @@ #include #include +#include enum eHeadersErrors { HEADERS_OK = 0, @@ -68,7 +69,7 @@ class CPluginManager { std::string headerError(const eHeadersErrors err); std::string headerErrorShort(const eHeadersErrors err); - std::string m_szWorkingPluginDirectory = ""; + std::string m_szWorkingPluginDirectory; }; inline std::unique_ptr g_pPluginManager; diff --git a/hyprpm/src/helpers/StringUtils.hpp b/hyprpm/src/helpers/StringUtils.hpp new file mode 100644 index 00000000..c1a5fd98 --- /dev/null +++ b/hyprpm/src/helpers/StringUtils.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include "Colors.hpp" + +template +std::string statusString(const std::string_view emoji, const std::string_view color, const std::string_view fmt, Args&&... args) { + std::string ret = std::format("{}{}{} ", color, emoji, Colors::RESET); + ret += std::vformat(fmt, std::make_format_args(args...)); + return ret; +} + +template +std::string successString(const std::string_view fmt, Args&&... args) { + return statusString("✔", Colors::GREEN, fmt, args...); +} + +template +std::string failureString(const std::string_view fmt, Args&&... args) { + return statusString("✖", Colors::RED, fmt, args...); +} + +template +std::string verboseString(const std::string_view fmt, Args&&... args) { + return statusString("[v]", Colors::BLUE, fmt, args...); +} + +template +std::string infoString(const std::string_view fmt, Args&&... args) { + return statusString("→", Colors::RESET, fmt, args...); +} diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 4f00f708..67f14aed 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -1,15 +1,16 @@ -#include "progress/CProgressBar.hpp" #include "helpers/Colors.hpp" +#include "helpers/StringUtils.hpp" #include "core/PluginManager.hpp" #include "core/DataState.hpp" -#include +#include #include #include +#include #include #include -const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager +constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┃ ┣ add [url] [git rev] → Install a new plugin repository from git. Git revision ┃ is optional, when set, commit locks are ignored. @@ -30,14 +31,14 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┗ )#"; -int main(int argc, char** argv, char** envp) { +int main(int argc, char** argv, char** envp) { std::vector ARGS{argc}; for (int i = 0; i < argc; ++i) { ARGS[i] = std::string{argv[i]}; } if (ARGS.size() < 2) { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 1; } @@ -47,7 +48,7 @@ int main(int argc, char** argv, char** envp) { for (int i = 1; i < argc; ++i) { if (ARGS[i].starts_with("-")) { if (ARGS[i] == "--help" || ARGS[i] == "-h") { - std::cout << HELP; + std::println("{}", HELP); return 0; } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { notify = true; @@ -57,9 +58,9 @@ int main(int argc, char** argv, char** envp) { noShallow = true; } else if (ARGS[i] == "--force" || ARGS[i] == "-f") { force = true; - std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; + std::println("{}", statusString("!", Colors::RED, "Using --force, I hope you know what you are doing.")); } else { - std::cerr << "Unrecognized option " << ARGS[i] << "\n"; + std::println(stderr, "Unrecognized option {}", ARGS[i]); return 1; } } else { @@ -68,7 +69,7 @@ int main(int argc, char** argv, char** envp) { } if (command.empty()) { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 0; } @@ -78,7 +79,7 @@ int main(int argc, char** argv, char** envp) { if (command[0] == "add") { if (command.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for add.\n"; + std::println(stderr, "{}", failureString("Not enough args for add.")); return 1; } @@ -90,7 +91,7 @@ int main(int argc, char** argv, char** envp) { return g_pPluginManager->addNewPluginRepo(command[1], rev) ? 0 : 1; } else if (command[0] == "remove") { if (ARGS.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for remove.\n"; + std::println(stderr, "{}", failureString("Not enough args for remove.")); return 1; } @@ -116,12 +117,12 @@ int main(int argc, char** argv, char** envp) { g_pPluginManager->notify(ICON_ERROR, 0, 10000, "[hyprpm] Couldn't update headers"); } else if (command[0] == "enable") { if (ARGS.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for enable.\n"; + std::println(stderr, "{}", failureString("Not enough args for enable.")); return 1; } if (!g_pPluginManager->enablePlugin(command[1])) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't enable plugin (missing?)\n"; + std::println(stderr, "{}", failureString("Couldn't enable plugin (missing?)")); return 1; } @@ -130,12 +131,12 @@ int main(int argc, char** argv, char** envp) { return 1; } else if (command[0] == "disable") { if (command.size() < 2) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Not enough args for disable.\n"; + std::println(stderr, "{}", failureString("Not enough args for disable.")); return 1; } if (!g_pPluginManager->disablePlugin(command[1])) { - std::cerr << Colors::RED << "✖" << Colors::RESET << " Couldn't disable plugin (missing?)\n"; + std::println(stderr, "{}", failureString("Couldn't disable plugin (missing?)")); return 1; } @@ -160,9 +161,9 @@ int main(int argc, char** argv, char** envp) { } else if (command[0] == "list") { g_pPluginManager->listAllPlugins(); } else { - std::cout << HELP; + std::println(stderr, "{}", HELP); return 1; } return 0; -} \ No newline at end of file +} diff --git a/hyprpm/src/progress/CProgressBar.cpp b/hyprpm/src/progress/CProgressBar.cpp index 45602f82..9f2df08a 100644 --- a/hyprpm/src/progress/CProgressBar.cpp +++ b/hyprpm/src/progress/CProgressBar.cpp @@ -1,11 +1,11 @@ #include "CProgressBar.hpp" -#include +#include #include #include #include -#include +#include #include #include @@ -16,11 +16,12 @@ void CProgressBar::printMessageAbove(const std::string& msg) { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); std::string spaces; + spaces.reserve(w.ws_col); for (size_t i = 0; i < w.ws_col; ++i) { spaces += ' '; } - std::cout << "\r" << spaces << "\r" << msg << "\n"; + std::println("\r{}\r{}", spaces, msg); print(); } @@ -29,15 +30,16 @@ void CProgressBar::print() { ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); if (m_bFirstPrint) - std::cout << "\n"; + std::print("\n"); m_bFirstPrint = false; std::string spaces; + spaces.reserve(w.ws_col); for (size_t i = 0; i < w.ws_col; ++i) { spaces += ' '; } - std::cout << "\r" << spaces << "\r"; + std::print("\r{}\r", spaces); std::string message = ""; @@ -74,7 +76,7 @@ void CProgressBar::print() { message += " " + std::format("{} / {}", m_iSteps, m_iMaxSteps) + " "; // draw message - std::cout << message + " " + m_szCurrentMessage; + std::print("{} {}", message, m_szCurrentMessage); std::fflush(stdout); -} \ No newline at end of file +} diff --git a/hyprpm/src/progress/CProgressBar.hpp b/hyprpm/src/progress/CProgressBar.hpp index 6ac18f21..dfcb36f7 100644 --- a/hyprpm/src/progress/CProgressBar.hpp +++ b/hyprpm/src/progress/CProgressBar.hpp @@ -14,4 +14,4 @@ class CProgressBar { private: bool m_bFirstPrint = true; -}; \ No newline at end of file +}; From b61d4c363679a880e8577a3d983d73dbab367a9d Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:23:56 +0200 Subject: [PATCH 0728/2393] hyprctl: convert std::cout and std::cerr to std::println() --- hyprctl/Strings.hpp | 2 ++ hyprctl/main.cpp | 37 +++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index 17725e77..f77626a5 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -1,5 +1,7 @@ #pragma once +#include + const std::string_view USAGE = R"#(usage: hyprctl [flags] [args...|--help] commands: diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 1ad189b7..1f7f8d74 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -44,11 +45,11 @@ struct SInstanceData { bool valid = true; }; -void log(std::string str) { +void log(const std::string& str) { if (quiet) return; - std::cout << str << "\n"; + std::println("{}", str); } std::string getRuntimeDir() { @@ -105,7 +106,7 @@ std::vector instances() { static volatile bool sigintReceived = false; void intHandler(int sig) { sigintReceived = true; - std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl; + std::println("[hyprctl] SIGINT received, closing connection"); } int rollingRead(const int socket) { @@ -115,12 +116,12 @@ int rollingRead(const int socket) { constexpr size_t BUFFER_SIZE = 8192; std::array buffer = {0}; long sizeWritten = 0; - std::cout << "[hyprctl] reading from socket following up log:" << std::endl; + std::println("[hyprctl] reading from socket following up log:"); while (!sigintReceived) { sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); if (sizeWritten < 0 && errno != EAGAIN) { if (errno != EINTR) - std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl; + std::println("Couldn't read (5): {}: {}", strerror(errno), errno); close(socket); return 5; } @@ -129,7 +130,7 @@ int rollingRead(const int socket) { break; if (sizeWritten > 0) { - std::cout << std::string(buffer.data(), sizeWritten); + std::println("{}", std::string(buffer.data(), sizeWritten)); buffer.fill('\0'); } @@ -323,7 +324,7 @@ int main(int argc, char** argv) { bool parseArgs = true; if (argc < 2) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -360,7 +361,7 @@ int main(int argc, char** argv) { ++i; if (i >= ARGS.size()) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -371,24 +372,24 @@ int main(int argc, char** argv) { const std::string& cmd = ARGS[0]; if (cmd == "hyprpaper") { - std::cout << HYPRPAPER_HELP << std::endl; + std::println("{}", HYPRPAPER_HELP); } else if (cmd == "notify") { - std::cout << NOTIFY_HELP << std::endl; + std::println("{}", NOTIFY_HELP); } else if (cmd == "output") { - std::cout << OUTPUT_HELP << std::endl; + std::println("{}", OUTPUT_HELP); } else if (cmd == "plugin") { - std::cout << PLUGIN_HELP << std::endl; + std::println("{}", PLUGIN_HELP); } else if (cmd == "setprop") { - std::cout << SETPROP_HELP << std::endl; + std::println("{}", SETPROP_HELP); } else if (cmd == "switchxkblayout") { - std::cout << SWITCHXKBLAYOUT_HELP << std::endl; + std::println("{}", SWITCHXKBLAYOUT_HELP); } else { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); } return 1; } else { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -399,7 +400,7 @@ int main(int argc, char** argv) { } if (fullRequest.empty()) { - std::cout << USAGE << std::endl; + std::println("{}", USAGE); return 1; } @@ -476,7 +477,7 @@ int main(int argc, char** argv) { else if (fullRequest.contains("/decorations")) exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/--help")) - std::cout << USAGE << std::endl; + std::println("{}", USAGE); else if (fullRequest.contains("/rollinglog") && needRoll) exitStatus = request(fullRequest, 0, true); else { From 05a5e0b4f1ced12f2a0330132f37b0081d7a5e4d Mon Sep 17 00:00:00 2001 From: Toni500git Date: Sun, 13 Oct 2024 14:24:10 +0200 Subject: [PATCH 0729/2393] hyprland: convert std::cout and std::cerr to std::println() --- src/Compositor.cpp | 14 +++++++------ src/debug/Log.cpp | 4 ++-- src/main.cpp | 51 ++++++++++++++++++++++++---------------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index dcc6422d..fd4979b0 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -9,7 +9,9 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +#include #include +#include #include #include #include @@ -138,37 +140,37 @@ CCompositor::CCompositor() { m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { - std::cout << "Bailing out, XDG_RUNTIME_DIR is invalid\n"; + std::println("Bailing out, $XDG_RUNTIME_DIR is invalid"); throw std::runtime_error("CCompositor() failed"); } if (!m_szHyprTempDataRoot.starts_with("/run/user")) - std::cout << "[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways...\n"; + std::println("[!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways..."); std::random_device dev; std::mt19937 engine(dev()); std::uniform_int_distribution<> distribution(0, INT32_MAX); - m_szInstanceSignature = GIT_COMMIT_HASH + std::string("_") + std::to_string(time(NULL)) + "_" + std::to_string(distribution(engine)); + m_szInstanceSignature = std::format("{}_{}_{}", GIT_COMMIT_HASH, std::time(NULL), distribution(engine)); setenv("HYPRLAND_INSTANCE_SIGNATURE", m_szInstanceSignature.c_str(), true); if (!std::filesystem::exists(m_szHyprTempDataRoot)) mkdir(m_szHyprTempDataRoot.c_str(), S_IRWXU); else if (!std::filesystem::is_directory(m_szHyprTempDataRoot)) { - std::cout << "Bailing out, " << m_szHyprTempDataRoot << " is not a directory\n"; + std::println("Bailing out, {} is not a directory", m_szHyprTempDataRoot); throw std::runtime_error("CCompositor() failed"); } m_szInstancePath = m_szHyprTempDataRoot + "/" + m_szInstanceSignature; if (std::filesystem::exists(m_szInstancePath)) { - std::cout << "Bailing out, " << m_szInstancePath << " exists??\n"; + std::println("Bailing out, {} exists??", m_szInstancePath); throw std::runtime_error("CCompositor() failed"); } if (mkdir(m_szInstancePath.c_str(), S_IRWXU) < 0) { - std::cout << "Bailing out, couldn't create " << m_szInstancePath << "\n"; + std::println("Bailing out, couldn't create {}", m_szInstancePath); throw std::runtime_error("CCompositor() failed"); } diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index a4c5b08e..5a314833 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -4,7 +4,7 @@ #include "RollingLogFollow.hpp" #include -#include +#include #include void Debug::init(const std::string& IS) { @@ -69,5 +69,5 @@ void Debug::log(LogLevel level, std::string str) { // log it to the stdout too. if (!disableStdout) - std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n"; + std::println("{}", ((coloredLogs && !**coloredLogs) ? str : coloredStr)); } diff --git a/src/main.cpp b/src/main.cpp index 45f212d3..6bbf73fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,9 @@ #include "init/initHelpers.hpp" #include "debug/HyprCtl.hpp" +#include #include +#include using namespace Hyprutils::String; #include @@ -17,15 +19,15 @@ using namespace Hyprutils::String; #include void help() { - std::cout << "usage: Hyprland [arg [...]].\n"; - std::cout << "\nArguments:\n"; - std::cout << " --help -h - Show this message again\n"; - std::cout << " --config FILE -c FILE - Specify config file to use\n"; - std::cout << " --socket NAME - Sets the Wayland socket name (for Wayland socket handover)\n"; - std::cout << " --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover)\n"; - std::cout << " --systeminfo - Prints system infos\n"; - std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n"; - std::cout << " --version -v - Print this binary's version\n"; + std::println("usage: Hyprland [arg [...]].\n"); + std::println(R"(Arguments: + --help -h - Show this message again + --config FILE -c FILE - Specify config file to use + --socket NAME - Sets the Wayland socket name (for Wayland socket handover) + --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover) + --systeminfo - Prints system infos + --i-am-really-stupid - Omits root user privileges check (why would you do that?) + --version -v - Print this binary's version)"); } int main(int argc, char** argv) { @@ -53,7 +55,7 @@ int main(int argc, char** argv) { for (auto it = args.begin(); it != args.end(); it++) { if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) { - std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n"; + std::println("[ WARNING ] Running Hyprland with superuser privileges might damage your system"); ignoreSudo = true; } else if (it->compare("--socket") == 0) { @@ -79,7 +81,7 @@ int main(int argc, char** argv) { if (fcntl(socketFd, F_GETFD) == -1) throw std::exception(); } catch (...) { - std::cerr << "[ ERROR ] Invalid Wayland FD!\n"; + std::println(stderr, "[ ERROR ] Invalid Wayland FD!"); help(); return 1; @@ -101,7 +103,7 @@ int main(int argc, char** argv) { throw std::exception(); } } catch (...) { - std::cerr << "[ ERROR ] Config file '" << configPath << "' doesn't exist!\n"; + std::println(stderr, "[ ERROR ] Config file '{}' doesn't exist!", configPath); help(); return 1; @@ -117,14 +119,13 @@ int main(int argc, char** argv) { return 0; } else if (it->compare("-v") == 0 || it->compare("--version") == 0) { - std::cout << versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "") << std::endl; + std::println("{}", versionRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; } else if (it->compare("--systeminfo") == 0) { - const auto SYSINFO = systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, ""); - std::cout << SYSINFO << "\n"; + std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; } else { - std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n"; + std::println(stderr, "[ ERROR ] Unknown option '{}' !", it->c_str()); help(); return 1; @@ -132,30 +133,32 @@ int main(int argc, char** argv) { } if (!ignoreSudo && Init::isSudo()) { - std::cerr << "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n"; - std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n"; + std::println(stderr, + "[ ERROR ] Hyprland was launched with superuser privileges, but the privileges check is not omitted.\n" + " Hint: Use the --i-am-really-stupid flag to omit that check."); return 1; } else if (ignoreSudo && Init::isSudo()) { - std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n"; + std::println("Superuser privileges check is omitted. I hope you know what you're doing."); } if (socketName.empty() ^ (socketFd == -1)) { - std::cerr << "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n"; - std::cerr << " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover.\n"; + std::println(stderr, + "[ ERROR ] Hyprland was launched with only one of --socket and --wayland-fd.\n" + " Hint: Pass both --socket and --wayland-fd to perform Wayland socket handover."); return 1; } - std::cout << "Welcome to Hyprland!\n"; + std::println("Welcome to Hyprland!"); // let's init the compositor. // it initializes basic Wayland stuff in the constructor. try { g_pCompositor = std::make_unique(); g_pCompositor->explicitConfigPath = configPath; - } catch (std::exception& e) { - std::cout << "Hyprland threw in ctor: " << e.what() << "\nCannot continue.\n"; + } catch (const std::exception& e) { + std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what()); return 1; } From 5c3bd8e93d9f25be3e16a0445ba6fce8d30b6d73 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 13 Oct 2024 17:26:39 +0100 Subject: [PATCH 0730/2393] notif-overlay: add a bit of padding for icons --- src/debug/HyprNotificationOverlay.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 29da20c8..16f80ab6 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -37,7 +37,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() { void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) { const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique()).get(); - PNOTIF->text = text; + PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->started.reset(); PNOTIF->timeMs = timeMs; From 8e51a36c7fd500e865e34f08ab4dc4331dca59cf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 14 Oct 2024 00:19:10 +0100 Subject: [PATCH 0731/2393] config/example: add optional smart gaps to the default config ref #8106 #8114 --- example/hyprland.conf | 7 +++++++ src/config/defaultConfig.hpp | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/example/hyprland.conf b/example/hyprland.conf index 3478bcff..6d7bddb8 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -117,6 +117,13 @@ animations { animation = workspaces, 1, 6, default } +# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all three if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 54ce6642..5c8b0e68 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -130,6 +130,13 @@ animations { animation = workspaces, 1, 6, default } +# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ +# "Smart gaps" / "No gaps when only" +# uncomment all three if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 +# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 + # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below From abfd550ee228ea23058039790e792b45d2467c8d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 14 Oct 2024 00:24:32 +0100 Subject: [PATCH 0732/2393] xwm: avoid infinite parent lookup loop in lookupParentExists ref #8045 --- src/xwayland/XWM.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index dcb22eae..248813bf 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -150,10 +150,17 @@ void CXWM::handleUnmapNotify(xcb_unmap_notify_event_t* e) { } static bool lookupParentExists(SP XSURF, SP prospectiveChild) { + std::vector> visited; + while (XSURF->parent) { if (XSURF->parent == prospectiveChild) return true; + visited.emplace_back(XSURF); + XSURF = XSURF->parent.lock(); + + if (std::find(visited.begin(), visited.end(), XSURF) != visited.end()) + return false; } return false; From e7fd0f5aec85c11a8eaf5e1abf8504f0a6d0710e Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sun, 13 Oct 2024 23:25:19 +0000 Subject: [PATCH 0733/2393] layout: deny auto-grouping a new floating window into a tiled group (#8108) --- src/layout/IHyprLayout.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 24ee13f4..80c9abff 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -186,12 +186,17 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { g_pCompositor->m_pLastWindow.lock() : g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); - if (*PAUTOGROUP // check if auto_group is enabled. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. - && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group - && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON - && !g_pXWaylandManager->shouldBeFloated(pWindow)) { // don't group XWayland windows that should be floated. + bool denied = false; + if (pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating) + denied = true; + + if (*PAUTOGROUP // check if auto_group is enabled. + && OPENINGON // check if OPENINGON exists. + && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. + && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group a new window that should be floated. + && !denied) { // don't group a new floated window into a tiled group. pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state From ce62521883e217aab4da305d71e40e4a50567dfb Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 14 Oct 2024 05:37:42 -0500 Subject: [PATCH 0734/2393] drm-lease: fix crashes and implementation (#8116) --- src/protocols/DRMLease.cpp | 28 ++++++++++++++++++++-------- src/protocols/DRMLease.hpp | 3 ++- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 37f2e2eb..d0114ce7 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -44,10 +44,6 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPleaseFD); - - resource->sendLeaseFd(aqlease->leaseFD); - lease = aqlease; for (auto const& m : requested) { @@ -61,8 +57,13 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SPsendFinished(); + LOGM(LOG, "Revoking lease for fd {}", lease->leaseFD); }); + LOGM(LOG, "Granting lease, sending fd {}", lease->leaseFD); + + resource->sendLeaseFd(lease->leaseFD); + close(lease->leaseFD); } @@ -70,6 +71,12 @@ bool CDRMLeaseResource::good() { return resource->resource(); } +CDRMLeaseResource::~CDRMLeaseResource() { + // destroy in this order to ensure listener gets called + lease.reset(); + listeners.destroyLease.reset(); +} + CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { if (!good()) return; @@ -100,7 +107,7 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP reso return; } - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), self.lock()); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), self.lock()); if (!RESOURCE) { resource->noMemory(); return; @@ -185,7 +192,8 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc close(fd); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { - sendConnector(m.lock()); + if (m) + sendConnector(m.lock()); } resource->sendDone(); @@ -196,10 +204,10 @@ bool CDRMLeaseDeviceResource::good() { } void CDRMLeaseDeviceResource::sendConnector(SP monitor) { - if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end()) + if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e && !e->dead && e->monitor == monitor; }) != connectorsSent.end()) return; - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), monitor); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), 0), monitor); if (!RESOURCE) { resource->noMemory(); return; @@ -267,6 +275,9 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) { } void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) { + for (const auto& m : m_vManagers) { + std::erase_if(m->connectorsSent, [resource](const auto& e) { return e.expired() || e->dead || e.get() == resource; }); + } std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; }); } @@ -279,6 +290,7 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { } void CDRMLeaseProtocol::offer(SP monitor) { + std::erase_if(primaryDevice->offeredOutputs, [](const auto& e) { return e.expired(); }); if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) return; diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index 56eaa3db..3671cfce 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -22,12 +22,13 @@ class CDRMLeaseRequestResource; class CDRMLeaseResource { public: CDRMLeaseResource(SP resource_, SP request); + ~CDRMLeaseResource(); bool good(); WP parent; std::vector> requested; - WP lease; + SP lease; int leaseFD = -1; From f309681d4a78d1c12d8a04fe37075a50a750c2ec Mon Sep 17 00:00:00 2001 From: deadacute <6218316+deadacute@users.noreply.github.com> Date: Sun, 13 Oct 2024 20:40:09 +0200 Subject: [PATCH 0735/2393] example: update desktop file to include DesktopNames --- example/hyprland.desktop | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/example/hyprland.desktop b/example/hyprland.desktop index 57ad076f..bb2801a9 100644 --- a/example/hyprland.desktop +++ b/example/hyprland.desktop @@ -2,4 +2,6 @@ Name=Hyprland Comment=An intelligent dynamic tiling Wayland compositor Exec=Hyprland -Type=Application \ No newline at end of file +Type=Application +DesktopNames=Hyprland +Keywords=tiling;wayland;compositor; From 22b1370ae512c92d84bbcd4cff2a3f8a4496c994 Mon Sep 17 00:00:00 2001 From: "fanlumaster(Fany Full)" <1730976608@qq.com> Date: Tue, 15 Oct 2024 01:03:16 +0800 Subject: [PATCH 0736/2393] IME: Fixup IME popup candidate windows position when scale is not 1.0 (#8117) --- src/managers/input/InputMethodPopup.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index a8757030..cf48f2a5 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -100,14 +100,14 @@ void CInputPopup::updateBox() { cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h}; } - Vector2D currentPopupSize = surface->getViewporterCorrectedSize(); + Vector2D currentPopupSize = surface->getViewporterCorrectedSize() / surface->resource()->current.scale; CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); Vector2D popupOffset(0, 0); if (parentBox.y + cursorBoxParent.y + cursorBoxParent.height + currentPopupSize.y > pMonitor->vecPosition.y + pMonitor->vecSize.y) - popupOffset.y = -currentPopupSize.y; + popupOffset.y -= currentPopupSize.y; else popupOffset.y = cursorBoxParent.height; From 01c2ff34ddcb5995409c33c2b549e93b98b56d6b Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 14 Oct 2024 18:31:17 +0000 Subject: [PATCH 0737/2393] layout: simplify the conditions to autogroup (#8120) --- src/layout/IHyprLayout.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 80c9abff..fa3f8b8d 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -191,14 +191,12 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { denied = true; if (*PAUTOGROUP // check if auto_group is enabled. - && OPENINGON // check if OPENINGON exists. - && OPENINGON != pWindow // fixes a freeze when activating togglefloat to transform a floating group into a tiled group. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. - && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group a new window that should be floated. - && !denied) { // don't group a new floated window into a tiled group. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // fixes the popups of XWayland programs running in a floating group. + && !denied) { // don't group a new floated window into a tiled group (for convenience). - pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state + pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group. static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); From ace803948aaed6328342ea57e81adc1a01236c71 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 16 Oct 2024 09:59:47 +0000 Subject: [PATCH 0738/2393] layout: enable group rules for new floating windows (#8122) * layout: enable group rules for new floating windows * fix comment * do not apply group rules to a new floating window if it shouldBeFloated. fixes child windows * comment --- src/layout/IHyprLayout.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index fa3f8b8d..892ed12c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -82,6 +82,8 @@ void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) { } void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { + if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows + pWindow->applyGroupRules(); CBox desiredGeometry = {0}; g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); @@ -193,7 +195,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { if (*PAUTOGROUP // check if auto_group is enabled. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. - && !g_pXWaylandManager->shouldBeFloated(pWindow) // fixes the popups of XWayland programs running in a floating group. + && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. && !denied) { // don't group a new floated window into a tiled group (for convenience). pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group. From 0baf166d39260c6d1d422cf528fb5fedc3010cdb Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 16 Oct 2024 10:01:31 +0000 Subject: [PATCH 0739/2393] [gha] Nix: update inputs --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index de9a4dce..0a12fe0a 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1728326504, - "narHash": "sha256-dQXAj+4d6neY7ldCiH6gNym3upP49PVxRzEPxXlD9Aw=", + "lastModified": 1728902391, + "narHash": "sha256-44bnoY0nAvbBQ/lVjmn511yL39Sv7SknV0BDxn34P3Q=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "65dd97b5d21e917295159bbef1d52e06963f4eb0", + "rev": "9874e08eec85b5542ca22494e127b0cdce46b786", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1727821604, - "narHash": "sha256-hNw5J6xatedqytYowx0mJKgctjA4lQARZFdgnzM2RpM=", + "lastModified": 1728669738, + "narHash": "sha256-EDNAU9AYcx8OupUzbTbWE1d3HYdeG0wO6Msg3iL1muk=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "d60e1e01e6e6633ef1c87148b9137cc1dd39263d", + "rev": "0264e698149fcb857a66a53018157b41f8d97bb0", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1727300645, - "narHash": "sha256-OvAtVLaSRPnbXzOwlR1fVqCXR7i+ICRX3aPMCdIiv+c=", + "lastModified": 1728941256, + "narHash": "sha256-WRypmcZ2Bw94lLmcmxYokVOHPJSZ7T06V49QZ4tkZeQ=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "3f5293432b6dc6a99f26aca2eba3876d2660665c", + "rev": "fd4be8b9ca932f7384e454bcd923c5451ef2aa85", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728018373, - "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", + "lastModified": 1728888510, + "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", + "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1728092656, - "narHash": "sha256-eMeCTJZ5xBeQ0f9Os7K8DThNVSo9gy4umZLDfF5q6OM=", + "lastModified": 1728778939, + "narHash": "sha256-WybK5E3hpGxtCYtBwpRj1E9JoiVxe+8kX83snTNaFHE=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "1211305a5b237771e13fcca0c51e60ad47326a9a", + "rev": "ff68f91754be6f3427e4986d7949e6273659be1d", "type": "github" }, "original": { From 781828a56e495439bfe9c0a701cb29f5e4e2df24 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 16 Oct 2024 21:59:29 +0100 Subject: [PATCH 0740/2393] output: send enter events on late wl_output binds fixes #6560 --- src/protocols/core/Compositor.cpp | 6 ++++++ src/protocols/core/Compositor.hpp | 2 ++ src/protocols/core/Output.cpp | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 37a4bdf1..3d4b63c1 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -589,3 +589,9 @@ void CWLCompositorProtocol::destroyResource(CWLSurfaceResource* resource) { void CWLCompositorProtocol::destroyResource(CWLRegionResource* resource) { std::erase_if(m_vRegions, [&](const auto& other) { return other.get() == resource; }); } + +void CWLCompositorProtocol::forEachSurface(std::function)> fn) { + for (auto& surf : m_vSurfaces) { + fn(surf); + } +} diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index dc1c851f..b3c067c9 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -169,6 +169,8 @@ class CWLCompositorProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void forEachSurface(std::function)> fn); + struct { CSignal newSurface; // SP } events; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 3e68937f..e9f35abc 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -1,4 +1,6 @@ #include "Output.hpp" +#include "Compositor.hpp" +#include "../../Compositor.hpp" #include "../../helpers/Monitor.hpp" CWLOutputResource::CWLOutputResource(SP resource_, SP pMonitor) : monitor(pMonitor), resource(resource_) { @@ -27,6 +29,25 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni } updateState(); + + PROTO::compositor->forEachSurface([](SP surf) { + auto HLSurf = CWLSurface::fromResource(surf); + + if (!HLSurf) + return; + + const auto GEOMETRY = HLSurf->getSurfaceBoxGlobal(); + + if (!GEOMETRY.has_value()) + return; + + for (auto& m : g_pCompositor->m_vMonitors) { + if (!m->logicalBox().overlaps(*GEOMETRY)) + continue; + + surf->enter(m); + } + }); } SP CWLOutputResource::fromResource(wl_resource* res) { From 86e9f69a69990feb880dadd0c2b8c067b2a96fa9 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 16 Oct 2024 21:13:35 +0000 Subject: [PATCH 0741/2393] layout: move applyGroupRules() to onWindowCreated() (#8139) --- src/layout/DwindleLayout.cpp | 4 ---- src/layout/IHyprLayout.cpp | 7 ++++--- src/layout/MasterLayout.cpp | 2 -- src/render/decorations/CHyprGroupBarDecoration.cpp | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 76b26af1..8a7426eb 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -308,8 +308,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir applyNodeDataToWindow(PNODE); - pWindow->applyGroupRules(); - return; } @@ -450,8 +448,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); recalculateMonitor(pWindow->m_iMonitorID); - - pWindow->applyGroupRules(); } void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 892ed12c..b8d92636 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -20,6 +20,9 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { pWindow->m_vPseudoSize = pWindow->m_vLastFloatingSize; + if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows + pWindow->applyGroupRules(); + bool autoGrouped = IHyprLayout::onWindowCreatedAutoGroup(pWindow); if (autoGrouped) return; @@ -82,8 +85,6 @@ void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) { } void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { - if (!g_pXWaylandManager->shouldBeFloated(pWindow)) // do not apply group rules to child windows - pWindow->applyGroupRules(); CBox desiredGeometry = {0}; g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); @@ -194,6 +195,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { if (*PAUTOGROUP // check if auto_group is enabled. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. + && OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. && !denied) { // don't group a new floated window into a tiled group (for convenience). @@ -204,7 +206,6 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { (*USECURRPOS ? OPENINGON : OPENINGON->getGroupTail())->insertWindowToGroup(pWindow); OPENINGON->setGroupCurrent(pWindow); - pWindow->applyGroupRules(); pWindow->updateWindowDecos(); recalculateWindow(pWindow); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 8fde960d..f983770b 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -116,8 +116,6 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire return; } - pWindow->applyGroupRules(); - static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index eca3f2cb..74a1e2e9 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -466,7 +466,6 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND std::swap(pDraggedHead->m_sGroupData.head, pWindowInsertEnd->m_sGroupData.head); m_pWindow->setGroupCurrent(pDraggedWindow); - pDraggedWindow->applyGroupRules(); pDraggedWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); From 09581d32fd465c5c4ff868090369ee67516c38a9 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Wed, 16 Oct 2024 16:13:59 -0500 Subject: [PATCH 0742/2393] hyprpm: Fix crashes due to misplaced fmt argument(s) (#8140) --- hyprpm/src/core/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 359b2c78..57c67641 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -697,7 +697,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { " This likely means that the plugin is either outdated, not yet available for your version, or broken.\n" "If you are on -git, update first.\n" "Try re-running with -v to see more verbose output.", - failureString("Plugin {} failed to build.")); + failureString("Plugin {} failed to build.", p.name)); p.failed = true; continue; } @@ -839,7 +839,7 @@ ePluginLoadStateReturn CPluginManager::ensurePluginsLoadState() { continue; loadUnloadPlugin(HYPRPMPATH + repoForName(p.name) + "/" + p.filename, true); - std::println("{}", successString("Loaded {}"), p.name); + std::println("{}", successString("Loaded {}", p.name)); } } From b57086aa4362117c1f1025246f618d760e44b026 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 16 Oct 2024 22:22:36 +0100 Subject: [PATCH 0743/2393] window: properly break cycles in X11TransientFor ref #8045 --- src/desktop/Window.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index fa85dc07..a393f361 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -451,15 +451,21 @@ PHLWINDOW CWindow::X11TransientFor() { if (!m_pXWaylandSurface || !m_pXWaylandSurface->parent) return nullptr; - auto s = m_pXWaylandSurface->parent; - auto oldParent = s; + auto s = m_pXWaylandSurface->parent; + std::vector> visited; while (s) { - // break cyclic loop of m_pXWaylandSurface being parent of itself, #TODO reject this from even being created? - if (!s->parent || s->parent == oldParent) + // break loops. Some X apps make them, and it seems like it's valid behavior?!?!?! + // TODO: we should reject loops being created in the first place. + if (std::find(visited.begin(), visited.end(), s) != visited.end()) break; + + visited.emplace_back(s.lock()); s = s->parent; } + if (s == m_pXWaylandSurface) + return nullptr; // dead-ass circle + for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pXWaylandSurface != s) continue; From 495b92fb535f51a38e5130e6b89bd1fb01ce8cfb Mon Sep 17 00:00:00 2001 From: Behzad Date: Thu, 17 Oct 2024 17:50:18 +0330 Subject: [PATCH 0744/2393] makefile: fix typo (#8127) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 59efc0ef..98267eea 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PREFIX = /usr/local legacyrenderer: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./buildZ + cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` legacyrendererdebug: From 5f30cb7753266316b85a460c6266995678187294 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Thu, 17 Oct 2024 20:03:17 +0000 Subject: [PATCH 0745/2393] windowrules: allow specifying max size in size window rule (#8021) * allow specifying max size in size window rule modified: src/events/Windows.cpp * clean up modified: src/events/Windows.cpp --- src/events/Windows.cpp | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e549907e..d2d5bebf 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -330,24 +330,38 @@ void Events::listener_mapWindow(void* owner, void* data) { for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("size")) { try { - const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); - const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); - const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) { + auto stringToPercentage = [](const std::string& VALUE, const float REL) { + if (VALUE.ends_with('%')) + return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100; + else + return std::stof(VALUE); + }; - const auto SIZEX = SIZEXSTR == "max" ? - std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : - (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x); - const auto SIZEY = SIZEYSTR == "max" ? - std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : - (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y); + if (VALUE.starts_with('<')) + return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL)); + else if (VALUE.starts_with('>')) + return std::max(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL)); + + return stringToPercentage(VALUE, REL); + }; + + const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); + const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); + const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); + + const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + + const float SIZEX = + SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); + + const float SIZEY = + SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size, applying to {}", PWINDOW); - PWINDOW->m_vRealSize = Vector2D(SIZEX, SIZEY); - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal(); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); + PWINDOW->clampWindowSize(Vector2D{SIZEXSTR.starts_with("<") ? 0 : SIZEX, SIZEYSTR.starts_with("<") ? 0 : SIZEY}, Vector2D{SIZEX, SIZEY}); PWINDOW->setHidden(false); } catch (...) { Debug::log(LOG, "Rule size failed, rule: {} -> {}", r.szRule, r.szValue); } From 0e630e9e74ad34683194a07cfe6afe55a2c0685f Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 17 Oct 2024 20:05:55 +0000 Subject: [PATCH 0746/2393] session-lock: reset seat grab on a new session lock (#8147) --- src/managers/SessionLockManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 260a3992..4e05695a 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "../protocols/FractionalScale.hpp" #include "../protocols/SessionLock.hpp" +#include "../managers/SeatManager.hpp" #include #include @@ -84,6 +85,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { }); g_pCompositor->focusSurface(nullptr); + g_pSeatManager->setGrab(nullptr); } bool CSessionLockManager::isSessionLocked() { From e5d3a71263187feec6c2249b3f7b74de0a71f47c Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 19 Oct 2024 14:49:56 +0000 Subject: [PATCH 0747/2393] config: fix generateConfig loop (#8164) * config: fix generateConfig loop * config: cleanup getMainConfigPath --- src/config/ConfigManager.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6ec63d4c..432b7faf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -688,14 +688,13 @@ std::string CConfigManager::getMainConfigPath() { if (const auto CFG_ENV = getenv("HYPRLAND_CONFIG"); CFG_ENV) return CFG_ENV; - Debug::log(TRACE, "Seems as if HYPRLAND_CONFIG isn't set, let's see what we can do with HOME."); - static const auto paths = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); - if (paths.first.has_value()) { - return paths.first.value(); - } else if (paths.second.has_value()) { - auto configPath = Hyprutils::Path::fullConfigPath(paths.second.value(), ISDEBUG ? "hyprlandd" : "hyprland"); - return generateConfig(configPath).value(); + const auto PATHS = Hyprutils::Path::findConfig(ISDEBUG ? "hyprlandd" : "hyprland"); + if (PATHS.first.has_value()) { + return PATHS.first.value(); + } else if (PATHS.second.has_value()) { + const auto CONFIGPATH = Hyprutils::Path::fullConfigPath(PATHS.second.value(), ISDEBUG ? "hyprlandd" : "hyprland"); + return generateConfig(CONFIGPATH).value(); } else throw std::runtime_error("Neither HOME nor XDG_CONFIG_HOME are set in the environment. Could not find config in XDG_CONFIG_DIRS or /etc/xdg."); } From 904f9b6aee6a4524fba554f76b32747f85f0609d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 16:09:39 +0100 Subject: [PATCH 0748/2393] foreign-toplevel: don't send updates to X11 OR windows --- src/protocols/ForeignToplevel.cpp | 29 ++++++++++++++++++++++++----- src/protocols/ForeignToplevel.hpp | 1 + 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 1f8cbcbe..38bb5e69 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -31,8 +31,8 @@ CForeignToplevelList::CForeignToplevelList(SP resourc }); for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->m_bFadingOut) - continue; + if (!PROTO::foreignToplevel->windowValidForForeign(w)) + return; onMap(w); } @@ -112,20 +112,35 @@ bool CForeignToplevelList::good() { CForeignToplevelProtocol::CForeignToplevelProtocol(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) { + auto window = std::any_cast(data); + + if (!windowValidForForeign(window)) + return; + for (auto const& m : m_vManagers) { - m->onMap(std::any_cast(data)); + m->onMap(window); } }); static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { + auto window = std::any_cast(data); + + if (!windowValidForForeign(window)) + return; + for (auto const& m : m_vManagers) { - m->onUnmap(std::any_cast(data)); + m->onUnmap(window); } }); static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { + auto window = std::any_cast(data); + + if (!windowValidForForeign(window)) + return; + for (auto const& m : m_vManagers) { - m->onTitle(std::any_cast(data)); + m->onTitle(window); } }); } @@ -148,3 +163,7 @@ void CForeignToplevelProtocol::onManagerResourceDestroy(CForeignToplevelList* mg void CForeignToplevelProtocol::destroyHandle(CForeignToplevelHandle* handle) { std::erase_if(m_vHandles, [&](const auto& other) { return other.get() == handle; }); } + +bool CForeignToplevelProtocol::windowValidForForeign(PHLWINDOW pWindow) { + return validMapped(pWindow) && !pWindow->isX11OverrideRedirect(); +} diff --git a/src/protocols/ForeignToplevel.hpp b/src/protocols/ForeignToplevel.hpp index d95db41f..076bfd7c 100644 --- a/src/protocols/ForeignToplevel.hpp +++ b/src/protocols/ForeignToplevel.hpp @@ -50,6 +50,7 @@ class CForeignToplevelProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(CForeignToplevelList* mgr); void destroyHandle(CForeignToplevelHandle* handle); + bool windowValidForForeign(PHLWINDOW pWindow); // std::vector> m_vManagers; From 48bf32c5de5628a4a17387375ea997f738a4f807 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 16:09:46 +0100 Subject: [PATCH 0749/2393] foreign-toplevel-wlr: don't send updates to X11 OR windows --- src/protocols/ForeignToplevelWlr.cpp | 26 +++++++++++++++++++++++++- src/protocols/ForeignToplevelWlr.hpp | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 291969db..1163a5e7 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -180,7 +180,7 @@ CForeignToplevelWlrManager::CForeignToplevelWlrManager(SPm_vWindows) { - if (!w->m_bIsMapped || w->m_bFadingOut) + if (!PROTO::foreignToplevelWlr->windowValidForForeign(w)) continue; onMap(w); @@ -313,6 +313,10 @@ bool CForeignToplevelWlrManager::good() { 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); + + if (!windowValidForForeign(PWINDOW)) + return; + for (auto const& m : m_vManagers) { m->onMap(PWINDOW); } @@ -320,6 +324,10 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); + + if (!windowValidForForeign(PWINDOW)) + return; + for (auto const& m : m_vManagers) { m->onUnmap(PWINDOW); } @@ -327,6 +335,10 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); + + if (!windowValidForForeign(PWINDOW)) + return; + for (auto const& m : m_vManagers) { m->onTitle(PWINDOW); } @@ -334,6 +346,10 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa static auto P3 = g_pHookSystem->hookDynamic("activeWindow", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); + + if (!windowValidForForeign(PWINDOW)) + return; + for (auto const& m : m_vManagers) { m->onNewFocus(PWINDOW); } @@ -348,6 +364,10 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa static auto P5 = g_pHookSystem->hookDynamic("fullscreen", [this](void* self, SCallbackInfo& info, std::any data) { const auto PWINDOW = std::any_cast(data); + + if (!windowValidForForeign(PWINDOW)) + return; + for (auto const& m : m_vManagers) { m->onFullscreen(PWINDOW); } @@ -383,3 +403,7 @@ PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res return nullptr; } + +bool CForeignToplevelWlrProtocol::windowValidForForeign(PHLWINDOW pWindow) { + return validMapped(pWindow) && !pWindow->isX11OverrideRedirect(); +} diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp index 99f63b47..e726707d 100644 --- a/src/protocols/ForeignToplevelWlr.hpp +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -63,6 +63,7 @@ class CForeignToplevelWlrProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(CForeignToplevelWlrManager* mgr); void destroyHandle(CForeignToplevelHandleWlr* handle); + bool windowValidForForeign(PHLWINDOW pWindow); // std::vector> m_vManagers; From 62ee5cc2739d70570dbe143c9bd75d00a51db942 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 16:21:47 +0100 Subject: [PATCH 0750/2393] monitor: modernize/refactor last legacy-handled events --- src/Compositor.cpp | 2 +- src/events/Events.hpp | 8 --- src/events/Monitors.cpp | 105 ---------------------------------------- src/helpers/Monitor.cpp | 74 +++++++++++++++++++++++++++- src/helpers/Monitor.hpp | 1 + 5 files changed, 74 insertions(+), 116 deletions(-) delete mode 100644 src/events/Monitors.cpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index fd4979b0..ca27f17a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3057,5 +3057,5 @@ void CCompositor::onNewMonitor(SP output) { } g_pHyprRenderer->damageMonitor(PNEWMONITOR.get()); - Events::listener_monitorFrame(PNEWMONITOR.get(), nullptr); + PNEWMONITOR->onMonitorFrame(); } diff --git a/src/events/Events.hpp b/src/events/Events.hpp index 0af16f64..84565979 100644 --- a/src/events/Events.hpp +++ b/src/events/Events.hpp @@ -24,12 +24,4 @@ namespace Events { DYNLISTENFUNC(requestMaximize); DYNLISTENFUNC(setOverrideRedirect); DYNLISTENFUNC(ackConfigure); - - // Monitor part 2 the sequel - DYNLISTENFUNC(monitorFrame); - DYNLISTENFUNC(monitorStateRequest); - DYNLISTENFUNC(monitorDamage); - DYNLISTENFUNC(monitorNeedsFrame); - DYNLISTENFUNC(monitorCommit); - DYNLISTENFUNC(monitorBind); }; diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp deleted file mode 100644 index 9d2210f6..00000000 --- a/src/events/Monitors.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "../Compositor.hpp" -#include "../helpers/WLClasses.hpp" -#include "../managers/input/InputManager.hpp" -#include "../render/Renderer.hpp" -#include "Events.hpp" -#include "../debug/HyprCtl.hpp" -#include "../config/ConfigValue.hpp" -#include "../protocols/Screencopy.hpp" -#include "../protocols/ToplevelExport.hpp" -#include - -// --------------------------------------------------------- // -// __ __ ____ _ _ _____ _______ ____ _____ _____ // -// | \/ |/ __ \| \ | |_ _|__ __/ __ \| __ \ / ____| // -// | \ / | | | | \| | | | | | | | | | |__) | (___ // -// | |\/| | | | | . ` | | | | | | | | | _ / \___ \ // -// | | | | |__| | |\ |_| |_ | | | |__| | | \ \ ____) | // -// |_| |_|\____/|_| \_|_____| |_| \____/|_| \_\_____/ // -// // -// --------------------------------------------------------- // - -void Events::listener_monitorFrame(void* owner, void* data) { - CMonitor* const PMONITOR = (CMonitor*)owner; - - if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { - Debug::log(WARN, "Attempted to render frame on inactive session!"); - - if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { - return m->output != g_pCompositor->m_pUnsafeOutput->output; - })) { - // restore from unsafe state - g_pCompositor->leaveUnsafeState(); - } - - return; // cannot draw on session inactive (different tty) - } - - if (!PMONITOR->m_bEnabled) - return; - - g_pHyprRenderer->recheckSolitaryForMonitor(PMONITOR); - - PMONITOR->tearingState.busy = false; - - if (PMONITOR->tearingState.activelyTearing && PMONITOR->solitaryClient.lock() /* can be invalidated by a recheck */) { - - if (!PMONITOR->tearingState.frameScheduledWhileBusy) - return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render? - - PMONITOR->tearingState.nextRenderTorn = true; - PMONITOR->tearingState.frameScheduledWhileBusy = false; - } - - static auto PENABLERAT = CConfigValue("misc:render_ahead_of_time"); - static auto PRATSAFE = CConfigValue("misc:render_ahead_safezone"); - - PMONITOR->lastPresentationTimer.reset(); - - if (*PENABLERAT && !PMONITOR->tearingState.nextRenderTorn) { - if (!PMONITOR->RATScheduled) { - // render - g_pHyprRenderer->renderMonitor(PMONITOR); - } - - PMONITOR->RATScheduled = false; - - const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR); - - if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate) - return; - - const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis(); - - PMONITOR->RATScheduled = true; - - const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE); - const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME); - - if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1) - g_pHyprRenderer->renderMonitor(PMONITOR); - else - wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP); - } else { - g_pHyprRenderer->renderMonitor(PMONITOR); - } -} - -void Events::listener_monitorNeedsFrame(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - - g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); -} - -void Events::listener_monitorCommit(void* owner, void* data) { - const auto PMONITOR = (CMonitor*)owner; - - if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER - PROTO::screencopy->onOutputCommit(PMONITOR); - PROTO::toplevelExport->onOutputCommit(PMONITOR); - } -} - -void Events::listener_monitorBind(void* owner, void* data) { - ; -} diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 091745df..74471f62 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -11,6 +11,8 @@ #include "../protocols/DRMLease.hpp" #include "../protocols/DRMSyncobj.hpp" #include "../protocols/core/Output.hpp" +#include "../protocols/Screencopy.hpp" +#include "../protocols/ToplevelExport.hpp" #include "../managers/PointerManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../protocols/core/Compositor.hpp" @@ -44,8 +46,13 @@ void CMonitor::onConnect(bool noRule) { outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); } - listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); }); - listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); }); + listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); }); + listeners.commit = output->events.commit.registerListener([this](std::any d) { + if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER + PROTO::screencopy->onOutputCommit(this); + PROTO::toplevelExport->onOutputCommit(this); + } + }); listeners.needsFrame = output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); @@ -939,6 +946,69 @@ void CMonitor::debugLastPresentation(const std::string& message) { lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f); } +void CMonitor::onMonitorFrame() { + if ((g_pCompositor->m_pAqBackend->hasSession() && !g_pCompositor->m_pAqBackend->session->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { + Debug::log(WARN, "Attempted to render frame on inactive session!"); + + if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) { + return m->output != g_pCompositor->m_pUnsafeOutput->output; + })) { + // restore from unsafe state + g_pCompositor->leaveUnsafeState(); + } + + return; // cannot draw on session inactive (different tty) + } + + if (!m_bEnabled) + return; + + g_pHyprRenderer->recheckSolitaryForMonitor(this); + + tearingState.busy = false; + + if (tearingState.activelyTearing && solitaryClient.lock() /* can be invalidated by a recheck */) { + + if (!tearingState.frameScheduledWhileBusy) + return; // we did not schedule a frame yet to be displayed, but we are tearing. Why render? + + tearingState.nextRenderTorn = true; + tearingState.frameScheduledWhileBusy = false; + } + + static auto PENABLERAT = CConfigValue("misc:render_ahead_of_time"); + static auto PRATSAFE = CConfigValue("misc:render_ahead_safezone"); + + lastPresentationTimer.reset(); + + if (*PENABLERAT && !tearingState.nextRenderTorn) { + if (!RATScheduled) { + // render + g_pHyprRenderer->renderMonitor(this); + } + + RATScheduled = false; + + const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(this); + + if (max + *PRATSAFE > 1000.0 / refreshRate) + return; + + const auto MSLEFT = 1000.0 / refreshRate - lastPresentationTimer.getMillis(); + + RATScheduled = true; + + const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE); + const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME); + + if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1) + g_pHyprRenderer->renderMonitor(this); + else + wl_event_source_timer_update(renderTimer, TIMETOSLEEP); + } else + g_pHyprRenderer->renderMonitor(this); +} + CMonitorState::CMonitorState(CMonitor* owner) { m_pOwner = owner; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index ad8a823b..ceb90232 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -186,6 +186,7 @@ class CMonitor { void setCTM(const Mat3x3& ctm); void debugLastPresentation(const std::string& message); + void onMonitorFrame(); bool m_bEnabled = false; bool m_bRenderingInitPassed = false; From 0eaf3581a340f2521d96fe46d7956913c72d7698 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 16:24:03 +0100 Subject: [PATCH 0751/2393] window: guard PMONITOR in commit listener ref #8170 --- src/events/Windows.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index d2d5bebf..37e5406c 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -775,7 +775,9 @@ void Events::listener_commitWindow(void* owner, void* data) { const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); - PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); + if (PMONITOR) + PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); + if (g_pSeatManager->isPointerFrameCommit) { g_pSeatManager->isPointerFrameSkipped = false; g_pSeatManager->isPointerFrameCommit = false; From ce3ba798df6bca5be1da4396644a9ef08a2acab4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 17:03:22 +0100 Subject: [PATCH 0752/2393] defaultConfig: improve smart gaps --- example/hyprland.conf | 14 ++++++++++---- src/config/defaultConfig.hpp | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 6d7bddb8..012446f3 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -119,10 +119,16 @@ animations { # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ # "Smart gaps" / "No gaps when only" -# uncomment all three if you wish to use that. -# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 -# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 -# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 +# uncomment all if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0 +# workspace = w[tg1], gapsout:0, gapsin:0 +# workspace = f[1], gapsout:0, gapsin:0 +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] +# windowrulev2 = rounding 0, floating:0, onworkspace:f[1] # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 5c8b0e68..a5d759de 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -132,10 +132,16 @@ animations { # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ # "Smart gaps" / "No gaps when only" -# uncomment all three if you wish to use that. -# workspace = w[t1], gapsout:0, gapsin:0, border: 0, rounding:0 -# workspace = w[tg1], gapsout:0, gapsin:0, border: 0, rounding:0 -# workspace = f[1], gapsout:0, gapsin:0, border: 0, rounding:0 +# uncomment all if you wish to use that. +# workspace = w[t1], gapsout:0, gapsin:0 +# workspace = w[tg1], gapsout:0, gapsin:0 +# workspace = f[1], gapsout:0, gapsin:0 +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] +# windowrulev2 = rounding 0, floating:0, onworkspace:f[1] # See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more dwindle { From f044e4c9514ec89c4c1fc8a523ca90b8cb907fb7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sat, 19 Oct 2024 23:03:29 +0100 Subject: [PATCH 0753/2393] internal: Move CMonitor to SP (#8178) * move monitors to sp * XD --- src/Compositor.cpp | 112 ++++++++--------- src/Compositor.hpp | 36 +++--- src/config/ConfigManager.cpp | 16 +-- src/config/ConfigManager.hpp | 4 +- src/debug/HyprCtl.cpp | 10 +- src/debug/HyprDebugOverlay.cpp | 18 +-- src/debug/HyprDebugOverlay.hpp | 24 ++-- src/debug/HyprNotificationOverlay.cpp | 6 +- src/debug/HyprNotificationOverlay.hpp | 8 +- src/desktop/DesktopTypes.hpp | 6 + src/desktop/LayerSurface.cpp | 6 +- src/desktop/Window.cpp | 2 +- src/desktop/Window.hpp | 2 +- src/events/Windows.cpp | 6 +- src/helpers/Monitor.cpp | 114 +++++++++--------- src/helpers/Monitor.hpp | 6 +- src/helpers/WLClasses.hpp | 20 +-- src/hyprerror/HyprError.cpp | 4 +- src/layout/DwindleLayout.cpp | 7 +- src/layout/MasterLayout.cpp | 7 +- src/managers/AnimationManager.cpp | 2 +- src/managers/CursorManager.cpp | 2 +- src/managers/KeybindManager.cpp | 16 +-- src/managers/KeybindManager.hpp | 2 +- src/managers/PointerManager.cpp | 34 ++---- src/managers/PointerManager.hpp | 2 - src/managers/ProtocolManager.cpp | 6 +- src/managers/ProtocolManager.hpp | 2 +- src/managers/SessionLockManager.cpp | 4 +- src/managers/XWaylandManager.cpp | 4 +- src/managers/input/InputManager.cpp | 10 +- src/managers/input/InputManager.hpp | 2 +- src/managers/input/InputMethodPopup.cpp | 6 +- src/managers/input/Swipe.cpp | 10 +- src/managers/input/Touch.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 4 +- src/protocols/ForeignToplevelWlr.hpp | 2 +- src/protocols/GammaControl.cpp | 8 +- src/protocols/GammaControl.hpp | 10 +- src/protocols/LayerShell.cpp | 6 +- src/protocols/LayerShell.hpp | 2 +- src/protocols/LinuxDMABUF.cpp | 4 +- src/protocols/OutputManagement.cpp | 22 ++-- src/protocols/OutputManagement.hpp | 24 ++-- src/protocols/OutputPower.cpp | 6 +- src/protocols/OutputPower.hpp | 4 +- src/protocols/PresentationTime.cpp | 4 +- src/protocols/Screencopy.cpp | 16 +-- src/protocols/Screencopy.hpp | 6 +- src/protocols/SessionLock.cpp | 8 +- src/protocols/SessionLock.hpp | 6 +- src/protocols/ToplevelExport.cpp | 2 +- src/protocols/ToplevelExport.hpp | 2 +- src/protocols/core/DataDevice.cpp | 2 +- src/protocols/core/DataDevice.hpp | 2 +- src/render/OpenGL.cpp | 22 ++-- src/render/OpenGL.hpp | 54 ++++----- src/render/Renderer.cpp | 62 +++++----- src/render/Renderer.hpp | 56 ++++----- .../decorations/CHyprBorderDecoration.cpp | 4 +- .../decorations/CHyprBorderDecoration.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 4 +- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.hpp | 2 +- .../decorations/IHyprWindowDecoration.hpp | 2 +- 66 files changed, 424 insertions(+), 446 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ca27f17a..b23b3194 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -412,8 +412,8 @@ void CCompositor::initAllSignals() { m_bSessionActive = true; for (auto const& m : m_vMonitors) { - scheduleFrameForMonitor(m.get()); - g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true); + scheduleFrameForMonitor(m); + g_pHyprRenderer->applyMonitorRule(m, &m->activeMonitorRule, true); } g_pConfigManager->m_bWantsMonitorReload = true; @@ -498,7 +498,7 @@ void CCompositor::cleanup() { m_vWindows.clear(); for (auto const& m : m_vMonitors) { - g_pHyprOpenGL->destroyMonitorResources(m.get()); + g_pHyprOpenGL->destroyMonitorResources(m); m->output->state->setEnabled(false); m->state.commit(); @@ -717,38 +717,38 @@ void CCompositor::startCompositor() { g_pEventLoopManager->enterLoop(); } -CMonitor* CCompositor::getMonitorFromID(const MONITORID& id) { +PHLMONITOR CCompositor::getMonitorFromID(const MONITORID& id) { for (auto const& m : m_vMonitors) { if (m->ID == id) { - return m.get(); + return m; } } return nullptr; } -CMonitor* CCompositor::getMonitorFromName(const std::string& name) { +PHLMONITOR CCompositor::getMonitorFromName(const std::string& name) { for (auto const& m : m_vMonitors) { if (m->szName == name) { - return m.get(); + return m; } } return nullptr; } -CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) { +PHLMONITOR CCompositor::getMonitorFromDesc(const std::string& desc) { for (auto const& m : m_vMonitors) { if (m->szDescription.starts_with(desc)) - return m.get(); + return m; } return nullptr; } -CMonitor* CCompositor::getMonitorFromCursor() { +PHLMONITOR CCompositor::getMonitorFromCursor() { return getMonitorFromVector(g_pPointerManager->position()); } -CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { +PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) { SP mon; for (auto const& m : m_vMonitors) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { @@ -772,13 +772,13 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) { if (!pBestMon) { // ????? Debug::log(WARN, "getMonitorFromVector no close mon???"); - return m_vMonitors.front().get(); + return m_vMonitors.front(); } - return pBestMon.get(); + return pBestMon; } - return mon.get(); + return mon; } void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { @@ -790,9 +790,9 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { } } -bool CCompositor::monitorExists(CMonitor* pMonitor) { +bool CCompositor::monitorExists(PHLMONITOR pMonitor) { for (auto const& m : m_vRealMonitors) { - if (m.get() == pMonitor) + if (m == pMonitor) return true; } @@ -982,20 +982,20 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } -CMonitor* CCompositor::getMonitorFromOutput(SP out) { +PHLMONITOR CCompositor::getMonitorFromOutput(SP out) { for (auto const& m : m_vMonitors) { if (m->output == out) { - return m.get(); + return m; } } return nullptr; } -CMonitor* CCompositor::getRealMonitorFromOutput(SP out) { +PHLMONITOR CCompositor::getRealMonitorFromOutput(SP out) { for (auto const& m : m_vRealMonitors) { if (m->output == out) { - return m.get(); + return m; } } @@ -1183,7 +1183,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo SURF->constraint()->activate(); } -SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, CMonitor* monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { +SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) { if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) @@ -1779,7 +1779,7 @@ bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { return false; } -bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* pMonitor) { +bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR pMonitor) { const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector(point); const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; @@ -1788,11 +1788,11 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const CMonitor* p return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); } -CMonitor* CCompositor::getMonitorInDirection(const char& dir) { - return this->getMonitorInDirection(m_pLastMonitor.get(), dir); +PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) { + return getMonitorInDirection(m_pLastMonitor.lock(), dir); } -CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) { +PHLMONITOR CCompositor::getMonitorInDirection(PHLMONITOR pSourceMonitor, const char& dir) { if (!pSourceMonitor) return nullptr; @@ -1800,7 +1800,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha const auto SIZEA = pSourceMonitor->vecSize; auto longestIntersect = -1; - CMonitor* longestIntersectMonitor = nullptr; + PHLMONITOR longestIntersectMonitor = nullptr; for (auto const& m : m_vMonitors) { if (m == m_pLastMonitor) @@ -1814,7 +1814,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = m.get(); + longestIntersectMonitor = m; } } break; @@ -1823,7 +1823,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha const auto INTERSECTLEN = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = m.get(); + longestIntersectMonitor = m; } } break; @@ -1833,7 +1833,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = m.get(); + longestIntersectMonitor = m; } } break; @@ -1843,7 +1843,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha const auto INTERSECTLEN = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x)); if (INTERSECTLEN > longestIntersect) { longestIntersect = INTERSECTLEN; - longestIntersectMonitor = m.get(); + longestIntersectMonitor = m; } } break; @@ -1990,7 +1990,7 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { return nextID; } -void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) { +void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) { const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace; @@ -2077,16 +2077,16 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB) EMIT_HOOK_EVENT("moveWorkspace", (std::vector{PWORKSPACEB, pMonitorA})); } -CMonitor* CCompositor::getMonitorFromString(const std::string& name) { +PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) { if (name == "current") - return g_pCompositor->m_pLastMonitor.get(); + return g_pCompositor->m_pLastMonitor.lock(); else if (isDirection(name)) return getMonitorInDirection(name[0]); else if (name[0] == '+' || name[0] == '-') { // relative if (m_vMonitors.size() == 1) - return m_vMonitors.begin()->get(); + return *m_vMonitors.begin(); const auto OFFSET = name[0] == '-' ? name : name.substr(1); @@ -2119,7 +2119,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { currentPlace = std::clamp(currentPlace, 0, (int)m_vMonitors.size() - 1); } - return m_vMonitors[currentPlace].get(); + return m_vMonitors[currentPlace]; } else if (isNumber(name)) { // change by ID MONITORID monID = MONITOR_INVALID; @@ -2143,7 +2143,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { continue; if (m->matchesStaticSelector(name)) { - return m.get(); + return m; } } } @@ -2151,7 +2151,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) { return nullptr; } -void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMonitor, bool noWarpCursor) { +void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) { // We trust the monitor to be correct. @@ -2226,7 +2226,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon } } - if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor.get()) { // if it was active, preserve its' status. If it wasn't, don't. + if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't. Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID); if (valid(pMonitor->activeWorkspace)) { @@ -2438,7 +2438,7 @@ void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { } } -void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) { +void CCompositor::scheduleFrameForMonitor(PHLMONITOR pMonitor, IOutput::scheduleFrameReason reason) { if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive) return; @@ -2555,7 +2555,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { if (*PNOWARPS && !force) { const auto PMONITORNEW = getMonitorFromVector(pos); - if (PMONITORNEW != m_pLastMonitor.get()) + if (PMONITORNEW != m_pLastMonitor) setActiveMonitor(PMONITORNEW); return; } @@ -2563,7 +2563,7 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) { g_pPointerManager->warpTo(pos); const auto PMONITORNEW = getMonitorFromVector(pos); - if (PMONITORNEW != m_pLastMonitor.get()) + if (PMONITORNEW != m_pLastMonitor) setActiveMonitor(PMONITORNEW); } @@ -2690,8 +2690,8 @@ void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name g_pEventManager->postEvent({"renameworkspace", std::to_string(PWORKSPACE->m_iID) + "," + PWORKSPACE->m_szName}); } -void CCompositor::setActiveMonitor(CMonitor* pMonitor) { - if (m_pLastMonitor.get() == pMonitor) +void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) { + if (m_pLastMonitor == pMonitor) return; if (!pMonitor) { @@ -2801,13 +2801,13 @@ PHLWINDOW CCompositor::getForceFocus() { } void CCompositor::arrangeMonitors() { - static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling"); + static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling"); - std::vector toArrange; - std::vector arranged; + std::vector toArrange; + std::vector arranged; for (auto const& m : m_vMonitors) - toArrange.push_back(m.get()); + toArrange.push_back(m); Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size()); @@ -2906,7 +2906,7 @@ void CCompositor::enterUnsafeState() { m_bUnsafeState = true; - setActiveMonitor(m_pUnsafeOutput); + setActiveMonitor(m_pUnsafeOutput.lock()); } void CCompositor::leaveUnsafeState() { @@ -2917,10 +2917,10 @@ void CCompositor::leaveUnsafeState() { m_bUnsafeState = false; - CMonitor* pNewMonitor = nullptr; + PHLMONITOR pNewMonitor = nullptr; for (auto const& pMonitor : m_vMonitors) { if (pMonitor->output != m_pUnsafeOutput->output) { - pNewMonitor = pMonitor.get(); + pNewMonitor = pMonitor; break; } } @@ -2931,7 +2931,7 @@ void CCompositor::leaveUnsafeState() { m_pUnsafeOutput->onDisconnect(); for (auto const& m : m_vMonitors) { - scheduleFrameForMonitor(m.get()); + scheduleFrameForMonitor(m); } } @@ -3007,7 +3007,7 @@ static void checkDefaultCursorWarp(SP monitor) { } // modechange happend check if cursor is on that monitor and warp it to middle to not place it out of bounds if resolution changed. - if (g_pCompositor->getMonitorFromCursor() == monitor.get()) { + if (g_pCompositor->getMonitorFromCursor() == monitor) { g_pCompositor->warpCursorTo(POS, true); g_pInputManager->refocus(); } @@ -3017,7 +3017,7 @@ void CCompositor::onNewMonitor(SP output) { // add it to real auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared(output)); if (std::string("HEADLESS-1") == output->name) { - g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get(); + g_pCompositor->m_pUnsafeOutput = PNEWMONITOR; output->name = "FALLBACK"; // we are allowed to do this :) } @@ -3040,12 +3040,12 @@ void CCompositor::onNewMonitor(SP output) { // ready to process if we have a real monitor if ((!g_pHyprRenderer->m_pMostHzMonitor || PNEWMONITOR->refreshRate > g_pHyprRenderer->m_pMostHzMonitor->refreshRate) && PNEWMONITOR->m_bEnabled) - g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get(); + g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR; g_pCompositor->m_bReadyToProcess = true; g_pConfigManager->m_bWantsMonitorReload = true; - g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get(), IOutput::AQ_SCHEDULE_NEW_MONITOR); + g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR, IOutput::AQ_SCHEDULE_NEW_MONITOR); checkDefaultCursorWarp(PNEWMONITOR); @@ -3056,6 +3056,6 @@ void CCompositor::onNewMonitor(SP output) { } } - g_pHyprRenderer->damageMonitor(PNEWMONITOR.get()); + g_pHyprRenderer->damageMonitor(PNEWMONITOR); PNEWMONITOR->onMonitorFrame(); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a57450f1..7fbd32e8 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -89,7 +89,7 @@ class CCompositor { bool m_bDPMSStateON = true; bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bNextIsUnsafe = false; - CMonitor* m_pUnsafeOutput = nullptr; // fallback output for the unsafe state + PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state bool m_bIsShuttingDown = false; bool m_bFinalRequests = false; bool m_bDesktopEnvSet = false; @@ -97,22 +97,22 @@ class CCompositor { // ------------------------------------------------- // - CMonitor* getMonitorFromID(const MONITORID&); - CMonitor* getMonitorFromName(const std::string&); - CMonitor* getMonitorFromDesc(const std::string&); - CMonitor* getMonitorFromCursor(); - CMonitor* getMonitorFromVector(const Vector2D&); + PHLMONITOR getMonitorFromID(const MONITORID&); + PHLMONITOR getMonitorFromName(const std::string&); + PHLMONITOR getMonitorFromDesc(const std::string&); + PHLMONITOR getMonitorFromCursor(); + PHLMONITOR getMonitorFromVector(const Vector2D&); void removeWindowFromVectorSafe(PHLWINDOW); void focusWindow(PHLWINDOW, SP pSurface = nullptr); void focusSurface(SP, PHLWINDOW pWindowOwner = nullptr); - bool monitorExists(CMonitor*); + bool monitorExists(PHLMONITOR); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); SP vectorToLayerSurface(const Vector2D&, std::vector*, Vector2D*, PHLLS*); - SP vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*); + SP vectorToLayerPopupSurface(const Vector2D&, PHLMONITOR monitor, Vector2D*, PHLLS*); SP vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl); Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP); - CMonitor* getMonitorFromOutput(SP); - CMonitor* getRealMonitorFromOutput(SP); + PHLMONITOR getMonitorFromOutput(SP); + PHLMONITOR getRealMonitorFromOutput(SP); PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); @@ -138,16 +138,16 @@ class CCompositor { PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); - bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr); - CMonitor* getMonitorInDirection(const char&); - CMonitor* getMonitorInDirection(CMonitor*, const char&); + bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); + PHLMONITOR getMonitorInDirection(const char&); + PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&); void updateAllWindowsAnimatedDecorationValues(); void updateWorkspaceWindows(const WORKSPACEID& id); void updateWindowAnimatedDecorationValues(PHLWINDOW); MONITORID getNextAvailableMonitorID(std::string const& name); - void moveWorkspaceToMonitor(PHLWORKSPACE, CMonitor*, bool noWarpCursor = false); - void swapActiveWorkspaces(CMonitor*, CMonitor*); - CMonitor* getMonitorFromString(const std::string&); + void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false); + void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR); + PHLMONITOR getMonitorFromString(const std::string&); bool workspaceIDOutOfBounds(const WORKSPACEID&); void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE); @@ -156,7 +156,7 @@ class CCompositor { void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON); void updateFullscreenFadeOnWorkspace(PHLWORKSPACE); PHLWINDOW getX11Parent(PHLWINDOW); - void scheduleFrameForMonitor(CMonitor*, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); + void scheduleFrameForMonitor(PHLMONITOR, Aquamarine::IOutput::scheduleFrameReason reason = Aquamarine::IOutput::AQ_SCHEDULE_CLIENT_UNKNOWN); void addToFadingOutSafe(PHLLS); void removeFromFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLWINDOW); @@ -169,7 +169,7 @@ class CCompositor { PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", bool isEmpty = true); // will be deleted next frame if left empty and unfocused! void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); - void setActiveMonitor(CMonitor*); + void setActiveMonitor(PHLMONITOR); bool isWorkspaceSpecial(const WORKSPACEID&); WORKSPACEID getNewSpecialID(); void performUserChecks(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 432b7faf..f16ebe46 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -943,9 +943,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { for (auto const& m : g_pCompositor->m_vMonitors) { // mark blur dirty - g_pHyprOpenGL->markBlurDirtyForMonitor(m.get()); + g_pHyprOpenGL->markBlurDirtyForMonitor(m); - g_pCompositor->scheduleFrameForMonitor(m.get()); + g_pCompositor->scheduleFrameForMonitor(m); // Force the compositor to fully re-render all monitors m->forceFullFrames = 2; @@ -1506,7 +1506,7 @@ void CConfigManager::performMonitorReload() { auto rule = getMonitorRuleFor(m); - if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule)) { + if (!g_pHyprRenderer->applyMonitorRule(m, &rule)) { overAgain = true; break; } @@ -1564,14 +1564,14 @@ void CConfigManager::ensureMonitorStatus() { auto rule = getMonitorRuleFor(rm); if (rule.disabled == rm->m_bEnabled) - g_pHyprRenderer->applyMonitorRule(rm.get(), &rule); + g_pHyprRenderer->applyMonitorRule(rm, &rule); } } -void CConfigManager::ensureVRR(CMonitor* pMonitor) { +void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { static auto PVRR = reinterpret_cast(getConfigValuePtr("misc:vrr")); - static auto ensureVRRForDisplay = [&](CMonitor* m) -> void { + static auto ensureVRRForDisplay = [&](PHLMONITOR m) -> void { if (!m->output || m->createdByUser) return; @@ -1641,7 +1641,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) { } for (auto const& m : g_pCompositor->m_vMonitors) { - ensureVRRForDisplay(m.get()); + ensureVRRForDisplay(m); } } @@ -1653,7 +1653,7 @@ void CConfigManager::addParseError(const std::string& err) { g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); } -CMonitor* CConfigManager::getBoundMonitorForWS(const std::string& wsname) { +PHLMONITOR CConfigManager::getBoundMonitorForWS(const std::string& wsname) { auto monitor = getBoundMonitorStringForWS(wsname); if (monitor.substr(0, 5) == "desc:") return g_pCompositor->getMonitorFromDesc(monitor.substr(5)); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 2134acf4..e9ed2d64 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -173,7 +173,7 @@ class CConfigManager { SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); std::string getDefaultWorkspaceFor(const std::string&); - CMonitor* getBoundMonitorForWS(const std::string&); + PHLMONITOR getBoundMonitorForWS(const std::string&); std::string getBoundMonitorStringForWS(const std::string&); const std::deque& getAllWorkspaceRules(); @@ -198,7 +198,7 @@ class CConfigManager { void appendMonitorRule(const SMonitorRule&); bool replaceMonitorRule(const SMonitorRule&); void ensureMonitorStatus(); - void ensureVRR(CMonitor* pMonitor = nullptr); + void ensureVRR(PHLMONITOR pMonitor = nullptr); std::string parseKeyword(const std::string&, const std::string&); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index e0bb2b83..e09fb529 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -54,7 +54,7 @@ static std::string formatToString(uint32_t drmFormat) { return "Invalid"; } -static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) { +static std::string availableModesForOutput(PHLMONITOR pMonitor, eHyprCtlOutputFormat format) { std::string result; for (auto const& m : pMonitor->output->modes) { @@ -117,7 +117,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), - availableModesForOutput(m.get(), format)); + availableModesForOutput(m, format)); } else { result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" @@ -128,7 +128,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m.get(), format)); + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m, format)); } return result; @@ -1030,7 +1030,7 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { // decorations will probably need a repaint if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { for (auto const& m : g_pCompositor->m_vMonitors) { - g_pHyprRenderer->damageMonitor(m.get()); + g_pHyprRenderer->damageMonitor(m); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } } @@ -1779,7 +1779,7 @@ std::string CHyprCtl::getReply(std::string request) { } for (auto const& m : g_pCompositor->m_vMonitors) { - g_pHyprRenderer->damageMonitor(m.get()); + g_pHyprRenderer->damageMonitor(m); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); } } diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 2da64e63..9326cfe0 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -7,7 +7,7 @@ CHyprDebugOverlay::CHyprDebugOverlay() { m_pTexture = makeShared(); } -void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { +void CHyprMonitorDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { m_dLastRenderTimes.push_back(durationUs / 1000.f); if (m_dLastRenderTimes.size() > (long unsigned int)pMonitor->refreshRate) @@ -17,7 +17,7 @@ void CHyprMonitorDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) m_pMonitor = pMonitor; } -void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { +void CHyprMonitorDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { m_dLastRenderTimesNoOverlay.push_back(durationUs / 1000.f); if (m_dLastRenderTimesNoOverlay.size() > (long unsigned int)pMonitor->refreshRate) @@ -27,7 +27,7 @@ void CHyprMonitorDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float dur m_pMonitor = pMonitor; } -void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { +void CHyprMonitorDebugOverlay::frameData(PHLMONITOR pMonitor) { m_dLastFrametimes.push_back(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_tpLastFrame).count() / 1000.f); if (m_dLastFrametimes.size() > (long unsigned int)pMonitor->refreshRate) @@ -39,7 +39,7 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) { m_pMonitor = pMonitor; // anim data too - const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get(); + const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor.lock() : g_pCompositor->m_pLastMonitor.lock(); if (PMONITORFORTICKS) { if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate) m_dLastAnimationTicks.pop_front(); @@ -188,21 +188,21 @@ int CHyprMonitorDebugOverlay::draw(int offset) { return posY - offset; } -void CHyprDebugOverlay::renderData(CMonitor* pMonitor, float durationUs) { +void CHyprDebugOverlay::renderData(PHLMONITOR pMonitor, float durationUs) { m_mMonitorOverlays[pMonitor].renderData(pMonitor, durationUs); } -void CHyprDebugOverlay::renderDataNoOverlay(CMonitor* pMonitor, float durationUs) { +void CHyprDebugOverlay::renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs) { m_mMonitorOverlays[pMonitor].renderDataNoOverlay(pMonitor, durationUs); } -void CHyprDebugOverlay::frameData(CMonitor* pMonitor) { +void CHyprDebugOverlay::frameData(PHLMONITOR pMonitor) { m_mMonitorOverlays[pMonitor].frameData(pMonitor); } void CHyprDebugOverlay::draw() { - const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); + const auto PMONITOR = g_pCompositor->m_vMonitors.front(); if (!m_pCairoSurface || !m_pCairo) { m_pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); @@ -218,7 +218,7 @@ void CHyprDebugOverlay::draw() { // draw the things int offsetY = 0; for (auto const& m : g_pCompositor->m_vMonitors) { - offsetY += m_mMonitorOverlays[m.get()].draw(offsetY); + offsetY += m_mMonitorOverlays[m].draw(offsetY); offsetY += 5; // for padding between mons } diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index e7742b35..19b9120a 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -5,7 +5,7 @@ #include "../render/Texture.hpp" #include #include -#include +#include class CHyprRenderer; @@ -13,9 +13,9 @@ class CHyprMonitorDebugOverlay { public: int draw(int offset); - void renderData(CMonitor* pMonitor, float durationUs); - void renderDataNoOverlay(CMonitor* pMonitor, float durationUs); - void frameData(CMonitor* pMonitor); + void renderData(PHLMONITOR pMonitor, float durationUs); + void renderDataNoOverlay(PHLMONITOR pMonitor, float durationUs); + void frameData(PHLMONITOR pMonitor); private: std::deque m_dLastFrametimes; @@ -23,7 +23,7 @@ class CHyprMonitorDebugOverlay { std::deque m_dLastRenderTimesNoOverlay; std::deque m_dLastAnimationTicks; std::chrono::high_resolution_clock::time_point m_tpLastFrame; - CMonitor* m_pMonitor = nullptr; + PHLMONITORREF m_pMonitor; CBox m_wbLastDrawnBox; friend class CHyprRenderer; @@ -33,17 +33,17 @@ class CHyprDebugOverlay { public: CHyprDebugOverlay(); void draw(); - void renderData(CMonitor*, float durationUs); - void renderDataNoOverlay(CMonitor*, float durationUs); - void frameData(CMonitor*); + void renderData(PHLMONITOR, float durationUs); + void renderDataNoOverlay(PHLMONITOR, float durationUs); + void frameData(PHLMONITOR); private: - std::unordered_map m_mMonitorOverlays; + std::map m_mMonitorOverlays; - cairo_surface_t* m_pCairoSurface = nullptr; - cairo_t* m_pCairo = nullptr; + cairo_surface_t* m_pCairoSurface = nullptr; + cairo_t* m_pCairo = nullptr; - SP m_pTexture; + SP m_pTexture; friend class CHyprMonitorDebugOverlay; friend class CHyprRenderer; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 16f80ab6..e46999e6 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -45,7 +45,7 @@ void CHyprNotificationOverlay::addNotification(const std::string& text, const CC PNOTIF->fontSize = fontSize; for (auto const& m : g_pCompositor->m_vMonitors) { - g_pCompositor->scheduleFrameForMonitor(m.get()); + g_pCompositor->scheduleFrameForMonitor(m); } } @@ -61,7 +61,7 @@ void CHyprNotificationOverlay::dismissNotifications(const int amount) { } } -CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { +CBox CHyprNotificationOverlay::drawNotifications(PHLMONITOR pMonitor) { static constexpr auto ANIM_DURATION_MS = 600.0; static constexpr auto ANIM_LAG_MS = 100.0; static constexpr auto NOTIF_LEFTBAR_SIZE = 5.0; @@ -187,7 +187,7 @@ CBox CHyprNotificationOverlay::drawNotifications(CMonitor* pMonitor) { return CBox{(int)(pMonitor->vecPosition.x + pMonitor->vecSize.x - maxWidth - 20), (int)pMonitor->vecPosition.y, (int)maxWidth + 20, (int)offsetY + 10}; } -void CHyprNotificationOverlay::draw(CMonitor* pMonitor) { +void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { const auto MONSIZE = pMonitor->vecTransformedSize; diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 352c44c9..0bba8b04 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -41,13 +41,13 @@ class CHyprNotificationOverlay { CHyprNotificationOverlay(); ~CHyprNotificationOverlay(); - void draw(CMonitor* pMonitor); + void draw(PHLMONITOR pMonitor); void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); void dismissNotifications(const int amount); bool hasAny(); private: - CBox drawNotifications(CMonitor* pMonitor); + CBox drawNotifications(PHLMONITOR pMonitor); CBox m_bLastDamage; std::deque> m_dNotifications; @@ -55,8 +55,8 @@ class CHyprNotificationOverlay { cairo_surface_t* m_pCairoSurface = nullptr; cairo_t* m_pCairo = nullptr; - CMonitor* m_pLastMonitor = nullptr; - Vector2D m_vecLastSize = Vector2D(-1, -1); + PHLMONITORREF m_pLastMonitor; + Vector2D m_vecLastSize = Vector2D(-1, -1); SP m_pTexture; }; diff --git a/src/desktop/DesktopTypes.hpp b/src/desktop/DesktopTypes.hpp index 4e40c4e0..7f812cc1 100644 --- a/src/desktop/DesktopTypes.hpp +++ b/src/desktop/DesktopTypes.hpp @@ -3,6 +3,7 @@ class CWorkspace; class CWindow; class CLayerSurface; +class CMonitor; /* Shared pointer to a workspace */ typedef SP PHLWORKSPACE; @@ -18,3 +19,8 @@ typedef WP PHLWINDOWREF; typedef SP PHLLS; /* Weak pointer to a layer surface */ typedef WP PHLLSREF; + +/* Shared pointer to a monitor */ +typedef SP PHLMONITOR; +/* Weak pointer to a monitor */ +typedef WP PHLMONITORREF; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 0e7e71b6..6c024ee0 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -6,9 +6,9 @@ #include "../managers/SeatManager.hpp" PHLLS CLayerSurface::create(SP resource) { - PHLLS pLS = SP(new CLayerSurface(resource)); + PHLLS pLS = SP(new CLayerSurface(resource)); - CMonitor* pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); + auto pMonitor = resource->monitor.empty() ? g_pCompositor->getMonitorFromCursor() : g_pCompositor->getMonitorFromName(resource->monitor); pLS->surface->assign(resource->surface.lock(), pLS); @@ -18,7 +18,7 @@ PHLLS CLayerSurface::create(SP resource) { } if (pMonitor->pMirrorOf) - pMonitor = g_pCompositor->m_vMonitors.front().get(); + pMonitor = g_pCompositor->m_vMonitors.front(); pLS->self = pLS; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index a393f361..1297bb83 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1188,7 +1188,7 @@ void CWindow::setSuspended(bool suspend) { m_bSuspended = suspend; } -bool CWindow::visibleOnMonitor(CMonitor* pMonitor) { +bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) { CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 9baf57c4..b2a8e763 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -424,7 +424,7 @@ class CWindow { float rounding(); bool canBeTorn(); void setSuspended(bool suspend); - bool visibleOnMonitor(CMonitor* pMonitor); + bool visibleOnMonitor(PHLMONITOR pMonitor); WORKSPACEID workspaceID(); bool onSpecialWorkspace(); void activate(bool force = false); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 37e5406c..21055f79 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -49,10 +49,10 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); - auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); + auto PMONITOR = g_pCompositor->m_pLastMonitor.lock(); if (!g_pCompositor->m_pLastMonitor) { g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({})); - PMONITOR = g_pCompositor->m_pLastMonitor.get(); + PMONITOR = g_pCompositor->m_pLastMonitor.lock(); } auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -314,7 +314,7 @@ void Events::listener_mapWindow(void* owner, void* data) { else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); - PMONITOR = g_pCompositor->m_pLastMonitor.get(); + PMONITOR = g_pCompositor->m_pLastMonitor.lock(); } } else workspaceSilent = false; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 74471f62..6ded5ea4 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -25,7 +25,7 @@ using namespace Hyprutils::String; using namespace Hyprutils::Utils; int ratHandler(void* data) { - g_pHyprRenderer->renderMonitor((CMonitor*)data); + g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); return 1; } @@ -49,12 +49,12 @@ void CMonitor::onConnect(bool noRule) { listeners.frame = output->events.frame.registerListener([this](std::any d) { onMonitorFrame(); }); listeners.commit = output->events.commit.registerListener([this](std::any d) { if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER - PROTO::screencopy->onOutputCommit(this); - PROTO::toplevelExport->onOutputCommit(this); + PROTO::screencopy->onOutputCommit(self.lock()); + PROTO::toplevelExport->onOutputCommit(self.lock()); } }); listeners.needsFrame = - output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); + output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); }); listeners.presented = output->events.present.registerListener([this](std::any d) { auto E = std::any_cast(d); @@ -84,7 +84,7 @@ void CMonitor::onConnect(bool noRule) { return; Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName); - g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true); + g_pHyprRenderer->applyMonitorRule(self.lock(), &activeMonitorRule, true); return; } @@ -98,7 +98,7 @@ void CMonitor::onConnect(bool noRule) { SMonitorRule rule = activeMonitorRule; rule.resolution = SIZE; - g_pHyprRenderer->applyMonitorRule(this, &rule); + g_pHyprRenderer->applyMonitorRule(self.lock(), &rule); }); tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM; @@ -171,7 +171,7 @@ void CMonitor::onConnect(bool noRule) { // set mode, also applies if (!noRule) - g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true); + g_pHyprRenderer->applyMonitorRule(self.lock(), &monitorRule, true); if (!state.commit()) Debug::log(WARN, "state.commit() failed in CMonitor::onCommit"); @@ -187,7 +187,7 @@ void CMonitor::onConnect(bool noRule) { continue; if (ws->m_szLastMonitor == szName || g_pCompositor->m_vMonitors.size() == 1 /* avoid lost workspaces on recover */) { - g_pCompositor->moveWorkspaceToMonitor(ws, this); + g_pCompositor->moveWorkspaceToMonitor(ws, self.lock()); ws->startAnim(true, true, true); ws->m_szLastMonitor = ""; } @@ -204,13 +204,13 @@ void CMonitor::onConnect(bool noRule) { setMirror(activeMonitorRule.mirrorOf); if (!g_pCompositor->m_pLastMonitor) // set the last monitor if it isnt set yet - g_pCompositor->setActiveMonitor(this); + g_pCompositor->setActiveMonitor(self.lock()); g_pHyprRenderer->arrangeLayersForMonitor(ID); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); // ensure VRR (will enable if necessary) - g_pConfigManager->ensureVRR(this); + g_pConfigManager->ensureVRR(self.lock()); // verify last mon valid bool found = false; @@ -222,19 +222,19 @@ void CMonitor::onConnect(bool noRule) { } if (!found) - g_pCompositor->setActiveMonitor(this); + g_pCompositor->setActiveMonitor(self.lock()); renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this); - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR); - PROTO::gamma->applyGammaToState(this); + PROTO::gamma->applyGammaToState(self.lock()); events.connect.emit(); g_pEventManager->postEvent(SHyprIPCEvent{"monitoradded", szName}); g_pEventManager->postEvent(SHyprIPCEvent{"monitoraddedv2", std::format("{},{},{}", ID, szName, szShortDescription)}); - EMIT_HOOK_EVENT("monitorAdded", this); + EMIT_HOOK_EVENT("monitorAdded", self.lock()); } void CMonitor::onDisconnect(bool destroy) { @@ -242,7 +242,7 @@ void CMonitor::onDisconnect(bool destroy) { if (g_pCompositor->m_bIsShuttingDown) return; g_pEventManager->postEvent(SHyprIPCEvent{"monitorremoved", szName}); - EMIT_HOOK_EVENT("monitorRemoved", this); + EMIT_HOOK_EVENT("monitorRemoved", self.lock()); g_pCompositor->arrangeMonitors(); }}; @@ -259,21 +259,21 @@ void CMonitor::onDisconnect(bool destroy) { events.disconnect.emit(); // Cleanup everything. Move windows back, snap cursor, shit. - CMonitor* BACKUPMON = nullptr; + PHLMONITOR BACKUPMON = nullptr; for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { - BACKUPMON = m.get(); + BACKUPMON = m; break; } } // remove mirror if (pMirrorOf) { - pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); + pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; })); // unlock software for mirrored monitor - g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); - pMirrorOf = nullptr; + g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock()); + pMirrorOf.reset(); } if (!mirrors.empty()) { @@ -340,16 +340,16 @@ void CMonitor::onDisconnect(bool destroy) { if (!state.commit()) Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect"); - if (g_pCompositor->m_pLastMonitor.get() == this) - g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput); + if (g_pCompositor->m_pLastMonitor == self) + g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput.lock()); - if (g_pHyprRenderer->m_pMostHzMonitor == this) { - int mostHz = 0; - CMonitor* pMonitorMostHz = nullptr; + if (g_pHyprRenderer->m_pMostHzMonitor == self) { + int mostHz = 0; + PHLMONITOR pMonitorMostHz = nullptr; for (auto const& m : g_pCompositor->m_vMonitors) { - if (m->refreshRate > mostHz && m.get() != this) { - pMonitorMostHz = m.get(); + if (m->refreshRate > mostHz && m != self) { + pMonitorMostHz = m; mostHz = m->refreshRate; } } @@ -361,11 +361,11 @@ void CMonitor::onDisconnect(bool destroy) { void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); - if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { + if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } else if (damage.damage(rg)) - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } void CMonitor::addDamage(const CRegion* rg) { @@ -374,13 +374,13 @@ void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CBox* box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); - if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { + if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { damage.damageEntire(); - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } if (damage.damage(*box)) - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { @@ -456,7 +456,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { if (PNEWWORKSPACE) { // workspace exists, move it to the newly connected monitor - g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, this); + g_pCompositor->moveWorkspaceToMonitor(PNEWWORKSPACE, self.lock()); activeWorkspace = PNEWWORKSPACE; g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); PNEWWORKSPACE->startAnim(true, true, true); @@ -485,7 +485,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { return; } - if (PMIRRORMON == this) { + if (PMIRRORMON == self) { Debug::log(ERR, "Cannot mirror self!"); return; } @@ -494,13 +494,13 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // disable mirroring if (pMirrorOf) { - pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == this; })); + pMirrorOf->mirrors.erase(std::find_if(pMirrorOf->mirrors.begin(), pMirrorOf->mirrors.end(), [&](const auto& other) { return other == self; })); // unlock software for mirrored monitor - g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf); + g_pPointerManager->unlockSoftwareForMonitor(pMirrorOf.lock()); } - pMirrorOf = nullptr; + pMirrorOf.reset(); // set rule const auto RULE = g_pConfigManager->getMonitorRuleFor(self.lock()); @@ -528,12 +528,12 @@ void CMonitor::setMirror(const std::string& mirrorOf) { setupDefaultWS(RULE); - g_pHyprRenderer->applyMonitorRule(this, (SMonitorRule*)&RULE, true); // will apply the offset and stuff + g_pHyprRenderer->applyMonitorRule(self.lock(), (SMonitorRule*)&RULE, true); // will apply the offset and stuff } else { - CMonitor* BACKUPMON = nullptr; + PHLMONITOR BACKUPMON = nullptr; for (auto const& m : g_pCompositor->m_vMonitors) { if (m.get() != this) { - BACKUPMON = m.get(); + BACKUPMON = m; break; } } @@ -557,14 +557,14 @@ void CMonitor::setMirror(const std::string& mirrorOf) { pMirrorOf = PMIRRORMON; - pMirrorOf->mirrors.push_back(this); + pMirrorOf->mirrors.push_back(self); // remove from mvmonitors - std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other.get() == this; }); + std::erase_if(g_pCompositor->m_vMonitors, [&](const auto& other) { return other == self; }); g_pCompositor->arrangeMonitors(); - g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front().get()); + g_pCompositor->setActiveMonitor(g_pCompositor->m_vMonitors.front()); g_pCompositor->sanityCheckWorkspaces(); @@ -654,11 +654,11 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo EMIT_HOOK_EVENT("workspace", pWorkspace); } - g_pHyprRenderer->damageMonitor(this); + g_pHyprRenderer->damageMonitor(self.lock()); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); - g_pConfigManager->ensureVRR(this); + g_pConfigManager->ensureVRR(self.lock()); g_pCompositor->updateSuspendedStates(); @@ -674,7 +674,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { if (activeSpecialWorkspace == pWorkspace) return; - g_pHyprRenderer->damageMonitor(this); + g_pHyprRenderer->damageMonitor(self.lock()); if (!pWorkspace) { // remove special if exists @@ -696,7 +696,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pCompositor->updateFullscreenFadeOnWorkspace(activeWorkspace); - g_pConfigManager->ensureVRR(this); + g_pConfigManager->ensureVRR(self.lock()); g_pCompositor->updateSuspendedStates(); @@ -764,11 +764,11 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pEventManager->postEvent(SHyprIPCEvent{"activespecial", pWorkspace->m_szName + "," + szName}); - g_pHyprRenderer->damageMonitor(this); + g_pHyprRenderer->damageMonitor(self.lock()); g_pCompositor->updateFullscreenFadeOnWorkspace(pWorkspace); - g_pConfigManager->ensureVRR(this); + g_pConfigManager->ensureVRR(self.lock()); g_pCompositor->updateSuspendedStates(); } @@ -824,7 +824,7 @@ void CMonitor::scheduleDone() { void CMonitor::setCTM(const Mat3x3& ctm_) { ctm = ctm_; ctmUpdated = true; - g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME); + g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME); } bool CMonitor::attemptDirectScanout() { @@ -963,7 +963,7 @@ void CMonitor::onMonitorFrame() { if (!m_bEnabled) return; - g_pHyprRenderer->recheckSolitaryForMonitor(this); + g_pHyprRenderer->recheckSolitaryForMonitor(self.lock()); tearingState.busy = false; @@ -984,12 +984,12 @@ void CMonitor::onMonitorFrame() { if (*PENABLERAT && !tearingState.nextRenderTorn) { if (!RATScheduled) { // render - g_pHyprRenderer->renderMonitor(this); + g_pHyprRenderer->renderMonitor(self.lock()); } RATScheduled = false; - const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(this); + const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(self.lock()); if (max + *PRATSAFE > 1000.0 / refreshRate) return; @@ -1002,11 +1002,11 @@ void CMonitor::onMonitorFrame() { const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME); if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME || TIMETOSLEEP < 1) - g_pHyprRenderer->renderMonitor(this); + g_pHyprRenderer->renderMonitor(self.lock()); else wl_event_source_timer_update(renderTimer, TIMETOSLEEP); } else - g_pHyprRenderer->renderMonitor(this); + g_pHyprRenderer->renderMonitor(self.lock()); } CMonitorState::CMonitorState(CMonitor* owner) { @@ -1040,7 +1040,7 @@ bool CMonitorState::commit() { if (!updateSwapchain()) return false; - EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner); + EMIT_HOOK_EVENT("preMonitorCommit", m_pOwner->self.lock()); ensureBufferPresent(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index ceb90232..f3d6d647 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -54,7 +54,7 @@ class CMonitorState { private: void ensureBufferPresent(); - CMonitor* m_pOwner; + CMonitor* m_pOwner = nullptr; }; class CMonitor { @@ -128,8 +128,8 @@ class CMonitor { WP self; // mirroring - CMonitor* pMirrorOf = nullptr; - std::vector mirrors; + PHLMONITORREF pMirrorOf; + std::vector mirrors; // ctm Mat3x3 ctm = Mat3x3::identity(); diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 51f90166..9f2836e7 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -18,9 +18,9 @@ class CWLSurfaceResource; AQUAMARINE_FORWARD(ISwitch); struct SRenderData { - CMonitor* pMonitor; - timespec* when; - double x, y; + PHLMONITORREF pMonitor; + timespec* when; + double x, y; // for iters void* data = nullptr; @@ -59,16 +59,16 @@ struct SRenderData { }; struct SSwipeGesture { - PHLWORKSPACE pWorkspaceBegin = nullptr; + PHLWORKSPACE pWorkspaceBegin = nullptr; - double delta = 0; + double delta = 0; - int initialDirection = 0; - float avgSpeed = 0; - int speedPoints = 0; - int touch_id = 0; + int initialDirection = 0; + float avgSpeed = 0; + int speedPoints = 0; + int touch_id = 0; - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; }; struct SSwitchDevice { diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 4044bcc9..4761346e 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -14,7 +14,7 @@ CHyprError::CHyprError() { if (!m_bIsCreated) return; - g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get()); + g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.lock()); m_bMonitorChanged = true; }); @@ -47,7 +47,7 @@ void CHyprError::createQueued() { m_fFadeOpacity.setValueAndWarp(0.f); m_fFadeOpacity = 1.f; - const auto PMONITOR = g_pCompositor->m_vMonitors.front().get(); + const auto PMONITOR = g_pCompositor->m_vMonitors.front(); const auto SCALE = PMONITOR->scale; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 8a7426eb..0fa57143 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -101,18 +101,17 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for if (pNode->isNode) return; - CMonitor* PMONITOR = nullptr; + PHLMONITOR PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { - PMONITOR = m.get(); + PMONITOR = m; break; } } - } else { + } else PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); - } if (!PMONITOR) { Debug::log(ERR, "Orphaned Node {}!!", pNode); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index f983770b..95b5afdf 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -594,18 +594,17 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { } void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { - CMonitor* PMONITOR = nullptr; + PHLMONITOR PMONITOR = nullptr; if (g_pCompositor->isWorkspaceSpecial(pNode->workspaceID)) { for (auto const& m : g_pCompositor->m_vMonitors) { if (m->activeSpecialWorkspaceID() == pNode->workspaceID) { - PMONITOR = m.get(); + PMONITOR = m; break; } } - } else { + } else PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); - } if (!PMONITOR) { Debug::log(ERR, "Orphaned Node {}!!", pNode); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 0ff94f1f..9ff7497d 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -85,7 +85,7 @@ void CAnimationManager::tick() { PHLWINDOW PWINDOW = av->m_pWindow.lock(); PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock(); PHLLS PLAYER = av->m_pLayer.lock(); - CMonitor* PMONITOR = nullptr; + PHLMONITOR PMONITOR = nullptr; bool animationsDisabled = animGlobalDisabled; if (PWINDOW) { diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 6f8292f7..34084a49 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -309,7 +309,7 @@ void CCursorManager::updateTheme() { for (auto const& m : g_pCompositor->m_vMonitors) { m->forceFullFrames = 5; - g_pCompositor->scheduleFrameForMonitor(m.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + g_pCompositor->scheduleFrameForMonitor(m, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d893e258..9c22fb93 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -271,11 +271,11 @@ void updateRelativeCursorCoords() { g_pCompositor->m_pLastWindow->m_vRelativeCursorCoordsOnLastWarp = g_pInputManager->getMouseCoordsInternal() - g_pCompositor->m_pLastWindow->m_vPosition; } -bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) { +bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) { if (!monitor) return false; - const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get(); + const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.lock(); if (!LASTMONITOR) return false; if (LASTMONITOR == monitor) { @@ -1096,7 +1096,7 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) { static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); static auto PWORKSPACECENTERON = CConfigValue("binds:workspace_center_on"); - const auto PMONITOR = g_pCompositor->m_pLastMonitor.get(); + const auto PMONITOR = g_pCompositor->m_pLastMonitor.lock(); if (!PMONITOR) return {.success = false, .error = "Last monitor not found"}; @@ -1260,7 +1260,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { } auto pWorkspace = g_pCompositor->getWorkspaceByID(WORKSPACEID); - CMonitor* pMonitor = nullptr; + PHLMONITOR pMonitor = nullptr; const auto POLDWS = PWINDOW->m_pWorkspace; static auto PALLOWWORKSPACECYCLES = CConfigValue("binds:allow_workspace_cycles"); @@ -1795,7 +1795,7 @@ SDispatchResult CKeybindManager::exitHyprland(std::string argz) { } SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) { - CMonitor* PMONITOR = g_pCompositor->getMonitorFromString(args); + PHLMONITOR PMONITOR = g_pCompositor->getMonitorFromString(args); if (!PMONITOR) { Debug::log(ERR, "Ignoring moveCurrentWorkspaceToMonitor: monitor doesnt exist"); @@ -1854,7 +1854,7 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"}; } - const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get(); + const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.lock(); if (!PCURRMONITOR) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!"); @@ -1944,7 +1944,7 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { continue; auto rule = g_pConfigManager->getMonitorRuleFor(m); - if (!g_pHyprRenderer->applyMonitorRule(m.get(), &rule, true)) { + if (!g_pHyprRenderer->applyMonitorRule(m, &rule, true)) { overAgain = true; break; } @@ -2427,7 +2427,7 @@ SDispatchResult CKeybindManager::dpms(std::string arg) { } if (enable) - g_pHyprRenderer->damageMonitor(m.get()); + g_pHyprRenderer->damageMonitor(m); m->events.dpmsChanged.emit(); } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index c81ca86f..8981dcaf 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -146,7 +146,7 @@ class CKeybindManager { void updateXKBTranslationState(); bool ensureMouseBindState(); - static bool tryMoveFocusToMonitor(CMonitor* monitor); + static bool tryMoveFocusToMonitor(PHLMONITOR monitor); static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 8c2a1bad..ae90349b 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -14,7 +14,7 @@ CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { - auto PMONITOR = std::any_cast(data)->self.lock(); + auto PMONITOR = std::any_cast(data); onMonitorLayoutChange(); @@ -29,7 +29,7 @@ CPointerManager::CPointerManager() { }); hooks.monitorPreRender = g_pHookSystem->hookDynamic("preMonitorCommit", [this](void* self, SCallbackInfo& info, std::any data) { - auto state = stateFor(std::any_cast(data)->self.lock()); + auto state = stateFor(std::any_cast(data)); if (!state) return; @@ -51,16 +51,7 @@ void CPointerManager::unlockSoftwareAll() { updateCursorBackend(); } -void CPointerManager::lockSoftwareForMonitor(CMonitor* Monitor) { - for (auto const& m : g_pCompositor->m_vMonitors) { - if (m->ID == Monitor->ID) { - lockSoftwareForMonitor(m); - return; - } - } -} - -void CPointerManager::lockSoftwareForMonitor(SP mon) { +void CPointerManager::lockSoftwareForMonitor(PHLMONITOR mon) { auto state = stateFor(mon); state->softwareLocks++; @@ -68,16 +59,7 @@ void CPointerManager::lockSoftwareForMonitor(SP mon) { updateCursorBackend(); } -void CPointerManager::unlockSoftwareForMonitor(CMonitor* Monitor) { - for (auto const& m : g_pCompositor->m_vMonitors) { - if (m->ID == Monitor->ID) { - unlockSoftwareForMonitor(m); - return; - } - } -} - -void CPointerManager::unlockSoftwareForMonitor(SP mon) { +void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) { auto state = stateFor(mon); state->softwareLocks--; if (state->softwareLocks < 0) @@ -387,7 +369,7 @@ bool CPointerManager::setHWCursorBuffer(SP state, SPcursorFrontBuffer = buf; if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent()) - g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); + g_pCompositor->scheduleFrameForMonitor(state->monitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE); return true; } @@ -446,7 +428,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmakeEGLCurrent(); - g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); + g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor; auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); if (!RBO) { @@ -503,7 +485,7 @@ SP CPointerManager::renderHWCursorBuffer(SPbind(); - g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO); + g_pHyprOpenGL->beginSimple(state->monitor.lock(), damage, RBO); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; @@ -514,7 +496,7 @@ SP CPointerManager::renderHWCursorBuffer(SPend(); glFlush(); - g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + g_pHyprOpenGL->m_RenderData.pMonitor.reset(); g_pHyprRenderer->onRenderbufferDestroy(RBO.get()); diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index 6b89eb16..aef2490d 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -45,8 +45,6 @@ class CPointerManager { void lockSoftwareForMonitor(SP pMonitor); void unlockSoftwareForMonitor(SP pMonitor); - void lockSoftwareForMonitor(CMonitor* pMonitor); - void unlockSoftwareForMonitor(CMonitor* pMonitor); void lockSoftwareAll(); void unlockSoftwareAll(); bool softwareLockedFor(SP pMonitor); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 25a34657..601e564d 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -62,7 +62,7 @@ #include #include -void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) { +void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { const bool ISMIRROR = pMonitor->isMirror(); // onModeChanged we check if the current mirror status matches the global. @@ -84,7 +84,7 @@ CProtocolManager::CProtocolManager() { // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { - auto M = std::any_cast(param); + auto M = std::any_cast(param); // ignore mirrored outputs. I don't think this will ever be hit as mirrors are applied after // this event is emitted iirc. @@ -103,7 +103,7 @@ CProtocolManager::CProtocolManager() { }); static auto P2 = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - auto M = std::any_cast(param); + auto M = std::any_cast(param); if (!PROTO::outputs.contains(M->szName)) return; PROTO::outputs.at(M->szName)->remove(); diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index d5629e9e..69dadd0f 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -16,7 +16,7 @@ class CProtocolManager { private: std::unordered_map m_mModeChangeListeners; - void onMonitorModeChange(CMonitor* pMonitor); + void onMonitorModeChange(PHLMONITOR pMonitor); }; inline std::unique_ptr g_pProtocolManager; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 4e05695a..1b28cc27 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -73,7 +73,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pInputManager->refocus(); for (auto const& m : g_pCompositor->m_vMonitors) - g_pHyprRenderer->damageMonitor(m.get()); + g_pHyprRenderer->damageMonitor(m); }); m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) { @@ -81,7 +81,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pCompositor->focusSurface(nullptr); for (auto const& m : g_pCompositor->m_vMonitors) - g_pHyprRenderer->damageMonitor(m.get()); + g_pHyprRenderer->damageMonitor(m); }); g_pCompositor->focusSurface(nullptr); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 8b63d37e..7b3081a2 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -247,7 +247,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - CMonitor* pMonitor = nullptr; + PHLMONITOR pMonitor = nullptr; double bestDistance = __FLT_MAX__; for (const auto& m : g_pCompositor->m_vMonitors) { const auto SIZ = *PXWLFORCESCALEZERO ? m->vecTransformedSize : m->vecSize; @@ -257,7 +257,7 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { if (distance < bestDistance) { bestDistance = distance; - pMonitor = m.get(); + pMonitor = m; } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index eef5e040..196f0b71 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -172,7 +172,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { m_vLastCursorPosFloored = MOUSECOORDSFLOORED; - const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.get() : g_pCompositor->getMonitorFromCursor(); + const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.lock() : g_pCompositor->getMonitorFromCursor(); // this can happen if there are no displays hooked up to Hyprland if (PMONITOR == nullptr) @@ -212,7 +212,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { Debug::log(ERR, "BUG THIS: Null SURF/CONSTRAINT in mouse refocus. Ignoring constraints. {:x} {:x}", (uintptr_t)SURF.get(), (uintptr_t)CONSTRAINT.get()); } - if (PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) + if (PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired()) g_pCompositor->setActiveMonitor(PMONITOR); if (g_pSessionLockManager->isSessionLocked()) { @@ -370,7 +370,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule) - g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.lock(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_MOVE); // grabs if (g_pSeatManager->seatGrab && !g_pSeatManager->seatGrab->accepts(foundSurface)) { @@ -720,7 +720,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // notify app if we didnt handle it g_pSeatManager->sendPointerButton(e.timeMs, e.button, e.state); - if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON) + if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor && PMON) g_pCompositor->setActiveMonitor(PMON); if (g_pSeatManager->seatGrab && e.state == WL_POINTER_BUTTON_STATE_PRESSED) { @@ -1359,7 +1359,7 @@ void CInputManager::refocus() { mouseMoveUnified(0, true); } -void CInputManager::refocusLastWindow(CMonitor* pMonitor) { +void CInputManager::refocusLastWindow(PHLMONITOR pMonitor) { if (!pMonitor) { refocus(); return; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index d5634796..10faff24 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -112,7 +112,7 @@ class CInputManager { Vector2D getMouseCoordsInternal(); void refocus(); - void refocusLastWindow(CMonitor* pMonitor); + void refocusLastWindow(PHLMONITOR pMonitor); void simulateMouseMovement(); void sendMotionEventsToFocused(); diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index cf48f2a5..ffb4edcc 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -100,11 +100,11 @@ void CInputPopup::updateBox() { cursorBoxParent = {0, 0, (int)parentBox.w, (int)parentBox.h}; } - Vector2D currentPopupSize = surface->getViewporterCorrectedSize() / surface->resource()->current.scale; + Vector2D currentPopupSize = surface->getViewporterCorrectedSize() / surface->resource()->current.scale; - CMonitor* pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); + PHLMONITOR pMonitor = g_pCompositor->getMonitorFromVector(parentBox.middle()); - Vector2D popupOffset(0, 0); + Vector2D popupOffset(0, 0); if (parentBox.y + cursorBoxParent.y + cursorBoxParent.height + currentPopupSize.y > pMonitor->vecPosition.y + pMonitor->vecSize.y) popupOffset.y -= currentPopupSize.y; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index aa1d3274..8f95c6c6 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -33,7 +33,7 @@ void CInputManager::beginWorkspaceSwipe() { m_sActiveSwipe.pWorkspaceBegin = PWORKSPACE; m_sActiveSwipe.delta = 0; - m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor.get(); + m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor; m_sActiveSwipe.avgSpeed = 0; m_sActiveSwipe.speedPoints = 0; @@ -179,7 +179,7 @@ void CInputManager::endWorkspaceSwipe() { } m_sActiveSwipe.pWorkspaceBegin->rememberPrevWorkspace(pSwitchedTo); - g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); + g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (PWORKSPACEL) PWORKSPACEL->m_bForceRendering = false; @@ -264,7 +264,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { if (workspaceIDLeft > m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) { if (*PSWIPENEW) { - g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); + g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); @@ -304,7 +304,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { if (workspaceIDRight < m_sActiveSwipe.pWorkspaceBegin->m_iID || !PWORKSPACE) { if (*PSWIPENEW) { - g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); + g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); @@ -341,7 +341,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); } - g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor); + g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 0333648a..454391af 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -18,7 +18,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : ""); - PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.get(); + PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.lock(); g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 1163a5e7..ffc335c9 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -44,7 +44,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPm_pWorkspace != monitor->activeWorkspace) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, monitor->activeWorkspace); - g_pCompositor->setActiveMonitor(monitor.get()); + g_pCompositor->setActiveMonitor(monitor); } } } @@ -116,7 +116,7 @@ wl_resource* CForeignToplevelHandleWlr::res() { return resource->resource(); } -void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { +void CForeignToplevelHandleWlr::sendMonitor(PHLMONITOR pMonitor) { if (lastMonitorID == pMonitor->ID) return; diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp index e726707d..880b7a14 100644 --- a/src/protocols/ForeignToplevelWlr.hpp +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -22,7 +22,7 @@ class CForeignToplevelHandleWlr { bool closed = false; MONITORID lastMonitorID = MONITOR_INVALID; - void sendMonitor(CMonitor* pMonitor); + void sendMonitor(PHLMONITOR pMonitor); void sendState(); friend class CForeignToplevelWlrManager; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index e794e543..14c6596f 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -143,11 +143,11 @@ void CGammaControl::applyToMonitor() { pMonitor->output->state->setGammaLut({}); } - g_pHyprRenderer->damageMonitor(pMonitor.get()); + g_pHyprRenderer->damageMonitor(pMonitor.lock()); } -CMonitor* CGammaControl::getMonitor() { - return pMonitor ? pMonitor.get() : nullptr; +PHLMONITOR CGammaControl::getMonitor() { + return pMonitor ? pMonitor.lock() : nullptr; } void CGammaControl::onMonitorDestroy() { @@ -186,7 +186,7 @@ void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, } } -void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) { +void CGammaControlProtocol::applyGammaToState(PHLMONITOR pMonitor) { for (auto const& g : m_vGammaControllers) { if (g->getMonitor() != pMonitor) continue; diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index bbdc0139..5cfcd60a 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -14,13 +14,13 @@ class CGammaControl { CGammaControl(SP resource_, wl_resource* output); ~CGammaControl(); - bool good(); - void applyToMonitor(); - CMonitor* getMonitor(); + bool good(); + void applyToMonitor(); + PHLMONITOR getMonitor(); private: SP resource; - WP pMonitor; + PHLMONITORREF pMonitor; size_t gammaSize = 0; bool gammaTableSet = false; std::vector gammaTable; // [r,g,b]+ @@ -39,7 +39,7 @@ class CGammaControlProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void applyGammaToState(CMonitor* pMonitor); + void applyGammaToState(PHLMONITOR pMonitor); private: void onManagerResourceDestroy(wl_resource* res); diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index c02d23f3..5ceae5f2 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -14,8 +14,8 @@ void CLayerShellResource::SState::reset() { margin = {0, 0, 0, 0}; } -CLayerShellResource::CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer) : - layerNamespace(namespace_), surface(surf_), resource(resource_) { +CLayerShellResource::CLayerShellResource(SP resource_, SP surf_, std::string namespace_, PHLMONITOR pMonitor, + zwlrLayerShellV1Layer layer) : layerNamespace(namespace_), surface(surf_), resource(resource_) { if (!good()) return; @@ -218,7 +218,7 @@ void CLayerShellProtocol::destroyResource(CLayerShellResource* surf) { void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id, wl_resource* surface, wl_resource* output, zwlrLayerShellV1Layer layer, std::string namespace_) { const auto CLIENT = pMgr->client(); - const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.get() : nullptr; + const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.lock() : nullptr; auto SURF = CWLSurfaceResource::fromResource(surface); if (!SURF) { diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 801bdfd6..ad6c1a75 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -26,7 +26,7 @@ class CLayerShellRole : public ISurfaceRole { }; class CLayerShellResource { public: - CLayerShellResource(SP resource_, SP surf_, std::string namespace_, CMonitor* pMonitor, zwlrLayerShellV1Layer layer); + CLayerShellResource(SP resource_, SP surf_, std::string namespace_, PHLMONITOR pMonitor, zwlrLayerShellV1Layer layer); ~CLayerShellResource(); bool good(); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index d9dd1d01..8e26c74f 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -452,7 +452,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const } static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { - auto pMonitor = std::any_cast(param); + auto pMonitor = std::any_cast(param); auto mon = pMonitor->self.lock(); auto tranche = SDMABUFTranche{ .device = mainDevice, @@ -464,7 +464,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const }); static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - auto pMonitor = std::any_cast(param); + auto pMonitor = std::any_cast(param); auto mon = pMonitor->self.lock(); std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); resetFormatTable(); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 3fd0cf6c..77cedd41 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -29,12 +29,12 @@ COutputManager::COutputManager(SP resource_) : resource(re // send all heads at start for (auto const& m : g_pCompositor->m_vRealMonitors) { - if (m.get() == g_pCompositor->m_pUnsafeOutput) + if (m == g_pCompositor->m_pUnsafeOutput) continue; LOGM(LOG, " | sending output head for {}", m->szName); - makeAndSendNewHead(m.get()); + makeAndSendNewHead(m); } sendDone(); @@ -44,7 +44,7 @@ bool COutputManager::good() { return resource->resource(); } -void COutputManager::makeAndSendNewHead(CMonitor* pMonitor) { +void COutputManager::makeAndSendNewHead(PHLMONITOR pMonitor) { if (stopped) return; @@ -63,7 +63,7 @@ void COutputManager::makeAndSendNewHead(CMonitor* pMonitor) { RESOURCE->sendAllData(); } -void COutputManager::ensureMonitorSent(CMonitor* pMonitor) { +void COutputManager::ensureMonitorSent(PHLMONITOR pMonitor) { if (pMonitor == g_pCompositor->m_pUnsafeOutput) return; @@ -86,7 +86,7 @@ void COutputManager::sendDone() { resource->sendDone(wl_display_next_serial(g_pCompositor->m_sWLDisplay)); } -COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) { +COutputHead::COutputHead(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!good()) return; @@ -105,7 +105,7 @@ COutputHead::COutputHead(SP resource_, CMonitor* pMonitor_) : m->resource->sendFinished(); } - pMonitor = nullptr; + pMonitor.reset(); for (auto const& m : PROTO::outputManagement->m_vManagers) { m->sendDone(); } @@ -221,8 +221,8 @@ void COutputHead::makeAndSendNewMode(SP mode) { RESOURCE->sendAllData(); } -CMonitor* COutputHead::monitor() { - return pMonitor; +PHLMONITOR COutputHead::monitor() { + return pMonitor.lock(); } COutputMode::COutputMode(SP resource_, SP mode_) : resource(resource_), mode(mode_) { @@ -424,14 +424,12 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { return true; } -COutputConfigurationHead::COutputConfigurationHead(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) { +COutputConfigurationHead::COutputConfigurationHead(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!good()) return; resource->setOnDestroy([this](CZwlrOutputConfigurationHeadV1* r) { PROTO::outputManagement->destroyResource(this); }); - listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any d) { pMonitor = nullptr; }); - resource->setSetMode([this](CZwlrOutputConfigurationHeadV1* r, wl_resource* outputMode) { const auto MODE = PROTO::outputManagement->modeFromResource(outputMode); @@ -612,7 +610,7 @@ void COutputManagementProtocol::destroyResource(COutputConfigurationHead* resour void COutputManagementProtocol::updateAllOutputs() { for (auto const& m : g_pCompositor->m_vRealMonitors) { for (auto const& mgr : m_vManagers) { - mgr->ensureMonitorSent(m.get()); + mgr->ensureMonitorSent(m); } } } diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index f4a84475..6deab017 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -56,7 +56,7 @@ class COutputManager { COutputManager(SP resource_); bool good(); - void ensureMonitorSent(CMonitor* pMonitor); + void ensureMonitorSent(PHLMONITOR pMonitor); void sendDone(); // holds the states for this manager. @@ -70,7 +70,7 @@ class COutputManager { std::vector> heads; - void makeAndSendNewHead(CMonitor* pMonitor); + void makeAndSendNewHead(PHLMONITOR pMonitor); friend class COutputManagementProtocol; }; @@ -92,16 +92,16 @@ class COutputMode { class COutputHead { public: - COutputHead(SP resource_, CMonitor* pMonitor_); + COutputHead(SP resource_, PHLMONITOR pMonitor_); - bool good(); - void sendAllData(); // this has to be separate as we need to send the head first, then set the data - void updateMode(); - CMonitor* monitor(); + bool good(); + void sendAllData(); // this has to be separate as we need to send the head first, then set the data + void updateMode(); + PHLMONITOR monitor(); private: SP resource; - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; void makeAndSendNewMode(SP mode); void sendCurrentMode(); @@ -119,7 +119,7 @@ class COutputHead { class COutputConfigurationHead { public: - COutputConfigurationHead(SP resource_, CMonitor* pMonitor_); + COutputConfigurationHead(SP resource_, PHLMONITOR pMonitor_); bool good(); @@ -127,11 +127,7 @@ class COutputConfigurationHead { private: SP resource; - CMonitor* pMonitor = nullptr; - - struct { - CHyprSignalListener monitorDestroy; - } listeners; + PHLMONITORREF pMonitor; friend class COutputConfiguration; }; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index 0c324bf0..257155e4 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -2,7 +2,7 @@ #include "../Compositor.hpp" #include "core/Output.hpp" -COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_) : resource(resource_), pMonitor(pMonitor_) { +COutputPower::COutputPower(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!resource->resource()) return; @@ -24,7 +24,7 @@ COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_ resource->sendMode(pMonitor->dpmsStatus ? ZWLR_OUTPUT_POWER_V1_MODE_ON : ZWLR_OUTPUT_POWER_V1_MODE_OFF); listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any v) { - pMonitor = nullptr; + pMonitor.reset(); resource->sendFailed(); }); @@ -68,7 +68,7 @@ void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uin } const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.get())).get(); + const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.lock())).get(); if (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/OutputPower.hpp b/src/protocols/OutputPower.hpp index 410742ca..91f2c5f3 100644 --- a/src/protocols/OutputPower.hpp +++ b/src/protocols/OutputPower.hpp @@ -11,14 +11,14 @@ class CMonitor; class COutputPower { public: - COutputPower(SP resource_, CMonitor* pMonitor); + COutputPower(SP resource_, PHLMONITOR pMonitor); bool good(); private: SP resource; - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; struct { CHyprSignalListener monitorDestroy; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 71f74cd5..b66694bf 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -73,8 +73,8 @@ void CPresentationFeedback::sendQueued(SP data, timespe CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - const auto PMONITOR = std::any_cast(param); - std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor.get() == PMONITOR; }); + const auto PMONITOR = std::any_cast(param); + std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); }); } diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 1b06a1fa..780c081d 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -19,7 +19,7 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t return; overlayCursor = !!overlay_cursor; - pMonitor = CWLOutputResource::fromResource(output)->monitor.get(); + pMonitor = CWLOutputResource::fromResource(output)->monitor; if (!pMonitor) { LOGM(ERR, "Client requested sharing of a monitor that doesnt exist"); @@ -38,7 +38,7 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t g_pHyprRenderer->makeEGLCurrent(); - shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor); + shmFormat = g_pHyprOpenGL->getPreferredReadFormat(pMonitor.lock()); if (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture output"); resource->sendFailed(); @@ -87,7 +87,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ return; } - if (!g_pCompositor->monitorExists(pMonitor)) { + if (!g_pCompositor->monitorExists(pMonitor.lock())) { LOGM(ERR, "Client requested sharing of a monitor that is gone"); resource->sendFailed(); PROTO::screencopy->destroyResource(this); @@ -165,7 +165,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ } if (!withDamage) - g_pHyprRenderer->damageMonitor(pMonitor); + g_pHyprRenderer->damageMonitor(pMonitor.lock()); } void CScreencopyFrame::share() { @@ -205,7 +205,7 @@ bool CScreencopyFrame::copyDmabuf() { CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) { + if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock(), nullptr, true)) { LOGM(ERR, "Can't copy: failed to begin rendering to dma frame"); return false; } @@ -240,7 +240,7 @@ bool CScreencopyFrame::copyShm() { CFramebuffer fb; fb.alloc(box.w, box.h, pMonitor->output->state->state().drmFormat); - if (!g_pHyprRenderer->beginRender(pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { + if (!g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { LOGM(ERR, "Can't copy: failed to begin rendering"); return false; } @@ -288,7 +288,7 @@ bool CScreencopyFrame::copyShm() { } } - g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + g_pHyprOpenGL->m_RenderData.pMonitor.reset(); LOGM(TRACE, "Copied frame via shm"); @@ -402,7 +402,7 @@ void CScreencopyProtocol::destroyResource(CScreencopyFrame* frame) { std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } -void CScreencopyProtocol::onOutputCommit(CMonitor* pMonitor) { +void CScreencopyProtocol::onOutputCommit(PHLMONITOR pMonitor) { if (m_vFramesAwaitingWrite.empty()) { g_pHyprRenderer->m_bDirectScanoutBlocked = false; return; // nothing to share diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index e121d0fd..62c9f8b8 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -60,7 +60,7 @@ class CScreencopyFrame { private: SP resource; - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; bool overlayCursor = false; bool withDamage = false; bool lockedSWCursors = false; @@ -88,7 +88,7 @@ class CScreencopyProtocol : public IWaylandProtocol { void destroyResource(CScreencopyClient* resource); void destroyResource(CScreencopyFrame* resource); - void onOutputCommit(CMonitor* pMonitor); + void onOutputCommit(PHLMONITOR pMonitor); private: std::vector> m_vFrames; @@ -98,7 +98,7 @@ class CScreencopyProtocol : public IWaylandProtocol { SP m_pSoftwareCursorTimer; bool m_bTimerArmed = false; - void shareAllFrames(CMonitor* pMonitor); + void shareAllFrames(PHLMONITOR pMonitor); void shareFrame(CScreencopyFrame* frame); void sendFrameDamage(CScreencopyFrame* frame); bool copyFrameDmabuf(CScreencopyFrame* frame); diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index b1f701bf..642a5b89 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -5,7 +5,7 @@ #include "core/Compositor.hpp" #include "core/Output.hpp" -CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_) : +CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, PHLMONITOR pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { if (!resource->resource()) return; @@ -82,8 +82,8 @@ bool CSessionLockSurface::inert() { return sessionLock.expired(); } -CMonitor* CSessionLockSurface::monitor() { - return pMonitor; +PHLMONITOR CSessionLockSurface::monitor() { + return pMonitor.lock(); } SP CSessionLockSurface::surface() { @@ -184,7 +184,7 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id LOGM(LOG, "New sessionLockSurface with id {}", id); auto PSURFACE = CWLSurfaceResource::fromResource(surface); - auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.get(); + auto PMONITOR = CWLOutputResource::fromResource(output)->monitor.lock(); SP sessionLock; for (auto const& l : m_vLocks) { diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp index a0c67e88..a1df6fcf 100644 --- a/src/protocols/SessionLock.hpp +++ b/src/protocols/SessionLock.hpp @@ -13,12 +13,12 @@ class CWLSurfaceResource; class CSessionLockSurface { public: - CSessionLockSurface(SP resource_, SP surface_, CMonitor* pMonitor_, WP owner_); + CSessionLockSurface(SP resource_, SP surface_, PHLMONITOR pMonitor_, WP owner_); ~CSessionLockSurface(); bool good(); bool inert(); - CMonitor* monitor(); + PHLMONITOR monitor(); SP surface(); struct { @@ -31,7 +31,7 @@ class CSessionLockSurface { SP resource; WP sessionLock; WP pSurface; - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; bool ackdConfigure = false; bool committed = false; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 66df5926..8b6208be 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -362,7 +362,7 @@ void CToplevelExportProtocol::destroyResource(CToplevelExportFrame* frame) { std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return !other || other.get() == frame; }); } -void CToplevelExportProtocol::onOutputCommit(CMonitor* pMonitor) { +void CToplevelExportProtocol::onOutputCommit(PHLMONITOR pMonitor) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 9686431b..bcfa161c 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -80,7 +80,7 @@ class CToplevelExportProtocol : IWaylandProtocol { void destroyResource(CToplevelExportFrame* frame); void onWindowUnmap(PHLWINDOW pWindow); - void onOutputCommit(CMonitor* pMonitor); + void onOutputCommit(PHLMONITOR pMonitor); private: std::vector> m_vClients; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 5644f243..056a72c4 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -681,7 +681,7 @@ void CWLDataDeviceProtocol::abortDrag() { g_pSeatManager->resendEnterEvents(); } -void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { +void CWLDataDeviceProtocol::renderDND(PHLMONITOR pMonitor, timespec* when) { if (!dnd.dndSurface || !dnd.dndSurface->current.texture) return; diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 50e9ac61..81ca1b11 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -131,7 +131,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); // renders and damages the dnd icon, if present - void renderDND(CMonitor* pMonitor, timespec* when); + void renderDND(PHLMONITOR pMonitor, timespec* when); // for inputmgr to force refocus // TODO: move handling to seatmgr bool dndActive(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 833e2ccb..fc2d1012 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -340,7 +340,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { initAssets(); - static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); + static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast(data)); }); RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); @@ -625,7 +625,7 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool return shader; } -bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { +bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { // passes requiring introspection are the ones that need to render blur, // or when we are rendering to a multigpu target @@ -731,7 +731,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) { return false; } -void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { +void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; #ifndef GLES2 @@ -783,7 +783,7 @@ void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, SP< m_RenderData.simplePass = true; } -void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { +void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { m_RenderData.pMonitor = pMonitor; static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); @@ -929,7 +929,7 @@ void CHyprOpenGLImpl::end() { } // reset our data - m_RenderData.pMonitor = nullptr; + m_RenderData.pMonitor.reset(); m_RenderData.mouseZoomFactor = 1.f; m_RenderData.mouseZoomUseMouse = true; m_RenderData.forceIntrospection = false; @@ -1858,11 +1858,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o return currentRenderToFB; } -void CHyprOpenGLImpl::markBlurDirtyForMonitor(CMonitor* pMonitor) { +void CHyprOpenGLImpl::markBlurDirtyForMonitor(PHLMONITOR pMonitor) { m_mMonitorRenderResources[pMonitor].blurFBDirty = true; } -void CHyprOpenGLImpl::preRender(CMonitor* pMonitor) { +void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) { static auto PBLURNEWOPTIMIZE = CConfigValue("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue("decoration:blur:xray"); static auto PBLUR = CConfigValue("decoration:blur:enabled"); @@ -2728,7 +2728,7 @@ void CHyprOpenGLImpl::initAssets() { CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); } -void CHyprOpenGLImpl::createBGTextureForMonitor(CMonitor* pMonitor) { +void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); Debug::log(LOG, "Creating a texture for BGTex"); @@ -2860,7 +2860,7 @@ void CHyprOpenGLImpl::clearWithTex() { auto TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor); if (TEXIT == m_mMonitorBGFBs.end()) { - createBGTextureForMonitor(m_RenderData.pMonitor); + createBGTextureForMonitor(m_RenderData.pMonitor.lock()); TEXIT = m_mMonitorBGFBs.find(m_RenderData.pMonitor); } @@ -2872,7 +2872,7 @@ void CHyprOpenGLImpl::clearWithTex() { } } -void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) { +void CHyprOpenGLImpl::destroyMonitorResources(PHLMONITOR pMonitor) { g_pHyprRenderer->makeEGLCurrent(); if (!g_pHyprOpenGL) @@ -2935,7 +2935,7 @@ void CHyprOpenGLImpl::setRenderModifEnabled(bool enabled) { m_RenderData.renderModif.enabled = enabled; } -uint32_t CHyprOpenGLImpl::getPreferredReadFormat(CMonitor* pMonitor) { +uint32_t CHyprOpenGLImpl::getPreferredReadFormat(PHLMONITOR pMonitor) { return pMonitor->output->state->state().drmFormat; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 0d1c267b..04f69d49 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -94,7 +94,7 @@ struct SMonitorRenderData { }; struct SCurrentRenderData { - CMonitor* pMonitor = nullptr; + PHLMONITORREF pMonitor; PHLWORKSPACE pWorkspace = nullptr; Mat3x3 projection; Mat3x3 savedProjection; @@ -149,8 +149,8 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); ~CHyprOpenGLImpl(); - void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(CMonitor*, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); + void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); void end(); void renderRect(CBox*, const CColor&, int round = 0); @@ -186,13 +186,13 @@ class CHyprOpenGLImpl { void scissor(const pixman_box32*, bool transform = true); void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(CMonitor*); + void destroyMonitorResources(PHLMONITOR); - void markBlurDirtyForMonitor(CMonitor*); + void markBlurDirtyForMonitor(PHLMONITOR); void preWindowPass(); bool preBlurQueued(); - void preRender(CMonitor*); + void preRender(PHLMONITOR); void saveBufferForMirror(CBox*); void renderMirrored(); @@ -205,31 +205,31 @@ class CHyprOpenGLImpl { void setDamage(const CRegion& damage, std::optional finalDamage = {}); - uint32_t getPreferredReadFormat(CMonitor* pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window - PHLLS m_pCurrentLayer; // hack to get the current rendered layer + PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window + PHLLS m_pCurrentLayer; // hack to get the current rendered layer - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; - std::unordered_map m_mMonitorRenderResources; - std::unordered_map m_mMonitorBGFBs; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; + std::unordered_map m_mMonitorRenderResources; + std::unordered_map m_mMonitorBGFBs; struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; @@ -282,7 +282,7 @@ class CHyprOpenGLImpl { void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); GLuint compileShader(const GLuint&, std::string, bool dynamic = false); - void createBGTextureForMonitor(CMonitor*); + void createBGTextureForMonitor(PHLMONITOR); void initShaders(); void initDRMFormats(); void initEGL(bool gbm); @@ -304,7 +304,7 @@ class CHyprOpenGLImpl { void preBlurForCurrentMonitor(); - bool passRequiresIntrospection(CMonitor* pMonitor); + bool passRequiresIntrospection(PHLMONITOR pMonitor); friend class CHyprRenderer; }; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index bc95abc6..1165b197 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -295,7 +295,7 @@ static void renderSurface(SP surface, int x, int y, void* da RDATA->surfaceCounter++; } -bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) { +bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { if (!pWindow->visibleOnMonitor(pMonitor)) return false; @@ -389,7 +389,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { return false; } -void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time) { +void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* time) { PHLWINDOW pWorkspaceWindow = nullptr; EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); @@ -479,7 +479,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(CMonitor* pMonitor, PHLWORK } } -void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time) { +void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* time) { PHLWINDOW lastWindow; EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); @@ -551,7 +551,7 @@ void CHyprRenderer::renderWorkspaceWindows(CMonitor* pMonitor, PHLWORKSPACE pWor } } -void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) { +void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) { if (pWindow->isHidden()) return; @@ -766,7 +766,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, CMonitor* pMonitor, timespec g_pHyprOpenGL->m_RenderData.clipBox = CBox(); } -void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time, bool popups) { +void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* time, bool popups) { if (!pLayer) return; @@ -835,7 +835,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, CMonitor* pMonitor, timespec* time g_pHyprOpenGL->m_RenderData.discardOpacity = DA; } -void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, timespec* time) { +void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, timespec* time) { const auto POS = pPopup->globalBox().pos(); SRenderData renderdata = {pMonitor, time, POS.x, POS.y}; @@ -851,7 +851,7 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, CMonitor* pMonitor, time SURF->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } -void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMonitor* pMonitor, timespec* time) { +void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, PHLMONITOR pMonitor, timespec* time) { SRenderData renderdata = {pMonitor, time, pMonitor->vecPosition.x, pMonitor->vecPosition.y}; renderdata.blur = false; @@ -863,7 +863,7 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon renderdata.surface->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } -void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { +void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { static auto PDIMSPECIAL = CConfigValue("decoration:dim_special"); static auto PBLURSPECIAL = CConfigValue("decoration:blur:special"); static auto PBLUR = CConfigValue("decoration:blur:enabled"); @@ -1036,7 +1036,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC g_pHyprOpenGL->m_RenderData.renderModif = {}; } -void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry) { +void CHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, timespec* now, const CBox& geometry) { TRACY_GPU_ZONE("RenderLockscreen"); if (g_pSessionLockManager->isSessionLocked()) { @@ -1052,7 +1052,7 @@ void CHyprRenderer::renderLockscreen(CMonitor* pMonitor, timespec* now, const CB } } -void CHyprRenderer::renderSessionLockMissing(CMonitor* pMonitor) { +void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { const auto ALPHA = g_pSessionLockManager->getRedScreenAlphaForMonitor(pMonitor->ID); CBox monbox = {{}, pMonitor->vecPixelSize}; @@ -1181,7 +1181,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPm_pLastMonitor.get()) { + if (pMonitor == g_pCompositor->m_pLastMonitor) { g_pHyprNotificationOverlay->draw(pMonitor); g_pHyprError->draw(); } // for drawing the debug overlay - if (pMonitor == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) { + if (pMonitor == g_pCompositor->m_vMonitors.front() && *PDEBUGOVERLAY == 1) { renderStartOverlay = std::chrono::high_resolution_clock::now(); g_pDebugOverlay->draw(); endRenderOverlay = std::chrono::high_resolution_clock::now(); @@ -1491,7 +1491,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pDebugOverlay->renderData(pMonitor, durationUs); if (*PDEBUGOVERLAY == 1) { - if (pMonitor == g_pCompositor->m_vMonitors.front().get()) { + if (pMonitor == g_pCompositor->m_vMonitors.front()) { const float noOverlayUs = durationUs - std::chrono::duration_cast(endRenderOverlay - renderStartOverlay).count() / 1000.f; g_pDebugOverlay->renderDataNoOverlay(pMonitor, noOverlayUs); } else { @@ -1500,7 +1500,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } } -bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { +bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it auto inFD = pMonitor->output->state->state().explicitInFence; @@ -1565,7 +1565,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { return ok; } -void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { +void CHyprRenderer::renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { Vector2D translate = {geometry.x, geometry.y}; float scale = (float)geometry.width / pMonitor->vecPixelSize.x; @@ -1582,7 +1582,7 @@ void CHyprRenderer::renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, g_pHyprOpenGL->m_RenderData.pWorkspace = nullptr; } -void CHyprRenderer::sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { +void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now) { for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || !w->m_pWLSurface->resource()) continue; @@ -1670,7 +1670,7 @@ static void applyExclusive(CBox& usableArea, uint32_t anchor, int32_t exclusive, } } -void CHyprRenderer::arrangeLayerArray(CMonitor* pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { +void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vector& layerSurfaces, bool exclusiveZone, CBox* usableArea) { CBox full_area = {pMonitor->vecPosition.x, pMonitor->vecPosition.y, pMonitor->vecSize.x, pMonitor->vecSize.y}; for (auto const& ls : layerSurfaces) { @@ -1865,7 +1865,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { windowBox.translate(pWindow->m_vFloatingOffset); for (auto const& m : g_pCompositor->m_vMonitors) { - if (forceFull || g_pHyprRenderer->shouldRenderWindow(pWindow, m.get())) { // only damage if window is rendered on monitor + if (forceFull || g_pHyprRenderer->shouldRenderWindow(pWindow, m)) { // only damage if window is rendered on monitor CBox fixedDamageBox = {windowBox.x - m->vecPosition.x, windowBox.y - m->vecPosition.y, windowBox.width, windowBox.height}; fixedDamageBox.scale(m->scale); m->addDamage(&fixedDamageBox); @@ -1881,7 +1881,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { Debug::log(LOG, "Damage: Window ({}): xy: {}, {} wh: {}, {}", pWindow->m_szTitle, windowBox.x, windowBox.y, windowBox.width, windowBox.height); } -void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { +void CHyprRenderer::damageMonitor(PHLMONITOR pMonitor) { if (g_pCompositor->m_bUnsafeState || pMonitor->isMirror()) return; @@ -1925,7 +1925,7 @@ void CHyprRenderer::damageRegion(const CRegion& rg) { } } -void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion) { +void CHyprRenderer::damageMirrorsWith(PHLMONITOR pMonitor, const CRegion& pRegion) { for (auto const& mirror : pMonitor->mirrors) { // transform the damage here, so it won't get clipped by the monitor damage ring @@ -1946,11 +1946,11 @@ void CHyprRenderer::damageMirrorsWith(CMonitor* pMonitor, const CRegion& pRegion mirror->addDamage(&transformed); - g_pCompositor->scheduleFrameForMonitor(mirror, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); + g_pCompositor->scheduleFrameForMonitor(mirror.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } } -void CHyprRenderer::renderDragIcon(CMonitor* pMonitor, timespec* time) { +void CHyprRenderer::renderDragIcon(PHLMONITOR pMonitor, timespec* time) { PROTO::data->renderDND(pMonitor, time); } @@ -1965,7 +1965,7 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& return DAMAGE_TRACKING_INVALID; } -bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { +bool CHyprRenderer::applyMonitorRule(PHLMONITOR pMonitor, SMonitorRule* pMonitorRule, bool force) { static auto PDISABLESCALECHECKS = CConfigValue("debug:disable_scale_checks"); @@ -2436,7 +2436,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { if (!g_pPointerManager->softwareLockedFor(m)) continue; - g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? + g_pHyprRenderer->damageMonitor(m); // TODO: maybe just damage the cursor area? } setCursorHidden(true); @@ -2448,7 +2448,7 @@ void CHyprRenderer::ensureCursorRenderingMode() { if (!g_pPointerManager->softwareLockedFor(m)) continue; - g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? + g_pHyprRenderer->damageMonitor(m); // TODO: maybe just damage the cursor area? } setCursorHidden(false); @@ -2479,7 +2479,7 @@ bool CHyprRenderer::shouldRenderCursor() { return !m_bCursorHidden && m_bCursorHasSurface; } -std::tuple CHyprRenderer::getRenderTimes(CMonitor* pMonitor) { +std::tuple CHyprRenderer::getRenderTimes(PHLMONITOR pMonitor) { const auto POVERLAY = &g_pDebugOverlay->m_mMonitorOverlays[pMonitor]; float avgRenderTime = 0; @@ -2590,7 +2590,7 @@ void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWork region.subtract(rg); } -bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { +bool CHyprRenderer::canSkipBackBufferClear(PHLMONITOR pMonitor) { for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { if (!ls->layerSurface) continue; @@ -2616,7 +2616,7 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) { return false; } -void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) { +void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { pMonitor->solitaryClient.reset(); // reset it, if we find one it will be set. if (g_pHyprNotificationOverlay->hasAny() || g_pSessionLockManager->isSessionLocked()) @@ -2704,7 +2704,7 @@ void CHyprRenderer::unsetEGL() { eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } -bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { +bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP buffer, CFramebuffer* fb, bool simple) { makeEGLCurrent(); @@ -2777,7 +2777,7 @@ void CHyprRenderer::endRender() { if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); else { - g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; + g_pHyprOpenGL->m_RenderData.pMonitor.reset(); g_pHyprOpenGL->m_RenderData.mouseZoomFactor = 1.f; g_pHyprOpenGL->m_RenderData.mouseZoomUseMouse = true; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 7d1ae4b1..41f40b5a 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -49,29 +49,29 @@ class CHyprRenderer { CHyprRenderer(); ~CHyprRenderer(); - void renderMonitor(CMonitor* pMonitor); + void renderMonitor(PHLMONITOR pMonitor); void arrangeLayersForMonitor(const MONITORID&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); void damageBox(CBox*, bool skipFrameSchedule = false); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageRegion(const CRegion&); - void damageMonitor(CMonitor*); - void damageMirrorsWith(CMonitor*, const CRegion&); - bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false); - bool shouldRenderWindow(PHLWINDOW, CMonitor*); + void damageMonitor(PHLMONITOR); + void damageMirrorsWith(PHLMONITOR, const CRegion&); + bool applyMonitorRule(PHLMONITOR, SMonitorRule*, bool force = false); + bool shouldRenderWindow(PHLWINDOW, PHLMONITOR); bool shouldRenderWindow(PHLWINDOW); void ensureCursorRenderingMode(); bool shouldRenderCursor(); void setCursorHidden(bool hide); void calculateUVForSurface(PHLWINDOW, SP, SP pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, bool fixMisalignedFSV1 = false); - std::tuple getRenderTimes(CMonitor* pMonitor); // avg max min - void renderLockscreen(CMonitor* pMonitor, timespec* now, const CBox& geometry); + std::tuple getRenderTimes(PHLMONITOR pMonitor); // avg max min + void renderLockscreen(PHLMONITOR pMonitor, timespec* now, const CBox& geometry); void setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace); void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods - bool canSkipBackBufferClear(CMonitor* pMonitor); - void recheckSolitaryForMonitor(CMonitor* pMonitor); + bool canSkipBackBufferClear(PHLMONITOR pMonitor); + void recheckSolitaryForMonitor(PHLMONITOR pMonitor); void setCursorSurface(SP surf, int hotspotX, int hotspotY, bool force = false); void setCursorFromName(const std::string& name, bool force = false); void onRenderbufferDestroy(CRenderbuffer* rb); @@ -84,13 +84,13 @@ class CHyprRenderer { // if RENDER_MODE_NORMAL, provided damage will be written to. // otherwise, it will be the one used. - bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); - void endRender(); + bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP buffer = {}, CFramebuffer* fb = nullptr, bool simple = false); + void endRender(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; - CMonitor* m_pMostHzMonitor = nullptr; - bool m_bDirectScanoutBlocked = false; + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; + PHLMONITORREF m_pMostHzMonitor; + bool m_bDirectScanoutBlocked = false; DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); @@ -115,20 +115,20 @@ class CHyprRenderer { } m_sLastCursorData; private: - void arrangeLayerArray(CMonitor*, const std::vector&, bool, CBox*); - void renderWorkspaceWindowsFullscreen(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) - void renderWorkspaceWindows(CMonitor*, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) - void renderWindow(PHLWINDOW, CMonitor*, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); - void renderLayer(PHLLS, CMonitor*, timespec*, bool popups = false); - void renderSessionLockSurface(SSessionLockSurface*, CMonitor*, timespec*); - void renderDragIcon(CMonitor*, timespec*); - void renderIMEPopup(CInputPopup*, CMonitor*, timespec*); - void renderWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); - void sendFrameEventsToWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything - void renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); - void renderSessionLockMissing(CMonitor* pMonitor); + void arrangeLayerArray(PHLMONITOR, const std::vector&, bool, CBox*); + void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) + void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) + void renderWindow(PHLWINDOW, PHLMONITOR, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); + void renderLayer(PHLLS, PHLMONITOR, timespec*, bool popups = false); + void renderSessionLockSurface(SSessionLockSurface*, PHLMONITOR, timespec*); + void renderDragIcon(PHLMONITOR, timespec*); + void renderIMEPopup(CInputPopup*, PHLMONITOR, timespec*); + void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); + void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now); // sends frame displayed events but doesn't actually render anything + void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const Vector2D& translate = {0, 0}, const float& scale = 1.f); + void renderSessionLockMissing(PHLMONITOR pMonitor); - bool commitPendingAndDoExplicitSync(CMonitor* pMonitor); + bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); bool m_bCursorHidden = false; bool m_bCursorHasSurface = false; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 1eaaa0af..68325a9c 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -46,7 +46,7 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { return box.translate(WORKSPACEOFFSET); } -void CHyprBorderDecoration::draw(CMonitor* pMonitor, float a) { +void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float a) { if (doesntWantBorders()) return; @@ -119,7 +119,7 @@ void CHyprBorderDecoration::damageEntire() { borderRegion.subtract(surfaceBoxShrunkRounding); for (auto const& m : g_pCompositor->m_vMonitors) { - if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow.lock(), m.get())) { + if (!g_pHyprRenderer->shouldRenderWindow(m_pWindow.lock(), m)) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); borderRegion.subtract(monitorRegion); } diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index 0e196565..5d248a81 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -11,7 +11,7 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a); + virtual void draw(PHLMONITOR, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 628a579a..a4388a67 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -67,7 +67,7 @@ void CHyprDropShadowDecoration::damageEntire() { } for (auto const& m : g_pCompositor->m_vMonitors) { - if (!g_pHyprRenderer->shouldRenderWindow(PWINDOW, m.get())) { + if (!g_pHyprRenderer->shouldRenderWindow(PWINDOW, m)) { const CRegion monitorRegion({m->vecPosition, m->vecSize}); shadowRegion.subtract(monitorRegion); } @@ -86,7 +86,7 @@ void CHyprDropShadowDecoration::updateWindow(PHLWINDOW pWindow) { m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); } -void CHyprDropShadowDecoration::draw(CMonitor* pMonitor, float a) { +void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float a) { const auto PWINDOW = m_pWindow.lock(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index ecd5a47b..fce9a7c7 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -11,7 +11,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a); + virtual void draw(PHLMONITOR, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 74a1e2e9..4219a5a8 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -94,7 +94,7 @@ void CHyprGroupBarDecoration::damageEntire() { g_pHyprRenderer->damageBox(&box); } -void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { +void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index bfb15d5c..e388fa38 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -31,7 +31,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(CMonitor*, float a); + virtual void draw(PHLMONITOR, float a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index a58560f3..99698a56 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -39,7 +39,7 @@ class IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply) = 0; - virtual void draw(CMonitor*, float a) = 0; + virtual void draw(PHLMONITOR, float a) = 0; virtual eDecorationType getDecorationType() = 0; From 6a5c342063814ca7e3d181f324c71305bcd656a0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 23:45:51 +0100 Subject: [PATCH 0754/2393] layersurface: round geom in arrangeLayerArray fixes #8171 --- src/render/Renderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1165b197..1946d5a2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1742,7 +1742,9 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vectorgeometry = box; applyExclusive(*usableArea, PSTATE->anchor, PSTATE->exclusive, PSTATE->exclusiveEdge, PSTATE->margin.top, PSTATE->margin.right, PSTATE->margin.bottom, PSTATE->margin.left); From a17850e41cabb455880b43032cf65041cd77ef25 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 23:47:28 +0100 Subject: [PATCH 0755/2393] layersurface: fixup brace style --- src/render/Renderer.cpp | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1946d5a2..5df0c070 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1693,51 +1693,51 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vectordesiredSize}; // Horizontal axis const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - if (box.width == 0) { + if (box.width == 0) box.x = bounds.x; - } else if ((PSTATE->anchor & both_horiz) == both_horiz) { + else if ((PSTATE->anchor & both_horiz) == both_horiz) box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) box.x = bounds.x; - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) box.x = bounds.x + (bounds.width - box.width); - } else { + else box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } + // Vertical axis const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if (box.height == 0) { + if (box.height == 0) box.y = bounds.y; - } else if ((PSTATE->anchor & both_vert) == both_vert) { + else if ((PSTATE->anchor & both_vert) == both_vert) box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) box.y = bounds.y; - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) box.y = bounds.y + (bounds.height - box.height); - } else { + else box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } + // Margin if (box.width == 0) { box.x += PSTATE->margin.left; box.width = bounds.width - (PSTATE->margin.left + PSTATE->margin.right); - } else if ((PSTATE->anchor & both_horiz) == both_horiz) { - // don't apply margins - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + } else if ((PSTATE->anchor & both_horiz) == both_horiz) + ; // don't apply margins + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) box.x += PSTATE->margin.left; - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) box.x -= PSTATE->margin.right; - } + if (box.height == 0) { box.y += PSTATE->margin.top; box.height = bounds.height - (PSTATE->margin.top + PSTATE->margin.bottom); - } else if ((PSTATE->anchor & both_vert) == both_vert) { - // don't apply margins - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + } else if ((PSTATE->anchor & both_vert) == both_vert) + ; // don't apply margins + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) box.y += PSTATE->margin.top; - } else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + else if ((PSTATE->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) box.y -= PSTATE->margin.bottom; - } + if (box.width <= 0 || box.height <= 0) { Debug::log(ERR, "LayerSurface {:x} has a negative/zero w/h???", (uintptr_t)ls.get()); continue; From 08cc063e175e48cea44d26b7e3762f4b8611f0c5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 19 Oct 2024 23:48:25 +0100 Subject: [PATCH 0756/2393] monitor: avoid crash on released buffer in surf --- src/helpers/Monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 6ded5ea4..d8889585 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -845,7 +845,7 @@ bool CMonitor::attemptDirectScanout() { return false; // we can't scanout shm buffers. - if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) + if (!PSURFACE->current.buffer || !PSURFACE->current.buffer->buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */) return false; Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get()); From 4093b993a2c79ce576702641134d745ab97c6b2c Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 21 Oct 2024 11:08:25 -0400 Subject: [PATCH 0757/2393] input: add snapping to floating windows (#8088) * add snapping to floating windows Works for both moving and resizing of windows. It comes with 3 options: `general:snap:enabled` - whether it's enabled, off by default `general:snap:window_gap` - minimum gap in pixels between windows before snapping. Setting to 0 effectively turns off this method of snapping. `general:snap:monitor_gap` - minimum gap in pixels between window and monitor edges before snapping. Again, setting it to 0 effectively turns it off. * snap: add more ignore criteria and change if clause into a guard * snap: refactor code * snap: new refactoring approach and account for border size * snap: do corner snapping after all edge snapping is done The approach of performing corner snaps after each individual edge snap results in far fewer scenarios where snapping can occur. After trying it out for a while, I found that I prefer an approach that's more prone to snapping. * snap: combine snapWindows and snapMonitor into a single function * snap: add forced aspect ratio functionality * snap: avoid directly referring to border_size config value * snap: address vaxerski feedback - add new line between functions - use std::function typedef for SnapFn and make snap functions static - avoid uninitialized variable declarations. - change ignore condition m_bIsX11 to isX11OverrideRedirect() - use braces for CBox and Vector2D declarations. - add SNAP_INVALID to eSnapEdge enum - use bitshift notation for eSnapEdge and eRectCorner - make performSnap a non-member function. * snap: add corner-snapping to forced aspect ratio mode --- src/config/ConfigDescriptions.hpp | 18 ++++ src/config/ConfigManager.cpp | 3 + src/layout/IHyprLayout.cpp | 155 +++++++++++++++++++++++++++++- src/layout/IHyprLayout.hpp | 18 +++- 4 files changed, 185 insertions(+), 9 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index bef5ee53..7e2dd1be 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -104,6 +104,24 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{0, 0, 4}, }, + SConfigOptionDescription{ + .value = "general:snap:enabled", + .description = "enable snapping for floating windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "general:snap:window_gap", + .description = "minimum gap in pixels between windows before snapping", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{10, 0, 100}, + }, + SConfigOptionDescription{ + .value = "general:snap:monitor_gap", + .description = "minimum gap in pixels between window and monitor edges before snapping", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{10, 0, 100}, + }, /* * decoration: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f16ebe46..1dbd248d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -341,6 +341,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("general:layout", {"dwindle"}); m_pConfig->addConfigValue("general:allow_tearing", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:resize_corner", Hyprlang::INT{0}); + m_pConfig->addConfigValue("general:snap:enabled", Hyprlang::INT{0}); + m_pConfig->addConfigValue("general:snap:window_gap", Hyprlang::INT{10}); + m_pConfig->addConfigValue("general:snap:monitor_gap", Hyprlang::INT{10}); m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index b8d92636..95919c65 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -396,6 +396,138 @@ void IHyprLayout::onEndDragWindow() { g_pInputManager->m_bWasDraggingWindow = false; } +static inline bool canSnap(const double sideA, const double sideB, const double gap) { + return std::abs(sideA - sideB) < gap; +} + +static void snapMoveLeft(double& pos, double& len, const double p) { + pos = p; +} + +static void snapMoveRight(double& pos, double& len, const double p) { + pos = p - len; +} + +static void snapResizeLeft(double& pos, double& len, const double p) { + len += pos - p; + pos = p; +} + +static void snapResizeRight(double& pos, double& len, const double p) { + len = p - pos; +} + +typedef std::function SnapFn; + +static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode mode, const int corner, const Vector2D& beginSize) { + static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); + static auto SNAPMONITORGAP = CConfigValue("general:snap:monitor_gap"); + + const SnapFn snapRight = (mode == MBIND_MOVE) ? snapMoveRight : snapResizeRight; + const SnapFn snapLeft = (mode == MBIND_MOVE) ? snapMoveLeft : snapResizeLeft; + const SnapFn snapDown = snapRight; + const SnapFn snapUp = snapLeft; + int snaps = 0; + + if (*SNAPWINDOWGAP) { + const auto PID = DRAGGINGWINDOW->getPID(); + const auto WSID = DRAGGINGWINDOW->workspaceID(); + const int BORD = DRAGGINGWINDOW->getRealBorderSize(); + + for (auto& other : g_pCompositor->m_vWindows) { + if (other->workspaceID() != WSID || other->getPID() == PID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) + continue; + + const int bord = std::max(BORD, other->getRealBorderSize()); + const double gap = *SNAPWINDOWGAP + bord; + + const CBox box = other->getWindowMainSurfaceBox(); + const CBox ob = {box.x, box.y, box.x + box.w, box.y + box.h}; + const CBox bb = {ob.x - bord, ob.y - bord, ob.w + bord, ob.h + bord}; + const Vector2D end = {pos.x + size.x, pos.y + size.y}; + + // only snap windows if their ranges intersect in the opposite axis + if (pos.y <= bb.h && bb.y <= end.y) { + if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(pos.x, bb.w, gap)) { + snapLeft(pos.x, size.x, bb.w); + snaps |= SNAP_LEFT; + } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, bb.x, gap)) { + snapRight(pos.x, size.x, bb.x); + snaps |= SNAP_RIGHT; + } + } + if (pos.x <= bb.w && bb.x <= end.x) { + if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(pos.y, bb.h, gap)) { + snapUp(pos.y, size.y, bb.h); + snaps |= SNAP_UP; + } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, bb.y, gap)) { + snapDown(pos.y, size.y, bb.y); + snaps |= SNAP_DOWN; + } + } + + // corner snapping + if (pos.x == bb.w || bb.x == pos.x + size.x) { + if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(pos.y, ob.y, gap)) { + snapUp(pos.y, size.y, ob.y); + snaps |= SNAP_UP; + } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, ob.h, gap)) { + snapDown(pos.y, size.y, ob.h); + snaps |= SNAP_DOWN; + } + } + if (pos.y == bb.h || bb.y == pos.y + size.y) { + if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(pos.x, ob.x, gap)) { + snapLeft(pos.x, size.x, ob.x); + snaps |= SNAP_LEFT; + } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, ob.w, gap)) { + snapRight(pos.x, size.x, ob.w); + snaps |= SNAP_RIGHT; + } + } + } + } + + if (*SNAPMONITORGAP) { + const auto MON = g_pCompositor->getMonitorFromID(DRAGGINGWINDOW->m_iMonitorID); + const CBox mon = {MON->vecPosition.x, MON->vecPosition.y, MON->vecPosition.x + MON->vecSize.x, MON->vecPosition.y + MON->vecSize.y}; + const double gap = *SNAPMONITORGAP; + + if (canSnap(pos.x, mon.x, gap)) { + snapLeft(pos.x, size.x, mon.x); + snaps |= SNAP_LEFT; + } + if (canSnap(pos.x + size.x, mon.w, gap)) { + snapRight(pos.x, size.x, mon.w); + snaps |= SNAP_RIGHT; + } + if (canSnap(pos.y, mon.y, gap)) { + snapUp(pos.y, size.y, mon.y); + snaps |= SNAP_UP; + } + if (canSnap(pos.y + size.y, mon.h, gap)) { + snapDown(pos.y, size.y, mon.h); + snaps |= SNAP_DOWN; + } + } + + if (mode == MBIND_RESIZE_FORCE_RATIO) { + const double RATIO = beginSize.y / beginSize.x; + + if ((corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) { + const double sizeY = size.x * RATIO; + if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT)) + pos.y += size.y - sizeY; + size.y = sizeY; + } else if ((corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) { + const double sizeX = size.y / RATIO; + if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT)) + pos.x += size.x - sizeX; + size.x = sizeX; + } + } +} + void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (g_pInputManager->currentlyDraggedWindow.expired()) return; @@ -418,6 +550,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { static auto PANIMATEMOUSE = CConfigValue("misc:animate_mouse_windowdragging"); static auto PANIMATE = CConfigValue("misc:animate_manual_resizes"); + static auto SNAPENABLED = CConfigValue("general:snap:enabled"); + const auto TIMERDELTA = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - TIMER).count(); const auto MSDELTA = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - MSTIMER).count(); const auto MSMONITOR = 1000.0 / g_pHyprRenderer->m_pMostHzMonitor->refreshRate; @@ -448,7 +582,13 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (g_pInputManager->dragMode == MBIND_MOVE) { - CBox wb = {m_vBeginDragPositionXY + DELTA, DRAGGINGWINDOW->m_vRealSize.goal()}; + Vector2D newPos = m_vBeginDragPositionXY + DELTA; + Vector2D newSize = DRAGGINGWINDOW->m_vRealSize.goal(); + + if (*SNAPENABLED && !DRAGGINGWINDOW->m_bDraggingTiled) + performSnap(newPos, newSize, DRAGGINGWINDOW, MBIND_MOVE, -1, m_vBeginDragSizeXY); + + CBox wb = {newPos, newSize}; wb.round(); if (*PANIMATEMOUSE) @@ -479,9 +619,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) newSize = newSize + Vector2D(-DELTA.x, DELTA.y); - if ((m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1) && - (g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || - (!(g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) && DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault()))) { + eMouseBindMode mode = g_pInputManager->dragMode; + if (DRAGGINGWINDOW->m_sWindowData.keepAspectRatio.valueOrDefault() && mode != MBIND_RESIZE_BLOCK_RATIO) + mode = MBIND_RESIZE_FORCE_RATIO; + + if (m_vBeginDragSizeXY.x >= 1 && m_vBeginDragSizeXY.y >= 1 && mode == MBIND_RESIZE_FORCE_RATIO) { const float RATIO = m_vBeginDragSizeXY.y / m_vBeginDragSizeXY.x; @@ -510,6 +652,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { else if (m_eGrabbedCorner == CORNER_BOTTOMLEFT) newPos = newPos + Vector2D((m_vBeginDragSizeXY - newSize).x, 0.0); + if (*SNAPENABLED) { + performSnap(newPos, newSize, DRAGGINGWINDOW, mode, m_eGrabbedCorner, m_vBeginDragSizeXY); + newSize = newSize.clamp(MINSIZE, MAXSIZE); + } + CBox wb = {newPos, newSize}; wb.round(); diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index f9e2de0d..f1659ccd 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -18,11 +18,19 @@ struct SLayoutMessageHeader { enum eFullscreenMode : int8_t; enum eRectCorner { - CORNER_NONE = 0, - CORNER_TOPLEFT, - CORNER_TOPRIGHT, - CORNER_BOTTOMRIGHT, - CORNER_BOTTOMLEFT + CORNER_NONE = 0, + CORNER_TOPLEFT = (1 << 0), + CORNER_TOPRIGHT = (1 << 1), + CORNER_BOTTOMRIGHT = (1 << 2), + CORNER_BOTTOMLEFT = (1 << 3), +}; + +enum eSnapEdge { + SNAP_INVALID = 0, + SNAP_UP = (1 << 0), + SNAP_DOWN = (1 << 1), + SNAP_LEFT = (1 << 2), + SNAP_RIGHT = (1 << 3), }; enum eDirection { From 9df0f0b66c66706c9ce8cf9f80e834d5abfc1e96 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:09:14 -0500 Subject: [PATCH 0758/2393] renderer: fix floating window damage (#8182) --- src/events/Windows.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 21055f79..57a28948 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -687,6 +687,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(PWINDOW); + g_pHyprRenderer->damageWindow(PWINDOW); + // do this after onWindowRemoved because otherwise it'll think the window is invalid PWINDOW->m_bIsMapped = false; @@ -726,8 +728,6 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->addToFadingOutSafe(PWINDOW); - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)); - if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it From 5e96d738e698f22969ca502d042d5751711c6d8a Mon Sep 17 00:00:00 2001 From: KAGEYAM4 <75798544+KAGEYAM4@users.noreply.github.com> Date: Tue, 22 Oct 2024 04:58:42 +0530 Subject: [PATCH 0759/2393] hyprpm: Add option to notify on fail and keep original notify (#8167) * Only generate notification on fail Hyprpm fail/pass notification are mutually exclusive. * Add option to notify on fail and keep original notify (#1) * Add option to notify on fail and keep original notify --------- Co-authored-by: KAGEYAM4 <75798544+KAGEYAM4@users.noreply.github.com> --------- Co-authored-by: littleblack111 --- hyprpm/src/main.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 67f14aed..55fb57e2 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -23,7 +23,8 @@ constexpr std::string_view HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┃ ┣ Flags: ┃ -┣ --notify | -n → Send a hyprland notification for important events (e.g. load fail) +┣ --notify | -n → Send a hyprland notification for important events (including both successes and fail events) +┣ --notify-fail | -nn → Send a hyprland notification for fail events only ┣ --help | -h → Show this menu ┣ --verbose | -v → Enable too much logging ┣ --force | -f → Force an operation ignoring checks (e.g. update -f) @@ -43,7 +44,7 @@ int main(int argc, char** argv, char** envp) { } std::vector command; - bool notify = false, verbose = false, force = false, noShallow = false; + bool notify = false, notifyFail = false, verbose = false, force = false, noShallow = false; for (int i = 1; i < argc; ++i) { if (ARGS[i].starts_with("-")) { @@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) { return 0; } else if (ARGS[i] == "--notify" || ARGS[i] == "-n") { notify = true; + } else if (ARGS[i] == "--notify-fail" || ARGS[i] == "-nn") { + notifyFail = notify = true; } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { verbose = true; } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { @@ -155,7 +158,7 @@ int main(int argc, char** argv, char** envp) { break; default: break; } - } else if (notify) { + } else if (notify && !notifyFail) { g_pPluginManager->notify(ICON_OK, 0, 4000, "[hyprpm] Loaded plugins"); } } else if (command[0] == "list") { From 29997ef4ba8ef0a80390e80199998d1390177454 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 22 Oct 2024 21:34:15 +0100 Subject: [PATCH 0760/2393] default/config: improve default animations objectively better --- example/hyprland.conf | 30 ++++++++++++++++++++++-------- src/config/defaultConfig.hpp | 30 ++++++++++++++++++++++-------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index 012446f3..f94cb1d1 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -103,18 +103,32 @@ decoration { # https://wiki.hyprland.org/Configuring/Variables/#animations animations { - enabled = true + enabled = yes, please :) # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more - bezier = myBezier, 0.05, 0.9, 0.1, 1.05 + bezier = easeOutQuint,0.23,1,0.32,1 + bezier = easeInOutCubic,0.65,0.05,0.36,1 + bezier = linear,0,0,1,1 + bezier = almostLinear,0.5,0.5,0.75,1.0 + bezier = quick,0.15,0,0.1,1 - animation = windows, 1, 7, myBezier - animation = windowsOut, 1, 7, default, popin 80% - animation = border, 1, 10, default - animation = borderangle, 1, 8, default - animation = fade, 1, 7, default - animation = workspaces, 1, 6, default + animation = global, 1, 10, default + animation = border, 1, 5.39, easeOutQuint + animation = windows, 1, 4.79, easeOutQuint + animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% + animation = windowsOut, 1, 1.49, linear, popin 87% + animation = fadeIn, 1, 1.73, almostLinear + animation = fadeOut, 1, 1.46, almostLinear + animation = fade, 1, 3.03, quick + animation = layers, 1, 3.81, easeOutQuint + animation = layersIn, 1, 4, easeOutQuint, fade + animation = layersOut, 1, 1.5, linear, fade + animation = fadeLayersIn, 1, 1.79, almostLinear + animation = fadeLayersOut, 1, 1.39, almostLinear + animation = workspaces, 1, 1.94, almostLinear, fade + animation = workspacesIn, 1, 1.21, almostLinear, fade + animation = workspacesOut, 1, 1.94, almostLinear, fade } # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index a5d759de..4a33ec91 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -116,18 +116,32 @@ decoration { # https://wiki.hyprland.org/Configuring/Variables/#animations animations { - enabled = true + enabled = yes, please :) # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more - bezier = myBezier, 0.05, 0.9, 0.1, 1.05 + bezier = easeOutQuint,0.23,1,0.32,1 + bezier = easeInOutCubic,0.65,0.05,0.36,1 + bezier = linear,0,0,1,1 + bezier = almostLinear,0.5,0.5,0.75,1.0 + bezier = quick,0.15,0,0.1,1 - animation = windows, 1, 7, myBezier - animation = windowsOut, 1, 7, default, popin 80% - animation = border, 1, 10, default - animation = borderangle, 1, 8, default - animation = fade, 1, 7, default - animation = workspaces, 1, 6, default + animation = global, 1, 10, default + animation = border, 1, 5.39, easeOutQuint + animation = windows, 1, 4.79, easeOutQuint + animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% + animation = windowsOut, 1, 1.49, linear, popin 87% + animation = fadeIn, 1, 1.73, almostLinear + animation = fadeOut, 1, 1.46, almostLinear + animation = fade, 1, 3.03, quick + animation = layers, 1, 3.81, easeOutQuint + animation = layersIn, 1, 4, easeOutQuint, fade + animation = layersOut, 1, 1.5, linear, fade + animation = fadeLayersIn, 1, 1.79, almostLinear + animation = fadeLayersOut, 1, 1.39, almostLinear + animation = workspaces, 1, 1.94, almostLinear, fade + animation = workspacesIn, 1, 1.21, almostLinear, fade + animation = workspacesOut, 1, 1.94, almostLinear, fade } # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ From 2b6ff6837e81a3b459f2f3cc366830c420a7a62e Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Tue, 22 Oct 2024 23:51:25 +0000 Subject: [PATCH 0761/2393] groups: add group_on_movetoworkspace (#8159) --- src/Compositor.cpp | 51 +++++++++++++++++++++++-------- src/config/ConfigDescriptions.hpp | 6 ++++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 5 +-- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b23b3194..313d57ac 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -34,6 +34,7 @@ #include "render/Renderer.hpp" #include "xwayland/XWayland.hpp" #include "helpers/ByteOperations.hpp" +#include "render/decorations/CHyprGroupBarDecoration.hpp" #include #include @@ -2748,21 +2749,47 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor if (FULLSCREEN) setWindowFullscreenInternal(pWindow, FSMODE_NONE); - if (!pWindow->m_bIsFloating) { + const PHLWINDOW pFirstWindowOnWorkspace = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID); + const int visibleWindowsOnWorkspace = g_pCompositor->getWindowsOnWorkspace(pWorkspace->m_iID, std::nullopt, true); + const auto PWINDOWMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; + const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + + if (!pWindow->m_bIsFloating) g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); - pWindow->moveToWorkspace(pWorkspace); - pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; - g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow); + + pWindow->moveToWorkspace(pWorkspace); + pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; + + static auto PGROUPONMOVETOWORKSPACE = CConfigValue("group:group_on_movetoworkspace"); + if (*PGROUPONMOVETOWORKSPACE && visibleWindowsOnWorkspace == 1 && pFirstWindowOnWorkspace && pFirstWindowOnWorkspace != pWindow && + pFirstWindowOnWorkspace->m_sGroupData.pNextWindow.lock() && pWindow->canBeGroupedInto(pFirstWindowOnWorkspace)) { + + pWindow->m_bIsFloating = pFirstWindowOnWorkspace->m_bIsFloating; // match the floating state. Needed to group tiled into floated and vice versa. + if (!pWindow->m_sGroupData.pNextWindow.expired()) { + PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock(); + while (next != pWindow) { + next->m_bIsFloating = pFirstWindowOnWorkspace->m_bIsFloating; // match the floating state of group members + next = next->m_sGroupData.pNextWindow.lock(); + } + } + + static auto USECURRPOS = CConfigValue("group:insert_after_current"); + (*USECURRPOS ? pFirstWindowOnWorkspace : pFirstWindowOnWorkspace->getGroupTail())->insertWindowToGroup(pWindow); + + pFirstWindowOnWorkspace->setGroupCurrent(pWindow); + pWindow->updateWindowDecos(); + g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); + + if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) + pWindow->addWindowDeco(std::make_unique(pWindow)); + } else { - const auto PWINDOWMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; + if (!pWindow->m_bIsFloating) + g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow); - const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); - - pWindow->moveToWorkspace(pWorkspace); - pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; - - pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; + if (pWindow->m_bIsFloating) + pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; } pWindow->updateToplevel(); diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 7e2dd1be..7910e865 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -808,6 +808,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "group:group_on_movetoworkspace", + .description = "whether using movetoworkspace[silent] will merge the window into the workspace's solitary unlocked group", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * group:groupbar: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1dbd248d..8237fd44 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -383,6 +383,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:merge_floated_into_tiled_on_groupbar", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:group_on_movetoworkspace", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 95919c65..655f2341 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -194,8 +194,9 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { denied = true; if (*PAUTOGROUP // check if auto_group is enabled. - && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. + && OPENINGON // this shouldn't be 0, but honestly, better safe than sorry. && OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group. + && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. && !denied) { // don't group a new floated window into a tiled group (for convenience). @@ -352,7 +353,7 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_bDraggingTiled = false; } - if (DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock()) { + if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) { std::vector members; PHLWINDOW curr = DRAGGINGWINDOW->getGroupHead(); do { From 6e0aadc585c6d9fdaaebfa5853adbf9610897c82 Mon Sep 17 00:00:00 2001 From: chitoroagad Date: Tue, 22 Oct 2024 18:05:30 +0100 Subject: [PATCH 0762/2393] updated flake.lock --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index 0a12fe0a..beb56b5c 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1728902391, - "narHash": "sha256-44bnoY0nAvbBQ/lVjmn511yL39Sv7SknV0BDxn34P3Q=", + "lastModified": 1729527199, + "narHash": "sha256-D5/YksfRga8Akd04ZtIkuYSIOjXVrAzQIQBSeplokzU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "9874e08eec85b5542ca22494e127b0cdce46b786", + "rev": "8d732fa8aff8b12ef2b1e2f00fc8153e41312b72", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728888510, - "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", + "lastModified": 1729413321, + "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", + "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1728778939, - "narHash": "sha256-WybK5E3hpGxtCYtBwpRj1E9JoiVxe+8kX83snTNaFHE=", + "lastModified": 1729104314, + "narHash": "sha256-pZRZsq5oCdJt3upZIU4aslS9XwFJ+/nVtALHIciX/BI=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "ff68f91754be6f3427e4986d7949e6273659be1d", + "rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6", "type": "github" }, "original": { From cdac64970e894c3211d94da8925fbf905b52a594 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Thu, 24 Oct 2024 01:32:39 +0500 Subject: [PATCH 0763/2393] Makefile: fix legacyrendererdebug typo (#8214) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 98267eea..7cf21119 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ legacyrenderer: legacyrendererdebug: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` + cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` release: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build From f603a22af0c8890b9742d761d44f0b595740f5b1 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:12:41 +0500 Subject: [PATCH 0764/2393] internal: Remove some unused lambda captures (#8218) --- src/devices/Tablet.cpp | 2 +- src/managers/TokenManager.cpp | 4 ++-- src/managers/input/InputManager.cpp | 2 +- src/protocols/DataDeviceWlr.cpp | 4 ++-- src/protocols/PrimarySelection.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/devices/Tablet.cpp b/src/devices/Tablet.cpp index 71ca8991..99e436fb 100644 --- a/src/devices/Tablet.cpp +++ b/src/devices/Tablet.cpp @@ -197,7 +197,7 @@ CTabletPad::CTabletPad(SP pad_) : pad(pad_) { }); }); - listeners.attach = pad->events.attach.registerListener([this](std::any d) { + listeners.attach = pad->events.attach.registerListener([](std::any d) { ; // TODO: this doesn't do anything in aq atm }); diff --git a/src/managers/TokenManager.cpp b/src/managers/TokenManager.cpp index cee97c1c..5efa2eb8 100644 --- a/src/managers/TokenManager.cpp +++ b/src/managers/TokenManager.cpp @@ -34,7 +34,7 @@ SP CTokenManager::getToken(const std::string& uuid) { // cleanup expired tokens const auto NOW = std::chrono::steady_clock::now(); - std::erase_if(m_mTokens, [this, &NOW](const auto& el) { return el.second->expiresAt < NOW; }); + std::erase_if(m_mTokens, [&NOW](const auto& el) { return el.second->expiresAt < NOW; }); if (!m_mTokens.contains(uuid)) return {}; @@ -46,4 +46,4 @@ void CTokenManager::removeToken(SP token) { if (!token) return; m_mTokens.erase(token->uuid); -} \ No newline at end of file +} diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 196f0b71..6f7d8017 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -905,7 +905,7 @@ void CInputManager::setupKeyboard(SP keeb) { keeb.get()); keeb->keyboardEvents.keymap.registerStaticListener( - [this](void* owner, std::any data) { + [](void* owner, std::any data) { auto PKEEB = ((IKeyboard*)owner)->self.lock(); const auto LAYOUT = PKEEB->getActiveLayout(); diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 69e28772..baf0a299 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -112,7 +112,7 @@ CWLRDataDevice::CWLRDataDevice(SP resource_) : resourc resource->setDestroy([this](CZwlrDataControlDeviceV1* r) { PROTO::dataWlr->destroyResource(this); }); resource->setOnDestroy([this](CZwlrDataControlDeviceV1* r) { PROTO::dataWlr->destroyResource(this); }); - resource->setSetSelection([this](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { + resource->setSetSelection([](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; if (!source) { LOGM(LOG, "wlr reset selection received"); @@ -129,7 +129,7 @@ CWLRDataDevice::CWLRDataDevice(SP resource_) : resourc g_pSeatManager->setCurrentSelection(source); }); - resource->setSetPrimarySelection([this](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { + resource->setSetPrimarySelection([](CZwlrDataControlDeviceV1* r, wl_resource* sourceR) { auto source = sourceR ? CWLRDataSource::fromResource(sourceR) : CSharedPointer{}; if (!source) { LOGM(LOG, "wlr reset primary selection received"); diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index f1db2d65..7602a466 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -113,7 +113,7 @@ CPrimarySelectionDevice::CPrimarySelectionDevice(SPsetDestroy([this](CZwpPrimarySelectionDeviceV1* r) { PROTO::primarySelection->destroyResource(this); }); resource->setOnDestroy([this](CZwpPrimarySelectionDeviceV1* r) { PROTO::primarySelection->destroyResource(this); }); - resource->setSetSelection([this](CZwpPrimarySelectionDeviceV1* r, wl_resource* sourceR, uint32_t serial) { + resource->setSetSelection([](CZwpPrimarySelectionDeviceV1* r, wl_resource* sourceR, uint32_t serial) { static auto PPRIMARYSEL = CConfigValue("misc:middle_click_paste"); if (!*PPRIMARYSEL) { From 7f46680ab16e8f67000a09d20fc7ba41e211f3ef Mon Sep 17 00:00:00 2001 From: czlabinger <118806077+czlabinger@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:01:08 +0200 Subject: [PATCH 0765/2393] hyprctl: add caps/num lock state for keyboards (#8145) --------- Co-authored-by: Behzad --- src/debug/HyprCtl.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index e09fb529..82290f94 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -549,6 +549,15 @@ std::string configErrorsRequest(eHyprCtlOutputFormat format, std::string request std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { std::string result = ""; + auto getModState = [](SP keyboard, const char* xkbModName) -> bool { + auto IDX = xkb_keymap_mod_get_index(keyboard->xkbKeymap, xkbModName); + + if (IDX == XKB_MOD_INVALID) + return false; + + return (keyboard->modifiersState.locked & (1 << IDX)) > 0; + }; + if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "{\n"; result += "\"mice\": [\n"; @@ -580,11 +589,13 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { "variant": "{}", "options": "{}", "active_keymap": "{}", + "capsLock": {}, + "numLock": {}, "main": {} }},)#", (uintptr_t)k.get(), escapeJSONStrings(k->hlName), escapeJSONStrings(k->currentRules.rules), escapeJSONStrings(k->currentRules.model), escapeJSONStrings(k->currentRules.layout), escapeJSONStrings(k->currentRules.variant), escapeJSONStrings(k->currentRules.options), escapeJSONStrings(KM), - (k->active ? "true" : "false")); + (getModState(k, XKB_MOD_NAME_CAPS) ? "true" : "false"), (getModState(k, XKB_MOD_NAME_NUM) ? "true" : "false"), (k->active ? "true" : "false")); } trimTrailingComma(result); @@ -668,9 +679,11 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) { for (auto const& k : g_pInputManager->m_vKeyboards) { const auto KM = k->getActiveLayout(); - result += std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tmain: {}\n", - (uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, - k->currentRules.options, KM, (k->active ? "yes" : "no")); + result += + std::format("\tKeyboard at {:x}:\n\t\t{}\n\t\t\trules: r \"{}\", m \"{}\", l \"{}\", v \"{}\", o \"{}\"\n\t\t\tactive keymap: {}\n\t\t\tcapsLock: " + "{}\n\t\t\tnumLock: {}\n\t\t\tmain: {}\n", + (uintptr_t)k.get(), k->hlName, k->currentRules.rules, k->currentRules.model, k->currentRules.layout, k->currentRules.variant, k->currentRules.options, + KM, (getModState(k, XKB_MOD_NAME_CAPS) ? "yes" : "no"), (getModState(k, XKB_MOD_NAME_NUM) ? "yes" : "no"), (k->active ? "yes" : "no")); } result += "\n\nTablets:\n"; From 3cec45d82113051d35e846e5d80719d8ea0f7002 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:50:53 +0500 Subject: [PATCH 0766/2393] Improve hyprland-session.service (#8225) --- example/hyprland-session.service | 1 + 1 file changed, 1 insertion(+) diff --git a/example/hyprland-session.service b/example/hyprland-session.service index 7d33f5b3..b6f0b55b 100644 --- a/example/hyprland-session.service +++ b/example/hyprland-session.service @@ -10,5 +10,6 @@ After=graphical-session-pre.target Type=notify ExecStart=/usr/bin/Hyprland ExecStop=/usr/bin/hyprctl dispatch exit +ExecStopPost=/usr/bin/systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP Restart=on-failure Slice=session.slice From f0e023bff2f2a25ffe5ed3166f55f7274d17c6bc Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 25 Oct 2024 12:26:48 +0200 Subject: [PATCH 0767/2393] security-context: avoid UB in C macro (#8229) to safely use wl_container_of with a class the class has to be no virtual functions, no inheritance, and uniform access control (e.g all public) work around this by putting this into a destroywrapper struct. --- src/protocols/SecurityContext.cpp | 12 ++++++++---- src/protocols/SecurityContext.hpp | 12 +++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index b42c3a97..13428b91 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -22,7 +22,8 @@ SP CSecurityContextSandboxedClient::create(int } static void onSecurityContextClientDestroy(wl_listener* l, void* d) { - CSecurityContextSandboxedClient* client = wl_container_of(l, client, destroyListener); + CSecurityContextSandboxedClientDestroyWrapper* wrap = wl_container_of(l, wrap, listener); + CSecurityContextSandboxedClient* client = wrap->parent; client->onDestroy(); } @@ -31,12 +32,15 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) if (!client) return; - destroyListener.notify = ::onSecurityContextClientDestroy; - wl_client_add_destroy_late_listener(client, &destroyListener); + wl_list_init(&destroyListener.listener.link); + destroyListener.listener.notify = ::onSecurityContextClientDestroy; + destroyListener.parent = this; + wl_client_add_destroy_late_listener(client, &destroyListener.listener); } CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { - wl_list_remove(&destroyListener.link); + wl_list_remove(&destroyListener.listener.link); + wl_list_init(&destroyListener.listener.link); close(clientFD); } diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index 76313bcf..63f58bde 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -37,14 +37,20 @@ class CSecurityContextManagerResource { SP resource; }; +class CSecurityContextSandboxedClient; +struct CSecurityContextSandboxedClientDestroyWrapper { + wl_listener listener; + CSecurityContextSandboxedClient* parent = nullptr; +}; + class CSecurityContextSandboxedClient { public: static SP create(int clientFD); ~CSecurityContextSandboxedClient(); - void onDestroy(); + void onDestroy(); - wl_listener destroyListener; + CSecurityContextSandboxedClientDestroyWrapper destroyListener; private: CSecurityContextSandboxedClient(int clientFD_); @@ -81,4 +87,4 @@ class CSecurityContextProtocol : public IWaylandProtocol { namespace PROTO { inline UP securityContext; -}; \ No newline at end of file +}; From e5384774a8258e44cc7f7b690ce4f6ad1f92b562 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Sat, 26 Oct 2024 01:38:59 +0500 Subject: [PATCH 0768/2393] example/hyprland-session.service: add support for xdg autostart (#8230) --- example/hyprland-session.service | 1 + 1 file changed, 1 insertion(+) diff --git a/example/hyprland-session.service b/example/hyprland-session.service index b6f0b55b..3089a961 100644 --- a/example/hyprland-session.service +++ b/example/hyprland-session.service @@ -3,6 +3,7 @@ Description=Hyprland - Tiling compositor with the looks Documentation=man:Hyprland(1) BindsTo=graphical-session.target Before=graphical-session.target +Wants=xdg-desktop-autostart.target Wants=graphical-session-pre.target After=graphical-session-pre.target From d5689bb53935ff1adbbfc9fdf5b1f542ce39efb2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 26 Oct 2024 02:06:13 +0100 Subject: [PATCH 0769/2393] internal: cleanup CMonitor usage and fix a few ref hogs ref #8221 --- src/Compositor.cpp | 8 +++---- src/Compositor.hpp | 6 ++--- src/config/ConfigManager.cpp | 2 +- src/config/ConfigManager.hpp | 2 +- src/debug/HyprDebugOverlay.hpp | 8 +++---- src/helpers/Monitor.cpp | 8 +++---- src/helpers/Monitor.hpp | 2 +- src/managers/PointerManager.cpp | 16 ++++++------- src/managers/PointerManager.hpp | 22 +++++++++--------- src/protocols/CTMControl.cpp | 2 +- src/protocols/CTMControl.hpp | 2 +- src/protocols/DRMLease.cpp | 6 ++--- src/protocols/DRMLease.hpp | 10 ++++----- src/protocols/LinuxDMABUF.cpp | 20 ++++++++--------- src/protocols/LinuxDMABUF.hpp | 12 +++++----- src/protocols/OutputManagement.cpp | 2 +- src/protocols/OutputManagement.hpp | 2 +- src/protocols/PresentationTime.cpp | 6 ++--- src/protocols/PresentationTime.hpp | 6 ++--- src/protocols/VirtualPointer.cpp | 4 ++-- src/protocols/VirtualPointer.hpp | 12 +++++----- src/protocols/XDGOutput.cpp | 2 +- src/protocols/XDGOutput.hpp | 4 ++-- src/protocols/core/Compositor.cpp | 6 ++--- src/protocols/core/Compositor.hpp | 8 +++---- src/protocols/core/Output.cpp | 4 ++-- src/protocols/core/Output.hpp | 8 +++---- src/render/OpenGL.hpp | 36 +++++++++++++++--------------- src/render/Renderer.cpp | 4 ++-- src/render/Renderer.hpp | 4 ++-- 30 files changed, 116 insertions(+), 118 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 313d57ac..743895aa 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -750,7 +750,7 @@ PHLMONITOR CCompositor::getMonitorFromCursor() { } PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) { - SP mon; + PHLMONITOR mon; for (auto const& m : m_vMonitors) { if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) { mon = m; @@ -759,8 +759,8 @@ PHLMONITOR CCompositor::getMonitorFromVector(const Vector2D& point) { } if (!mon) { - float bestDistance = 0.f; - SP pBestMon; + float bestDistance = 0.f; + PHLMONITOR pBestMon; for (auto const& m : m_vMonitors) { float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize); @@ -3008,7 +3008,7 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) { return {}; } -static void checkDefaultCursorWarp(SP monitor) { +static void checkDefaultCursorWarp(PHLMONITOR monitor) { static auto PCURSORMONITOR = CConfigValue("cursor:default_monitor"); static bool cursorDefaultDone = false; static bool firstLaunch = true; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 7fbd32e8..208b6ecf 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -59,8 +59,8 @@ class CCompositor { std::string m_szInstancePath = ""; std::string m_szCurrentSplash = "error"; - std::vector> m_vMonitors; - std::vector> m_vRealMonitors; // for all monitors, even those turned off + std::vector m_vMonitors; + std::vector m_vRealMonitors; // for all monitors, even those turned off std::vector m_vWindows; std::vector m_vLayers; std::vector m_vWorkspaces; @@ -80,7 +80,7 @@ class CCompositor { WP m_pLastFocus; PHLWINDOWREF m_pLastWindow; - WP m_pLastMonitor; + PHLMONITORREF m_pLastMonitor; std::vector m_vWindowFocusHistory; // first element is the most recently focused. diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8237fd44..e2dc4b0f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1087,7 +1087,7 @@ std::string CConfigManager::getDeviceString(const std::string& dev, const std::s return VAL; } -SMonitorRule CConfigManager::getMonitorRuleFor(const SP PMONITOR) { +SMonitorRule CConfigManager::getMonitorRuleFor(const PHLMONITOR PMONITOR) { auto applyWlrOutputConfig = [PMONITOR](SMonitorRule rule) -> SMonitorRule { const auto CONFIG = PROTO::outputManagement->getOutputStateFor(PMONITOR); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index e9ed2d64..cf053daa 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -169,7 +169,7 @@ class CConfigManager { static std::string getMainConfigPath(); const std::string getConfigString(); - SMonitorRule getMonitorRuleFor(const SP); + SMonitorRule getMonitorRuleFor(const PHLMONITOR); SWorkspaceRule getWorkspaceRuleFor(PHLWORKSPACE workspace); std::string getDefaultWorkspaceFor(const std::string&); diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index 19b9120a..89d1d606 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -38,12 +38,12 @@ class CHyprDebugOverlay { void frameData(PHLMONITOR); private: - std::map m_mMonitorOverlays; + std::map m_mMonitorOverlays; - cairo_surface_t* m_pCairoSurface = nullptr; - cairo_t* m_pCairo = nullptr; + cairo_surface_t* m_pCairoSurface = nullptr; + cairo_t* m_pCairo = nullptr; - SP m_pTexture; + SP m_pTexture; friend class CHyprMonitorDebugOverlay; friend class CHyprRenderer; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d8889585..41290b7d 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -71,7 +71,7 @@ void CMonitor::onConnect(bool noRule) { Debug::log(LOG, "Removing monitor {} from realMonitors", szName); - std::erase_if(g_pCompositor->m_vRealMonitors, [&](SP& el) { return el.get() == this; }); + std::erase_if(g_pCompositor->m_vRealMonitors, [&](PHLMONITOR& el) { return el.get() == this; }); }); listeners.state = output->events.state.registerListener([this](std::any d) { @@ -149,7 +149,7 @@ void CMonitor::onConnect(bool noRule) { return; } - SP* thisWrapper = nullptr; + PHLMONITOR* thisWrapper = nullptr; // find the wrap for (auto& m : g_pCompositor->m_vRealMonitors) { @@ -356,7 +356,7 @@ void CMonitor::onDisconnect(bool destroy) { g_pHyprRenderer->m_pMostHzMonitor = pMonitorMostHz; } - std::erase_if(g_pCompositor->m_vMonitors, [&](SP& el) { return el.get() == this; }); + std::erase_if(g_pCompositor->m_vMonitors, [&](PHLMONITOR& el) { return el.get() == this; }); } void CMonitor::addDamage(const pixman_region32_t* rg) { @@ -509,7 +509,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // push to mvmonitors - SP* thisWrapper = nullptr; + PHLMONITOR* thisWrapper = nullptr; // find the wrap for (auto& m : g_pCompositor->m_vRealMonitors) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index f3d6d647..dce44b4a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -125,7 +125,7 @@ class CMonitor { SP outTimeline; uint64_t commitSeq = 0; - WP self; + PHLMONITORREF self; // mirroring PHLMONITORREF pMirrorOf; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index ae90349b..0d6e0206 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -69,7 +69,7 @@ void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) { updateCursorBackend(); } -bool CPointerManager::softwareLockedFor(SP mon) { +bool CPointerManager::softwareLockedFor(PHLMONITOR mon) { auto state = stateFor(mon); return state->softwareLocks > 0 || state->hardwareFailed; } @@ -82,7 +82,7 @@ bool CPointerManager::hasCursor() { return currentCursorImage.pBuffer || currentCursorImage.surface; } -SP CPointerManager::stateFor(SP mon) { +SP CPointerManager::stateFor(PHLMONITOR mon) { auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; }); if (it == monitorStates.end()) return monitorStates.emplace_back(makeShared(mon)); @@ -503,7 +503,7 @@ SP CPointerManager::renderHWCursorBuffer(SP pMonitor, timespec* now, CRegion& damage, std::optional overridePos) { +void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* now, CRegion& damage, std::optional overridePos) { if (!hasCursor()) return; @@ -538,7 +538,7 @@ void CPointerManager::renderSoftwareCursorsFor(SP pMonitor, timespec* currentCursorImage.surface->resource()->frame(now); } -Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { +Vector2D CPointerManager::getCursorPosForMonitor(PHLMONITOR pMonitor) { return CBox{pointerPos - pMonitor->vecPosition, {0, 0}} .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale) @@ -546,7 +546,7 @@ Vector2D CPointerManager::getCursorPosForMonitor(SP pMonitor) { pMonitor->scale; } -Vector2D CPointerManager::transformedHotspot(SP pMonitor) { +Vector2D CPointerManager::transformedHotspot(PHLMONITOR pMonitor) { if (!pMonitor->cursorSwapchain) return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors @@ -556,7 +556,7 @@ Vector2D CPointerManager::transformedHotspot(SP pMonitor) { .pos(); } -CBox CPointerManager::getCursorBoxLogicalForMonitor(SP pMonitor) { +CBox CPointerManager::getCursorBoxLogicalForMonitor(PHLMONITOR pMonitor) { return getCursorBoxGlobal().translate(-pMonitor->vecPosition); } @@ -678,7 +678,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) { void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { - SP currentMonitor = g_pCompositor->m_pLastMonitor.lock(); + PHLMONITOR currentMonitor = g_pCompositor->m_pLastMonitor.lock(); if (!currentMonitor || !dev) return; @@ -1055,7 +1055,7 @@ void CPointerManager::detachTablet(SP tablet) { std::erase_if(tabletListeners, [tablet](const auto& e) { return e->tablet.expired() || e->tablet == tablet; }); } -void CPointerManager::damageCursor(SP pMonitor) { +void CPointerManager::damageCursor(PHLMONITOR pMonitor) { for (auto const& mw : monitorStates) { if (mw->monitor != pMonitor) continue; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index aef2490d..a0cd0fff 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -43,18 +43,18 @@ class CPointerManager { void setCursorSurface(SP buf, const Vector2D& hotspot); void resetCursorImage(bool apply = true); - void lockSoftwareForMonitor(SP pMonitor); - void unlockSoftwareForMonitor(SP pMonitor); + void lockSoftwareForMonitor(PHLMONITOR pMonitor); + void unlockSoftwareForMonitor(PHLMONITOR pMonitor); void lockSoftwareAll(); void unlockSoftwareAll(); - bool softwareLockedFor(SP pMonitor); + bool softwareLockedFor(PHLMONITOR pMonitor); - void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); + void renderSoftwareCursorsFor(PHLMONITOR pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); // this is needed e.g. during screensharing where // the software cursors aren't locked during the cursor move, but they // are rendered later. - void damageCursor(SP pMonitor); + void damageCursor(PHLMONITOR pMonitor); // Vector2D position(); @@ -78,13 +78,13 @@ class CPointerManager { Vector2D closestValid(const Vector2D& pos); // returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot. - Vector2D getCursorPosForMonitor(SP pMonitor); + Vector2D getCursorPosForMonitor(PHLMONITOR pMonitor); // returns the thing in logical coordinates of the monitor - CBox getCursorBoxLogicalForMonitor(SP pMonitor); + CBox getCursorBoxLogicalForMonitor(PHLMONITOR pMonitor); // returns the thing in global coords CBox getCursorBoxGlobal(); - Vector2D transformedHotspot(SP pMonitor); + Vector2D transformedHotspot(PHLMONITOR pMonitor); SP getCurrentCursorTexture(); @@ -160,10 +160,10 @@ class CPointerManager { Vector2D storedUnaccel = {0, 0}; struct SMonitorPointerState { - SMonitorPointerState(SP m) : monitor(m) {} + SMonitorPointerState(PHLMONITOR m) : monitor(m) {} ~SMonitorPointerState() {} - WP monitor; + PHLMONITORREF monitor; int softwareLocks = 0; bool hardwareFailed = false; @@ -176,7 +176,7 @@ class CPointerManager { }; std::vector> monitorStates; - SP stateFor(SP mon); + SP stateFor(PHLMONITOR mon); bool attemptHardwareCursor(SP state); SP renderHWCursorBuffer(SP state, SP texture); bool setHWCursorBuffer(SP state, SP buf); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index f2a54c6f..cddad830 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -81,6 +81,6 @@ void CHyprlandCTMControlProtocol::destroyResource(CHyprlandCTMControlResource* r std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; }); } -void CHyprlandCTMControlProtocol::setCTM(SP monitor, const Mat3x3& ctm) { +void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) { monitor->setCTM(ctm); } diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index 08f1b0e8..70bc79bc 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -31,7 +31,7 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { private: void destroyResource(CHyprlandCTMControlResource* resource); - void setCTM(SP monitor, const Mat3x3& ctm); + void setCTM(PHLMONITOR monitor, const Mat3x3& ctm); // std::vector> m_vManagers; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index d0114ce7..be5a6985 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -129,7 +129,7 @@ SP CDRMLeaseConnectorResource::fromResource(wl_resou return data ? data->self.lock() : nullptr; } -CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { +CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, PHLMONITOR monitor_) : monitor(monitor_), resource(resource_) { if (!good()) return; @@ -203,7 +203,7 @@ bool CDRMLeaseDeviceResource::good() { return resource->resource(); } -void CDRMLeaseDeviceResource::sendConnector(SP monitor) { +void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e && !e->dead && e->monitor == monitor; }) != connectorsSent.end()) return; @@ -289,7 +289,7 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { std::erase_if(m_vLeases, [resource](const auto& e) { return e.get() == resource; }); } -void CDRMLeaseProtocol::offer(SP monitor) { +void CDRMLeaseProtocol::offer(PHLMONITOR monitor) { std::erase_if(primaryDevice->offeredOutputs, [](const auto& e) { return e.expired(); }); if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) return; diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index 3671cfce..37de40e3 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -56,7 +56,7 @@ class CDRMLeaseRequestResource { class CDRMLeaseConnectorResource { public: - CDRMLeaseConnectorResource(SP resource_, SP monitor_); + CDRMLeaseConnectorResource(SP resource_, PHLMONITOR monitor_); static SP fromResource(wl_resource*); bool good(); @@ -64,7 +64,7 @@ class CDRMLeaseConnectorResource { WP self; WP parent; - WP monitor; + PHLMONITORREF monitor; bool dead = false; private: @@ -82,7 +82,7 @@ class CDRMLeaseDeviceResource { CDRMLeaseDeviceResource(SP resource_); bool good(); - void sendConnector(SP monitor); + void sendConnector(PHLMONITOR monitor); std::vector> connectorsSent; @@ -102,7 +102,7 @@ class CDRMLeaseDevice { bool success = false; SP backend; - std::vector> offeredOutputs; + std::vector offeredOutputs; }; class CDRMLeaseProtocol : public IWaylandProtocol { @@ -111,7 +111,7 @@ class CDRMLeaseProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void offer(SP monitor); + void offer(PHLMONITOR monitor); private: void destroyResource(CDRMLeaseDeviceResource* resource); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 8e26c74f..e81d7e01 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -21,7 +21,7 @@ static std::optional devIDFromFD(int fd) { return stat.st_rdev; } -CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector, SDMABUFTranche>> tranches_) : +CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector> tranches_) : rendererTranche(_rendererTranche), monitorTranches(tranches_) { std::vector formatsVec; @@ -436,7 +436,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const .formats = g_pHyprOpenGL->getDRMFormats(), }; - std::vector, SDMABUFTranche>> tches; + std::vector> tches; if (g_pCompositor->m_pAqBackend->hasSession()) { // this assumes there's only 1 device used for both scanout and rendering @@ -453,20 +453,18 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { auto pMonitor = std::any_cast(param); - auto mon = pMonitor->self.lock(); auto tranche = SDMABUFTranche{ .device = mainDevice, .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, - .formats = mon->output->getRenderFormats(), + .formats = pMonitor->output->getRenderFormats(), }; - formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche)); + formatTable->monitorTranches.push_back(std::make_pair<>(pMonitor, tranche)); resetFormatTable(); }); static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { auto pMonitor = std::any_cast(param); - auto mon = pMonitor->self.lock(); - std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); + std::erase_if(formatTable->monitorTranches, [pMonitor](std::pair pair) { return pair.first == pMonitor; }); resetFormatTable(); }); } @@ -508,8 +506,8 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { for (auto const& feedback : m_vFeedbacks) { feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { - SP mon; - auto HLSurface = CWLSurface::fromResource(feedback->surface); + PHLMONITOR mon; + auto HLSurface = CWLSurface::fromResource(feedback->surface); if (auto w = HLSurface->getWindow(); w) if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) mon = m->self.lock(); @@ -560,7 +558,7 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); } -void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { +void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, PHLMONITOR pMonitor) { SP feedbackResource; for (auto const& f : m_vFeedbacks) { if (f->surface != surface) @@ -582,7 +580,7 @@ void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface } const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(), - [pMonitor](std::pair, SDMABUFTranche> pair) { return pair.first == pMonitor; }); + [pMonitor](std::pair pair) { return pair.first == pMonitor; }); if (monitorTranchePair == formatTable->monitorTranches.end()) { LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 0e25cdc6..e4941a6d 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -48,13 +48,13 @@ struct SDMABUFTranche { class CDMABUFFormatTable { public: - CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector, SDMABUFTranche>> tranches); + CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector> tranches); ~CDMABUFFormatTable(); - int tableFD = -1; - size_t tableSize = 0; - SDMABUFTranche rendererTranche; - std::vector, SDMABUFTranche>> monitorTranches; + int tableFD = -1; + size_t tableSize = 0; + SDMABUFTranche rendererTranche; + std::vector> monitorTranches; }; class CLinuxDMABBUFParamsResource { @@ -111,7 +111,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { ~CLinuxDMABufV1Protocol(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void updateScanoutTranche(SP surface, SP pMonitor); + void updateScanoutTranche(SP surface, PHLMONITOR pMonitor); private: void destroyResource(CLinuxDMABUFResource* resource); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 77cedd41..0c6a3348 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -633,7 +633,7 @@ SP COutputManagementProtocol::modeFromResource(wl_resource* r) { return nullptr; } -SP COutputManagementProtocol::getOutputStateFor(SP pMonitor) { +SP COutputManagementProtocol::getOutputStateFor(PHLMONITOR pMonitor) { for (auto const& m : m_vManagers) { if (!m->monitorStates.contains(pMonitor->szName)) continue; diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 6deab017..b9e7ce98 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -153,7 +153,7 @@ class COutputManagementProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); // doesn't have to return one - SP getOutputStateFor(SP pMonitor); + SP getOutputStateFor(PHLMONITOR pMonitor); private: void destroyResource(COutputManager* resource); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index b66694bf..411036c3 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -14,7 +14,7 @@ void CQueuedPresentationData::setPresentationType(bool zeroCopy_) { zeroCopy = zeroCopy_; } -void CQueuedPresentationData::attachMonitor(SP pMonitor_) { +void CQueuedPresentationData::attachMonitor(PHLMONITOR pMonitor_) { pMonitor = pMonitor_; } @@ -73,7 +73,7 @@ void CPresentationFeedback::sendQueued(SP data, timespe CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { - const auto PMONITOR = std::any_cast(param); + const auto PMONITOR = PHLMONITORREF{std::any_cast(param)}; std::erase_if(m_vQueue, [PMONITOR](const auto& other) { return !other->surface || other->pMonitor == PMONITOR; }); }); } @@ -107,7 +107,7 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su } } -void CPresentationProtocol::onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { +void CPresentationProtocol::onPresented(PHLMONITOR pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { timespec now; timespec* presentedAt = when; if (!presentedAt) { diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index 421bb838..d9b45448 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -14,7 +14,7 @@ class CQueuedPresentationData { CQueuedPresentationData(SP surf); void setPresentationType(bool zeroCopy); - void attachMonitor(SP pMonitor); + void attachMonitor(PHLMONITOR pMonitor); void presented(); void discarded(); @@ -24,7 +24,7 @@ class CQueuedPresentationData { private: bool wasPresented = false; bool zeroCopy = false; - WP pMonitor; + PHLMONITORREF pMonitor; WP surface; friend class CPresentationFeedback; @@ -53,7 +53,7 @@ class CPresentationProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); - void onPresented(SP pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); + void onPresented(PHLMONITOR pMonitor, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags); void queueData(SP data); private: diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index eb92a640..4c5aa13a 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -1,7 +1,7 @@ #include "VirtualPointer.hpp" #include "core/Output.hpp" -CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, WP boundOutput_) : boundOutput(boundOutput_), resource(resource_) { +CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, PHLMONITORREF boundOutput_) : boundOutput(boundOutput_), resource(resource_) { if (!good()) return; @@ -134,7 +134,7 @@ void CVirtualPointerProtocol::destroyResource(CVirtualPointerV1Resource* pointer std::erase_if(m_vPointers, [&](const auto& other) { return other.get() == pointer; }); } -void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP output) { +void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, PHLMONITORREF output) { const auto RESOURCE = m_vPointers.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id), output)); diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 7ee450dc..68fe124e 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -12,7 +12,7 @@ class CVirtualPointerV1Resource { public: - CVirtualPointerV1Resource(SP resource_, WP boundOutput_); + CVirtualPointerV1Resource(SP resource_, PHLMONITORREF boundOutput_); ~CVirtualPointerV1Resource(); struct { @@ -35,12 +35,12 @@ class CVirtualPointerV1Resource { CSignal holdEnd; } events; - bool good(); - wl_client* client(); + bool good(); + wl_client* client(); - std::string name; + std::string name; - WP boundOutput; + PHLMONITORREF boundOutput; private: SP resource; @@ -63,7 +63,7 @@ class CVirtualPointerProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyResource(CVirtualPointerV1Resource* pointer); - void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, WP output); + void onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr, wl_resource* seat, uint32_t id, PHLMONITORREF output); // std::vector> m_vManagers; diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 0598e713..deb87829 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -95,7 +95,7 @@ void CXDGOutputProtocol::updateAllOutputs() { // -CXDGOutput::CXDGOutput(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { +CXDGOutput::CXDGOutput(SP resource_, PHLMONITOR monitor_) : monitor(monitor_), resource(resource_) { if (!resource->resource()) return; diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 520f3aaa..6a5be284 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -10,12 +10,12 @@ class CWLOutputProtocol; class CXDGOutput { public: - CXDGOutput(SP resource, SP monitor_); + CXDGOutput(SP resource, PHLMONITOR monitor_); void sendDetails(); private: - WP monitor; + PHLMONITORREF monitor; SP resource; WP outputProto; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 3d4b63c1..9a2e00a9 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -182,7 +182,7 @@ wl_client* CWLSurfaceResource::client() { return pClient; } -void CWLSurfaceResource::enter(SP monitor) { +void CWLSurfaceResource::enter(PHLMONITOR monitor) { if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) != enteredOutputs.end()) return; @@ -209,7 +209,7 @@ void CWLSurfaceResource::enter(SP monitor) { resource->sendEnter(output->getResource().get()); } -void CWLSurfaceResource::leave(SP monitor) { +void CWLSurfaceResource::leave(PHLMONITOR monitor) { if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end()) return; @@ -509,7 +509,7 @@ void CWLSurfaceResource::updateCursorShm() { memcpy(shmData.data(), pixelData, bufLen); } -void CWLSurfaceResource::presentFeedback(timespec* when, SP pMonitor) { +void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor) { frame(when); auto FEEDBACK = makeShared(self.lock()); FEEDBACK->attachMonitor(pMonitor); diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index b3c067c9..fbffd966 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -60,8 +60,8 @@ class CWLSurfaceResource { bool good(); wl_client* client(); - void enter(SP monitor); - void leave(SP monitor); + void enter(PHLMONITOR monitor); + void leave(PHLMONITOR monitor); void sendPreferredTransform(wl_output_transform t); void sendPreferredScale(int32_t scale); void frame(timespec* now); @@ -115,7 +115,7 @@ class CWLSurfaceResource { std::vector> callbacks; WP self; WP hlSurface; - std::vector> enteredOutputs; + std::vector enteredOutputs; bool mapped = false; std::vector> subsurfaces; SP role; @@ -124,7 +124,7 @@ class CWLSurfaceResource { void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); - void presentFeedback(timespec* when, SP pMonitor); + void presentFeedback(timespec* when, PHLMONITOR pMonitor); void lockPendingState(); void unlockPendingState(); diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index e9f35abc..edeeb584 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -3,7 +3,7 @@ #include "../../Compositor.hpp" #include "../../helpers/Monitor.hpp" -CWLOutputResource::CWLOutputResource(SP resource_, SP pMonitor) : monitor(pMonitor), resource(resource_) { +CWLOutputResource::CWLOutputResource(SP resource_, PHLMONITOR pMonitor) : monitor(pMonitor), resource(resource_) { if (!good()) return; @@ -83,7 +83,7 @@ void CWLOutputResource::updateState() { resource->sendDone(); } -CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP pMonitor) : +CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, PHLMONITOR pMonitor) : IWaylandProtocol(iface, ver, name), monitor(pMonitor), szName(pMonitor->szName) { listeners.modeChanged = monitor->events.modeChanged.registerListener([this](std::any d) { diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 49c32ec1..a4c81d72 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -12,7 +12,7 @@ class CWLOutputProtocol; class CWLOutputResource { public: - CWLOutputResource(SP resource_, SP pMonitor); + CWLOutputResource(SP resource_, PHLMONITOR pMonitor); static SP fromResource(wl_resource*); bool good(); @@ -20,7 +20,7 @@ class CWLOutputResource { SP getResource(); void updateState(); - WP monitor; + PHLMONITORREF monitor; WP owner; WP self; @@ -33,14 +33,14 @@ class CWLOutputResource { class CWLOutputProtocol : public IWaylandProtocol { public: - CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, SP pMonitor); + CWLOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name, PHLMONITOR pMonitor); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); SP outputResourceFrom(wl_client* client); void sendDone(); - WP monitor; + PHLMONITORREF monitor; WP self; // will mark the protocol for removal, will be removed when no. of bound outputs is 0 (or when overwritten by a new global) diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 04f69d49..115dcac7 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -206,30 +206,30 @@ class CHyprOpenGLImpl { void setDamage(const CRegion& damage, std::optional finalDamage = {}); uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window - PHLLS m_pCurrentLayer; // hack to get the current rendered layer + PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window + PHLLS m_pCurrentLayer; // hack to get the current rendered layer - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; - std::unordered_map m_mMonitorRenderResources; - std::unordered_map m_mMonitorBGFBs; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; + std::map m_mMonitorRenderResources; + std::map m_mMonitorBGFBs; struct { PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 5df0c070..c69167c8 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1085,7 +1085,7 @@ void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } -void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, SP pMonitor, bool main, const Vector2D& projSize, +void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize, const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { Vector2D uvTL; @@ -1603,7 +1603,7 @@ void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE } } -void CHyprRenderer::setSurfaceScanoutMode(SP surface, SP monitor) { +void CHyprRenderer::setSurfaceScanoutMode(SP surface, PHLMONITOR monitor) { if (!PROTO::linuxDma) return; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 41f40b5a..4524008b 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -64,7 +64,7 @@ class CHyprRenderer { void ensureCursorRenderingMode(); bool shouldRenderCursor(); void setCursorHidden(bool hide); - void calculateUVForSurface(PHLWINDOW, SP, SP pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, + void calculateUVForSurface(PHLWINDOW, SP, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, bool fixMisalignedFSV1 = false); std::tuple getRenderTimes(PHLMONITOR pMonitor); // avg max min void renderLockscreen(PHLMONITOR pMonitor, timespec* now, const CBox& geometry); @@ -95,7 +95,7 @@ class CHyprRenderer { DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); - void setSurfaceScanoutMode(SP surface, SP monitor); // nullptr monitor resets + void setSurfaceScanoutMode(SP surface, PHLMONITOR monitor); // nullptr monitor resets void initiateManualCrash(); bool m_bCrashingInProgress = false; From 3dd8db83f166733d1dd6a753bd6eb07727320768 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 26 Oct 2024 02:12:43 +0100 Subject: [PATCH 0770/2393] pointer: add default auto for no_hw_cursors auto defaults to off on nvidia, on for everyone else. Gotta wait until we do fucking drm_dumb and it fucking works --- src/config/ConfigDescriptions.hpp | 4 ++-- src/config/ConfigManager.cpp | 14 +++++++++++++- src/config/ConfigManager.hpp | 2 ++ src/managers/PointerManager.cpp | 12 ++++-------- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 7910e865..0177f92b 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1244,8 +1244,8 @@ inline static const std::vector CONFIG_OPTIONS = { SConfigOptionDescription{ .value = "cursor:no_hardware_cursors", .description = "disables hardware cursors", - .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, }, SConfigOptionDescription{ .value = "cursor:no_break_fs_vrr", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e2dc4b0f..909dfc63 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -552,7 +552,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); - m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); @@ -2778,6 +2778,18 @@ const std::vector& CConfigManager::getAllDescriptions( return CONFIG_OPTIONS; } +bool CConfigManager::shouldUseSoftwareCursors() { + static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + + switch (*PNOHW) { + case 0: return false; + case 1: return true; + default: return g_pHyprRenderer->isNvidia(); + } + + return true; +} + std::string SConfigOptionDescription::jsonify() const { auto parseData = [this]() -> std::string { return std::visit( diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index cf053daa..88b74b6e 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -200,6 +200,8 @@ class CConfigManager { void ensureMonitorStatus(); void ensureVRR(PHLMONITOR pMonitor = nullptr); + bool shouldUseSoftwareCursors(); + std::string parseKeyword(const std::string&, const std::string&); void addParseError(const std::string&); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 0d6e0206..d2114e79 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -247,9 +247,7 @@ void CPointerManager::resetCursorImage(bool apply) { } void CPointerManager::updateCursorBackend() { - static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); - - const auto CURSORBOX = getCursorBoxGlobal(); + const auto CURSORBOX = getCursorBoxGlobal(); for (auto const& m : g_pCompositor->m_vMonitors) { auto state = stateFor(m); @@ -268,7 +266,7 @@ void CPointerManager::updateCursorBackend() { continue; } - if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) { + if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors() || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->hardwareFailed = true; @@ -641,15 +639,13 @@ Vector2D CPointerManager::closestValid(const Vector2D& pos) { } void CPointerManager::damageIfSoftware() { - auto b = getCursorBoxGlobal().expand(4); - - static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); + auto b = getCursorBoxGlobal().expand(4); for (auto const& mw : monitorStates) { if (mw->monitor.expired() || !mw->monitor->output) continue; - if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { + if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } From 0b29caf9ab86518ff474eed5e7d19c12f96ebbd0 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sat, 26 Oct 2024 01:22:37 +0000 Subject: [PATCH 0771/2393] core: fix group members disappearing when you move the group to another monitor (#8237) * fix group members disappearance when you move the group to another monitor * remove repeated action --- src/Compositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 743895aa..d4e2db17 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2795,11 +2795,11 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor pWindow->updateToplevel(); pWindow->updateDynamicRules(); pWindow->uncacheWindowDecos(); + pWindow->updateGroupOutputs(); if (!pWindow->m_sGroupData.pNextWindow.expired()) { PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock(); while (next != pWindow) { - next->moveToWorkspace(pWorkspace); next->updateToplevel(); next = next->m_sGroupData.pNextWindow.lock(); } From c356e425008cba8bd0c87487a2c79b9be4eda2aa Mon Sep 17 00:00:00 2001 From: Damianu Date: Sat, 26 Oct 2024 17:50:31 +0200 Subject: [PATCH 0772/2393] misc: Fix bad links to wiki (#8240) Same as in https://github.com/hyprwm/hyprland-wiki/pull/828 --- README.md | 2 +- docs/ISSUE_GUIDELINES.md | 2 +- example/hyprland.conf | 2 +- src/config/defaultConfig.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f271c29c..0970819c 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more... -[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ +[Configure]: https://wiki.hyprland.org/Configuring/ [Stars]: https://starchart.cc/hyprwm/Hyprland [Hypr]: https://github.com/hyprwm/Hypr diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md index 2f6cbbf8..9328642d 100644 --- a/docs/ISSUE_GUIDELINES.md +++ b/docs/ISSUE_GUIDELINES.md @@ -3,7 +3,7 @@ First of all, please remember to: - Check that your issue is not a duplicate - Read the [FAQ](https://wiki.hyprland.org/FAQ/) -- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland) +- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/)
diff --git a/example/hyprland.conf b/example/hyprland.conf index f94cb1d1..f1139c3b 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -1,6 +1,6 @@ # This is an example Hyprland config file. # Refer to the wiki for more information. -# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ +# https://wiki.hyprland.org/Configuring/ # Please note not all available settings / options are set here. # For a full list, see the wiki diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 4a33ec91..facb16e2 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -13,7 +13,7 @@ autogenerated = 1 # remove this line to remove the warning # This is an example Hyprland config file. # Refer to the wiki for more information. -# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ +# https://wiki.hyprland.org/Configuring/ # Please note not all available settings / options are set here. # For a full list, see the wiki From f3f7d3629a632682b1b3acf800f0b5fb10cd48f4 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:49:00 +0500 Subject: [PATCH 0773/2393] Build with hyprland-session.service (#8251) Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 10 ++++++++++ meson.build | 3 +++ .../hyprland-session.service.in | 6 +++--- {example => systemd}/hyprland-systemd.desktop | 0 systemd/meson.build | 15 +++++++++++++++ 5 files changed, 31 insertions(+), 3 deletions(-) rename example/hyprland-session.service => systemd/hyprland-session.service.in (61%) rename {example => systemd}/hyprland-systemd.desktop (100%) create mode 100644 systemd/meson.build diff --git a/CMakeLists.txt b/CMakeLists.txt index df919d76..ec8c331e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,9 @@ include(GNUInstallDirs) set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) +set(BINDIR ${CMAKE_INSTALL_BINDIR}) configure_file(hyprland.pc.in hyprland.pc @ONLY) +configure_file(systemd/hyprland-session.service.in systemd/hyprland-session.service @ONLY) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") @@ -357,6 +359,11 @@ install( install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + +# session file -systemd +install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + # allow Hyprland to find assets add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") @@ -397,3 +404,6 @@ install( DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland FILES_MATCHING PATTERN "*.h*") + +#install systemd service +install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user) diff --git a/meson.build b/meson.build index 33e8fdbe..d0ba9a5c 100644 --- a/meson.build +++ b/meson.build @@ -80,6 +80,8 @@ if get_option('tracy_enable') and get_option('buildtype') != 'debugoptimized' warning('Profiling builds should set -- buildtype = debugoptimized') endif + + subdir('protocols') subdir('src') subdir('hyprctl') @@ -87,6 +89,7 @@ subdir('hyprpm/src') subdir('assets') subdir('example') subdir('docs') +subdir('systemd') # Generate hyprland.pc pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') diff --git a/example/hyprland-session.service b/systemd/hyprland-session.service.in similarity index 61% rename from example/hyprland-session.service rename to systemd/hyprland-session.service.in index 3089a961..dafdc141 100644 --- a/example/hyprland-session.service +++ b/systemd/hyprland-session.service.in @@ -9,8 +9,8 @@ After=graphical-session-pre.target [Service] Type=notify -ExecStart=/usr/bin/Hyprland -ExecStop=/usr/bin/hyprctl dispatch exit -ExecStopPost=/usr/bin/systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP +ExecStart=@PREFIX@/@BINDIR@/Hyprland +ExecStop=@PREFIX@/@BINDIR@/hyprctl dispatch exit +ExecStopPost=systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP Restart=on-failure Slice=session.slice diff --git a/example/hyprland-systemd.desktop b/systemd/hyprland-systemd.desktop similarity index 100% rename from example/hyprland-systemd.desktop rename to systemd/hyprland-systemd.desktop diff --git a/systemd/meson.build b/systemd/meson.build new file mode 100644 index 00000000..497e64f4 --- /dev/null +++ b/systemd/meson.build @@ -0,0 +1,15 @@ +install_data( + 'hyprland-systemd.desktop', + install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), + install_tag: 'runtime', +) + +conf_data = configuration_data() +conf_data.set('PREFIX', get_option('prefix')) +conf_data.set('BINDIR', get_option('bindir')) + +configure_file( + configuration: conf_data, + input: 'hyprland-session.service.in', + output: '@BASENAME@', + install_dir: join_paths(get_option('libdir'), 'systemd/user') ) From a3d3b4fd64a51a8c1663b450bd2a408f1f0fa9b3 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Sun, 27 Oct 2024 00:44:55 +0000 Subject: [PATCH 0774/2393] groups: fix swallowing (#8223) * fix swallowing for groups * remove unnecessary check * clang-format * clarify comment * make variables consistent * make aditional variables consistent --- src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 32 +++++++++---------- src/layout/IHyprLayout.cpp | 29 +++++++---------- .../decorations/CHyprGroupBarDecoration.cpp | 7 ++-- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index b2a8e763..9867a8c9 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -357,6 +357,7 @@ class CWindow { // swallowing PHLWINDOWREF m_pSwallowed; + bool m_bGroupSwallowed = false; // focus stuff bool m_bStayFocused = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 57a28948..e8abe30d 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -44,8 +44,6 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PINACTIVEALPHA = CConfigValue("decoration:inactive_opacity"); static auto PACTIVEALPHA = CConfigValue("decoration:active_opacity"); static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); - static auto PSWALLOW = CConfigValue("misc:enable_swallow"); - static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); @@ -322,6 +320,10 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->updateWindowData(); + // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. + const auto SWALLOWER = PWINDOW->getSwallower(); + PWINDOW->m_pSwallowed = SWALLOWER; + if (PWINDOW->m_bIsFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); PWINDOW->m_bCreatedOverFullscreen = true; @@ -567,20 +569,12 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pCompositor->focusWindow(nullptr); } - // verify swallowing - if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) { - const auto SWALLOWER = PWINDOW->getSwallower(); - - if (SWALLOWER) { - // swallow - PWINDOW->m_pSwallowed = SWALLOWER; - - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); - - SWALLOWER->setHidden(true); - - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); - } + // swallow + if (SWALLOWER) { + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); + g_pHyprRenderer->damageWindow(SWALLOWER); + SWALLOWER->setHidden(true); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); } PWINDOW->m_bFirstMap = false; @@ -662,7 +656,13 @@ void Events::listener_unmapWindow(void* owner, void* data) { // swallowing if (valid(PWINDOW->m_pSwallowed)) { PWINDOW->m_pSwallowed->setHidden(false); + + if (PWINDOW->m_sGroupData.pNextWindow.lock()) + PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); + + PWINDOW->m_pSwallowed->m_bGroupSwallowed = false; PWINDOW->m_pSwallowed.reset(); } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 655f2341..454a6132 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -184,22 +184,20 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { - static auto PAUTOGROUP = CConfigValue("group:auto_group"); - PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? - g_pCompositor->m_pLastWindow.lock() : - g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + static auto PAUTOGROUP = CConfigValue("group:auto_group"); + const PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? + g_pCompositor->m_pLastWindow.lock() : + g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + const bool FLOATEDINTOTILED = pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating; + const bool SWALLOWING = pWindow->m_pSwallowed || pWindow->m_bGroupSwallowed; - bool denied = false; - if (pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating) - denied = true; - - if (*PAUTOGROUP // check if auto_group is enabled. + if ((*PAUTOGROUP || SWALLOWING) // continue if auto_group is enabled or if dealing with window swallowing. && OPENINGON // this shouldn't be 0, but honestly, better safe than sorry. && OPENINGON != pWindow // prevent freeze when the "group set" window rule makes the new window to be already a group. && OPENINGON->m_sGroupData.pNextWindow.lock() // check if OPENINGON is a group. && pWindow->canBeGroupedInto(OPENINGON) // check if the new window can be grouped into OPENINGON. - && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !denied. - && !denied) { // don't group a new floated window into a tiled group (for convenience). + && !g_pXWaylandManager->shouldBeFloated(pWindow) // don't group child windows. Fix for floated groups. Tiled groups don't need this because we check if !FLOATEDINTOTILED. + && !FLOATEDINTOTILED) { // don't group a new floated window into a tiled group (for convenience). pWindow->m_bIsFloating = OPENINGON->m_bIsFloating; // match the floating state. Needed to autogroup a new tiled window into a floated group. @@ -341,12 +339,9 @@ void IHyprLayout::onEndDragWindow() { if (pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, DRAGGINGWINDOW)) return; - bool denied = false; - if (!pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled) - denied = true; - - static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); - if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !denied) { + const bool FLOATEDINTOTILED = !pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled; + static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !FLOATEDINTOTILED) { if (DRAGGINGWINDOW->m_bDraggingTiled) { changeWindowFloatingMode(DRAGGINGWINDOW); DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4219a5a8..1868bb5c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -405,12 +405,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND static auto PSTACKED = CConfigValue("group:groupbar:stacked"); static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); static auto PMERGEFLOATEDINTOTILEDONGROUPBAR = CConfigValue("group:merge_floated_into_tiled_on_groupbar"); + const bool FLOATEDINTOTILED = !m_pWindow->m_bIsFloating && !pDraggedWindow->m_bDraggingTiled; - bool denied = false; - if (!m_pWindow->m_bIsFloating && !pDraggedWindow->m_bDraggingTiled && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) - denied = true; - - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || denied) + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || (FLOATEDINTOTILED && !*PMERGEFLOATEDINTOTILEDONGROUPBAR)) return false; const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; From f9b52203f58bcb716144d89ee9f85fe12ebfe94d Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 27 Oct 2024 18:51:26 +0100 Subject: [PATCH 0775/2393] internal: optimize cursor move a bit (#8264) * window: inline and const getWindowMainSurfaceBox getWindowMainSurfaceBox gets called a lot of times from deep down from mousemoveunified, profiling mousemoveunified it spends quite a lot of cpu time in here, let the compiler optimize the call to getWindowMainSurfaceBox by inlining and making it const. reducing the overhead. * inputmgr: return early and use std::any_of return early in mousemoveunified to reduce the amount of unnecessery calls to various pointers when not needed, also make isconstrained use std::any_of instead of for loop to use the STL optimized paths with hopes and dreams marginally faster. * decoration: return early, reduce temporar copy return earlier and reduce the temp copies by using one .lock instead of two --- src/desktop/Window.cpp | 4 --- src/desktop/Window.hpp | 10 +++--- src/managers/input/InputManager.cpp | 35 +++++++------------ .../decorations/DecorationPositioner.cpp | 14 ++++---- 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 1297bb83..0772b676 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -240,10 +240,6 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) { return box; } -CBox CWindow::getWindowMainSurfaceBox() { - return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; -} - SBoxExtents CWindow::getFullWindowReservedArea() { return g_pDecorationPositioner->getWindowDecorationReserved(m_pSelf.lock()); } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 9867a8c9..64f39558 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -396,10 +396,12 @@ class CWindow { } // methods - CBox getFullWindowBoundingBox(); - SBoxExtents getFullWindowExtents(); - CBox getWindowBoxUnified(uint64_t props); - CBox getWindowMainSurfaceBox(); + CBox getFullWindowBoundingBox(); + SBoxExtents getFullWindowExtents(); + CBox getWindowBoxUnified(uint64_t props); + inline CBox getWindowMainSurfaceBox() const { + return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + } CBox getWindowIdealBoundingBoxIgnoreReserved(); void addWindowDeco(std::unique_ptr deco); void updateWindowDecos(); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 6f7d8017..028286bf 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -139,6 +139,15 @@ void CInputManager::sendMotionEventsToFocused() { } void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { + if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) + return; + + Vector2D const mouseCoords = getMouseCoordsInternal(); + auto const MOUSECOORDSFLOORED = mouseCoords.floor(); + + if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) + return; + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); @@ -159,15 +168,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { PHLWINDOW pFoundWindow; PHLLS pFoundLayerSurface; - if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) - return; - - Vector2D mouseCoords = getMouseCoordsInternal(); - const auto MOUSECOORDSFLOORED = mouseCoords.floor(); - - if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) - return; - EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED); m_vLastCursorPosFloored = MOUSECOORDSFLOORED; @@ -1418,19 +1418,10 @@ void CInputManager::unconstrainMouse() { } bool CInputManager::isConstrained() { - for (auto const& c : m_vConstraints) { - const auto C = c.lock(); - - if (!C) - continue; - - if (!C->isActive() || C->owner()->resource() != g_pCompositor->m_pLastFocus) - continue; - - return true; - } - - return false; + return std::any_of(m_vConstraints.begin(), m_vConstraints.end(), [](auto const& c) { + const auto constraint = c.lock(); + return constraint && constraint->isActive() && constraint->owner()->resource() == g_pCompositor->m_pLastFocus; + }); } bool CInputManager::isLocked() { diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 4666a59e..3eb45546 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -297,15 +297,16 @@ SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, CBox accum = pWindow->getWindowMainSurfaceBox(); for (auto const& data : m_vWindowPositioningDatas) { - if (data->pWindow.lock() != pWindow) - continue; - - if (!data->pWindow.lock() || !data->pDecoration) + if (!data->pDecoration) continue; if (!(data->pDecoration->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT) && inputOnly) continue; + auto const window = data->pWindow.lock(); + if (!window || window != pWindow) + continue; + CBox decoBox; if (data->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { @@ -373,9 +374,10 @@ CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { } CBox CDecorationPositioner::getWindowDecorationBox(IHyprWindowDecoration* deco) { - const auto DATA = getDataFor(deco, deco->m_pWindow.lock()); + auto const window = deco->m_pWindow.lock(); + const auto DATA = getDataFor(deco, window); CBox box = DATA->lastReply.assignedGeometry; - box.translate(getEdgeDefinedPoint(DATA->positioningInfo.edges, deco->m_pWindow.lock())); + box.translate(getEdgeDefinedPoint(DATA->positioningInfo.edges, window)); return box; } From b6e226c3200276978e487a68a16fd696fcb7e7c8 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 27 Oct 2024 14:26:42 -0400 Subject: [PATCH 0776/2393] groupbar: set locked color when groups are globally locked (#8257) --- src/render/decorations/CHyprGroupBarDecoration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 1868bb5c..e342e244 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -143,7 +143,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float a) { auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked; + const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked || g_pKeybindManager->m_bGroupsLocked; const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; From 5d4b54b01286c10d4b6bf402a772b5938b054ce6 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 27 Oct 2024 18:45:38 +0000 Subject: [PATCH 0777/2393] core: move internal structures to monitor pointers (#8266) --- src/Compositor.cpp | 63 ++++++++++++++-------------- src/debug/HyprCtl.cpp | 6 +-- src/desktop/LayerSurface.cpp | 24 ++++++----- src/desktop/LayerSurface.hpp | 5 ++- src/desktop/Window.cpp | 54 +++++++++++++----------- src/desktop/Window.hpp | 5 ++- src/desktop/Workspace.cpp | 30 +++++++------ src/desktop/Workspace.hpp | 11 ++--- src/events/Windows.cpp | 34 +++++++-------- src/helpers/MiscFunctions.cpp | 6 +-- src/helpers/Monitor.cpp | 20 ++++----- src/layout/DwindleLayout.cpp | 18 ++++---- src/layout/IHyprLayout.cpp | 18 ++++---- src/layout/MasterLayout.cpp | 40 +++++++++--------- src/managers/AnimationManager.cpp | 6 +-- src/managers/KeybindManager.cpp | 34 +++++++-------- src/managers/XWaylandManager.cpp | 2 +- src/managers/input/Swipe.cpp | 3 +- src/managers/input/Touch.cpp | 4 +- src/protocols/ForeignToplevelWlr.cpp | 4 +- src/protocols/LinuxDMABUF.cpp | 2 +- src/protocols/ToplevelExport.cpp | 8 ++-- src/render/OpenGL.cpp | 12 +++--- src/render/Renderer.cpp | 32 +++++++------- 24 files changed, 226 insertions(+), 215 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d4e2db17..a2fe9935 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -834,7 +834,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; const auto BB = w->getWindowBoxUnified(properties); - const auto PWINDOWMONITOR = getMonitorFromID(w->m_iMonitorID); + const auto PWINDOWMONITOR = w->m_pMonitor.lock(); // to avoid focusing windows behind special workspaces from other monitors if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace && @@ -1063,7 +1063,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface if (pWindow->m_bPinned) pWindow->m_pWorkspace = m_pLastMonitor->activeWorkspace; - const auto PMONITOR = getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!isWorkspaceVisible(pWindow->m_pWorkspace)) { const auto PWORKSPACE = pWindow->m_pWorkspace; @@ -1259,7 +1259,7 @@ bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { if (!valid(w)) return false; - const auto PMONITOR = getMonitorFromID(w->m_iMonitorID); + const auto PMONITOR = w->m_pMonitor.lock(); if (PMONITOR->activeSpecialWorkspace) return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID; @@ -1354,7 +1354,7 @@ PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { if (!PWORKSPACE) return nullptr; - const auto PMONITOR = getMonitorFromID(PWORKSPACE->m_iMonitorID); + const auto PMONITOR = PWORKSPACE->m_pMonitor.lock(); for (auto const& w : m_vWindows) { if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden()) @@ -1405,7 +1405,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { } if (pw->m_bIsMapped) - g_pHyprRenderer->damageMonitor(getMonitorFromID(pw->m_iMonitorID)); + g_pHyprRenderer->damageMonitor(pw->m_pMonitor.lock()); }; if (top) @@ -1444,7 +1444,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { auto w = ww.lock(); - if (w->m_iMonitorID != monid) + if (w->monitorID() != monid && w->m_pMonitor) continue; if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { @@ -1474,7 +1474,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { continue; } - if (ls->monitorID != monid) + if (ls->monitorID() != monid && ls->monitor) continue; // mark blur for recalc @@ -1537,7 +1537,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { static auto PMETHOD = CConfigValue("binds:focus_preferred_method"); static auto PMONITORFALLBACK = CConfigValue("binds:window_direction_monitor_fallback"); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!PMONITOR) return nullptr; // ?? @@ -1558,13 +1558,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; - if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) + if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) continue; if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; - if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor) continue; const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); @@ -1650,13 +1650,13 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) continue; - if (pWindow->m_iMonitorID == w->m_iMonitorID && pWindow->m_pWorkspace != w->m_pWorkspace) + if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) continue; if (PWORKSPACE->m_bHasFullscreenWindow && !w->isFullscreen() && !w->m_bCreatedOverFullscreen) continue; - if (!*PMONITORFALLBACK && pWindow->m_iMonitorID != w->m_iMonitorID) + if (!*PMONITORFALLBACK && pWindow->m_pMonitor != w->m_pMonitor) continue; const auto DIST = w->middle().distance(pWindow->middle()); @@ -1996,7 +1996,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace; - PWORKSPACEA->m_iMonitorID = pMonitorB->ID; + PWORKSPACEA->m_pMonitor = pMonitorB; PWORKSPACEA->moveToMonitor(pMonitorB->ID); for (auto const& w : m_vWindows) { @@ -2006,7 +2006,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor continue; } - w->m_iMonitorID = pMonitorB->ID; + w->m_pMonitor = pMonitorB; // additionally, move floating and fs windows manually if (w->m_bIsFloating) @@ -2021,7 +2021,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor } } - PWORKSPACEB->m_iMonitorID = pMonitorA->ID; + PWORKSPACEB->m_pMonitor = pMonitorA; PWORKSPACEB->moveToMonitor(pMonitorA->ID); for (auto const& w : m_vWindows) { @@ -2031,7 +2031,7 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor continue; } - w->m_iMonitorID = pMonitorA->ID; + w->m_pMonitor = pMonitorA; // additionally, move floating and fs windows manually if (w->m_bIsFloating) @@ -2156,12 +2156,12 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo // We trust the monitor to be correct. - if (pWorkspace->m_iMonitorID == pMonitor->ID) + if (pWorkspace->m_pMonitor == pMonitor) return; Debug::log(LOG, "moveWorkspaceToMonitor: Moving {} to monitor {}", pWorkspace->m_iID, pMonitor->ID); - const auto POLDMON = getMonitorFromID(pWorkspace->m_iMonitorID); + const auto POLDMON = pWorkspace->m_pMonitor.lock(); const bool SWITCHINGISACTIVE = POLDMON ? POLDMON->activeWorkspace == pWorkspace : false; @@ -2171,7 +2171,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo nextWorkspaceOnMonitorID = pWorkspace->m_iID; else { for (auto const& w : m_vWorkspaces) { - if (w->m_iMonitorID == POLDMON->ID && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) { + if (w->m_pMonitor == POLDMON && w->m_iID != pWorkspace->m_iID && !w->m_bIsSpecialWorkspace) { nextWorkspaceOnMonitorID = w->m_iID; break; } @@ -2196,7 +2196,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo } // move the workspace - pWorkspace->m_iMonitorID = pMonitor->ID; + pWorkspace->m_pMonitor = pMonitor; pWorkspace->moveToMonitor(pMonitor->ID); for (auto const& w : m_vWindows) { @@ -2206,7 +2206,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo continue; } - w->m_iMonitorID = pMonitor->ID; + w->m_pMonitor = pMonitor; // additionally, move floating and fs windows manually if (w->m_bIsMapped && !w->isHidden()) { @@ -2299,7 +2299,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { } } - const auto PMONITOR = getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = pWorkspace->m_pMonitor.lock(); if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { @@ -2342,7 +2342,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS state.internal = std::clamp(state.internal, (eFullscreenMode)0, FSMODE_MAX); state.client = std::clamp(state.client, (eFullscreenMode)0, FSMODE_MAX); - const auto PMONITOR = getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); const auto PWORKSPACE = PWINDOW->m_pWorkspace; const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal); @@ -2360,7 +2360,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS if (!CHANGEINTERNAL) { PWINDOW->updateDynamicRules(); updateWindowAnimatedDecorationValues(PWINDOW); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); return; } @@ -2375,7 +2375,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS PWINDOW->updateDynamicRules(); updateWindowAnimatedDecorationValues(PWINDOW); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); // make all windows on the same workspace under the fullscreen window for (auto const& w : m_vWindows) { @@ -2663,13 +2663,12 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO auto monID = monid; // check if bound - if (const auto PMONITOR = g_pConfigManager->getBoundMonitorForWS(NAME); PMONITOR) { + if (const auto PMONITOR = g_pConfigManager->getBoundMonitorForWS(NAME); PMONITOR) monID = PMONITOR->ID; - } const bool SPECIAL = id >= SPECIAL_WORKSPACE_START && id <= -2; - const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, monID, NAME, SPECIAL, isEmpty)); + const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty)); PWORKSPACE->m_fAlpha.setValueAndWarp(0); @@ -2751,15 +2750,15 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor const PHLWINDOW pFirstWindowOnWorkspace = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID); const int visibleWindowsOnWorkspace = g_pCompositor->getWindowsOnWorkspace(pWorkspace->m_iID, std::nullopt, true); - const auto PWINDOWMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock(); const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; - const auto PWORKSPACEMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock(); if (!pWindow->m_bIsFloating) g_pLayoutManager->getCurrentLayout()->onWindowRemovedTiling(pWindow); pWindow->moveToWorkspace(pWorkspace); - pWindow->m_iMonitorID = pWorkspace->m_iMonitorID; + pWindow->m_pMonitor = pWorkspace->m_pMonitor; static auto PGROUPONMOVETOWORKSPACE = CConfigValue("group:group_on_movetoworkspace"); if (*PGROUPONMOVETOWORKSPACE && visibleWindowsOnWorkspace == 1 && pFirstWindowOnWorkspace && pFirstWindowOnWorkspace != pWindow && @@ -3077,7 +3076,7 @@ void CCompositor::onNewMonitor(SP output) { checkDefaultCursorWarp(PNEWMONITOR); for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_iMonitorID == PNEWMONITOR->ID) { + if (w->m_pMonitor == PNEWMONITOR) { w->m_iLastSurfaceMonitorID = MONITOR_INVALID; w->updateSurfaceScaleTransformDetails(); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 82290f94..bf3ecfc8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -242,7 +242,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), - (int64_t)w->m_iMonitorID, escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), + (int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); @@ -254,7 +254,7 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\n", (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), - (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->m_iMonitorID, w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), + (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w)); } @@ -288,7 +288,7 @@ std::string clientsRequest(eHyprCtlOutputFormat format, std::string request) { std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat format) { const auto PLASTW = w->getLastFocusedWindow(); - const auto PMONITOR = g_pCompositor->getMonitorFromID(w->m_iMonitorID); + const auto PMONITOR = w->m_pMonitor.lock(); if (format == eHyprCtlOutputFormat::FORMAT_JSON) { return std::format(R"#({{ "id": {}, diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 6c024ee0..f073da82 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -26,7 +26,7 @@ PHLLS CLayerSurface::create(SP resource) { pLS->layer = resource->current.layer; pLS->popupHead = std::make_unique(pLS); - pLS->monitorID = pMonitor->ID; + pLS->monitor = pMonitor; pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); @@ -50,7 +50,7 @@ PHLLS CLayerSurface::create(SP resource) { void CLayerSurface::registerCallbacks() { alpha.setUpdateCallback([this](void*) { if (dimAround) - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(monitorID)); + g_pHyprRenderer->damageMonitor(monitor.lock()); }); } @@ -82,9 +82,9 @@ CLayerSurface::~CLayerSurface() { void CLayerSurface::onDestroy() { Debug::log(LOG, "LayerSurface {:x} destroyed", (uintptr_t)layerSurface.get()); - const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); + const auto PMONITOR = monitor.lock(); - if (!g_pCompositor->getMonitorFromID(monitorID)) + if (!PMONITOR) Debug::log(WARN, "Layersurface destroyed on an invalid monitor (removed?)"); if (!fadingOut) { @@ -137,7 +137,7 @@ void CLayerSurface::onMap() { g_pCompositor->removeFromFadingOutSafe(self.lock()); // fix if it changed its mon - const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); + const auto PMONITOR = monitor.lock(); if (!PMONITOR) return; @@ -197,7 +197,7 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); - if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { + if (!monitor || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); g_pCompositor->addToFadingOutSafe(self.lock()); @@ -221,7 +221,7 @@ void CLayerSurface::onUnmap() { g_pCompositor->addToFadingOutSafe(self.lock()); - const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); + const auto PMONITOR = monitor.lock(); const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); @@ -256,13 +256,13 @@ void CLayerSurface::onCommit() { if (layerSurface->surface && !layerSurface->surface->current.texture) { fadingOut = false; geometry = {}; - g_pHyprRenderer->arrangeLayersForMonitor(monitorID); + g_pHyprRenderer->arrangeLayersForMonitor(monitorID()); } return; } - const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); + const auto PMONITOR = monitor.lock(); if (!PMONITOR) return; @@ -336,7 +336,7 @@ void CLayerSurface::onCommit() { // moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // so unfocus the surface here. g_pCompositor->focusSurface(nullptr); - g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); + g_pInputManager->refocusLastWindow(monitor.lock()); } else if (!WASEXCLUSIVE && ISEXCLUSIVE) { // if now exclusive and not previously g_pSeatManager->setGrab(nullptr); @@ -545,3 +545,7 @@ int CLayerSurface::popupsCount() { popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; } + +MONITORID CLayerSurface::monitorID() { + return monitor ? monitor->ID : MONITOR_INVALID; +} diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index e0f17039..6aa8eb81 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -42,7 +42,7 @@ class CLayerSurface { bool mapped = false; uint32_t layer = 0; - MONITORID monitorID = -1; + PHLMONITORREF monitor; bool fadingOut = false; bool readyToDelete = false; @@ -70,6 +70,7 @@ class CLayerSurface { void onMap(); void onUnmap(); void onCommit(); + MONITORID monitorID(); private: struct { @@ -83,6 +84,6 @@ class CLayerSurface { // For the list lookup bool operator==(const CLayerSurface& rhs) const { - return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; + return layerSurface == rhs.layerSurface && monitor == rhs.monitor; } }; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 0772b676..e4f987eb 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -113,7 +113,7 @@ SBoxExtents CWindow::getFullWindowExtents() { const int BORDERSIZE = getRealBorderSize(); if (m_sWindowData.dimAround.valueOrDefault()) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; } @@ -173,7 +173,7 @@ SBoxExtents CWindow::getFullWindowExtents() { CBox CWindow::getFullWindowBoundingBox() { if (m_sWindowData.dimAround.valueOrDefault()) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } @@ -186,7 +186,7 @@ CBox CWindow::getFullWindowBoundingBox() { } CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); if (!PMONITOR) return {m_vPosition, m_vSize}; @@ -221,7 +221,7 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() { CBox CWindow::getWindowBoxUnified(uint64_t properties) { if (m_sWindowData.dimAround.valueOrDefault()) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); if (PMONITOR) return {PMONITOR->vecPosition.x, PMONITOR->vecPosition.y, PMONITOR->vecSize.x, PMONITOR->vecSize.y}; } @@ -352,9 +352,9 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) { const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(m_iLastSurfaceMonitorID); - m_iLastSurfaceMonitorID = m_iMonitorID; + m_iLastSurfaceMonitorID = monitorID(); - const auto PNEWMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PNEWMONITOR = m_pMonitor.lock(); if (!PNEWMONITOR) return; @@ -366,10 +366,10 @@ void CWindow::updateSurfaceScaleTransformDetails(bool force) { m_pWLSurface->resource()->breadthfirst([PNEWMONITOR](SP s, const Vector2D& offset, void* d) { s->enter(PNEWMONITOR->self.lock()); }, nullptr); } - m_pWLSurface->resource()->breadthfirst( - [this](SP s, const Vector2D& offset, void* d) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); + m_pWLSurface->resource()->breadthfirst( + [PMONITOR](SP s, const Vector2D& offset, void* d) { const auto PSURFACE = CWLSurface::fromResource(s); if (PSURFACE && PSURFACE->m_fLastScale == PMONITOR->scale) return; @@ -404,7 +404,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; - m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->m_iMonitorID : -1; + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); m_fMovingToWorkspaceAlpha = 0.F; m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); @@ -415,11 +415,11 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID()); g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -431,14 +431,14 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { if (const auto SWALLOWED = m_pSwallowed.lock()) { SWALLOWED->moveToWorkspace(pWorkspace); - SWALLOWED->m_iMonitorID = m_iMonitorID; + SWALLOWED->m_pMonitor = m_pMonitor; } // update xwayland coords g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(OLDWORKSPACE->m_iMonitorID); PMONITOR) + if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); } } @@ -517,19 +517,19 @@ void CWindow::onUnmap() { std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) PMONITOR->setSpecialWorkspace(nullptr); } - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this) PMONITOR->solitaryClient.reset(); g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); m_pWorkspace.reset(); @@ -790,7 +790,7 @@ void CWindow::updateDynamicRules() { EMIT_HOOK_EVENT("windowUpdateRules", m_pSelf.lock()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); } // check if the point is "hidden" under a rounded corner of the window @@ -857,7 +857,7 @@ void CWindow::createGroup() { g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("1,{:x}", (uintptr_t)this)}); @@ -875,7 +875,7 @@ void CWindow::destroyGroup() { updateWindowDecos(); g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); g_pEventManager->postEvent(SHyprIPCEvent{"togglegroup", std::format("0,{:x}", (uintptr_t)this)}); @@ -911,7 +911,7 @@ void CWindow::destroyGroup() { g_pCompositor->updateWorkspaceWindows(workspaceID()); g_pCompositor->updateWorkspaceWindowData(workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); if (!addresses.empty()) @@ -1087,7 +1087,7 @@ void CWindow::updateGroupOutputs() { const auto WS = m_pWorkspace; while (curr.get() != this) { - curr->m_iMonitorID = m_iMonitorID; + curr->m_pMonitor = m_pMonitor; curr->moveToWorkspace(WS); curr->m_vRealPosition = m_vRealPosition.goal(); @@ -1209,7 +1209,7 @@ void CWindow::onWorkspaceAnimUpdate() { if (!PWORKSPACE) return; - const auto PWSMON = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); + const auto PWSMON = m_pMonitor.lock(); if (!PWSMON) return; @@ -1275,6 +1275,10 @@ WORKSPACEID CWindow::workspaceID() { return m_pWorkspace ? m_pWorkspace->m_iID : m_iLastWorkspace; } +MONITORID CWindow::monitorID() { + return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID; +} + bool CWindow::onSpecialWorkspace() { return m_pWorkspace ? m_pWorkspace->m_bIsSpecialWorkspace : g_pCompositor->isWorkspaceSpecial(m_iLastWorkspace); } @@ -1461,7 +1465,7 @@ void CWindow::onX11Configure(CBox box) { m_pXWaylandSurface->configure(box); m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) m_fX11SurfaceScaledBy = PMONITOR->scale; return; } @@ -1487,7 +1491,7 @@ void CWindow::onX11Configure(CBox box) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); if (*PXWLFORCESCALEZERO) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); PMONITOR) { + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); m_fX11SurfaceScaledBy = PMONITOR->scale; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 64f39558..825e8ca2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -272,12 +272,12 @@ class CWindow { bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bWasMaximized = false; sFullscreenState m_sFullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE}; - MONITORID m_iMonitorID = -1; std::string m_szTitle = ""; std::string m_szClass = ""; std::string m_szInitialTitle = ""; std::string m_szInitialClass = ""; PHLWORKSPACE m_pWorkspace; + PHLMONITORREF m_pMonitor; bool m_bIsMapped = false; @@ -429,6 +429,7 @@ class CWindow { void setSuspended(bool suspend); bool visibleOnMonitor(PHLMONITOR pMonitor); WORKSPACEID workspaceID(); + MONITORID monitorID(); bool onSpecialWorkspace(); void activate(bool force = false); int surfacesCount(); @@ -559,7 +560,7 @@ struct std::formatter : std::formatter { if (formatWorkspace) std::format_to(out, ", workspace: {}", w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID); if (formatMonitor) - std::format_to(out, ", monitor: {}", w->m_iMonitorID); + std::format_to(out, ", monitor: {}", w->monitorID()); if (formatClass) std::format_to(out, ", class: {}", w->m_szClass); return std::format_to(out, "]"); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 2d92659c..2e1e91f2 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -5,14 +5,14 @@ #include using namespace Hyprutils::String; -PHLWORKSPACE CWorkspace::create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { - PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmpty); +PHLWORKSPACE CWorkspace::create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) { + PHLWORKSPACE workspace = makeShared(id, monitor, name, special, isEmpty); workspace->init(workspace); return workspace; } -CWorkspace::CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special, bool isEmpty) { - m_iMonitorID = monitorID; +CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special, bool isEmpty) { + m_pMonitor = monitor; m_iID = id; m_szName = name; m_bIsSpecialWorkspace = special; @@ -103,7 +103,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { }); if (ANIMSTYLE.starts_with("slidefade")) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); float movePerc = 100.f; if (ANIMSTYLE.find("%") != std::string::npos) { @@ -151,7 +151,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { } } else if (ANIMSTYLE == "slidevert") { // fallback is slide - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP; m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. @@ -164,7 +164,7 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { } } else { // fallback is slide - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID); + const auto PMONITOR = m_pMonitor.lock(); const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP; m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. @@ -224,7 +224,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.name = prev->m_szName; - if (prev->m_iMonitorID == m_iMonitorID) { + if (prev->m_pMonitor == m_pMonitor) { m_sPrevWorkspacePerMonitor.id = prev->m_iID; m_sPrevWorkspacePerMonitor.name = prev->m_szName; } @@ -347,7 +347,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { const auto PMONITOR = g_pCompositor->getMonitorFromString(prop); - if (!(PMONITOR ? PMONITOR->ID == m_iMonitorID : false)) + if (!(PMONITOR ? PMONITOR == m_pMonitor : false)) return false; continue; } @@ -512,12 +512,16 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { } void CWorkspace::markInert() { - m_bInert = true; - m_iID = WORKSPACE_INVALID; - m_iMonitorID = MONITOR_INVALID; - m_bVisible = false; + m_bInert = true; + m_iID = WORKSPACE_INVALID; + m_bVisible = false; + m_pMonitor.reset(); } bool CWorkspace::inert() { return m_bInert; } + +MONITORID CWorkspace::monitorID() { + return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID; +} diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 7a32459c..3ed9f50c 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -17,16 +17,16 @@ class CWindow; class CWorkspace { public: - static PHLWORKSPACE create(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); + static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); // use create() don't use this - CWorkspace(WORKSPACEID id, MONITORID monitorID, std::string name, bool special = false, bool isEmpty = true); + CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true); ~CWorkspace(); // Workspaces ID-based have IDs > 0 // and workspaces name-based have IDs starting with -1337 - WORKSPACEID m_iID = WORKSPACE_INVALID; - std::string m_szName = ""; - MONITORID m_iMonitorID = MONITOR_INVALID; + WORKSPACEID m_iID = WORKSPACE_INVALID; + std::string m_szName = ""; + PHLMONITORREF m_pMonitor; // Previous workspace ID and name is stored during a workspace change, allowing travel // to the previous workspace. SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; @@ -68,6 +68,7 @@ class CWorkspace { void setActive(bool on); void moveToMonitor(const MONITORID&); + MONITORID monitorID(); PHLWINDOW getLastFocusedWindow(); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index e8abe30d..30d982fb 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -53,7 +53,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PMONITOR = g_pCompositor->m_pLastMonitor.lock(); } auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; - PWINDOW->m_iMonitorID = PMONITOR->ID; + PWINDOW->m_pMonitor = PMONITOR; PWINDOW->m_pWorkspace = PWORKSPACE; PWINDOW->m_bIsMapped = true; PWINDOW->m_bReadyToDelete = false; @@ -144,18 +144,18 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); if (MONITORSTR == "unset") { - PWINDOW->m_iMonitorID = PMONITOR->ID; + PWINDOW->m_pMonitor = PMONITOR; } else { if (isNumber(MONITORSTR)) { const MONITORID MONITOR = std::stoi(MONITORSTR); - if (!g_pCompositor->getMonitorFromID(MONITOR)) - PWINDOW->m_iMonitorID = 0; + if (const auto PM = g_pCompositor->getMonitorFromID(MONITOR); PM) + PWINDOW->m_pMonitor = PM; else - PWINDOW->m_iMonitorID = MONITOR; + PWINDOW->m_pMonitor = g_pCompositor->m_vMonitors.at(0); } else { const auto PMONITOR = g_pCompositor->getMonitorFromName(MONITORSTR); if (PMONITOR) - PWINDOW->m_iMonitorID = PMONITOR->ID; + PWINDOW->m_pMonitor = PMONITOR; else { Debug::log(ERR, "No monitor in monitor {} rule", MONITORSTR); continue; @@ -163,10 +163,10 @@ void Events::listener_mapWindow(void* owner, void* data) { } } - const auto PMONITORFROMID = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock(); - if (PWINDOW->m_iMonitorID != PMONITOR->ID) { - g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->m_iMonitorID)); + if (PWINDOW->m_pMonitor != PMONITOR) { + g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID())); PMONITOR = PMONITORFROMID; } PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; @@ -296,19 +296,19 @@ void Events::listener_mapWindow(void* owner, void* data) { auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); if (!pWorkspace) - pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->m_iMonitorID, requestedWorkspaceName); + pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName); PWORKSPACE = pWorkspace; PWINDOW->m_pWorkspace = pWorkspace; - PWINDOW->m_iMonitorID = pWorkspace->m_iMonitorID; + PWINDOW->m_pMonitor = pWorkspace->m_pMonitor; - if (g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace) + if (PWINDOW->m_pMonitor.lock()->activeSpecialWorkspace && !pWorkspace->m_bIsSpecialWorkspace) workspaceSilent = true; if (!workspaceSilent) { if (pWorkspace->m_bIsSpecialWorkspace) - g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID)->setSpecialWorkspace(pWorkspace); + pWorkspace->m_pMonitor->setSpecialWorkspace(pWorkspace); else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID) g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName); @@ -574,7 +574,7 @@ void Events::listener_mapWindow(void* owner, void* data) { g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); g_pHyprRenderer->damageWindow(SWALLOWER); SWALLOWER->setHidden(true); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); } PWINDOW->m_bFirstMap = false; @@ -635,7 +635,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { return; } - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); if (PMONITOR) { PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition; PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value(); @@ -773,7 +773,7 @@ void Events::listener_commitWindow(void* owner, void* data) { if (!PWINDOW->m_pWorkspace->m_bVisible) return; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); if (PMONITOR) PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow"); @@ -911,7 +911,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); if (*PXWLFORCESCALEZERO) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); PMONITOR) { + if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) { PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); } } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 20c79a2b..29861af7 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -302,7 +302,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Collect all the workspaces we can't jump to. for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID)) { + if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor)) { // Can't jump to this workspace invalidWSes.insert(ws->m_iID); } @@ -320,7 +320,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { // Prepare all named workspaces in case when we need them std::vector namedWSes; for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) || ws->m_iID >= 0) + if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor) || ws->m_iID >= 0) continue; namedWSes.push_back(ws->m_iID); @@ -464,7 +464,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { std::vector validWSes; for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_bIsSpecialWorkspace || (ws->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID && !onAllMonitors)) + if (ws->m_bIsSpecialWorkspace || (ws->m_pMonitor != g_pCompositor->m_pLastMonitor && !onAllMonitors)) continue; validWSes.push_back(ws->m_iID); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 41290b7d..9e71bf5f 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -314,9 +314,8 @@ void CMonitor::onDisconnect(bool destroy) { // move workspaces std::deque wspToMove; for (auto const& w : g_pCompositor->m_vWorkspaces) { - if (w->m_iMonitorID == ID || !g_pCompositor->getMonitorFromID(w->m_iMonitorID)) { + if (w->m_pMonitor == self || !w->m_pMonitor) wspToMove.push_back(w); - } } for (auto const& w : wspToMove) { @@ -464,7 +463,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { if (newDefaultWorkspaceName == "") newDefaultWorkspaceName = std::to_string(wsID); - PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, ID, newDefaultWorkspaceName)); + PNEWWORKSPACE = g_pCompositor->m_vWorkspaces.emplace_back(CWorkspace::create(wsID, self.lock(), newDefaultWorkspaceName)); } activeWorkspace = PNEWWORKSPACE; @@ -541,9 +540,8 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // move all the WS std::deque wspToMove; for (auto const& w : g_pCompositor->m_vWorkspaces) { - if (w->m_iMonitorID == ID) { + if (w->m_pMonitor == self || !w->m_pMonitor) wspToMove.push_back(w); - } } for (auto const& w : wspToMove) { @@ -626,7 +624,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo } if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && - !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { + !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); auto pWindow = pWorkspace->getLastFocusedWindow(); @@ -687,7 +685,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); - if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { + if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { if (const auto PLAST = activeWorkspace->getLastFocusedWindow(); PLAST) g_pCompositor->focusWindow(PLAST); else @@ -710,7 +708,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { bool animate = true; //close if open elsewhere - const auto PMONITORWORKSPACEOWNER = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITORWORKSPACEOWNER = pWorkspace->m_pMonitor.lock(); if (PMONITORWORKSPACEOWNER->activeSpecialWorkspace == pWorkspace) { PMONITORWORKSPACEOWNER->activeSpecialWorkspace.reset(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITORWORKSPACEOWNER->ID); @@ -723,7 +721,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { } // open special - pWorkspace->m_iMonitorID = ID; + pWorkspace->m_pMonitor = self; activeSpecialWorkspace = pWorkspace; activeSpecialWorkspace->m_bVisible = true; if (animate) @@ -731,7 +729,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { for (auto const& w : g_pCompositor->m_vWindows) { if (w->m_pWorkspace == pWorkspace) { - w->m_iMonitorID = ID; + w->m_pMonitor = self; w->updateSurfaceScaleTransformDetails(); w->setAnimationsToMove(); @@ -755,7 +753,7 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(ID); - if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_iMonitorID == ID)) { + if (!(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { if (const auto PLAST = pWorkspace->getLastFocusedWindow(); PLAST) g_pCompositor->focusWindow(PLAST); else diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 0fa57143..059dda99 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -111,7 +111,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for } } } else - PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); + PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_pMonitor.lock(); if (!PMONITOR) { Debug::log(ERR, "Orphaned Node {}!!", pNode); @@ -234,7 +234,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir m_lDwindleNodesData.push_back(SDwindleNodeData()); const auto PNODE = &m_lDwindleNodesData.back(); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); static auto PUSEACTIVE = CConfigValue("dwindle:use_active_for_splits"); static auto PDEFAULTSPLIT = CConfigValue("dwindle:default_split_ratio"); @@ -446,7 +446,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir NEWPARENT->recalcSizePosRecursive(false, horizontalOverride, verticalOverride); - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); } void CHyprDwindleLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { @@ -512,7 +512,7 @@ void CHyprDwindleLayout::recalculateMonitor(const MONITORID& monid) { } void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = pWorkspace->m_pMonitor.lock(); if (!PMONITOR) return; @@ -577,7 +577,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn static auto PSMARTRESIZING = CConfigValue("dwindle:smart_resizing"); // get some data about our window - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); const bool DISPLAYLEFT = STICKS(PWINDOW->m_vPosition.x, PMONITOR->vecPosition.x + PMONITOR->vecReservedTopLeft.x); const bool DISPLAYRIGHT = STICKS(PWINDOW->m_vPosition.x + PWINDOW->m_vSize.x, PMONITOR->vecPosition.x + PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x); const bool DISPLAYTOP = STICKS(PWINDOW->m_vPosition.y, PMONITOR->vecPosition.y + PMONITOR->vecReservedTopLeft.y); @@ -750,7 +750,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn } void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); const auto PWORKSPACE = pWindow->m_pWorkspace; // save position and size if floating @@ -860,9 +860,9 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, const auto PMONITORFOCAL = g_pCompositor->getMonitorFromVector(focalPoint); - if (PMONITORFOCAL->ID != pWindow->m_iMonitorID) { + if (PMONITORFOCAL != pWindow->m_pMonitor) { pWindow->moveToWorkspace(PMONITORFOCAL->activeWorkspace); - pWindow->m_iMonitorID = PMONITORFOCAL->ID; + pWindow->m_pMonitor = PMONITORFOCAL; } onWindowCreatedTiling(pWindow); @@ -900,7 +900,7 @@ void CHyprDwindleLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { PNODE->pWindow = pWindow2; if (PNODE->workspaceID != PNODE2->workspaceID) { - std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); + std::swap(pWindow2->m_pMonitor, pWindow->m_pMonitor); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace); } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 454a6132..a3c14e41 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -13,7 +13,7 @@ void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); pWindow->m_vLastFloatingSize = PMONITOR->vecSize / 2.f; } else pWindow->m_vLastFloatingSize = Vector2D(desiredGeometry.width, desiredGeometry.height); @@ -88,7 +88,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { CBox desiredGeometry = {0}; g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (pWindow->m_bIsX11) { Vector2D xy = {desiredGeometry.x, desiredGeometry.y}; @@ -485,7 +485,7 @@ static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, } if (*SNAPMONITORGAP) { - const auto MON = g_pCompositor->getMonitorFromID(DRAGGINGWINDOW->m_iMonitorID); + const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); const CBox mon = {MON->vecPosition.x, MON->vecPosition.y, MON->vecPosition.x + MON->vecSize.x, MON->vecPosition.y + MON->vecSize.y}; const double gap = *SNAPMONITORGAP; @@ -677,7 +677,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); if (PMONITOR && !SPECIAL) { - DRAGGINGWINDOW->m_iMonitorID = PMONITOR->ID; + DRAGGINGWINDOW->m_pMonitor = PMONITOR; DRAGGINGWINDOW->moveToWorkspace(PMONITOR->activeWorkspace); DRAGGINGWINDOW->updateGroupOutputs(); @@ -705,8 +705,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { EMIT_HOOK_EVENT("changeFloatingMode", pWindow); if (!TILED) { - const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); - pWindow->m_iMonitorID = PNEWMON->ID; + const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); + pWindow->m_pMonitor = PNEWMON; pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace); pWindow->updateGroupOutputs(); @@ -734,7 +734,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vRealSize.setValue(PSAVEDSIZE); // fix pseudo leaving artifacts - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); + g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock()); if (pWindow == g_pCompositor->m_pLastWindow) m_pLastTiledWindow = pWindow; @@ -757,7 +757,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_vSize = wb.pos(); pWindow->m_vPosition = wb.size(); - g_pHyprRenderer->damageMonitor(g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID)); + g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock()); pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); @@ -847,7 +847,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || - pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_iMonitorID != g_pCompositor->m_pLastMonitor->ID) + pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_pMonitor != g_pCompositor->m_pLastMonitor) return nullptr; return pWindowCandidate; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 95b5afdf..a2321a41 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -80,7 +80,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire static auto PNEWONTOP = CConfigValue("master:new_on_top"); static auto PNEWSTATUS = CConfigValue("master:new_status"); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before"; const bool BNEWISMASTER = *PNEWSTATUS == "master"; @@ -229,7 +229,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire } // recalc - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); } void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { @@ -279,7 +279,7 @@ void CHyprMasterLayout::onWindowRemovedTiling(PHLWINDOW pWindow) { } } } - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); } void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) { @@ -297,7 +297,7 @@ void CHyprMasterLayout::recalculateMonitor(const MONITORID& monid) { } void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = pWorkspace->m_pMonitor.lock(); if (!PMONITOR) return; @@ -604,7 +604,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { } } } else - PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_iMonitorID); + PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_pMonitor.lock(); if (!PMONITOR) { Debug::log(ERR, "Orphaned Node {}!!", pNode); @@ -711,7 +711,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne return; } - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); static auto ALWAYSCENTER = CConfigValue("master:always_center_master"); static auto PSMARTRESIZING = CConfigValue("master:smart_resizing"); @@ -840,7 +840,7 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne } void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFullscreenMode CURRENT_EFFECTIVE_MODE, const eFullscreenMode EFFECTIVE_MODE) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); const auto PWORKSPACE = pWindow->m_pWorkspace; // save position and size if floating @@ -896,7 +896,7 @@ void CHyprMasterLayout::recalculateWindow(PHLWINDOW pWindow) { if (!PNODE) return; - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); } SWindowRenderLayoutHints CHyprMasterLayout::requestRenderHints(PHLWINDOW pWindow) { @@ -922,9 +922,9 @@ void CHyprMasterLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, // if different monitors, send to monitor onWindowRemovedTiling(pWindow); pWindow->moveToWorkspace(PWINDOW2->m_pWorkspace); - pWindow->m_iMonitorID = PWINDOW2->m_iMonitorID; + pWindow->m_pMonitor = PWINDOW2->m_pMonitor; if (!silent) { - const auto pMonitor = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto pMonitor = pWindow->m_pMonitor.lock(); g_pCompositor->setActiveMonitor(pMonitor); } onWindowCreatedTiling(pWindow); @@ -946,7 +946,7 @@ void CHyprMasterLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { return; if (PNODE->workspaceID != PNODE2->workspaceID) { - std::swap(pWindow2->m_iMonitorID, pWindow->m_iMonitorID); + std::swap(pWindow2->m_pMonitor, pWindow->m_pMonitor); std::swap(pWindow2->m_pWorkspace, pWindow->m_pWorkspace); } @@ -957,9 +957,9 @@ void CHyprMasterLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { pWindow->setAnimationsToMove(); pWindow2->setAnimationsToMove(); - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); if (PNODE2->workspaceID != PNODE->workspaceID) - recalculateMonitor(pWindow2->m_iMonitorID); + recalculateMonitor(pWindow2->monitorID()); g_pHyprRenderer->damageWindow(pWindow); g_pHyprRenderer->damageWindow(pWindow2); @@ -978,7 +978,7 @@ void CHyprMasterLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exa float newRatio = exact ? ratio : PMASTER->percMaster + ratio; PMASTER->percMaster = std::clamp(newRatio, 0.05f, 0.95f); - recalculateMonitor(pWindow->m_iMonitorID); + recalculateMonitor(pWindow->monitorID()); } PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next) { @@ -1185,7 +1185,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri PNODE->isMaster = true; } - recalculateMonitor(header.pWindow->m_iMonitorID); + recalculateMonitor(header.pWindow->monitorID()); } else if (command == "removemaster") { @@ -1217,7 +1217,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri PNODE->isMaster = false; } - recalculateMonitor(header.pWindow->m_iMonitorID); + recalculateMonitor(header.pWindow->monitorID()); } else if (command == "orientationleft" || command == "orientationright" || command == "orientationtop" || command == "orientationbottom" || command == "orientationcenter") { const auto PWINDOW = header.pWindow; @@ -1239,7 +1239,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri else if (command == "orientationcenter") PWORKSPACEDATA->orientation = ORIENTATION_CENTER; - recalculateMonitor(header.pWindow->m_iMonitorID); + recalculateMonitor(header.pWindow->monitorID()); } else if (command == "orientationnext") { runOrientationCycle(header, nullptr, 1); @@ -1274,7 +1274,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri } } - recalculateMonitor(PWINDOW->m_iMonitorID); + recalculateMonitor(PWINDOW->monitorID()); } else if (command == "rollprev") { const auto PWINDOW = header.pWindow; const auto PNODE = getNodeFromWindow(PWINDOW); @@ -1300,7 +1300,7 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri } } - recalculateMonitor(PWINDOW->m_iMonitorID); + recalculateMonitor(PWINDOW->monitorID()); } return 0; @@ -1338,7 +1338,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi nextOrPrev = cycle.size() + (nextOrPrev % (int)cycle.size()); PWORKSPACEDATA->orientation = cycle.at(nextOrPrev); - recalculateMonitor(header.pWindow->m_iMonitorID); + recalculateMonitor(header.pWindow->monitorID()); } void CHyprMasterLayout::buildOrientationCycleVectorFromEOperation(std::vector& cycle) { diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 9ff7497d..0bdf5a7a 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -99,12 +99,12 @@ void CAnimationManager::tick() { PDECO->damageEntire(); } - PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + PMONITOR = PWINDOW->m_pMonitor.lock(); if (!PMONITOR) continue; animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); } else if (PWORKSPACE) { - PMONITOR = g_pCompositor->getMonitorFromID(PWORKSPACE->m_iMonitorID); + PMONITOR = PWORKSPACE->m_pMonitor.lock(); if (!PMONITOR) continue; @@ -325,7 +325,7 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo const auto GOALPOS = pWindow->m_vRealPosition.goal(); const auto GOALSIZE = pWindow->m_vRealSize.goal(); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!PMONITOR) return; // unsafe state most likely diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9c22fb93..b54b71ed 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -349,9 +349,9 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { g_pInputManager->m_pForcedFocus.reset(); } - if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) { + if (PLASTWINDOW && PLASTWINDOW->m_pMonitor != PWINDOWTOCHANGETO->m_pMonitor) { // event - const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID); + const auto PNEWMON = PWINDOWTOCHANGETO->m_pMonitor.lock(); g_pCompositor->setActiveMonitor(PNEWMON); } @@ -1011,7 +1011,7 @@ static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional< } g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); return {}; @@ -1035,7 +1035,7 @@ SDispatchResult CKeybindManager::centerWindow(std::string args) { if (!PWINDOW || !PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) return {.success = false, .error = "No floating window found"}; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); auto RESERVEDOFFSET = Vector2D(); if (args == "1") @@ -1081,7 +1081,7 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU const auto ID = PCURRENTWORKSPACE->m_iID; if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) { - if (PER_MON && PCURRENTWORKSPACE->m_iMonitorID != PWORKSPACETOCHANGETO->m_iMonitorID) + if (PER_MON && PCURRENTWORKSPACE->m_pMonitor != PWORKSPACETOCHANGETO->m_pMonitor) return {WORKSPACE_NOT_CHANGED, ""}; return {ID, PWORKSPACETOCHANGETO->m_szName}; } @@ -1135,7 +1135,7 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) { g_pInputManager->releaseAllMouseButtons(); - const auto PMONITORWORKSPACEOWNER = PMONITOR->ID == pWorkspaceToChangeTo->m_iMonitorID ? PMONITOR : g_pCompositor->getMonitorFromID(pWorkspaceToChangeTo->m_iMonitorID); + const auto PMONITORWORKSPACEOWNER = PMONITOR == pWorkspaceToChangeTo->m_pMonitor ? PMONITOR : pWorkspaceToChangeTo->m_pMonitor.lock(); if (!PMONITORWORKSPACEOWNER) return {.success = false, .error = "Workspace to switch to has no monitor"}; @@ -1270,11 +1270,11 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { if (pWorkspace) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); - pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + pMonitor = pWorkspace->m_pMonitor.lock(); g_pCompositor->setActiveMonitor(pMonitor); } else { - pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); - pMonitor = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->monitorID(), workspaceName, false); + pMonitor = pWorkspace->m_pMonitor.lock(); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } @@ -1283,7 +1283,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { if (pWorkspace->m_bIsSpecialWorkspace) pMonitor->setSpecialWorkspace(pWorkspace); else if (POLDWS->m_bIsSpecialWorkspace) - g_pCompositor->getMonitorFromID(POLDWS->m_iMonitorID)->setSpecialWorkspace(nullptr); + POLDWS->m_pMonitor.lock()->setSpecialWorkspace(nullptr); if (*PALLOWWORKSPACECYCLES) pWorkspace->rememberPrevWorkspace(POLDWS); @@ -1328,7 +1328,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { if (pWorkspace) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } else { - pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->m_iMonitorID, workspaceName, false); + pWorkspace = g_pCompositor->createNewWorkspace(WORKSPACEID, PWINDOW->monitorID(), workspaceName, false); g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } @@ -1475,7 +1475,7 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) { if (PLASTWINDOW->m_bIsFloating) { std::optional vPosx, vPosy; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PLASTWINDOW->m_iMonitorID); + const auto PMONITOR = PLASTWINDOW->m_pMonitor.lock(); const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); switch (arg) { @@ -1882,8 +1882,8 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args workspaceID = pWorkspace->m_iID; } - if (pWorkspace->m_iMonitorID != PCURRMONITOR->ID) { - const auto POLDMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + if (pWorkspace->m_pMonitor != PCURRMONITOR) { + const auto POLDMONITOR = pWorkspace->m_pMonitor.lock(); if (!POLDMONITOR) { // wat Debug::log(ERR, "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"); return {.success = false, .error = "focusWorkspaceOnCurrentMonitor old monitor doesn't exist!"}; @@ -2509,7 +2509,7 @@ SDispatchResult CKeybindManager::pinActive(std::string args) { PWINDOW->m_bPinned = !PWINDOW->m_bPinned; - const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); + const auto PMONITOR = PWINDOW->m_pMonitor.lock(); if (!PMONITOR) { Debug::log(ERR, "pin: monitor not found"); @@ -2658,9 +2658,9 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow); // This removes groupped property! - if (pWindow->m_iMonitorID != pWindowInDirection->m_iMonitorID) { + if (pWindow->m_pMonitor != pWindowInDirection->m_pMonitor) { pWindow->moveToWorkspace(pWindowInDirection->m_pWorkspace); - pWindow->m_iMonitorID = pWindowInDirection->m_iMonitorID; + pWindow->m_pMonitor = pWindowInDirection->m_pMonitor; } static auto USECURRPOS = CConfigValue("group:insert_after_current"); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 7b3081a2..d0dda8e6 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -117,7 +117,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 8f95c6c6..ba0783fa 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -15,9 +15,8 @@ void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { int onMonitor = 0; for (auto const& w : g_pCompositor->m_vWorkspaces) { - if (w->m_iMonitorID == g_pCompositor->m_pLastMonitor->ID && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) { + if (w->m_pMonitor == g_pCompositor->m_pLastMonitor && !g_pCompositor->isWorkspaceSpecial(w->m_iID)) onMonitor++; - } } if (onMonitor < 2 && !*PSWIPENEW) diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 454391af..4e3980aa 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -123,7 +123,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { return; } if (validMapped(m_sTouchData.touchFocusWindow)) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID); + const auto PMONITOR = m_sTouchData.touchFocusWindow->m_pMonitor.lock(); g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); @@ -133,7 +133,7 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { g_pSeatManager->sendTouchMotion(e.timeMs, e.touchID, local); } else if (!m_sTouchData.touchFocusLS.expired()) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID); + const auto PMONITOR = m_sTouchData.touchFocusLS->monitor.lock(); g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index ffc335c9..06814c88 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -207,7 +207,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { resource->sendToplevel(NEWHANDLE->resource.get()); NEWHANDLE->resource->sendAppId(pWindow->m_szClass.c_str()); NEWHANDLE->resource->sendTitle(pWindow->m_szTitle.c_str()); - if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) + if (const auto PMONITOR = pWindow->m_pMonitor.lock(); PMONITOR) NEWHANDLE->sendMonitor(PMONITOR); NEWHANDLE->sendState(); NEWHANDLE->resource->sendDone(); @@ -266,7 +266,7 @@ void CForeignToplevelWlrManager::onMoveMonitor(PHLWINDOW pWindow) { if (!H || H->closed) return; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!PMONITOR) return; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index e81d7e01..7b2bcbf4 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -509,7 +509,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { PHLMONITOR mon; auto HLSurface = CWLSurface::fromResource(feedback->surface); if (auto w = HLSurface->getWindow(); w) - if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) + if (auto m = w->m_pMonitor.lock(); m) mon = m->self.lock(); if (!mon) { diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 8b6208be..f2af89db 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -97,7 +97,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re resource->setDestroy([this](CHyprlandToplevelExportFrameV1* pFrame) { PROTO::toplevelExport->destroyResource(this); }); resource->setCopy([this](CHyprlandToplevelExportFrameV1* pFrame, wl_resource* res, int32_t ignoreDamage) { this->copy(pFrame, res, ignoreDamage); }); - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); g_pHyprRenderer->makeEGLCurrent(); @@ -239,7 +239,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); // no need for end, cuz it's shm // render the client - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); CRegion fakeDamage{0, 0, PMONITOR->vecPixelSize.x * 10, PMONITOR->vecPixelSize.y * 10}; g_pHyprRenderer->makeEGLCurrent(); @@ -296,7 +296,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { } bool CToplevelExportFrame::copyDmabuf(timespec* now) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; @@ -383,7 +383,7 @@ void CToplevelExportProtocol::onOutputCommit(PHLMONITOR pMonitor) { const auto PWINDOW = f->pWindow; - if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) + if (pMonitor != PWINDOW->m_pMonitor.lock()) continue; CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index fc2d1012..9e524fa4 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -693,7 +693,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { if (*PBLURSPECIAL) { for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (!ws->m_bIsSpecialWorkspace || ws->m_iMonitorID != pMonitor->ID) + if (!ws->m_bIsSpecialWorkspace || ws->m_pMonitor != pMonitor) continue; if (ws->m_fAlpha.value() == 0) @@ -2219,7 +2219,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFramebuffer) { // we trust the window is valid. - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) return; @@ -2267,7 +2267,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { // we trust the window is valid. - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) return; @@ -2319,7 +2319,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) { // we trust the window is valid. - const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); + const auto PMONITOR = pLayer->monitor.lock(); if (!PMONITOR || !PMONITOR->output || PMONITOR->vecPixelSize.x <= 0 || PMONITOR->vecPixelSize.y <= 0) return; @@ -2372,7 +2372,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { if (!FBDATA->m_cTex->m_iTexID) return; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + const auto PMONITOR = pWindow->m_pMonitor.lock(); CBox windowBox; // some mafs to figure out the correct box @@ -2411,7 +2411,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { if (!FBDATA->m_cTex->m_iTexID) return; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pLayer->monitorID); + const auto PMONITOR = pLayer->monitor.lock(); CBox layerBox; // some mafs to figure out the correct box diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index c69167c8..1c38eb4e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -314,7 +314,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_iMonitorID == pMonitor->ID) { + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_pMonitor == pMonitor) { if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) return true; @@ -327,10 +327,10 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return false; } - if (pWindow->m_iMonitorID == pMonitor->ID) + if (pWindow->m_pMonitor == pMonitor) return true; - if (!g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace) && pWindow->m_iMonitorID != pMonitor->ID) + if (!g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace) && pWindow->m_pMonitor != pMonitor) return false; // if not, check if it maybe is active on a different monitor. @@ -341,7 +341,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if window is tiled and it's flying in, don't render on other mons (for slide) - if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_iMonitorID != pMonitor->ID) + if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_pMonitor != pMonitor) return false; if (pWindow->m_vRealPosition.isBeingAnimated()) { @@ -379,7 +379,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { return true; for (auto const& m : g_pCompositor->m_vMonitors) { - if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) + if (PWORKSPACE && PWORKSPACE->m_pMonitor == m && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) return true; if (m->activeSpecialWorkspace && pWindow->onSpecialWorkspace()) @@ -422,10 +422,10 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (w->isFullscreen() || !w->m_bIsFloating) continue; - if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; - if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID) + if (pWorkspace->m_bIsSpecialWorkspace && w->m_pMonitor != pWorkspace->m_pMonitor) continue; // special on another are rendered as a part of the base pass renderWindow(w, pMonitor, time, true, RENDER_PASS_ALL); @@ -439,14 +439,14 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering))) continue; - if (w->m_iMonitorID != pMonitor->ID) + if (w->m_pMonitor != pMonitor) continue; } if (!w->isFullscreen()) continue; - if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; if (shouldRenderWindow(w, pMonitor)) @@ -469,10 +469,10 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) continue; - if (w->m_iMonitorID == pWorkspace->m_iMonitorID && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; - if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID) + if (pWorkspace->m_bIsSpecialWorkspace && w->m_pMonitor != pWorkspace->m_pMonitor) continue; // special on another are rendered as a part of the base pass renderWindow(w, pMonitor, time, true, RENDER_PASS_ALL); @@ -543,7 +543,7 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; - if (pWorkspace->m_bIsSpecialWorkspace && w->m_iMonitorID != pWorkspace->m_iMonitorID) + if (pWorkspace->m_bIsSpecialWorkspace && w->m_pMonitor != pWorkspace->m_pMonitor) continue; // special on another are rendered as a part of the base pass // render the bad boy @@ -556,7 +556,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe return; if (pWindow->m_bFadingOut) { - if (pMonitor->ID == pWindow->m_iMonitorID) // TODO: fix this + if (pMonitor == pWindow->m_pMonitor) // TODO: fix this g_pHyprOpenGL->renderSnapshot(pWindow); return; } @@ -965,7 +965,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // and then special for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_iMonitorID == pMonitor->ID && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { + if (ws->m_pMonitor == pMonitor && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { const auto SPECIALANIMPROGRS = ws->m_vRenderOffset.isBeingAnimated() ? ws->m_vRenderOffset.getCurveValue() : ws->m_fAlpha.getCurveValue(); const bool ANIMOUT = !pMonitor->activeSpecialWorkspace; @@ -2533,7 +2533,7 @@ void CHyprRenderer::initiateManualCrash() { void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace) { CRegion rg; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = pWorkspace->m_pMonitor.lock(); if (!PMONITOR->activeSpecialWorkspace) return; @@ -2562,7 +2562,7 @@ void CHyprRenderer::setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pW void CHyprRenderer::setOccludedForBackLayers(CRegion& region, PHLWORKSPACE pWorkspace) { CRegion rg; - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWorkspace->m_iMonitorID); + const auto PMONITOR = pWorkspace->m_pMonitor.lock(); static auto PBLUR = CConfigValue("decoration:blur:enabled"); static auto PBLURSIZE = CConfigValue("decoration:blur:size"); From b1120ec4334abdb57677354dfcdcf48b6c34f397 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 27 Oct 2024 23:39:52 +0000 Subject: [PATCH 0778/2393] layout: window snapping cleanup + fixes way better now heh fixes #8259 fixes #8267 --- src/layout/IHyprLayout.cpp | 94 ++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index a3c14e41..30b5632c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -415,7 +415,7 @@ static void snapResizeRight(double& pos, double& len, const double p) { typedef std::function SnapFn; -static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode mode, const int corner, const Vector2D& beginSize) { +static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode mode, const int corner, const Vector2D& beginSize) { static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); static auto SNAPMONITORGAP = CConfigValue("general:snap:monitor_gap"); @@ -425,59 +425,59 @@ static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, const SnapFn snapUp = snapLeft; int snaps = 0; + const int DRAGGINGBORDERSIZE = DRAGGINGWINDOW->getRealBorderSize(); + CBox sourceBox = CBox{sourcePos, sourceSize}.expand(DRAGGINGBORDERSIZE); + if (*SNAPWINDOWGAP) { const auto PID = DRAGGINGWINDOW->getPID(); const auto WSID = DRAGGINGWINDOW->workspaceID(); - const int BORD = DRAGGINGWINDOW->getRealBorderSize(); for (auto& other : g_pCompositor->m_vWindows) { if (other->workspaceID() != WSID || other->getPID() == PID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) continue; - const int bord = std::max(BORD, other->getRealBorderSize()); - const double gap = *SNAPWINDOWGAP + bord; + const int BORDERSIZE = other->getRealBorderSize(); + const double GAPSIZE = *SNAPWINDOWGAP + BORDERSIZE; - const CBox box = other->getWindowMainSurfaceBox(); - const CBox ob = {box.x, box.y, box.x + box.w, box.y + box.h}; - const CBox bb = {ob.x - bord, ob.y - bord, ob.w + bord, ob.h + bord}; - const Vector2D end = {pos.x + size.x, pos.y + size.y}; + const CBox SURFBB = other->getWindowMainSurfaceBox().expand(BORDERSIZE); + const Vector2D end = sourceBox.pos() + sourceBox.size(); // only snap windows if their ranges intersect in the opposite axis - if (pos.y <= bb.h && bb.y <= end.y) { - if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(pos.x, bb.w, gap)) { - snapLeft(pos.x, size.x, bb.w); + if (sourceBox.y <= SURFBB.y + SURFBB.h && SURFBB.y <= end.y) { + if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceBox.x, SURFBB.x + SURFBB.w, GAPSIZE)) { + snapLeft(sourceBox.x, sourceBox.w, SURFBB.x + SURFBB.w); snaps |= SNAP_LEFT; - } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, bb.x, gap)) { - snapRight(pos.x, size.x, bb.x); + } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, SURFBB.x, GAPSIZE)) { + snapRight(sourceBox.x, sourceBox.w, SURFBB.x); snaps |= SNAP_RIGHT; } } - if (pos.x <= bb.w && bb.x <= end.x) { - if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(pos.y, bb.h, gap)) { - snapUp(pos.y, size.y, bb.h); + if (sourceBox.x <= SURFBB.x + SURFBB.w && SURFBB.x <= end.x) { + if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceBox.y, SURFBB.y + SURFBB.h, GAPSIZE)) { + snapUp(sourceBox.y, sourceBox.h, SURFBB.y + SURFBB.h); snaps |= SNAP_UP; - } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, bb.y, gap)) { - snapDown(pos.y, size.y, bb.y); + } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, SURFBB.y, GAPSIZE)) { + snapDown(sourceBox.y, sourceBox.h, SURFBB.y); snaps |= SNAP_DOWN; } } // corner snapping - if (pos.x == bb.w || bb.x == pos.x + size.x) { - if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(pos.y, ob.y, gap)) { - snapUp(pos.y, size.y, ob.y); + if (sourceBox.x == SURFBB.x + SURFBB.w || SURFBB.x == sourceBox.x + sourceBox.w) { + if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceBox.y, SURFBB.y, GAPSIZE)) { + snapUp(sourceBox.y, sourceBox.w, SURFBB.y); snaps |= SNAP_UP; - } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, ob.h, gap)) { - snapDown(pos.y, size.y, ob.h); + } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, SURFBB.y + SURFBB.h, GAPSIZE)) { + snapDown(sourceBox.y, sourceBox.h, SURFBB.y + SURFBB.h); snaps |= SNAP_DOWN; } } - if (pos.y == bb.h || bb.y == pos.y + size.y) { - if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(pos.x, ob.x, gap)) { - snapLeft(pos.x, size.x, ob.x); + if (sourceBox.y == SURFBB.y + SURFBB.h || SURFBB.y == sourceBox.y + sourceBox.w) { + if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceBox.x, SURFBB.x, GAPSIZE)) { + snapLeft(sourceBox.x, sourceBox.w, SURFBB.x); snaps |= SNAP_LEFT; - } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, ob.w, gap)) { - snapRight(pos.x, size.x, ob.w); + } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, SURFBB.x + SURFBB.w, GAPSIZE)) { + snapRight(sourceBox.x, sourceBox.w, SURFBB.x + SURFBB.w); snaps |= SNAP_RIGHT; } } @@ -485,24 +485,26 @@ static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, } if (*SNAPMONITORGAP) { - const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); - const CBox mon = {MON->vecPosition.x, MON->vecPosition.y, MON->vecPosition.x + MON->vecSize.x, MON->vecPosition.y + MON->vecSize.y}; + const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); + const CBox mon = + CBox{MON->vecPosition.x + MON->vecReservedTopLeft.x, MON->vecPosition.y + MON->vecReservedTopLeft.y, + MON->vecSize.x - MON->vecReservedTopLeft.x - MON->vecReservedBottomRight.x, MON->vecSize.y - MON->vecReservedBottomRight.y - MON->vecReservedTopLeft.y}; const double gap = *SNAPMONITORGAP; - if (canSnap(pos.x, mon.x, gap)) { - snapLeft(pos.x, size.x, mon.x); + if (canSnap(sourceBox.x, mon.x, gap)) { + snapLeft(sourceBox.x, sourceBox.w, mon.x); snaps |= SNAP_LEFT; } - if (canSnap(pos.x + size.x, mon.w, gap)) { - snapRight(pos.x, size.x, mon.w); + if (canSnap(sourceBox.x + sourceBox.w, mon.x + mon.w, gap)) { + snapRight(sourceBox.x, sourceBox.w, mon.w + mon.x); snaps |= SNAP_RIGHT; } - if (canSnap(pos.y, mon.y, gap)) { - snapUp(pos.y, size.y, mon.y); + if (canSnap(sourceBox.y, mon.y, gap)) { + snapUp(sourceBox.y, sourceBox.h, mon.y); snaps |= SNAP_UP; } - if (canSnap(pos.y + size.y, mon.h, gap)) { - snapDown(pos.y, size.y, mon.h); + if (canSnap(sourceBox.y + sourceBox.h, mon.y + mon.h, gap)) { + snapDown(sourceBox.y, sourceBox.h, mon.h + mon.y); snaps |= SNAP_DOWN; } } @@ -511,17 +513,21 @@ static void performSnap(Vector2D& pos, Vector2D& size, PHLWINDOW DRAGGINGWINDOW, const double RATIO = beginSize.y / beginSize.x; if ((corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) { - const double sizeY = size.x * RATIO; + const double sizeY = sourceBox.h * RATIO; if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT)) - pos.y += size.y - sizeY; - size.y = sizeY; + sourceBox.y += sourceBox.h - sizeY; + sourceBox.h = sizeY; } else if ((corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) { - const double sizeX = size.y / RATIO; + const double sizeX = sourceBox.h / RATIO; if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT)) - pos.x += size.x - sizeX; - size.x = sizeX; + sourceBox.x += sourceBox.w - sizeX; + sourceBox.w = sizeX; } } + + sourceBox.expand(-DRAGGINGBORDERSIZE).round(); + sourcePos = sourceBox.pos(); + sourceSize = sourceBox.size(); } void IHyprLayout::onMouseMove(const Vector2D& mousePos) { From 6cf193e1662f6f750e964a3e174ae017246b4d48 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 27 Oct 2024 23:41:22 +0000 Subject: [PATCH 0779/2393] layout: don't snap to self and allow same-pid snaps fixes #8255 --- src/layout/IHyprLayout.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 30b5632c..bd81500d 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -429,11 +429,10 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA CBox sourceBox = CBox{sourcePos, sourceSize}.expand(DRAGGINGBORDERSIZE); if (*SNAPWINDOWGAP) { - const auto PID = DRAGGINGWINDOW->getPID(); const auto WSID = DRAGGINGWINDOW->workspaceID(); for (auto& other : g_pCompositor->m_vWindows) { - if (other->workspaceID() != WSID || other->getPID() == PID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) + if (other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) continue; const int BORDERSIZE = other->getRealBorderSize(); From 2c481202effe707451608e272b5a801f8c970052 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 28 Oct 2024 09:39:05 -0400 Subject: [PATCH 0780/2393] layout: slight adjustments to snapping logic (#8273) fixes some bugs with resizing and corner snapping --- src/layout/IHyprLayout.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index bd81500d..e3606532 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -464,14 +464,14 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA // corner snapping if (sourceBox.x == SURFBB.x + SURFBB.w || SURFBB.x == sourceBox.x + sourceBox.w) { if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceBox.y, SURFBB.y, GAPSIZE)) { - snapUp(sourceBox.y, sourceBox.w, SURFBB.y); + snapUp(sourceBox.y, sourceBox.h, SURFBB.y); snaps |= SNAP_UP; } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, SURFBB.y + SURFBB.h, GAPSIZE)) { snapDown(sourceBox.y, sourceBox.h, SURFBB.y + SURFBB.h); snaps |= SNAP_DOWN; } } - if (sourceBox.y == SURFBB.y + SURFBB.h || SURFBB.y == sourceBox.y + sourceBox.w) { + if (sourceBox.y == SURFBB.y + SURFBB.h || SURFBB.y == sourceBox.y + sourceBox.h) { if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceBox.x, SURFBB.x, GAPSIZE)) { snapLeft(sourceBox.x, sourceBox.w, SURFBB.x); snaps |= SNAP_LEFT; @@ -512,7 +512,7 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA const double RATIO = beginSize.y / beginSize.x; if ((corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) { - const double sizeY = sourceBox.h * RATIO; + const double sizeY = sourceBox.w * RATIO; if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT)) sourceBox.y += sourceBox.h - sizeY; sourceBox.h = sizeY; From d49a1334a8af7c704626cdf1746cb72415ad6d0d Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 28 Oct 2024 16:52:14 +0000 Subject: [PATCH 0781/2393] swallow: check if swallow_regex doesn't exist (#8265) Avoid to run CWindow::getSwallower() when `swallow_regex` doesn't exist in the user's config file. --- src/desktop/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e4f987eb..60f3b79d 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1535,7 +1535,7 @@ PHLWINDOW CWindow::getSwallower() { static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); static auto PSWALLOW = CConfigValue("misc:enable_swallow"); - if (!*PSWALLOW || (*PSWALLOWREGEX).empty()) + if (!*PSWALLOW || std::string{*PSWALLOWREGEX} == STRVAL_EMPTY || (*PSWALLOWREGEX).empty()) return nullptr; // check parent From c7315617eb6186912d03232e1968f32b88f153f2 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Mon, 28 Oct 2024 19:02:52 +0100 Subject: [PATCH 0782/2393] internal: few more marginal optimisations from profiling (#8271) * deco: reduce local temporars and function calls profiling shows this is a high used function, reduce the amount of function calls and local temporar copies and also check if we even need to add extents at all in the loop. * popup: optimize bfhelper in popups pass nodes as const reference and reserve the size of the children node vector help reduce the reallocations. * procotol: make compositor bfhelper use const ref use const ref for nodes and reserve second nodes vector size to reduce amount of reallocation needed. --- src/desktop/Popup.cpp | 3 +- src/desktop/Popup.hpp | 2 +- src/protocols/core/Compositor.cpp | 3 +- src/protocols/core/Compositor.hpp | 2 +- .../decorations/DecorationPositioner.cpp | 39 +++++++++++-------- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 9e254fa6..58995f00 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -288,12 +288,13 @@ bool CPopup::visible() { return false; } -void CPopup::bfHelper(std::vector nodes, std::function fn, void* data) { +void CPopup::bfHelper(std::vector const& nodes, std::function fn, void* data) { for (auto const& n : nodes) { fn(n, data); } std::vector nodes2; + nodes2.reserve(nodes.size() * 2); for (auto const& n : nodes) { for (auto const& c : n->m_vChildren) { diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 04996612..f34b8a2c 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -81,5 +81,5 @@ class CPopup { Vector2D localToGlobal(const Vector2D& rel); Vector2D t1ParentCoords(); - static void bfHelper(std::vector nodes, std::function fn, void* data); + static void bfHelper(std::vector const& nodes, std::function fn, void* data); }; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 9a2e00a9..d78d3d8b 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -252,9 +252,10 @@ void CWLSurfaceResource::resetRole() { role = makeShared(); } -void CWLSurfaceResource::bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data) { +void CWLSurfaceResource::bfHelper(std::vector> const& nodes, std::function, const Vector2D&, void*)> fn, void* data) { std::vector> nodes2; + nodes2.reserve(nodes.size() * 2); // first, gather all nodes below for (auto const& n : nodes) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index fbffd966..e5bdf082 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -147,7 +147,7 @@ class CWLSurfaceResource { void dropPendingBuffer(); void dropCurrentBuffer(); void commitPendingState(); - void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); + void bfHelper(std::vector> const& nodes, std::function, const Vector2D&, void*)> fn, void* data); void updateCursorShm(); friend class CWLPointerResource; diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 3eb45546..995283c6 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -294,13 +294,11 @@ SBoxExtents CDecorationPositioner::getWindowDecorationReserved(PHLWINDOW pWindow } SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, bool inputOnly) { - CBox accum = pWindow->getWindowMainSurfaceBox(); + CBox const mainSurfaceBox = pWindow->getWindowMainSurfaceBox(); + CBox accum = mainSurfaceBox; for (auto const& data : m_vWindowPositioningDatas) { - if (!data->pDecoration) - continue; - - if (!(data->pDecoration->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT) && inputOnly) + if (!data->pDecoration || (inputOnly && !(data->pDecoration->getDecorationFlags() & DECORATION_ALLOWS_MOUSE_INPUT))) continue; auto const window = data->pWindow.lock(); @@ -308,31 +306,40 @@ SBoxExtents CDecorationPositioner::getWindowDecorationExtents(PHLWINDOW pWindow, continue; CBox decoBox; - if (data->positioningInfo.policy == DECORATION_POSITION_ABSOLUTE) { - decoBox = data->pWindow->getWindowMainSurfaceBox(); + decoBox = mainSurfaceBox; decoBox.addExtents(data->positioningInfo.desiredExtents); } else { - decoBox = data->lastReply.assignedGeometry; - const auto EDGEPOINT = getEdgeDefinedPoint(data->positioningInfo.edges, pWindow); - decoBox.translate(EDGEPOINT); + decoBox = data->lastReply.assignedGeometry; + decoBox.translate(getEdgeDefinedPoint(data->positioningInfo.edges, pWindow)); } + // Check bounds only if decoBox extends beyond accum SBoxExtents extentsToAdd; + bool needUpdate = false; - if (decoBox.x < accum.x) + if (decoBox.x < accum.x) { extentsToAdd.topLeft.x = accum.x - decoBox.x; - if (decoBox.y < accum.y) + needUpdate = true; + } + if (decoBox.y < accum.y) { extentsToAdd.topLeft.y = accum.y - decoBox.y; - if (decoBox.x + decoBox.w > accum.x + accum.w) + needUpdate = true; + } + if (decoBox.x + decoBox.w > accum.x + accum.w) { extentsToAdd.bottomRight.x = (decoBox.x + decoBox.w) - (accum.x + accum.w); - if (decoBox.y + decoBox.h > accum.y + accum.h) + needUpdate = true; + } + if (decoBox.y + decoBox.h > accum.y + accum.h) { extentsToAdd.bottomRight.y = (decoBox.y + decoBox.h) - (accum.y + accum.h); + needUpdate = true; + } - accum.addExtents(extentsToAdd); + if (needUpdate) + accum.addExtents(extentsToAdd); } - return accum.extentsFrom(pWindow->getWindowMainSurfaceBox()); + return accum.extentsFrom(mainSurfaceBox); } CBox CDecorationPositioner::getBoxWithIncludedDecos(PHLWINDOW pWindow) { From 7188ee4f992966c5793efebd6dc70ab377820066 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:18:58 +0000 Subject: [PATCH 0783/2393] hyprctl: move setprop into dispatchers (#8275) * move setprop into dispatchers modified: src/debug/HyprCtl.cpp modified: src/managers/KeybindManager.cpp modified: src/managers/KeybindManager.hpp * add deprecated modified: src/debug/HyprCtl.cpp --- src/debug/HyprCtl.cpp | 97 +-------------------------------- src/managers/KeybindManager.cpp | 95 ++++++++++++++++++++++++++++++++ src/managers/KeybindManager.hpp | 1 + 3 files changed, 98 insertions(+), 95 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index bf3ecfc8..93e0f620 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1262,101 +1262,8 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) { } std::string dispatchSetProp(eHyprCtlOutputFormat format, std::string request) { - CVarList vars(request, 0, ' '); - - if (vars.size() < 4) - return "not enough args"; - - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); - - if (!PWINDOW) - return "window not found"; - - const auto PROP = vars[2]; - const auto VAL = vars[3]; - - bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault(); - - try { - if (PROP == "animationstyle") { - PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP); - } else if (PROP == "maxsize") { - PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP); - PWINDOW->m_vRealSize = Vector2D(std::min((double)PWINDOW->m_sWindowData.maxSize.value().x, PWINDOW->m_vRealSize.goal().x), - std::min((double)PWINDOW->m_sWindowData.maxSize.value().y, PWINDOW->m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - PWINDOW->setHidden(false); - } else if (PROP == "minsize") { - PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL + " " + vars[4]), PRIORITY_SET_PROP); - PWINDOW->m_vRealSize = Vector2D(std::max((double)PWINDOW->m_sWindowData.minSize.value().x, PWINDOW->m_vRealSize.goal().x), - std::max((double)PWINDOW->m_sWindowData.minSize.value().y, PWINDOW->m_vRealSize.goal().y)); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - PWINDOW->setHidden(false); - } else if (PROP == "alpha") { - PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); - } else if (PROP == "alphainactive") { - PWINDOW->m_sWindowData.alphaInactive = - CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); - } else if (PROP == "alphafullscreen") { - PWINDOW->m_sWindowData.alphaFullscreen = - CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); - } else if (PROP == "alphaoverride") { - PWINDOW->m_sWindowData.alpha = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); - } else if (PROP == "alphainactiveoverride") { - PWINDOW->m_sWindowData.alphaInactive = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); - } else if (PROP == "alphafullscreenoverride") { - PWINDOW->m_sWindowData.alphaFullscreen = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); - } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { - CGradientValueData colorData = {}; - if (vars.size() > 4) { - for (int i = 3; i < static_cast(vars.size()); ++i) { - const auto TOKEN = vars[i]; - if (TOKEN.ends_with("deg")) - colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); - else - colorData.m_vColors.push_back(configStringToInt(TOKEN)); - } - } else if (VAL != "-1") - colorData.m_vColors.push_back(configStringToInt(VAL)); - - if (PROP == "activebordercolor") - PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); - else - PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); - } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) { - auto pWindowDataElement = search->second(PWINDOW); - if (VAL == "toggle") - *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP); - else if (VAL == "unset") - pWindowDataElement->unset(PRIORITY_SET_PROP); - else - *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP); - } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) { - if (VAL == "unset") - search->second(PWINDOW)->unset(PRIORITY_SET_PROP); - else - *(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP); - } else { - return "prop not found"; - } - } catch (std::exception& e) { return "error in parsing prop value: " + std::string(e.what()); } - - g_pCompositor->updateAllWindowsAnimatedDecorationValues(); - - if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) { - g_pCompositor->focusWindow(nullptr); - g_pCompositor->focusWindow(PWINDOW); - g_pCompositor->focusWindow(PLASTWINDOW); - } - - for (auto const& m : g_pCompositor->m_vMonitors) - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); - - return "ok"; + auto result = g_pKeybindManager->m_mDispatchers["setprop"](request.substr(request.find_first_of(' ') + 1, -1)); + return "DEPRECATED: use hyprctl dispatch setprop instead" + (result.success ? "" : "\n" + result.error); } std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index b54b71ed..c2779c58 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -126,6 +126,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; m_mDispatchers["event"] = event; m_mDispatchers["global"] = global; + m_mDispatchers["setprop"] = setProp; m_tScrollTimer.reset(); @@ -2891,3 +2892,97 @@ SDispatchResult CKeybindManager::event(std::string args) { g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); return {}; } + +SDispatchResult CKeybindManager::setProp(std::string args) { + CVarList vars(args, 3, ' '); + + if (vars.size() < 3) + return {.success = false, .error = "Not enough args"}; + + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[0]); + + if (!PWINDOW) + return {.success = false, .error = "Window not found"}; + + const auto PROP = vars[1]; + const auto VAL = vars[2]; + + bool noFocus = PWINDOW->m_sWindowData.noFocus.valueOrDefault(); + + try { + if (PROP == "animationstyle") { + PWINDOW->m_sWindowData.animationStyle = CWindowOverridableVar(VAL, PRIORITY_SET_PROP); + } else if (PROP == "maxsize") { + PWINDOW->m_sWindowData.maxSize = CWindowOverridableVar(configStringToVector2D(VAL), PRIORITY_SET_PROP); + PWINDOW->clampWindowSize(std::nullopt, PWINDOW->m_sWindowData.maxSize.value()); + PWINDOW->setHidden(false); + } else if (PROP == "minsize") { + PWINDOW->m_sWindowData.minSize = CWindowOverridableVar(configStringToVector2D(VAL), PRIORITY_SET_PROP); + PWINDOW->clampWindowSize(PWINDOW->m_sWindowData.minSize.value(), std::nullopt); + PWINDOW->setHidden(false); + } else if (PROP == "alpha") { + PWINDOW->m_sWindowData.alpha = CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alpha.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); + } else if (PROP == "alphainactive") { + PWINDOW->m_sWindowData.alphaInactive = + CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); + } else if (PROP == "alphafullscreen") { + PWINDOW->m_sWindowData.alphaFullscreen = + CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); + } else if (PROP == "alphaoverride") { + PWINDOW->m_sWindowData.alpha = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + } else if (PROP == "alphainactiveoverride") { + PWINDOW->m_sWindowData.alphaInactive = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + } else if (PROP == "alphafullscreenoverride") { + PWINDOW->m_sWindowData.alphaFullscreen = + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { + CGradientValueData colorData = {}; + if (vars.size() > 4) { + for (int i = 3; i < static_cast(vars.size()); ++i) { + const auto TOKEN = vars[i]; + if (TOKEN.ends_with("deg")) + colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); + else + colorData.m_vColors.push_back(configStringToInt(TOKEN)); + } + } else if (VAL != "-1") + colorData.m_vColors.push_back(configStringToInt(VAL)); + + if (PROP == "activebordercolor") + PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); + else + PWINDOW->m_sWindowData.inactiveBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); + } else if (auto search = g_pConfigManager->mbWindowProperties.find(PROP); search != g_pConfigManager->mbWindowProperties.end()) { + auto pWindowDataElement = search->second(PWINDOW); + if (VAL == "toggle") + *pWindowDataElement = CWindowOverridableVar(!pWindowDataElement->valueOrDefault(), PRIORITY_SET_PROP); + else if (VAL == "unset") + pWindowDataElement->unset(PRIORITY_SET_PROP); + else + *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP); + } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) { + if (VAL == "unset") + search->second(PWINDOW)->unset(PRIORITY_SET_PROP); + else + *(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP); + } else { + return {.success = false, .error = "Prop not found"}; + } + } catch (std::exception& e) { return {.success = false, .error = std::format("Error parsing prop value: {}", std::string(e.what()))}; } + + g_pCompositor->updateAllWindowsAnimatedDecorationValues(); + + if (!(PWINDOW->m_sWindowData.noFocus.valueOrDefault() == noFocus)) { + g_pCompositor->focusWindow(nullptr); + g_pCompositor->focusWindow(PWINDOW); + g_pCompositor->focusWindow(PLASTWINDOW); + } + + for (auto const& m : g_pCompositor->m_vMonitors) + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); + + return {}; +} diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 8981dcaf..24a09836 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -217,6 +217,7 @@ class CKeybindManager { static SDispatchResult denyWindowFromGroup(std::string); static SDispatchResult global(std::string); static SDispatchResult event(std::string); + static SDispatchResult setProp(std::string); friend class CCompositor; friend class CInputManager; From d679d200299ed4670f0d0f138c793d5f507b7cec Mon Sep 17 00:00:00 2001 From: staticssleever668 Date: Mon, 28 Oct 2024 22:25:27 +0300 Subject: [PATCH 0784/2393] seat: avoid sending pointless 'keymap' and 'repeat_info' events (#8276) #### Describe your PR, what does it fix/add? Fix lag spikes when pressing more than 6 keys at the same time. #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.) Debugging process:
This is triggered by typing some applications, like CopyQ or XWayland. Typing in Firefox doesn't lead to lag, however it itself does lag handling these events. Profiling CopyQ shows that paths leading to `QtWaylandClient::QWaylandInputDevice::Keyboard::keyboard` take over 80% of processing time of an otherwise idle program. Looking at output of 'wev' even when it's not focused shows same events received over and over again. ``` [14: wl_keyboard] repeat_info: rate: 25 keys/sec; delay: 300 ms [14: wl_keyboard] keymap: format: 1 (xkb v1), size: 64754 ``` Looking at what passes through CInputManager::onKeyboardKey() -> CSeatManager::setKeyboard() shows Hyprland 'switching' between endpoints of the same keyboard, one of them being named like the other but with '-1' suffix.
Tested changing layouts in Fcitx5 and with following config. ``` input:kb_layout = us,cz input:kb_variant = ,qwerty input:kb_options = grp:alt_shift_toggle ``` Also tested changing 'input:repeat_delay' while running. Curiously, now these events appear in the output of 'wev' only once. Changing layouts still seems to work fine though. #### Is it ready for merging, or does it need work? Ready for merging. --- src/protocols/core/Seat.cpp | 24 ++++++++++++++++++------ src/protocols/core/Seat.hpp | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 6ae0ddc4..d95e0e12 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -317,12 +317,13 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; - int fd; - uint32_t size; + std::string_view keymap; + int fd; + uint32_t size; if (keyboard) { - fd = keyboard->xkbKeymapFD; - size = keyboard->xkbKeymapString.length() + 1; + keymap = keyboard->xkbKeymapString; + fd = keyboard->xkbKeymapFD; + size = keyboard->xkbKeymapString.length() + 1; } else { fd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (fd < 0) { @@ -332,6 +333,15 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { size = 0; } + if (keymap == lastKeymap) { + if (!keyboard) + close(fd); + return; + } + lastKeymap = keymap; + + const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; + resource->sendKeymap(format, fd, size); if (!keyboard) @@ -396,8 +406,10 @@ void CWLKeyboardResource::sendMods(uint32_t depressed, uint32_t latched, uint32_ } void CWLKeyboardResource::repeatInfo(uint32_t rate, uint32_t delayMs) { - if (!owner || resource->version() < 4) + if (!owner || resource->version() < 4 || (rate == lastRate && delayMs == lastDelayMs)) return; + lastRate = rate; + lastDelayMs = delayMs; resource->sendRepeatInfo(rate, delayMs); } diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 755a9c2f..1b43dd04 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -119,6 +119,10 @@ class CWLKeyboardResource { struct { CHyprSignalListener destroySurface; } listeners; + + std::string lastKeymap = ""; + uint32_t lastRate = 0; + uint32_t lastDelayMs = 0; }; class CWLSeatResource { From 5f721dce36651232ae245d872c17dfa3aae5cc6c Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 30 Oct 2024 10:00:58 +0000 Subject: [PATCH 0785/2393] group: fix moveWindowIntoGroup (#8297) --- src/layout/IHyprLayout.cpp | 19 ++++++++----------- src/managers/KeybindManager.cpp | 3 +-- .../decorations/CHyprGroupBarDecoration.cpp | 6 +++--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index e3606532..f2616668 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -341,7 +341,9 @@ void IHyprLayout::onEndDragWindow() { const bool FLOATEDINTOTILED = !pWindow->m_bIsFloating && !DRAGGINGWINDOW->m_bDraggingTiled; static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); + if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !FLOATEDINTOTILED) { + if (DRAGGINGWINDOW->m_bDraggingTiled) { changeWindowFloatingMode(DRAGGINGWINDOW); DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; @@ -349,17 +351,12 @@ void IHyprLayout::onEndDragWindow() { } if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) { - std::vector members; - PHLWINDOW curr = DRAGGINGWINDOW->getGroupHead(); - do { - members.push_back(curr); - curr = curr->m_sGroupData.pNextWindow.lock(); - } while (curr != members[0]); - - for (auto it = members.begin(); it != members.end(); ++it) { - (*it)->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members - if (pWindow->m_bIsFloating) - (*it)->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members + PHLWINDOW next = DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock(); + while (next != DRAGGINGWINDOW) { + next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members + next->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members + next->m_vRealPosition = pWindow->m_vRealPosition.goal(); // match the position of group members + next = next->m_sGroupData.pNextWindow.lock(); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c2779c58..5be6a1d9 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2665,9 +2665,8 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn } static auto USECURRPOS = CConfigValue("group:insert_after_current"); - pWindowInDirection = *USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail(); + (*USECURRPOS ? pWindowInDirection : pWindowInDirection->getGroupTail())->insertWindowToGroup(pWindow); - pWindowInDirection->insertWindowToGroup(pWindow); pWindowInDirection->setGroupCurrent(pWindow); pWindow->updateWindowDecos(); g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index e342e244..c9f812d7 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -439,9 +439,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND // restores the group for (auto it = members.begin(); it != members.end(); ++it) { - (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members - if (pWindowInsertAfter->m_bIsFloating) - (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members + (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members + (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members + (*it)->m_vRealPosition = pWindowInsertAfter->m_vRealPosition.goal(); // match the position of group members if (std::next(it) != members.end()) (*it)->m_sGroupData.pNextWindow = *std::next(it); else From 12c1bb936dd463c4188def1c73c2bb786433a6dc Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:58:36 +0000 Subject: [PATCH 0786/2393] internal: check size limit in layouts (#8298) modified: src/desktop/Window.cpp modified: src/desktop/Window.hpp modified: src/events/Windows.cpp modified: src/helpers/MiscFunctions.cpp modified: src/helpers/MiscFunctions.hpp modified: src/layout/DwindleLayout.cpp modified: src/layout/IHyprLayout.cpp modified: src/layout/MasterLayout.cpp modified: src/macros.hpp --- src/desktop/Window.cpp | 2 +- src/desktop/Window.hpp | 7 +++++++ src/events/Windows.cpp | 32 +++++++++++--------------------- src/helpers/MiscFunctions.cpp | 7 +++++++ src/helpers/MiscFunctions.hpp | 1 + src/layout/DwindleLayout.cpp | 4 +++- src/layout/IHyprLayout.cpp | 19 +++++++++---------- src/layout/MasterLayout.cpp | 4 +++- src/macros.hpp | 2 ++ 9 files changed, 44 insertions(+), 34 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 60f3b79d..20fed565 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1255,7 +1255,7 @@ int CWindow::surfacesCount() { void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { const Vector2D REALSIZE = m_vRealSize.goal(); - const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{0.f, 0.f}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); + const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); const Vector2D DELTA = REALSIZE - NEWSIZE; m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 825e8ca2..b8dd3cf7 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -144,6 +144,13 @@ class CWindowOverridableVar { unset(priority); } + operator std::optional() { + if (hasValue()) + return value(); + else + return std::nullopt; + } + private: std::map values; T defaultValue; // used for toggling, so required for bool diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 30d982fb..f946ce03 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -334,13 +334,6 @@ void Events::listener_mapWindow(void* owner, void* data) { try { auto stringToFloatClamp = [](const std::string& VALUE, const float CURR, const float REL) { - auto stringToPercentage = [](const std::string& VALUE, const float REL) { - if (VALUE.ends_with('%')) - return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100; - else - return std::stof(VALUE); - }; - if (VALUE.starts_with('<')) return std::min(CURR, stringToPercentage(VALUE.substr(1, VALUE.length() - 1), REL)); else if (VALUE.starts_with('>')) @@ -355,11 +348,11 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); - const float SIZEX = - SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); + const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : + stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); - const float SIZEY = - SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); + const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : + stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size, applying to {}", PWINDOW); @@ -472,18 +465,15 @@ void Events::listener_mapWindow(void* owner, void* data) { for (auto const& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("size")) { try { - const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); - const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); - const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); + const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); + const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); + const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); - const auto SIZEX = SIZEXSTR == "max" ? - std::clamp(MAXSIZE.x, 20.0, PMONITOR->vecSize.x) : - (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.x); - const auto SIZEY = SIZEYSTR == "max" ? - std::clamp(MAXSIZE.y, 20.0, PMONITOR->vecSize.y) : - (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * PMONITOR->vecSize.y); + const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x); + + const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : stringToPercentage(SIZEYSTR, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size (tiled), applying to {}", PWINDOW); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 29861af7..878f5ca1 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -863,3 +863,10 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { *ro_fd_ptr = ro_fd; return true; } + +float stringToPercentage(const std::string& VALUE, const float REL) { + if (VALUE.ends_with('%')) + return (std::stof(VALUE.substr(0, VALUE.length() - 1)) * REL) / 100.f; + else + return std::stof(VALUE); +}; diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index f696fc5d..34b23746 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -40,6 +40,7 @@ void throwError(const std::string& err); bool envEnabled(const std::string& env); int allocateSHMFile(size_t len); bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +float stringToPercentage(const std::string& VALUE, const float REL); template [[deprecated("use std::format instead")]] std::string getFormat(std::format_string fmt, Args&&... args) { diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 059dda99..32f64e4e 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -568,7 +568,9 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0)); + PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize.goal() + pixResize) + .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; } diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f2616668..73e7a125 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -881,18 +881,17 @@ Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // ge for (auto const& r : g_pConfigManager->getMatchingRules(pWindow, true, true)) { if (r.szRule.starts_with("size")) { try { - const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); - const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); - const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); + const auto VALUE = r.szRule.substr(r.szRule.find(' ') + 1); + const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); + const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); + const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); - const auto SIZEX = SIZEXSTR == "max" ? - std::clamp(MAXSIZE.x, 20.0, g_pCompositor->m_pLastMonitor->vecSize.x) : - (!SIZEXSTR.contains('%') ? std::stoi(SIZEXSTR) : std::stof(SIZEXSTR.substr(0, SIZEXSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.x); - const auto SIZEY = SIZEYSTR == "max" ? - std::clamp(MAXSIZE.y, 20.0, g_pCompositor->m_pLastMonitor->vecSize.y) : - (!SIZEYSTR.contains('%') ? std::stoi(SIZEYSTR) : std::stof(SIZEYSTR.substr(0, SIZEYSTR.length() - 1)) * 0.01 * g_pCompositor->m_pLastMonitor->vecSize.y); + const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) : + stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x); + + const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.y) : + stringToPercentage(SIZEYSTR, g_pCompositor->m_pLastMonitor->vecSize.y); sizeOverride = {SIZEX, SIZEY}; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index a2321a41..afe79ecf 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -706,7 +706,9 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = Vector2D(std::max((PWINDOW->m_vRealSize.goal() + pixResize).x, 20.0), std::max((PWINDOW->m_vRealSize.goal() + pixResize).y, 20.0)); + PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize.goal() + pixResize) + .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; } diff --git a/src/macros.hpp b/src/macros.hpp index 44014085..8915e12d 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -29,6 +29,8 @@ #define MONITOR_INVALID -1L +#define MIN_WINDOW_SIZE 20.0 + #define LISTENER(name) \ void listener_##name(wl_listener*, void*); \ inline wl_listener listen_##name = {.notify = listener_##name} From ee91df62f0be6ac65eae0eb3ed74383a3671aef7 Mon Sep 17 00:00:00 2001 From: nickodei <46863421+nickodei@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:12:16 +0100 Subject: [PATCH 0787/2393] input: simulate mouse movement after scroll to refocus window (#8279) --- src/managers/input/InputManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 028286bf..91c12ece 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -831,6 +831,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { int32_t deltaDiscrete = std::abs(discrete) != 0 && std::abs(discrete) < 1 ? std::copysign(1, discrete) : std::round(discrete); g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, delta, deltaDiscrete, value120, e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); + simulateMouseMovement(); } Vector2D CInputManager::getMouseCoordsInternal() { From a0b2169ed600b71627188dcd208b26911da8d583 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 30 Oct 2024 22:14:43 +0000 Subject: [PATCH 0788/2393] input: revert #8279 --- src/managers/input/InputManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 91c12ece..028286bf 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -831,7 +831,6 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { int32_t deltaDiscrete = std::abs(discrete) != 0 && std::abs(discrete) < 1 ? std::copysign(1, discrete) : std::round(discrete); g_pSeatManager->sendPointerAxis(e.timeMs, e.axis, delta, deltaDiscrete, value120, e.source, WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL); - simulateMouseMovement(); } Vector2D CInputManager::getMouseCoordsInternal() { From 7c7a84ff60f8c1e00c6a0de3f7656f0bbd933d56 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 31 Oct 2024 00:20:32 +0100 Subject: [PATCH 0789/2393] internal: more profiling less calls and local copies (#8300) * compositor: reduce amount of window box copies mousemoveunified can call this very frequently, the cbox copying actually shows up as an impact in such cases, move it down in the scope and only do it when necessery. * core: constify and reference frequent calls profiling shows these as frequent called functions try to reduce the amount of copies with references and const the variables. * pointermgr: remove not used local copy, const ref remove unneded local copies and const ref cursorsize. * inputmgr: reduce amount of calls to vectortowindow the amount of calls to g_pCompositor->vectorToWindowUnified fast ramps up in cpu usage with enough windows existing and moving the mouse, move the PWINDOWIDEAL up and reuse it if its already the same. * protocol: compositor remove unused local copy remove unused local copy of accumulateCurrentBufferDamage and const previousBuffer. * renderer: reduce scope of variables and refactor move a few variables down in their scopes to reduce the amount of calls and copies when not needed, also add one more for loop in renderWorkspaceWindows and store the windows in a vector with weakpointers that should be rendered, this adds a loop but reduces the amount of repeated calls to shouldRenderWindow and also makes the rest of the loops go over way smaller vector when many windows exist. --- src/Compositor.cpp | 29 ++++++---- src/managers/PointerManager.cpp | 19 +++---- src/managers/eventLoop/EventLoopManager.cpp | 2 +- src/managers/input/InputManager.cpp | 14 +++-- src/protocols/core/Compositor.cpp | 6 +- src/render/Renderer.cpp | 55 ++++++++++--------- .../decorations/CHyprBorderDecoration.cpp | 2 +- .../decorations/CHyprBorderDecoration.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 +- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.hpp | 2 +- .../decorations/IHyprWindowDecoration.hpp | 2 +- 13 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a2fe9935..65891633 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -811,10 +811,10 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { for (auto const& w : m_vWindows | std::views::reverse) { - const auto BB = w->getWindowBoxUnified(properties); - CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { + const auto BB = w->getWindowBoxUnified(properties); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (box.containsPoint(g_pPointerManager->position())) return w; @@ -833,22 +833,25 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular continue; - const auto BB = w->getWindowBoxUnified(properties); const auto PWINDOWMONITOR = w->m_pMonitor.lock(); // to avoid focusing windows behind special workspaces from other monitors - if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace && - BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y && - BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) - continue; + if (!*PSPECIALFALLTHRU && PWINDOWMONITOR && PWINDOWMONITOR->activeSpecialWorkspace && w->m_pWorkspace != PWINDOWMONITOR->activeSpecialWorkspace) { + const auto BB = w->getWindowBoxUnified(properties); + if (BB.x >= PWINDOWMONITOR->vecPosition.x && BB.y >= PWINDOWMONITOR->vecPosition.y && + BB.x + BB.width <= PWINDOWMONITOR->vecPosition.x + PWINDOWMONITOR->vecSize.x && + BB.y + BB.height <= PWINDOWMONITOR->vecPosition.y + PWINDOWMONITOR->vecSize.y) + continue; + } - CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect()) continue; + const auto BB = w->getWindowBoxUnified(properties); + CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); if (box.containsPoint(g_pPointerManager->position())) { if (w->m_bIsX11 && w->isX11OverrideRedirect() && !w->m_pXWaylandSurface->wantsFocus()) { @@ -906,10 +909,12 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special != w->onSpecialWorkspace()) continue; - CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; - if (!w->m_bIsFloating && w->m_bIsMapped && box.containsPoint(pos) && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && - !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) - return w; + if (!w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && + w != pIgnoreWindow) { + CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; + if (box.containsPoint(pos)) + return w; + } } return nullptr; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index d2114e79..b309ba82 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -52,7 +52,7 @@ void CPointerManager::unlockSoftwareAll() { } void CPointerManager::lockSoftwareForMonitor(PHLMONITOR mon) { - auto state = stateFor(mon); + auto const state = stateFor(mon); state->softwareLocks++; if (state->softwareLocks == 1) @@ -60,7 +60,7 @@ void CPointerManager::lockSoftwareForMonitor(PHLMONITOR mon) { } void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) { - auto state = stateFor(mon); + auto const state = stateFor(mon); state->softwareLocks--; if (state->softwareLocks < 0) state->softwareLocks = 0; @@ -70,7 +70,7 @@ void CPointerManager::unlockSoftwareForMonitor(PHLMONITOR mon) { } bool CPointerManager::softwareLockedFor(PHLMONITOR mon) { - auto state = stateFor(mon); + auto const state = stateFor(mon); return state->softwareLocks > 0 || state->hardwareFailed; } @@ -250,14 +250,13 @@ void CPointerManager::updateCursorBackend() { const auto CURSORBOX = getCursorBoxGlobal(); for (auto const& m : g_pCompositor->m_vMonitors) { - auto state = stateFor(m); - if (!m->m_bEnabled || !m->dpmsStatus) { Debug::log(TRACE, "Not updating hw cursors: disabled / dpms off display"); continue; } auto CROSSES = !m->logicalBox().intersection(CURSORBOX).empty(); + auto state = stateFor(m); if (!CROSSES) { if (state->cursorFrontBuffer) @@ -373,10 +372,8 @@ bool CPointerManager::setHWCursorBuffer(SP state, SP CPointerManager::renderHWCursorBuffer(SP state, SP texture) { - auto output = state->monitor->output; - - auto maxSize = output->cursorPlaneSize(); - auto cursorSize = currentCursorImage.size; + auto maxSize = state->monitor->output->cursorPlaneSize(); + auto const& cursorSize = currentCursorImage.size; if (maxSize == Vector2D{}) return nullptr; @@ -423,8 +420,6 @@ SP CPointerManager::renderHWCursorBuffer(SPmakeEGLCurrent(); g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor; @@ -483,7 +478,7 @@ SP CPointerManager::renderHWCursorBuffer(SPbind(); - g_pHyprOpenGL->beginSimple(state->monitor.lock(), damage, RBO); + g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT16_MAX, INT16_MAX}, RBO); g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 081268c3..755ecbbc 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -98,7 +98,7 @@ void CEventLoopManager::nudgeTimers() { long nextTimerUs = 10 * 1000 * 1000; // 10s for (auto const& t : m_sTimers.timers) { - if (const auto µs = t->leftUs(); µs < nextTimerUs) + if (auto const& µs = t->leftUs(); µs < nextTimerUs) nextTimerUs = µs; } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 028286bf..af725927 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -291,7 +291,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); // then, we check if the workspace doesnt have a fullscreen window - const auto PWORKSPACE = PMONITOR->activeWorkspace; + const auto PWORKSPACE = PMONITOR->activeWorkspace; + const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN) { pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); @@ -301,8 +302,6 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { return; } - const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); - if (PWINDOWIDEAL && ((PWINDOWIDEAL->m_bIsFloating && PWINDOWIDEAL->m_bCreatedOverFullscreen) /* floating over fullscreen */ || (PMONITOR->activeSpecialWorkspace == PWINDOWIDEAL->m_pWorkspace) /* on an open special workspace */)) @@ -322,7 +321,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FSMODE_MAXIMIZED) { if (!foundSurface) { if (PMONITOR->activeSpecialWorkspace) { - pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); + if (pFoundWindow != PWINDOWIDEAL) + pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (pFoundWindow && !pFoundWindow->onSpecialWorkspace()) { pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); @@ -335,7 +335,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (!foundSurface) { - pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); + if (pFoundWindow != PWINDOWIDEAL) + pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); @@ -344,7 +345,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } } else { - pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); + if (pFoundWindow != PWINDOWIDEAL) + pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); } if (pFoundWindow) { diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index d78d3d8b..57f61f87 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -423,10 +423,8 @@ void CWLSurfaceResource::unlockPendingState() { } void CWLSurfaceResource::commitPendingState() { - auto previousBuffer = current.buffer; - CRegion previousBufferDamage = accumulateCurrentBufferDamage(); - - current = pending; + auto const previousBuffer = current.buffer; + current = pending; pending.damage.clear(); pending.bufferDamage.clear(); pending.newBuffer = false; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1c38eb4e..1dedcc7d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -158,9 +158,7 @@ static void renderSurface(SP surface, int x, int y, void* da if (!surface->current.texture) return; - const auto& TEXTURE = surface->current.texture; - const auto RDATA = (SRenderData*)data; - const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; + const auto& TEXTURE = surface->current.texture; // this is bad, probably has been logged elsewhere. Means the texture failed // uploading to the GPU. @@ -175,6 +173,8 @@ static void renderSurface(SP surface, int x, int y, void* da } } + const auto RDATA = (SRenderData*)data; + const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; TRACY_GPU_ZONE("RenderSurface"); double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y; @@ -484,36 +484,43 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo EMIT_HOOK_EVENT("render", RENDER_PRE_WINDOWS); - // Non-floating main + std::vector windows; + windows.reserve(g_pCompositor->m_vWindows.size()); + for (auto const& w : g_pCompositor->m_vWindows) { if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) continue; - if (w->m_bIsFloating) - continue; // floating are in the second pass - if (!shouldRenderWindow(w, pMonitor)) continue; + windows.push_back(w); + } + + // Non-floating main + for (auto& w : windows) { + if (w->m_bIsFloating) + continue; // floating are in the second pass + if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; // render active window after all others of this pass if (w == g_pCompositor->m_pLastWindow) { - lastWindow = w; + lastWindow = w.lock(); continue; } // render the bad boy - renderWindow(w, pMonitor, time, true, RENDER_PASS_MAIN); + renderWindow(w.lock(), pMonitor, time, true, RENDER_PASS_MAIN); } if (lastWindow) renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); // Non-floating popup - for (auto const& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) + for (auto& w : windows) { + if (!w) continue; if (w->m_bIsFloating) @@ -522,24 +529,19 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; - if (!shouldRenderWindow(w, pMonitor)) - continue; - // render the bad boy - renderWindow(w, pMonitor, time, true, RENDER_PASS_POPUP); + renderWindow(w.lock(), pMonitor, time, true, RENDER_PASS_POPUP); + w.reset(); } // floating on top - for (auto const& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || (!w->m_bIsMapped && !w->m_bFadingOut)) + for (auto& w : windows) { + if (!w) continue; if (!w->m_bIsFloating || w->m_bPinned) continue; - if (!shouldRenderWindow(w, pMonitor)) - continue; - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; @@ -547,7 +549,7 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo continue; // special on another are rendered as a part of the base pass // render the bad boy - renderWindow(w, pMonitor, time, true, RENDER_PASS_ALL); + renderWindow(w.lock(), pMonitor, time, true, RENDER_PASS_ALL); } } @@ -1093,8 +1095,8 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPcurrent.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 - Vector2D bufferSize = pSurface->current.bufferSize; - auto bufferSource = pSurface->current.viewport.source; + Vector2D const& bufferSize = pSurface->current.bufferSize; + auto const& bufferSource = pSurface->current.viewport.source; // calculate UV for the basic src_box. Assume dest == size. Scale to dest later uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y); @@ -1904,10 +1906,11 @@ void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { if (m->isMirror()) continue; // don't damage mirrors traditionally - CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; - damageBox.scale(m->scale); - if (!skipFrameSchedule) + if (!skipFrameSchedule) { + CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; + damageBox.scale(m->scale); m->addDamage(&damageBox); + } } static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 68325a9c..d62e67c4 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -46,7 +46,7 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { return box.translate(WORKSPACEOFFSET); } -void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float a) { +void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (doesntWantBorders()) return; diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index 5d248a81..bc9d7836 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -11,7 +11,7 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(PHLMONITOR, float a); + virtual void draw(PHLMONITOR, float const& a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index a4388a67..79d5940b 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -86,7 +86,7 @@ void CHyprDropShadowDecoration::updateWindow(PHLWINDOW pWindow) { m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); } -void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float a) { +void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { const auto PWINDOW = m_pWindow.lock(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index fce9a7c7..8335cde9 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -11,7 +11,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(PHLMONITOR, float a); + virtual void draw(PHLMONITOR, float const& a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index c9f812d7..ec9f876b 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -94,7 +94,7 @@ void CHyprGroupBarDecoration::damageEntire() { g_pHyprRenderer->damageBox(&box); } -void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float a) { +void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index e388fa38..338a8449 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -31,7 +31,7 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply); - virtual void draw(PHLMONITOR, float a); + virtual void draw(PHLMONITOR, float const& a); virtual eDecorationType getDecorationType(); diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 99698a56..d6d57902 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -39,7 +39,7 @@ class IHyprWindowDecoration { virtual void onPositioningReply(const SDecorationPositioningReply& reply) = 0; - virtual void draw(PHLMONITOR, float a) = 0; + virtual void draw(PHLMONITOR, float const& a) = 0; virtual eDecorationType getDecorationType() = 0; From 93b4478e70af6ffb08a4a66a6d0364c3296db296 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Thu, 31 Oct 2024 07:21:08 -0400 Subject: [PATCH 0790/2393] snap: add option `border_overlap` and other improvements (#8289) * snap: add option `border_overlap` and other improvements I really liked the way borders used to overlap when snapping and how only the window's main surface would snap to the monitor, so I would like to bring that behavior back, but in the form of a config option. Other improvements include: - reduced the number of snap functions from 4 down to 2, and only one ever gets called at any given time. - border size should not be added to gap size. It seemed like the right thing to do at the time, but it makes snapping feel way stronger than it actually should. - all const variables have been given the all-caps naming convention. - to avoid excessive casting, border size is declared as a double. - to avoid excessive x + w, y + h calculations. I'm using a struct called Range and working only with start and end values until the very end of the function. - check for both monitor snapping as well as reserved monitor space snapping in a relatively efficient way. * snap: always border-align for corners and reserved monitor space We probably don't want to treat reserved monitor space as if it were just a smaller monitor. Instead, it should be treated more like a borderless window, which means our window's border should never encroach upon it. --- src/config/ConfigDescriptions.hpp | 6 ++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 161 +++++++++++++++--------------- 3 files changed, 89 insertions(+), 79 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 0177f92b..07034e71 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -122,6 +122,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{10, 0, 100}, }, + SConfigOptionDescription{ + .value = "general:snap:border_overlap", + .description = "if true, windows snap such that only one border's worth of space is between them", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * decoration: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 909dfc63..f1ba8d7f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -344,6 +344,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("general:snap:enabled", Hyprlang::INT{0}); m_pConfig->addConfigValue("general:snap:window_gap", Hyprlang::INT{10}); m_pConfig->addConfigValue("general:snap:monitor_gap", Hyprlang::INT{10}); + m_pConfig->addConfigValue("general:snap:border_overlap", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_hyprland_logo", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_splash_rendering", Hyprlang::INT{0}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 73e7a125..980311d6 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -389,91 +389,93 @@ void IHyprLayout::onEndDragWindow() { g_pInputManager->m_bWasDraggingWindow = false; } -static inline bool canSnap(const double sideA, const double sideB, const double gap) { - return std::abs(sideA - sideB) < gap; +static inline bool canSnap(const double SIDEA, const double SIDEB, const double GAP) { + return std::abs(SIDEA - SIDEB) < GAP; } -static void snapMoveLeft(double& pos, double& len, const double p) { - pos = p; +static void snapMove(double& start, double& end, const double P) { + end = P + (end - start); + start = P; } -static void snapMoveRight(double& pos, double& len, const double p) { - pos = p - len; -} - -static void snapResizeLeft(double& pos, double& len, const double p) { - len += pos - p; - pos = p; -} - -static void snapResizeRight(double& pos, double& len, const double p) { - len = p - pos; +static void snapResize(double& start, double& end, const double P) { + start = P; } typedef std::function SnapFn; -static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode mode, const int corner, const Vector2D& beginSize) { - static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); - static auto SNAPMONITORGAP = CConfigValue("general:snap:monitor_gap"); +static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode MODE, const int CORNER, const Vector2D& BEGINSIZE) { + static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); + static auto SNAPMONITORGAP = CConfigValue("general:snap:monitor_gap"); + static auto SNAPBORDEROVERLAP = CConfigValue("general:snap:border_overlap"); - const SnapFn snapRight = (mode == MBIND_MOVE) ? snapMoveRight : snapResizeRight; - const SnapFn snapLeft = (mode == MBIND_MOVE) ? snapMoveLeft : snapResizeLeft; - const SnapFn snapDown = snapRight; - const SnapFn snapUp = snapLeft; - int snaps = 0; + const SnapFn SNAP = (MODE == MBIND_MOVE) ? snapMove : snapResize; + int snaps = 0; + const bool OVERLAP = *SNAPBORDEROVERLAP; const int DRAGGINGBORDERSIZE = DRAGGINGWINDOW->getRealBorderSize(); - CBox sourceBox = CBox{sourcePos, sourceSize}.expand(DRAGGINGBORDERSIZE); + + struct SRange { + double start = 0; + double end = 0; + }; + SRange sourceX = {sourcePos.x, sourcePos.x + sourceSize.x}; + SRange sourceY = {sourcePos.y, sourcePos.y + sourceSize.y}; if (*SNAPWINDOWGAP) { - const auto WSID = DRAGGINGWINDOW->workspaceID(); + const double GAPSIZE = *SNAPWINDOWGAP; + const auto WSID = DRAGGINGWINDOW->workspaceID(); for (auto& other : g_pCompositor->m_vWindows) { if (other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) continue; - const int BORDERSIZE = other->getRealBorderSize(); - const double GAPSIZE = *SNAPWINDOWGAP + BORDERSIZE; + const int OTHERBORDERSIZE = other->getRealBorderSize(); + const double BORDERSIZE = OVERLAP ? std::max(DRAGGINGBORDERSIZE, OTHERBORDERSIZE) : (DRAGGINGBORDERSIZE + OTHERBORDERSIZE); - const CBox SURFBB = other->getWindowMainSurfaceBox().expand(BORDERSIZE); - const Vector2D end = sourceBox.pos() + sourceBox.size(); + const CBox SURF = other->getWindowMainSurfaceBox(); + const SRange SURFBX = {SURF.x - BORDERSIZE, SURF.x + SURF.w + BORDERSIZE}; + const SRange SURFBY = {SURF.y - BORDERSIZE, SURF.y + SURF.h + BORDERSIZE}; - // only snap windows if their ranges intersect in the opposite axis - if (sourceBox.y <= SURFBB.y + SURFBB.h && SURFBB.y <= end.y) { - if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceBox.x, SURFBB.x + SURFBB.w, GAPSIZE)) { - snapLeft(sourceBox.x, sourceBox.w, SURFBB.x + SURFBB.w); + // only snap windows if their ranges overlap in the opposite axis + if (sourceY.start <= SURFBY.end && SURFBY.start <= sourceY.end) { + if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFBX.end, GAPSIZE)) { + SNAP(sourceX.start, sourceX.end, SURFBX.end); snaps |= SNAP_LEFT; - } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, SURFBB.x, GAPSIZE)) { - snapRight(sourceBox.x, sourceBox.w, SURFBB.x); + } else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(sourceX.end, SURFBX.start, GAPSIZE)) { + SNAP(sourceX.end, sourceX.start, SURFBX.start); snaps |= SNAP_RIGHT; } } - if (sourceBox.x <= SURFBB.x + SURFBB.w && SURFBB.x <= end.x) { - if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceBox.y, SURFBB.y + SURFBB.h, GAPSIZE)) { - snapUp(sourceBox.y, sourceBox.h, SURFBB.y + SURFBB.h); + if (sourceX.start <= SURFBX.end && SURFBX.start <= sourceX.end) { + if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFBY.end, GAPSIZE)) { + SNAP(sourceY.start, sourceY.end, SURFBY.end); snaps |= SNAP_UP; - } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, SURFBB.y, GAPSIZE)) { - snapDown(sourceBox.y, sourceBox.h, SURFBB.y); + } else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(sourceY.end, SURFBY.start, GAPSIZE)) { + SNAP(sourceY.end, sourceY.start, SURFBY.start); snaps |= SNAP_DOWN; } } // corner snapping - if (sourceBox.x == SURFBB.x + SURFBB.w || SURFBB.x == sourceBox.x + sourceBox.w) { - if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceBox.y, SURFBB.y, GAPSIZE)) { - snapUp(sourceBox.y, sourceBox.h, SURFBB.y); + const double BORDERDIFF = OTHERBORDERSIZE - DRAGGINGBORDERSIZE; + if (sourceX.start == SURFBX.end || SURFBX.start == sourceX.end) { + const SRange SURFY = {SURF.y - BORDERDIFF, SURF.y + SURF.h + BORDERDIFF}; + if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && canSnap(sourceY.start, SURFY.start, GAPSIZE)) { + SNAP(sourceY.start, sourceY.end, SURFY.start); snaps |= SNAP_UP; - } else if (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(end.y, SURFBB.y + SURFBB.h, GAPSIZE)) { - snapDown(sourceBox.y, sourceBox.h, SURFBB.y + SURFBB.h); + } else if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && canSnap(sourceY.end, SURFY.end, GAPSIZE)) { + SNAP(sourceY.end, sourceY.start, SURFY.end); snaps |= SNAP_DOWN; } } - if (sourceBox.y == SURFBB.y + SURFBB.h || SURFBB.y == sourceBox.y + sourceBox.h) { - if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceBox.x, SURFBB.x, GAPSIZE)) { - snapLeft(sourceBox.x, sourceBox.w, SURFBB.x); + if (sourceY.start == SURFBY.end || SURFBY.start == sourceY.end) { + const SRange SURFX = {SURF.x - BORDERDIFF, SURF.x + SURF.w + BORDERDIFF}; + if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && canSnap(sourceX.start, SURFX.start, GAPSIZE)) { + SNAP(sourceX.start, sourceX.end, SURFX.start); snaps |= SNAP_LEFT; - } else if (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(end.x, SURFBB.x + SURFBB.w, GAPSIZE)) { - snapRight(sourceBox.x, sourceBox.w, SURFBB.x + SURFBB.w); + } else if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && canSnap(sourceX.end, SURFX.end, GAPSIZE)) { + SNAP(sourceX.end, sourceX.start, SURFX.end); snaps |= SNAP_RIGHT; } } @@ -481,49 +483,50 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA } if (*SNAPMONITORGAP) { - const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); - const CBox mon = - CBox{MON->vecPosition.x + MON->vecReservedTopLeft.x, MON->vecPosition.y + MON->vecReservedTopLeft.y, - MON->vecSize.x - MON->vecReservedTopLeft.x - MON->vecReservedBottomRight.x, MON->vecSize.y - MON->vecReservedBottomRight.y - MON->vecReservedTopLeft.y}; - const double gap = *SNAPMONITORGAP; + const double GAPSIZE = *SNAPMONITORGAP; + const double BORDERSIZE = OVERLAP ? 0 : DRAGGINGBORDERSIZE; + const double BORDERDIFF = DRAGGINGBORDERSIZE - BORDERSIZE; + const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); - if (canSnap(sourceBox.x, mon.x, gap)) { - snapLeft(sourceBox.x, sourceBox.w, mon.x); + SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecSize.x - BORDERSIZE}; + SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecSize.y - BORDERSIZE}; + + if (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE)) { + SNAP(sourceX.start, sourceX.end, monX.start); snaps |= SNAP_LEFT; } - if (canSnap(sourceBox.x + sourceBox.w, mon.x + mon.w, gap)) { - snapRight(sourceBox.x, sourceBox.w, mon.w + mon.x); + if (canSnap(sourceX.end, monX.end, GAPSIZE) || canSnap(sourceX.end, (monX.end -= MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE)) { + SNAP(sourceX.end, sourceX.start, monX.end); snaps |= SNAP_RIGHT; } - if (canSnap(sourceBox.y, mon.y, gap)) { - snapUp(sourceBox.y, sourceBox.h, mon.y); + if (canSnap(sourceY.start, monY.start, GAPSIZE) || canSnap(sourceY.start, (monY.start += MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE)) { + SNAP(sourceY.start, sourceY.end, monY.start); snaps |= SNAP_UP; } - if (canSnap(sourceBox.y + sourceBox.h, mon.y + mon.h, gap)) { - snapDown(sourceBox.y, sourceBox.h, mon.h + mon.y); + if (canSnap(sourceY.end, monY.end, GAPSIZE) || canSnap(sourceY.end, (monY.end -= MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE)) { + SNAP(sourceY.end, sourceY.start, monY.end); snaps |= SNAP_DOWN; } } - if (mode == MBIND_RESIZE_FORCE_RATIO) { - const double RATIO = beginSize.y / beginSize.x; - - if ((corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (corner & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) { - const double sizeY = sourceBox.w * RATIO; - if (corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT)) - sourceBox.y += sourceBox.h - sizeY; - sourceBox.h = sizeY; - } else if ((corner & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (corner & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) { - const double sizeX = sourceBox.h / RATIO; - if (corner & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT)) - sourceBox.x += sourceBox.w - sizeX; - sourceBox.w = sizeX; + if (MODE == MBIND_RESIZE_FORCE_RATIO) { + if ((CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && snaps & SNAP_LEFT) || (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && snaps & SNAP_RIGHT)) { + const double SIZEY = (sourceX.end - sourceX.start) * (BEGINSIZE.y / BEGINSIZE.x); + if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT)) + sourceY.start = sourceY.end - SIZEY; + else + sourceY.end = sourceY.start + SIZEY; + } else if ((CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && snaps & SNAP_UP) || (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && snaps & SNAP_DOWN)) { + const double SIZEX = (sourceY.end - sourceY.start) * (BEGINSIZE.x / BEGINSIZE.y); + if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT)) + sourceX.start = sourceX.end - SIZEX; + else + sourceX.end = sourceX.start + SIZEX; } } - sourceBox.expand(-DRAGGINGBORDERSIZE).round(); - sourcePos = sourceBox.pos(); - sourceSize = sourceBox.size(); + sourcePos = {sourceX.start, sourceY.start}; + sourceSize = {sourceX.end - sourceX.start, sourceY.end - sourceY.start}; } void IHyprLayout::onMouseMove(const Vector2D& mousePos) { From c4d214c42d743a69f606ff476b7266b3ace7d70e Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 1 Nov 2024 07:30:26 -0500 Subject: [PATCH 0791/2393] monitors: fix vrr breaking monitor disconnect (#8314) --- src/config/ConfigManager.cpp | 8 +++++--- src/helpers/Monitor.cpp | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f1ba8d7f..62c71dc7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1608,9 +1608,6 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { m->vrrActive = true; return; } else if (USEVRR == 2) { - /* fullscreen */ - m->vrrActive = true; - const auto PWORKSPACE = m->activeWorkspace; if (!PWORKSPACE) @@ -1619,6 +1616,9 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN); if (WORKSPACEFULL) { + /* fullscreen */ + m->vrrActive = true; + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(true); @@ -1631,6 +1631,8 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name); } else if (!WORKSPACEFULL) { + m->vrrActive = false; + m->output->state->resetExplicitFences(); m->output->state->setAdaptiveSync(false); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9e71bf5f..bfab2fd3 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -334,6 +334,7 @@ void CMonitor::onDisconnect(bool destroy) { activeWorkspace.reset(); output->state->resetExplicitFences(); + output->state->setAdaptiveSync(false); output->state->setEnabled(false); if (!state.commit()) From 3852418d2446555509738bf1486940042107afe7 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 1 Nov 2024 13:03:06 +0000 Subject: [PATCH 0792/2393] hyprctl: reload windowrules on reloadAll --- src/debug/HyprCtl.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 93e0f620..f5c63f86 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1041,7 +1041,8 @@ std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) { } // decorations will probably need a repaint - if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source") { + if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" || + COMMAND.starts_with("windowrule")) { for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); @@ -1698,6 +1699,14 @@ std::string CHyprCtl::getReply(std::string request) { rd.blurFBDirty = true; } + for (auto const& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || !g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) + continue; + + w->updateDynamicRules(); + g_pCompositor->updateWindowAnimatedDecorationValues(w); + } + for (auto const& m : g_pCompositor->m_vMonitors) { g_pHyprRenderer->damageMonitor(m); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m->ID); From d8b865366af9d5ed30d2ee0a437b9a3ed43c10bd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 1 Nov 2024 15:52:03 +0000 Subject: [PATCH 0793/2393] renderer: Add a missing texture asset and a user check When an asset is missing, instead of a black screen, render an obnoxious, yet standard, missing texture. Additionally, warn the user assets failed to load. Shoutout to Arch for having their assets broken for months. Fix your shit. I am tired of it, and it's negatively impacting users. --- src/Compositor.cpp | 6 ++ src/render/Framebuffer.cpp | 15 +++- src/render/OpenGL.cpp | 155 +++++++++++++++++++++++++------------ src/render/OpenGL.hpp | 14 ++-- src/render/Renderer.cpp | 20 ++--- 5 files changed, 139 insertions(+), 71 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 65891633..62612398 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2738,6 +2738,12 @@ void CCompositor::performUserChecks() { CColor{}, 15000, ICON_WARNING); } } + + if (g_pHyprOpenGL->failedAssetsNo > 0) { + g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!", + g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""), + CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR); + } } void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace) { diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index c48ff6f3..7e086778 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -2,7 +2,7 @@ #include "OpenGL.hpp" CFramebuffer::CFramebuffer() { - m_cTex = makeShared(); + ; } bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { @@ -12,6 +12,9 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { uint32_t glFormat = FormatUtils::drmFormatToGL(drmFormat); uint32_t glType = FormatUtils::glFormatToType(glFormat); + if (!m_cTex) + m_cTex = makeShared(); + if (!m_iFbAllocated) { firstAlloc = true; glGenFramebuffers(1, &m_iFb); @@ -54,7 +57,8 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); + if (g_pHyprOpenGL) + glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); m_vSize = Vector2D(w, h); @@ -85,14 +89,17 @@ void CFramebuffer::bind() { #else glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); #endif - glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); + if (g_pHyprOpenGL) + glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); + else + glViewport(0, 0, m_vSize.x, m_vSize.y); } void CFramebuffer::release() { if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); - m_cTex->destroyTexture(); + m_cTex.reset(); m_iFbAllocated = false; m_vSize = Vector2D(); } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 9e524fa4..20963707 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -13,6 +13,13 @@ #include #include +const std::vector ASSET_PATHS = { +#ifdef DATAROOTDIR + DATAROOTDIR, +#endif + "/usr/share", +}; + inline void loadGLProc(void* pProc, const char* name) { void* proc = (void*)eglGetProcAddress(name); if (proc == NULL) { @@ -2595,11 +2602,32 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const cairo_surface_flush(CAIROSURFACE); } -SP CHyprOpenGLImpl::loadAsset(const std::string& file) { - const auto CAIROSURFACE = cairo_image_surface_create_from_png(file.c_str()); +SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { - if (!CAIROSURFACE) - return nullptr; + std::string fullPath; + for (auto& e : ASSET_PATHS) { + std::string p = std::string{e} + "/hypr/" + filename; + std::error_code ec; + if (std::filesystem::exists(p, ec)) { + fullPath = p; + break; + } else + Debug::log(LOG, "loadAsset: looking at {} unsuccessful: ec {}", filename, ec.message()); + } + + if (fullPath.empty()) { + failedAssetsNo++; + Debug::log(ERR, "loadAsset: looking for {} failed (no provider found)", filename); + return m_pMissingAssetTexture; + } + + const auto CAIROSURFACE = cairo_image_surface_create_from_png(fullPath.c_str()); + + if (!CAIROSURFACE) { + failedAssetsNo++; + Debug::log(ERR, "loadAsset: failed to load {} (corrupt / inaccessible / not png)", fullPath); + return m_pMissingAssetTexture; + } const auto CAIROFORMAT = cairo_image_surface_get_format(CAIROSURFACE); auto tex = makeShared(); @@ -2710,51 +2738,68 @@ SP CHyprOpenGLImpl::renderText(const std::string& text, CColor col, in return tex; } -void CHyprOpenGLImpl::initAssets() { - std::string assetsPath = ""; -#ifndef DATAROOTDIR - assetsPath = "/usr/share/hypr/"; -#else - assetsPath = std::format("{}{}", DATAROOTDIR, "/hypr/"); -#endif +void CHyprOpenGLImpl::initMissingAssetTexture() { + SP tex = makeShared(); + tex->allocate(); - m_pLockDeadTexture = loadAsset(assetsPath + "lockdead.png"); - m_pLockDead2Texture = loadAsset(assetsPath + "lockdead2.png"); + const auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512); + const auto CAIRO = cairo_create(CAIROSURFACE); + + cairo_set_antialias(CAIRO, CAIRO_ANTIALIAS_NONE); + cairo_save(CAIRO); + cairo_set_source_rgba(CAIRO, 0, 0, 0, 1); + cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE); + cairo_paint(CAIRO); + cairo_set_source_rgba(CAIRO, 1, 0, 1, 1); + cairo_rectangle(CAIRO, 256, 0, 256, 256); + cairo_fill(CAIRO); + cairo_rectangle(CAIRO, 0, 256, 256, 256); + cairo_fill(CAIRO); + cairo_restore(CAIRO); + + cairo_surface_flush(CAIROSURFACE); + + tex->m_vSize = {512, 512}; + + // copy the data to an OpenGL texture we have + const GLint glFormat = GL_RGBA; + const GLint glType = GL_UNSIGNED_BYTE; + + const auto DATA = cairo_image_surface_get_data(CAIROSURFACE); + glBindTexture(GL_TEXTURE_2D, tex->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifndef GLES2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, glFormat, tex->m_vSize.x, tex->m_vSize.y, 0, glFormat, glType, DATA); + + cairo_surface_destroy(CAIROSURFACE); + cairo_destroy(CAIRO); + + m_pMissingAssetTexture = tex; +} + +void CHyprOpenGLImpl::initAssets() { + initMissingAssetTexture(); + + static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); + + const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); + + m_pLockDeadTexture = loadAsset("lockdead.png"); + m_pLockDead2Texture = loadAsset("lockdead2.png"); m_pLockTtyTextTexture = renderText(std::format("Running on tty {}", g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? std::to_string(g_pCompositor->m_pAqBackend->session->vt) : "unknown"), CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); -} -void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { - RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); - - Debug::log(LOG, "Creating a texture for BGTex"); - - static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); - static auto PNOSPLASH = CConfigValue("misc:disable_splash_rendering"); - static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); - - const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); - - if (*PRENDERTEX) - return; - - // release the last tex if exists - const auto PFB = &m_mMonitorBGFBs[pMonitor]; - PFB->release(); - - PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); - - if (!m_pBackgroundTexture) { - std::string texPath = ""; -#ifndef DATAROOTDIR - texPath = "/usr/share/hypr/wall"; -#else - texPath = std::format("{}{}", DATAROOTDIR, "/hypr/wall"); -#endif + // create the default background texture + { + std::string texPath = std::format("{}", "wall"); // get the adequate tex if (FORCEWALLPAPER == -1) { @@ -2767,15 +2812,29 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { texPath += ".png"; - // check if wallpapers exist - std::error_code err; - if (!std::filesystem::exists(texPath, err)) { - Debug::log(ERR, "createBGTextureForMonitor: failed, file \"{}\" doesn't exist or access denied, ec: {}", texPath, err.message()); - return; // the texture will be empty, oh well. We'll clear with a solid color anyways. - } - m_pBackgroundTexture = loadAsset(texPath); } +} + +void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { + RASSERT(m_RenderData.pMonitor, "Tried to createBGTex without begin()!"); + + Debug::log(LOG, "Creating a texture for BGTex"); + + static auto PRENDERTEX = CConfigValue("misc:disable_hyprland_logo"); + static auto PNOSPLASH = CConfigValue("misc:disable_splash_rendering"); + + if (*PRENDERTEX) + return; + + // release the last tex if exists + const auto PFB = &m_mMonitorBGFBs[pMonitor]; + PFB->release(); + + PFB->alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + + if (!m_pBackgroundTexture) // ?!?!?! + return; // create a new one with cairo SP tex = makeShared(); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 115dcac7..c594a7cc 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -215,11 +215,12 @@ class CHyprOpenGLImpl { GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; + uint failedAssetsNo = 0; bool m_bReloadScreenShader = true; // at launch it can be set @@ -277,7 +278,7 @@ class CHyprOpenGLImpl { CShader m_sFinalScreenShader; CTimer m_tGlobalTimer; - SP m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; + SP m_pMissingAssetTexture, m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); @@ -290,6 +291,7 @@ class CHyprOpenGLImpl { SP loadAsset(const std::string& file); SP renderText(const std::string& text, CColor col, int pt, bool italic = false); void initAssets(); + void initMissingAssetTexture(); // std::optional> getModsForFormat(EGLint format); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 1dedcc7d..a133899b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1063,22 +1063,16 @@ void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { if (ANY_PRESENT) { // render image2, without instructions. Lock still "alive", unless texture dead - if (g_pHyprOpenGL->m_pLockDead2Texture) - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA); - else - g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA); } else { // render image, with instructions. Lock is gone. - if (g_pHyprOpenGL->m_pLockDeadTexture) { - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA); + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA); - // also render text for the tty number - if (g_pHyprOpenGL->m_pLockTtyTextTexture) { - CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize}; - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F); - } - } else - g_pHyprOpenGL->renderRect(&monbox, CColor(1.0, 0.2, 0.2, ALPHA)); + // also render text for the tty number + if (g_pHyprOpenGL->m_pLockTtyTextTexture) { + CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize}; + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F); + } } if (ALPHA < 1.f) /* animate */ From 3c0605c68e50416819fea471a8fbef05e4a18684 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Fri, 1 Nov 2024 22:21:36 +0500 Subject: [PATCH 0794/2393] hyprland-systemd.desktop improvements (#8318) --- systemd/hyprland-systemd.desktop | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/systemd/hyprland-systemd.desktop b/systemd/hyprland-systemd.desktop index b36a87b2..8c065a81 100644 --- a/systemd/hyprland-systemd.desktop +++ b/systemd/hyprland-systemd.desktop @@ -1,5 +1,7 @@ [Desktop Entry] -Name=Hyprland +Name=Hyprland (systemd session) Comment=An intelligent dynamic tiling Wayland compositor Exec=systemctl --user start --wait hyprland-session Type=Application +DesktopNames=Hyprland (systemd session) +Keywords=tiling;wayland;compositor; From 29e7dc642831801d14480cf7e4bb19f6ffb118e9 Mon Sep 17 00:00:00 2001 From: Pavel Solovev Date: Fri, 1 Nov 2024 13:54:17 +0000 Subject: [PATCH 0795/2393] Systemd fixes Fix installation path, install the service only if the systemd option is enabled --- meson.build | 3 ++- systemd/meson.build | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index d0ba9a5c..76765645 100644 --- a/meson.build +++ b/meson.build @@ -53,7 +53,9 @@ epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs # Handle options if get_option('systemd').enabled() + systemd = dependency('systemd') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') + subdir('systemd') endif if get_option('legacy_renderer').enabled() @@ -89,7 +91,6 @@ subdir('hyprpm/src') subdir('assets') subdir('example') subdir('docs') -subdir('systemd') # Generate hyprland.pc pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') diff --git a/systemd/meson.build b/systemd/meson.build index 497e64f4..2cd5312a 100644 --- a/systemd/meson.build +++ b/systemd/meson.build @@ -7,9 +7,11 @@ install_data( conf_data = configuration_data() conf_data.set('PREFIX', get_option('prefix')) conf_data.set('BINDIR', get_option('bindir')) +user_unit_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir', + pkgconfig_define: ['prefix', get_option('prefix')]) configure_file( configuration: conf_data, input: 'hyprland-session.service.in', output: '@BASENAME@', - install_dir: join_paths(get_option('libdir'), 'systemd/user') ) + install_dir: user_unit_dir ) From 32b18179dd789cde948c97eb3c2ebbdd6af36bf7 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 1 Nov 2024 19:31:20 +0200 Subject: [PATCH 0796/2393] CMake: systemd fixes --- CMakeLists.txt | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec8c331e..877ba461 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,6 @@ set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(BINDIR ${CMAKE_INSTALL_BINDIR}) configure_file(hyprland.pc.in hyprland.pc @ONLY) -configure_file(systemd/hyprland-session.service.in systemd/hyprland-session.service @ONLY) set(CMAKE_MESSAGE_LOG_LEVEL "STATUS") @@ -223,6 +222,16 @@ if(NO_SYSTEMD) else() message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") add_compile_definitions(USES_SYSTEMD) + configure_file(systemd/hyprland-session.service.in + systemd/hyprland-session.service @ONLY) + + # session file -systemd + install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + + # install systemd service + install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service + DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user) endif() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) @@ -359,11 +368,6 @@ install( install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) - -# session file -systemd -install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) - # allow Hyprland to find assets add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") @@ -404,6 +408,3 @@ install( DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland FILES_MATCHING PATTERN "*.h*") - -#install systemd service -install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user) From 40081cb330fa838ad9c0a7b87c20b2300ea7fb38 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 2 Nov 2024 15:26:25 +0000 Subject: [PATCH 0797/2393] renderer: improve api around new framebuffer changes ref #8325 --- src/protocols/Screencopy.cpp | 2 +- src/protocols/ToplevelExport.cpp | 2 +- src/render/Framebuffer.cpp | 19 ++++- src/render/Framebuffer.hpp | 12 ++- src/render/OpenGL.cpp | 75 ++++++++++--------- .../decorations/CHyprDropShadowDecoration.cpp | 2 +- 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 780c081d..1fcaff05 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -253,7 +253,7 @@ bool CScreencopyFrame::copyShm() { g_pHyprOpenGL->setMonitorTransformEnabled(false); #ifndef GLES2 - glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.m_iFb); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.getFBID()); #else glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb); #endif diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index f2af89db..04c089d7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -279,7 +279,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { outFB.bind(); #ifndef GLES2 - glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.m_iFb); + glBindFramebuffer(GL_READ_FRAMEBUFFER, outFB.getFBID()); #endif glPixelStorei(GL_PACK_ALIGNMENT, 1); diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 7e086778..814a3339 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -65,9 +65,10 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { return true; } -void CFramebuffer::addStencil() { +void CFramebuffer::addStencil(SP tex) { // TODO: Allow this with gles2 #ifndef GLES2 + m_pStencilTex = tex; glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_vSize.x, m_vSize.y, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, 0); @@ -109,5 +110,17 @@ CFramebuffer::~CFramebuffer() { } bool CFramebuffer::isAllocated() { - return m_iFbAllocated; -} \ No newline at end of file + return m_iFbAllocated && m_cTex; +} + +SP CFramebuffer::getTexture() { + return m_cTex; +} + +GLuint CFramebuffer::getFBID() { + return m_iFbAllocated ? m_iFb : 0; +} + +SP CFramebuffer::getStencilTex() { + return m_pStencilTex; +} diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index ca7f9e8a..84dfeef1 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -9,17 +9,23 @@ class CFramebuffer { ~CFramebuffer(); bool alloc(int w, int h, uint32_t format = GL_RGBA); - void addStencil(); + void addStencil(SP tex); void bind(); void release(); void reset(); bool isAllocated(); + SP getTexture(); + SP getStencilTex(); + GLuint getFBID(); Vector2D m_vSize; + private: SP m_cTex; - GLuint m_iFb; - bool m_iFbAllocated{false}; + GLuint m_iFb = -1; + bool m_iFbAllocated = false; SP m_pStencilTex; + + friend class CRenderbuffer; }; \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 20963707..415bb920 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -830,15 +830,15 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb if (m_RenderData.pCurrentMonData->offloadFB.m_vSize != pMonitor->vecPixelSize) { m_RenderData.pCurrentMonData->stencilTex->allocate(); - m_RenderData.pCurrentMonData->offloadFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offMainFB.m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); + + m_RenderData.pCurrentMonData->offloadFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); + m_RenderData.pCurrentMonData->mirrorFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); + m_RenderData.pCurrentMonData->mirrorSwapFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); + m_RenderData.pCurrentMonData->offMainFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); } if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) @@ -870,10 +870,9 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb // we can render to the rbo / fbo (fake) directly const auto PFBO = fb ? fb : PRBO->getFB(); m_RenderData.currentFB = PFBO; - if (PFBO->m_pStencilTex != m_RenderData.pCurrentMonData->stencilTex) { - PFBO->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - PFBO->addStencil(); - } + if (PFBO->getStencilTex() != m_RenderData.pCurrentMonData->stencilTex) + PFBO->addStencil(m_RenderData.pCurrentMonData->stencilTex); + PFBO->bind(); m_bOffloadedFramebuffer = false; } @@ -924,9 +923,9 @@ void CHyprOpenGLImpl::end() { blend(false); if (m_sFinalScreenShader.program < 1 && !g_pHyprRenderer->m_bCrashingInProgress) - renderTexturePrimitive(m_RenderData.pCurrentMonData->offloadFB.m_cTex, &monbox); + renderTexturePrimitive(m_RenderData.pCurrentMonData->offloadFB.getTexture(), &monbox); else - renderTexture(m_RenderData.pCurrentMonData->offloadFB.m_cTex, &monbox, 1.f); + renderTexture(m_RenderData.pCurrentMonData->offloadFB.getTexture(), &monbox, 1.f); blend(true); @@ -1269,7 +1268,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round m_bEndFrame = true; // fix transformed const auto SAVEDRENDERMODIF = m_RenderData.renderModif; m_RenderData.renderModif = {}; // fix shit - renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, blurA, &damage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, &damage, 0, false, false, false); m_bEndFrame = false; m_RenderData.renderModif = SAVEDRENDERMODIF; @@ -1629,7 +1628,8 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf glBindTexture(tex->m_iTarget, tex->m_iTexID); glActiveTexture(GL_TEXTURE0 + 1); - glBindTexture(matte.m_cTex->m_iTarget, matte.m_cTex->m_iTexID); + auto matteTex = matte.getTexture(); + glBindTexture(matteTex->m_iTarget, matteTex->m_iTexID); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1696,9 +1696,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(m_RenderData.currentFB->m_cTex->m_iTarget, m_RenderData.currentFB->m_cTex->m_iTexID); + auto currentTex = m_RenderData.currentFB->getTexture(); - glTexParameteri(m_RenderData.currentFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(currentTex->m_iTarget, currentTex->m_iTexID); + + glTexParameteri(currentTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURPREPARE.program); @@ -1740,9 +1742,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); + auto currentTex = currentRenderToFB->getTexture(); - glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(currentTex->m_iTarget, currentTex->m_iTexID); + + glTexParameteri(currentTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(pShader->program); @@ -1790,7 +1794,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o // draw the things. // first draw is swap -> mirr PMIRRORFB->bind(); - glBindTexture(PMIRRORSWAPFB->m_cTex->m_iTarget, PMIRRORSWAPFB->m_cTex->m_iTexID); + glBindTexture(PMIRRORSWAPFB->getTexture()->m_iTarget, PMIRRORSWAPFB->getTexture()->m_iTexID); // damage region will be scaled, make a temp CRegion tempDamage{damage}; @@ -1818,9 +1822,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o glActiveTexture(GL_TEXTURE0); - glBindTexture(currentRenderToFB->m_cTex->m_iTarget, currentRenderToFB->m_cTex->m_iTexID); + auto currentTex = currentRenderToFB->getTexture(); - glTexParameteri(currentRenderToFB->m_cTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(currentTex->m_iTarget, currentTex->m_iTexID); + + glTexParameteri(currentTex->m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glUseProgram(m_RenderData.pCurrentMonData->m_shBLURFINISH.program); @@ -1858,7 +1864,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o } // finish - glBindTexture(PMIRRORFB->m_cTex->m_iTarget, 0); + glBindTexture(PMIRRORFB->getTexture()->m_iTarget, 0); blend(BLENDBEFORE); @@ -1972,7 +1978,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { clear(CColor(0, 0, 0, 0)); m_bEndFrame = true; // fix transformed - renderTextureInternalWithDamage(POUTFB->m_cTex, &wholeMonitor, 1, &fakeDamage, 0, false, true, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, &fakeDamage, 0, false, true, false); m_bEndFrame = false; m_RenderData.currentFB->bind(); @@ -2003,7 +2009,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin static auto PBLURNEWOPTIMIZE = CConfigValue("decoration:blur:new_optimizations"); static auto PBLURXRAY = CConfigValue("decoration:blur:xray"); - if (!m_RenderData.pCurrentMonData->blurFB.m_cTex->m_iTexID) + if (!m_RenderData.pCurrentMonData->blurFB.getTexture()) return false; if (pWindow && pWindow->m_sWindowData.xray.hasValue() && !pWindow->m_sWindowData.xray.valueOrDefault()) @@ -2105,7 +2111,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float setMonitorTransformEnabled(true); if (!USENEWOPTIMIZE) setRenderModifEnabled(false); - renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? blurA : a * blurA, &texDamage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, *PBLURIGNOREOPACITY ? blurA : a * blurA, &texDamage, 0, false, false, false); if (!USENEWOPTIMIZE) setRenderModifEnabled(true); setMonitorTransformEnabled(false); @@ -2238,9 +2244,8 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr g_pHyprRenderer->makeEGLCurrent(); - pFramebuffer->m_pStencilTex = m_RenderData.pCurrentMonData->stencilTex; - pFramebuffer->alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); + pFramebuffer->addStencil(m_RenderData.pCurrentMonData->stencilTex); g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer); @@ -2376,7 +2381,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { const auto FBDATA = &m_mWindowFramebuffers.at(ref); - if (!FBDATA->m_cTex->m_iTexID) + if (!FBDATA->getTexture()) return; const auto PMONITOR = pWindow->m_pMonitor.lock(); @@ -2402,7 +2407,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { m_bEndFrame = true; - renderTextureInternalWithDamage(FBDATA->m_cTex, &windowBox, pWindow->m_fAlpha.value(), &fakeDamage, 0); + renderTextureInternalWithDamage(FBDATA->getTexture(), &windowBox, pWindow->m_fAlpha.value(), &fakeDamage, 0); m_bEndFrame = false; } @@ -2415,7 +2420,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { const auto FBDATA = &m_mLayerFramebuffers.at(pLayer); - if (!FBDATA->m_cTex->m_iTexID) + if (!FBDATA->getTexture()) return; const auto PMONITOR = pLayer->monitor.lock(); @@ -2435,7 +2440,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { m_bEndFrame = true; - renderTextureInternalWithDamage(FBDATA->m_cTex, &layerBox, pLayer->alpha.value(), &fakeDamage, 0); + renderTextureInternalWithDamage(FBDATA->getTexture(), &layerBox, pLayer->alpha.value(), &fakeDamage, 0); m_bEndFrame = false; } @@ -2526,7 +2531,7 @@ void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { blend(false); - renderTexture(m_RenderData.currentFB->m_cTex, box, 1.f, 0, false, false); + renderTexture(m_RenderData.currentFB->getTexture(), box, 1.f, 0, false, false); blend(true); @@ -2548,7 +2553,7 @@ void CHyprOpenGLImpl::renderMirrored() { monbox.y = (monitor->vecTransformedSize.y - monbox.h) / 2; const auto PFB = &m_mMonitorRenderResources[mirrored].monitorMirrorFB; - if (!PFB->isAllocated() || PFB->m_cTex->m_iTexID <= 0) + if (!PFB->isAllocated() || !PFB->getTexture()) return; // replace monitor projection to undo the mirrored monitor's projection @@ -2561,7 +2566,7 @@ void CHyprOpenGLImpl::renderMirrored() { // clear stuff outside of mirrored area (e.g. when changing to mirrored) clear(CColor(0, 0, 0, 0)); - renderTexture(PFB->m_cTex, &monbox, 1.f, 0, false, false); + renderTexture(PFB->getTexture(), &monbox, 1.f, 0, false, false); // reset matrix for further drawing m_RenderData.monitorProjection = monitor->projMatrix; @@ -2926,7 +2931,7 @@ void CHyprOpenGLImpl::clearWithTex() { if (TEXIT != m_mMonitorBGFBs.end()) { CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; m_bEndFrame = true; - renderTexture(TEXIT->second.m_cTex, &monbox, 1); + renderTexture(TEXIT->second.getTexture(), &monbox, 1); m_bEndFrame = false; } } @@ -2978,7 +2983,7 @@ void CHyprOpenGLImpl::bindOffMain() { void CHyprOpenGLImpl::renderOffToMain(CFramebuffer* off) { CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - renderTexturePrimitive(off->m_cTex, &monbox); + renderTexturePrimitive(off->getTexture(), &monbox); } void CHyprOpenGLImpl::bindBackOnMain() { diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 79d5940b..f146776f 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -199,7 +199,7 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { CBox monbox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.m_cTex, &monbox, alphaFB); + g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.getTexture(), &monbox, alphaFB); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); From 514e0ff509f3bf4c98515f08216ac2eeb8797517 Mon Sep 17 00:00:00 2001 From: diniamo Date: Sun, 3 Nov 2024 09:52:09 +0100 Subject: [PATCH 0798/2393] flake: update nixpkgs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index beb56b5c..27803dc5 100644 --- a/flake.lock +++ b/flake.lock @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1729413321, - "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", + "lastModified": 1730531603, + "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", + "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", "type": "github" }, "original": { From 5833abbbd11dca718379863cb2fb5c2423f5d7e7 Mon Sep 17 00:00:00 2001 From: trianta <56975502+Trimutex@users.noreply.github.com> Date: Sun, 3 Nov 2024 08:59:46 -0600 Subject: [PATCH 0799/2393] xwayland: minor fixups for stability (#8323) * xwayland: add inline safe closing of fds and fix LOCK_FILE_MODE permissions * xwayland: auto recreate xwayland instance if it crashes * xwayland: delay auto-restart until later --- src/xwayland/Server.cpp | 25 +++++++++++++------------ src/xwayland/XWM.cpp | 3 +++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 5ad9ff23..f356af18 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -30,7 +30,7 @@ constexpr int SOCKET_DIR_PERMISSIONS = 0755; constexpr int SOCKET_BACKLOG = 1; constexpr int MAX_SOCKET_RETRIES = 32; -constexpr int LOCK_FILE_MODE = 044; +constexpr int LOCK_FILE_MODE = 0444; static bool setCloseOnExec(int fd, bool cloexec) { int flags = fcntl(fd, F_GETFD); @@ -58,6 +58,11 @@ void cleanUpSocket(int fd, const char* path) { unlink(path); } +inline void closeSocketSafely(int& fd) { + if (fd >= 0) + close(fd); +} + static int createSocket(struct sockaddr_un* addr, size_t path_size) { socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; int fd = socket(AF_UNIX, SOCK_STREAM, 0); @@ -252,8 +257,8 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - close(xFDs[0]); - close(xFDs[1]); + closeSocketSafely(xFDs[0]); + closeSocketSafely(xFDs[1]); std::string lockPath = std::format("/tmp/.X{}-lock", display); safeRemove(lockPath); @@ -283,14 +288,10 @@ void CXWaylandServer::die() { if (pipeFd >= 0) close(pipeFd); - if (waylandFDs[0] >= 0) - close(waylandFDs[0]); - if (waylandFDs[1] >= 0) - close(waylandFDs[1]); - if (xwmFDs[0] >= 0) - close(xwmFDs[0]); - if (xwmFDs[1] >= 0) - close(xwmFDs[1]); + closeSocketSafely(waylandFDs[0]); + closeSocketSafely(waylandFDs[1]); + closeSocketSafely(xwmFDs[0]); + closeSocketSafely(xwmFDs[1]); // possible crash. Better to leak a bit. //if (xwaylandClient) @@ -407,7 +408,7 @@ bool CXWaylandServer::start() { close(notify[1]); close(waylandFDs[1]); - close(xwmFDs[1]); + closeSocketSafely(xwmFDs[1]); waylandFDs[1] = -1; xwmFDs[1] = -1; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 248813bf..87fc34e4 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -13,6 +13,7 @@ #include "../defines.hpp" #include "../Compositor.hpp" #include "../protocols/core/Seat.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" @@ -691,6 +692,8 @@ int CXWM::onEvent(int fd, uint32_t mask) { Debug::log(CRIT, "XWayland has yeeten the xwm off?!"); g_pXWayland->pWM.reset(); g_pXWayland->pServer.reset(); + // Attempt to create fresh instance + g_pEventLoopManager->doLater([]() { g_pXWayland = std::make_unique(true); }); return 0; } From 180c26ada6233c3c59c331cb14a64aac1eeb2941 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 3 Nov 2024 15:16:08 +0000 Subject: [PATCH 0800/2393] renderer: safeguard against non-sampleable currentFB in blurMainFb fixes #8325 --- src/render/Framebuffer.cpp | 6 ++++++ src/render/OpenGL.cpp | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 814a3339..bf75d414 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -97,12 +97,18 @@ void CFramebuffer::bind() { } void CFramebuffer::release() { + if (!m_iFbAllocated && !m_cTex) + return; + + Debug::log(TRACE, "fb {} released", m_iFb); + if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); m_cTex.reset(); m_iFbAllocated = false; m_vSize = Vector2D(); + m_iFb = 0; } CFramebuffer::~CFramebuffer() { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 415bb920..45837509 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1656,6 +1656,11 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf // Dual (or more) kawase blur CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* originalDamage) { + if (!m_RenderData.currentFB->getTexture()) { + Debug::log(ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)"); + return &m_RenderData.pCurrentMonData->mirrorFB; // return something to sample from at least + } + TRACY_GPU_ZONE("RenderBlurMainFramebufferWithDamage"); const auto BLENDBEFORE = m_bBlend; From cd0d0491261728260de3d1aff150e1b6c05f9e86 Mon Sep 17 00:00:00 2001 From: Gliczy <129636582+Gliczy@users.noreply.github.com> Date: Sun, 3 Nov 2024 17:08:13 +0100 Subject: [PATCH 0801/2393] flake.lock: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 27803dc5..560014b6 100644 --- a/flake.lock +++ b/flake.lock @@ -293,11 +293,11 @@ ] }, "locked": { - "lastModified": 1728166987, - "narHash": "sha256-w6dVTguAn9zJ+7aPOhBQgDz8bn6YZ7b56cY8Kg5HJRI=", + "lastModified": 1730187742, + "narHash": "sha256-M0umGIIvVFqCwA0fQ5edivMTbRYA0r/5tXK8sr+M7EA=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "fb9c8d665af0588bb087f97d0f673ddf0d501787", + "rev": "998f646762b94fbac61b0271ce66d3e617262858", "type": "github" }, "original": { From 44899cd5488831b147f385f201959625bd010898 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 4 Nov 2024 19:43:23 +0200 Subject: [PATCH 0802/2393] nix/overlays: fix xdph overlay Partial fix for https://github.com/hyprwm/Hyprland/issues/8343 --- nix/overlays.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/overlays.nix b/nix/overlays.nix index a78f3003..b1eb66ad 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -63,7 +63,7 @@ in { # Packages for extra software recommended for usage with Hyprland, # including forked or patched packages for compatibility. hyprland-extras = lib.composeManyExtensions [ - inputs.xdph.overlays.xdg-desktop-portal-hyprland + inputs.xdph.overlays.default ]; # udis86 from nixpkgs is too old, and also does not provide a .pc file From 0fb9a04526b06adfb3fd16b64e13b7d110ae7855 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 4 Nov 2024 20:01:40 +0200 Subject: [PATCH 0803/2393] flake.lock: update xdph --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 560014b6..8cee27e3 100644 --- a/flake.lock +++ b/flake.lock @@ -293,11 +293,11 @@ ] }, "locked": { - "lastModified": 1730187742, - "narHash": "sha256-M0umGIIvVFqCwA0fQ5edivMTbRYA0r/5tXK8sr+M7EA=", + "lastModified": 1730743262, + "narHash": "sha256-iTLqj3lU8kFehPm5tXpctzkD274t/k1nwSSq3qCWXeg=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "998f646762b94fbac61b0271ce66d3e617262858", + "rev": "09b23cef06fe248e61cec8862c04b9bcb62f4b6d", "type": "github" }, "original": { From 88e9e0394541a853600bc2c910005c05fa156269 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 4 Nov 2024 19:42:47 +0000 Subject: [PATCH 0804/2393] renderer: add expand_undersized_textures adds an option to disable the texture expansion for textures that are smaller while resizing up --- src/config/ConfigManager.cpp | 1 + src/render/Renderer.cpp | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 62c71dc7..c5d53e6a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -590,6 +590,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2}); m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2}); m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0}); + m_pConfig->addConfigValue("render:expand_undersized_textures", Hyprlang::INT{1}); // devices m_pConfig->addSpecialCategory("device", {"name"}); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index a133899b..6af3a99d 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1084,8 +1084,10 @@ void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize, const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { if (!pWindow || !pWindow->m_bIsX11) { - Vector2D uvTL; - Vector2D uvBR = Vector2D(1, 1); + static auto PEXPANDEDGES = CConfigValue("render:expand_undersized_textures"); + + Vector2D uvTL; + Vector2D uvBR = Vector2D(1, 1); if (pSurface->current.viewport.hasSource) { // we stretch it to dest. if no dest, to 1,1 @@ -1115,16 +1117,18 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SPscale); - const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination; - const auto EXPECTED_SIZE = - ((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale) - .round(); - if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) { - // this will not work with shm AFAIK, idk why. - // NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much - const auto FIX = projSize / EXPECTED_SIZE; - uvBR = uvBR * FIX; + if (*PEXPANDEDGES) { + const auto MONITOR_WL_SCALE = std::ceil(pMonitor->scale); + const bool SCALE_UNAWARE = MONITOR_WL_SCALE != pSurface->current.scale && !pSurface->current.viewport.hasDestination; + const auto EXPECTED_SIZE = + ((pSurface->current.viewport.hasDestination ? pSurface->current.viewport.destination : pSurface->current.bufferSize / pSurface->current.scale) * pMonitor->scale) + .round(); + if (!SCALE_UNAWARE && (EXPECTED_SIZE.x < projSize.x || EXPECTED_SIZE.y < projSize.y)) { + // this will not work with shm AFAIK, idk why. + // NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much + const auto FIX = projSize / EXPECTED_SIZE; + uvBR = uvBR * FIX; + } } g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft = uvTL; From e3882b23d09aad7f5c3a708536c87b062f3b0d8d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 09:59:03 +0000 Subject: [PATCH 0805/2393] screencopy: fix build with legacyrenderer fixes #8355 --- src/protocols/Screencopy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 1fcaff05..a7e515cb 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -255,7 +255,7 @@ bool CScreencopyFrame::copyShm() { #ifndef GLES2 glBindFramebuffer(GL_READ_FRAMEBUFFER, fb.getFBID()); #else - glBindFramebuffer(GL_FRAMEBUFFER, fb.m_iFb); + glBindFramebuffer(GL_FRAMEBUFFER, fb.getFBID()); #endif const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); From d1638a09bacd84b994de3f77746b74f427b9d41e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 15:44:40 +0000 Subject: [PATCH 0806/2393] shadow: add sharp and refactor options options moved to decoration:shadow: --- src/Compositor.cpp | 11 +++--- src/config/ConfigDescriptions.hpp | 24 ++++++++----- src/config/ConfigManager.cpp | 17 +++++----- src/managers/AnimationManager.cpp | 2 +- src/render/OpenGL.cpp | 6 ++-- .../decorations/CHyprDropShadowDecoration.cpp | 34 +++++++++++++------ .../decorations/CHyprDropShadowDecoration.hpp | 2 ++ 7 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 62612398..495a2d85 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1893,8 +1893,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { static auto PINACTIVEALPHA = CConfigValue("decoration:inactive_opacity"); static auto PACTIVEALPHA = CConfigValue("decoration:active_opacity"); static auto PFULLSCREENALPHA = CConfigValue("decoration:fullscreen_opacity"); - static auto PSHADOWCOL = CConfigValue("decoration:col.shadow"); - static auto PSHADOWCOLINACTIVE = CConfigValue("decoration:col.shadow_inactive"); + static auto PSHADOWCOL = CConfigValue("decoration:shadow:color"); + static auto PSHADOWCOLINACTIVE = CConfigValue("decoration:shadow:color_inactive"); static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); static auto PDIMENABLED = CConfigValue("decoration:dim_inactive"); @@ -1965,11 +1965,10 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { - if (pWindow == m_pLastWindow) { + if (pWindow == m_pLastWindow) pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); - } else { - pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); - } + else + pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); } else { pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow } diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 07034e71..5327c599 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -158,49 +158,55 @@ inline static const std::vector CONFIG_OPTIONS = { .data = SConfigOptionDescription::SFloatData{1, 0, 1}, }, SConfigOptionDescription{ - .value = "decoration:drop_shadow", + .value = "decoration:shadow:enabled", .description = "enable drop shadows on windows", .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, SConfigOptionDescription{ - .value = "decoration:shadow_range", + .value = "decoration:shadow:range", .description = "Shadow range (size) in layout px", .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{4, 0, 100}, }, SConfigOptionDescription{ - .value = "decoration:shadow_render_power", + .value = "decoration:shadow:render_power", .description = "in what power to render the falloff (more power, the faster the falloff) [1 - 4]", .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{3, 1, 4}, }, SConfigOptionDescription{ - .value = "decoration:shadow_ignore_window", + .value = "decoration:shadow:sharp", + .description = "whether the shadow should be sharp or not. Akin to an infinitely high render power.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "decoration:shadow:ignore_window", .description = "if true, the shadow will not be rendered behind the window itself, only around it.", .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, SConfigOptionDescription{ - .value = "decoration:col.shadow", + .value = "decoration:shadow:color", .description = "shadow's color. Alpha dictates shadow's opacity.", .type = CONFIG_OPTION_COLOR, .data = SConfigOptionDescription::SColorData{0xee1a1a1a}, }, SConfigOptionDescription{ - .value = "decoration:col.shadow_inactive", + .value = "decoration:shadow:color_inactive", .description = "inactive shadow color. (if not set, will fall back to col.shadow)", .type = CONFIG_OPTION_COLOR, - .data = SConfigOptionDescription::SColorData{}, //##TODO UNSET? + .data = SConfigOptionDescription::SColorData{}, //TODO: UNSET? }, SConfigOptionDescription{ - .value = "decoration:shadow_offset", + .value = "decoration:shadow:offset", .description = "shadow's rendering offset.", .type = CONFIG_OPTION_VECTOR, .data = SConfigOptionDescription::SVectorData{{}, {-250, -250}, {250, 250}}, }, SConfigOptionDescription{ - .value = "decoration:shadow_scale", + .value = "decoration:shadow:scale", .description = "shadow's scale. [0.0 - 1.0]", .type = CONFIG_OPTION_FLOAT, .data = SConfigOptionDescription::SFloatData{1, 0, 1}, diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c5d53e6a..eafe4cbb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -431,14 +431,15 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("decoration:inactive_opacity", {1.F}); m_pConfig->addConfigValue("decoration:fullscreen_opacity", {1.F}); m_pConfig->addConfigValue("decoration:no_blur_on_oversized", Hyprlang::INT{0}); - m_pConfig->addConfigValue("decoration:drop_shadow", Hyprlang::INT{1}); - m_pConfig->addConfigValue("decoration:shadow_range", Hyprlang::INT{4}); - m_pConfig->addConfigValue("decoration:shadow_render_power", Hyprlang::INT{3}); - m_pConfig->addConfigValue("decoration:shadow_ignore_window", Hyprlang::INT{1}); - m_pConfig->addConfigValue("decoration:shadow_offset", Hyprlang::VEC2{0, 0}); - m_pConfig->addConfigValue("decoration:shadow_scale", {1.f}); - m_pConfig->addConfigValue("decoration:col.shadow", Hyprlang::INT{0xee1a1a1a}); - m_pConfig->addConfigValue("decoration:col.shadow_inactive", {(Hyprlang::INT)INT_MAX}); + m_pConfig->addConfigValue("decoration:shadow:enabled", Hyprlang::INT{1}); + m_pConfig->addConfigValue("decoration:shadow:range", Hyprlang::INT{4}); + m_pConfig->addConfigValue("decoration:shadow:render_power", Hyprlang::INT{3}); + m_pConfig->addConfigValue("decoration:shadow:ignore_window", Hyprlang::INT{1}); + m_pConfig->addConfigValue("decoration:shadow:offset", Hyprlang::VEC2{0, 0}); + m_pConfig->addConfigValue("decoration:shadow:scale", {1.f}); + m_pConfig->addConfigValue("decoration:shadow:sharp", Hyprlang::INT{0}); + m_pConfig->addConfigValue("decoration:shadow:color", Hyprlang::INT{0xee1a1a1a}); + m_pConfig->addConfigValue("decoration:shadow:color_inactive", {(Hyprlang::INT)INT64_MAX}); m_pConfig->addConfigValue("decoration:dim_inactive", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:dim_strength", {0.5f}); m_pConfig->addConfigValue("decoration:dim_special", {0.2f}); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 0bdf5a7a..ceb594aa 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -64,7 +64,7 @@ void CAnimationManager::tick() { if (!*PANIMENABLED) animGlobalDisabled = true; - static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:drop_shadow"); + static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:shadow:enabled"); const auto DEFAULTBEZIER = m_mBezierCurves.find("default"); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 45837509..52392436 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2465,7 +2465,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const box = &newBox; - static auto PSHADOWPOWER = CConfigValue("decoration:shadow_render_power"); + static auto PSHADOWPOWER = CConfigValue("decoration:shadow:render_power"); const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); @@ -2475,7 +2475,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); - glEnable(GL_BLEND); + blend(true); glUseProgram(m_RenderData.pCurrentMonData->m_shSHADOW.program); @@ -2485,7 +2485,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const glMatrix.transpose(); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); + glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r * col.a * a, col.g * col.a * a, col.b * col.a * a, col.a * a); const auto TOPLEFT = Vector2D(range + round, range + round); const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index f146776f..893ad498 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -36,7 +36,7 @@ std::string CHyprDropShadowDecoration::getDisplayName() { } void CHyprDropShadowDecoration::damageEntire() { - static auto PSHADOWS = CConfigValue("decoration:drop_shadow"); + static auto PSHADOWS = CConfigValue("decoration:shadow:enabled"); if (*PSHADOWS != 1) return; // disabled @@ -52,7 +52,7 @@ void CHyprDropShadowDecoration::damageEntire() { shadowBox.translate(PWORKSPACE->m_vRenderOffset.value()); shadowBox.translate(PWINDOW->m_vFloatingOffset); - static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow_ignore_window"); + static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); const auto ROUNDING = PWINDOW->rounding(); const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; @@ -102,11 +102,11 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (PWINDOW->m_sWindowData.noShadow.valueOrDefault()) return; - static auto PSHADOWS = CConfigValue("decoration:drop_shadow"); - static auto PSHADOWSIZE = CConfigValue("decoration:shadow_range"); - static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow_ignore_window"); - static auto PSHADOWSCALE = CConfigValue("decoration:shadow_scale"); - static auto PSHADOWOFFSET = CConfigValue("decoration:shadow_offset"); + static auto PSHADOWS = CConfigValue("decoration:shadow:enabled"); + static auto PSHADOWSIZE = CConfigValue("decoration:shadow:range"); + static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); + static auto PSHADOWSCALE = CConfigValue("decoration:shadow:scale"); + static auto PSHADOWOFFSET = CConfigValue("decoration:shadow:offset"); if (*PSHADOWS != 1) return; // disabled @@ -184,7 +184,7 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(&fullBox, CColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); // render black window box ("clip") g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); @@ -204,9 +204,8 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->setMonitorTransformEnabled(false); g_pHyprOpenGL->m_RenderData.damage = saveDamage; - } else { - g_pHyprOpenGL->renderRoundedShadow(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); - } + } else + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); @@ -215,3 +214,16 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { return DECORATION_LAYER_BOTTOM; } + +void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CColor color, float a) { + static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); + + g_pHyprOpenGL->blend(true); + + color.a *= a; + + if (*PSHADOWSHARP) + g_pHyprOpenGL->renderRect(box, color, round); + else + g_pHyprOpenGL->renderRoundedShadow(box, round, range, color, 1.F); +} diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 8335cde9..933ee0ef 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -34,6 +34,8 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; + void drawShadowInternal(CBox* box, int round, int range, CColor color, float a); + CBox m_bLastWindowBox = {0}; CBox m_bLastWindowBoxWithDecos = {0}; }; From 55ccb1a8cf2c8541a32890e9b76e7c20fc9227cd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 16:00:39 +0000 Subject: [PATCH 0807/2393] shaders: fixup jagged edges in texture rounded corners --- src/render/shaders/Textures.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index 6ac33a0a..e99d0a49 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -5,24 +5,27 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { return R"#( - // branchless baby! + // shoutout me: I fixed this shader being a bit pixelated while watching hentai + highp vec2 pixCoord = vec2(gl_FragCoord); pixCoord -= topLeft + fullSize * 0.5; pixCoord *= vec2(lessThan(pixCoord, vec2(0.0))) * -2.0 + 1.0; pixCoord -= fullSize * 0.5 - radius; pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left + const float SMOOTHING_CONSTANT = 0.651724; // smoothing constant for the edge: more = blurrier, but smoother + if (pixCoord.x + pixCoord.y > radius) { float dist = length(pixCoord); - if (dist > radius) + if (dist > radius + SMOOTHING_CONSTANT * 2.0) discard; - if (dist > radius - 1.0) { + if (dist > radius - SMOOTHING_CONSTANT * 2.0) { float dist = length(pixCoord); - float normalized = 1.0 - smoothstep(0.0, 1.0, dist - radius + 0.5); + float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; From 0920572e703201368c9fbcc9108ce1888600ffa2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 16:11:05 +0000 Subject: [PATCH 0808/2393] shaders: improve corner AA in borders shader --- src/render/shaders/Border.hpp | 10 ++++++++-- src/render/shaders/SharedValues.hpp | 3 +++ src/render/shaders/Textures.hpp | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/render/shaders/SharedValues.hpp diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp index a33694a7..1f4a1d97 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/Border.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include "SharedValues.hpp" // makes a stencil without corners inline const std::string FRAGBORDER1 = R"#( @@ -72,18 +74,22 @@ void main() { pixCoordOuter += vec2(1.0, 1.0) / fullSize; if (min(pixCoord.x, pixCoord.y) > 0.0 && radius > 0.0) { + // smoothing constant for the edge: more = blurrier, but smoother + const float SMOOTHING_CONSTANT = )#" + + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; + float dist = length(pixCoord); float distOuter = length(pixCoordOuter); float h = (thick / 2.0); if (dist < radius - h) { // lower - float normalized = smoothstep(0.0, 1.0, dist - radius + thick + 0.5); + float normalized = smoothstep(0.0, 1.0, (dist - radius + thick + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); additionalAlpha *= normalized; done = true; } else if (min(pixCoordOuter.x, pixCoordOuter.y) > 0.0) { // higher - float normalized = 1.0 - smoothstep(0.0, 1.0, distOuter - radiusOuter + 0.5); + float normalized = 1.0 - smoothstep(0.0, 1.0, (distOuter - radiusOuter + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); additionalAlpha *= normalized; done = true; } else if (distOuter < radiusOuter - h) { diff --git a/src/render/shaders/SharedValues.hpp b/src/render/shaders/SharedValues.hpp new file mode 100644 index 00000000..9a74c892 --- /dev/null +++ b/src/render/shaders/SharedValues.hpp @@ -0,0 +1,3 @@ +#pragma once + +constexpr float SHADER_ROUNDED_SMOOTHING_FACTOR = M_PI / 5.34665792551; \ No newline at end of file diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index e99d0a49..b203ad04 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include "SharedValues.hpp" inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVarName) -> std::string { return R"#( @@ -13,7 +15,9 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar pixCoord -= fullSize * 0.5 - radius; pixCoord += vec2(1.0, 1.0) / fullSize; // center the pix dont make it top-left - const float SMOOTHING_CONSTANT = 0.651724; // smoothing constant for the edge: more = blurrier, but smoother + // smoothing constant for the edge: more = blurrier, but smoother + const float SMOOTHING_CONSTANT = )#" + + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; if (pixCoord.x + pixCoord.y > radius) { From 64c46db0872a576a993035ac1fa5e40af53ca001 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 16:20:04 +0000 Subject: [PATCH 0809/2393] hyprctl: add mirrorOf to hyprctl monitors fixes #8026 --- src/debug/HyprCtl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f5c63f86..3e0c75a6 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -107,6 +107,7 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer "activelyTearing": {}, "disabled": {}, "currentFormat": "{}", + "mirrorOf": "{}", "availableModes": [{}] }},)#", @@ -117,18 +118,19 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (uint64_t)m->solitaryClient.get(), (m->tearingState.activelyTearing ? "true" : "false"), (m->m_bEnabled ? "false" : "true"), formatToString(m->output->state->state().drmFormat), - availableModesForOutput(m, format)); + m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); } else { result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t" "special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t" - "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n", + "dpmsStatus: {}\n\tvrr: {}\n\tsolitary: {:x}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tmirrorOf: {}\n\tavailableModes: {}\n\n", m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription, m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, (uint64_t)m->solitaryClient.get(), - m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), availableModesForOutput(m, format)); + m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->output->state->state().drmFormat), + m->pMirrorOf ? std::format("{}", m->pMirrorOf->ID) : "none", availableModesForOutput(m, format)); } return result; From 81ad218b8b082ce4c9b04bbb668d3c219fc4ff6f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 5 Nov 2024 16:28:55 +0000 Subject: [PATCH 0810/2393] shadow: fix double premultiplication shader takes straight alpha aaaa --- src/render/OpenGL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 52392436..eb0a029f 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2485,7 +2485,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const glMatrix.transpose(); glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shSHADOW.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r * col.a * a, col.g * col.a * a, col.b * col.a * a, col.a * a); + glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); const auto TOPLEFT = Vector2D(range + round, range + round); const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); From e4ab28b1fb063e5554c953c721779644ef6ada08 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:03:37 +0500 Subject: [PATCH 0811/2393] defaultConfig: update default config values for shadows (#8360) --- example/hyprland.conf | 10 ++++++---- src/config/defaultConfig.hpp | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index f1139c3b..edeeac01 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -86,10 +86,12 @@ decoration { active_opacity = 1.0 inactive_opacity = 1.0 - drop_shadow = true - shadow_range = 4 - shadow_render_power = 3 - col.shadow = rgba(1a1a1aee) + shadow { + enabled = true + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } # https://wiki.hyprland.org/Configuring/Variables/#blur blur { diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index facb16e2..02781770 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -99,10 +99,12 @@ decoration { active_opacity = 1.0 inactive_opacity = 1.0 - drop_shadow = true - shadow_range = 4 - shadow_render_power = 3 - col.shadow = rgba(1a1a1aee) + shadow { + enabled = true + range = 4 + render_power = 3 + color = rgba(1a1a1aee) + } # https://wiki.hyprland.org/Configuring/Variables/#blur blur { From 3bf6f78dad5f78dd8f4f519ceaa5a98671c90b14 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:14:48 +0500 Subject: [PATCH 0812/2393] hyprland-systemd.desktop: change name back to Hyprland (#8351) --- systemd/hyprland-systemd.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemd/hyprland-systemd.desktop b/systemd/hyprland-systemd.desktop index 8c065a81..64ebbd47 100644 --- a/systemd/hyprland-systemd.desktop +++ b/systemd/hyprland-systemd.desktop @@ -3,5 +3,5 @@ Name=Hyprland (systemd session) Comment=An intelligent dynamic tiling Wayland compositor Exec=systemctl --user start --wait hyprland-session Type=Application -DesktopNames=Hyprland (systemd session) +DesktopNames=Hyprland Keywords=tiling;wayland;compositor; From 97a309b7844aea82b200139febc99998e7f06402 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 6 Nov 2024 14:02:39 +0000 Subject: [PATCH 0813/2393] layershell: check if workspace is valid in onMap ref #8296 --- src/desktop/LayerSurface.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index f073da82..eb3cdfd2 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -175,8 +175,7 @@ void CLayerSurface::onMap() { CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); - const auto WORKSPACE = PMONITOR->activeWorkspace; - const bool FULLSCREEN = WORKSPACE->m_bHasFullscreenWindow && WORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN; + const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); readyToDelete = false; From 8f42401aa8ac5a7778e29024be7ef3e0a063de13 Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Wed, 6 Nov 2024 17:52:10 +0100 Subject: [PATCH 0814/2393] groups: add merge_groups_on_groupbar (#8362) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/layout/DwindleLayout.cpp | 5 ----- src/layout/IHyprLayout.cpp | 10 +++------- src/layout/MasterLayout.cpp | 20 +++++++------------ .../decorations/CHyprGroupBarDecoration.cpp | 8 +++++++- 6 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 5327c599..12e81f2a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -778,6 +778,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:merge_groups_on_groupbar", + .description = "whether one group will be merged with another when dragged into its groupbar", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "general:col.border_active", .description = "border color for inactive windows", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index eafe4cbb..769a7525 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -381,6 +381,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_groups_on_drag", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:merge_groups_on_groupbar", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:merge_floated_into_tiled_on_groupbar", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:auto_group", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:drag_into_group", Hyprlang::INT{1}); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 32f64e4e..e6e9090f 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -310,11 +310,6 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir return; } - if (!m_vOverrideFocalPoint && g_pInputManager->m_bWasDraggingWindow) { - if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) - return; - } - // get the node under our cursor m_lDwindleNodesData.push_back(SDwindleNodeData()); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 980311d6..a312555f 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -344,12 +344,6 @@ void IHyprLayout::onEndDragWindow() { if (pWindow->m_sGroupData.pNextWindow.lock() && DRAGGINGWINDOW->canBeGroupedInto(pWindow) && *PDRAGINTOGROUP == 1 && !FLOATEDINTOTILED) { - if (DRAGGINGWINDOW->m_bDraggingTiled) { - changeWindowFloatingMode(DRAGGINGWINDOW); - DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; - DRAGGINGWINDOW->m_bDraggingTiled = false; - } - if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) { PHLWINDOW next = DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock(); while (next != DRAGGINGWINDOW) { @@ -360,7 +354,9 @@ void IHyprLayout::onEndDragWindow() { } } - DRAGGINGWINDOW->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of the window + DRAGGINGWINDOW->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of the window + DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; + DRAGGINGWINDOW->m_bDraggingTiled = false; if (pWindow->m_bIsFloating) g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index afe79ecf..b8b3efea 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -101,21 +101,15 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire PNODE->workspaceID = pWindow->workspaceID(); PNODE->pWindow = pWindow; - const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID); - static auto PMFACT = CConfigValue("master:mfact"); - float lastSplitPercent = *PMFACT; + const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID); + static auto PMFACT = CConfigValue("master:mfact"); + float lastSplitPercent = *PMFACT; - auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow.lock()) && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? - getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()) : - getMasterNodeOnWorkspace(pWindow->workspaceID()); - - const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); - - if (g_pInputManager->m_bWasDraggingWindow && OPENINGON) { - if (OPENINGON->pWindow->checkInputOnDecos(INPUT_TYPE_DRAG_END, MOUSECOORDS, pWindow)) - return; - } + auto OPENINGON = isWindowTiled(g_pCompositor->m_pLastWindow.lock()) && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? + getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()) : + getMasterNodeOnWorkspace(pWindow->workspaceID()); + const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); eOrientation orientation = getDynamicOrientation(pWindow->m_pWorkspace); const auto NODEIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *PNODE); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index ec9f876b..b5189be5 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -405,10 +405,16 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND static auto PSTACKED = CConfigValue("group:groupbar:stacked"); static auto PDRAGINTOGROUP = CConfigValue("group:drag_into_group"); static auto PMERGEFLOATEDINTOTILEDONGROUPBAR = CConfigValue("group:merge_floated_into_tiled_on_groupbar"); + static auto PMERGEGROUPSONGROUPBAR = CConfigValue("group:merge_groups_on_groupbar"); const bool FLOATEDINTOTILED = !m_pWindow->m_bIsFloating && !pDraggedWindow->m_bDraggingTiled; - if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || (FLOATEDINTOTILED && !*PMERGEFLOATEDINTOTILEDONGROUPBAR)) + g_pInputManager->m_bWasDraggingWindow = false; + + if (!pDraggedWindow->canBeGroupedInto(m_pWindow.lock()) || (*PDRAGINTOGROUP != 1 && *PDRAGINTOGROUP != 2) || (FLOATEDINTOTILED && !*PMERGEFLOATEDINTOTILEDONGROUPBAR) || + (!*PMERGEGROUPSONGROUPBAR && pDraggedWindow->m_sGroupData.pNextWindow.lock() && m_pWindow->m_sGroupData.pNextWindow.lock())) { + g_pInputManager->m_bWasDraggingWindow = true; return false; + } const float BARRELATIVE = *PSTACKED ? pos.y - assignedBoxGlobal().y - (m_fBarHeight + BAR_PADDING_OUTER_VERT) / 2 : pos.x - assignedBoxGlobal().x - m_fBarWidth / 2; const float BARSIZE = *PSTACKED ? m_fBarHeight + BAR_PADDING_OUTER_VERT : m_fBarWidth + BAR_HORIZONTAL_PADDING; From 083a5cf3c1127dd2f638c3e9a665a88dd54a59a4 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 6 Nov 2024 19:50:01 +0200 Subject: [PATCH 0815/2393] CI: update actions --- .github/workflows/ci.yaml | 2 +- .github/workflows/man-update.yaml | 4 ++-- .github/workflows/nix-update-inputs.yml | 4 ++-- .github/workflows/release.yaml | 2 +- .github/workflows/security-checks.yml | 2 +- .github/workflows/stale.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7739d2b2..22421d18 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -39,7 +39,7 @@ jobs: tar -cvf Hyprland.tar.xz hyprland - name: Release - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Build archive path: Hyprland.tar.xz diff --git a/.github/workflows/man-update.yaml b/.github/workflows/man-update.yaml index b47787c0..6c0a72f3 100644 --- a/.github/workflows/man-update.yaml +++ b/.github/workflows/man-update.yaml @@ -17,14 +17,14 @@ jobs: run: sudo apt install pandoc - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.PAT }} - name: Build man pages run: make man - - uses: stefanzweifel/git-auto-commit-action@v4 + - uses: stefanzweifel/git-auto-commit-action@v5 name: Commit with: commit_message: "[gha] build man pages" diff --git a/.github/workflows/nix-update-inputs.yml b/.github/workflows/nix-update-inputs.yml index a8f68f3b..c9a094a2 100644 --- a/.github/workflows/nix-update-inputs.yml +++ b/.github/workflows/nix-update-inputs.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.PAT }} @@ -22,6 +22,6 @@ jobs: run: nix/update-inputs.sh - name: Commit - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: "[gha] Nix: update inputs" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d5ff1aa0..44baff97 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,7 +11,7 @@ jobs: steps: - name: Checkout Hyprland id: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: recursive diff --git a/.github/workflows/security-checks.yml b/.github/workflows/security-checks.yml index 4f539132..284500e6 100644 --- a/.github/workflows/security-checks.yml +++ b/.github/workflows/security-checks.yml @@ -13,7 +13,7 @@ jobs: security-events: write steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Scan with Flawfinder uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index b8be5f55..9d2eed80 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -19,7 +19,7 @@ jobs: pull-requests: write steps: - - uses: actions/stale@v5 + - uses: actions/stale@v9 with: repo-token: ${{ secrets.STALEBOT_PAT }} stale-issue-label: "stale" From 0ec128e5ed5e15aaebff6c4b5983326ab524d690 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 6 Nov 2024 22:11:41 +0000 Subject: [PATCH 0816/2393] renderer: don't rely on datarootdir for local share --- src/render/OpenGL.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index eb0a029f..63a7e822 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -18,6 +18,7 @@ const std::vector ASSET_PATHS = { DATAROOTDIR, #endif "/usr/share", + "/usr/local/share", }; inline void loadGLProc(void* pProc, const char* name) { From 2ec2b3bfb39ba22ba945bb23dc95970dfa50eb5a Mon Sep 17 00:00:00 2001 From: dawsers <47487972+dawsers@users.noreply.github.com> Date: Thu, 7 Nov 2024 00:30:17 +0100 Subject: [PATCH 0817/2393] renderer: minor fixup to window rendering logic (#8359) Don't render animating windows out of their monitor when they are not moving workspaces --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6af3a99d..469acda9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -355,7 +355,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { windowBox.translate(pWindow->m_vFloatingOffset); const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize}; - if (!windowBox.intersection(monitorBox).empty()) + if (!windowBox.intersection(monitorBox).empty() && (pWindow->workspaceID() == pMonitor->activeWorkspaceID() || pWindow->m_iMonitorMovedFrom != -1)) return true; } From 2dd0b2af71b2bd37f1febc608897f56d1eabab4c Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 7 Nov 2024 10:51:48 +0200 Subject: [PATCH 0818/2393] flake.lock: update --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 8cee27e3..b9055015 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1729527199, - "narHash": "sha256-D5/YksfRga8Akd04ZtIkuYSIOjXVrAzQIQBSeplokzU=", + "lastModified": 1730968822, + "narHash": "sha256-NocDjINsh6ismkhb0Xr6xPRksmhuB2WGf8ZmXMhxu7Y=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "8d732fa8aff8b12ef2b1e2f00fc8153e41312b72", + "rev": "a49bc3583ff223f426cb3526fdaa4bcaa247ec14", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1728941256, - "narHash": "sha256-WRypmcZ2Bw94lLmcmxYokVOHPJSZ7T06V49QZ4tkZeQ=", + "lastModified": 1730968903, + "narHash": "sha256-zFvzLXcSm0Ia4XI1SE4FQ9KE63hlGrRWhLtwMolWuR8=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "fd4be8b9ca932f7384e454bcd923c5451ef2aa85", + "rev": "3ce0cde8709cdacbfba471f8e828433b58a561e9", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730531603, - "narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", + "lastModified": 1730785428, + "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", + "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", "type": "github" }, "original": { @@ -205,11 +205,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1720386169, - "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "lastModified": 1730741070, + "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1729104314, - "narHash": "sha256-pZRZsq5oCdJt3upZIU4aslS9XwFJ+/nVtALHIciX/BI=", + "lastModified": 1730814269, + "narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "3c3e88f0f544d6bb54329832616af7eb971b6be6", + "rev": "d70155fdc00df4628446352fc58adc640cd705c2", "type": "github" }, "original": { From e58e97b0a38b8ccc87a4304c9e4e2b37c9966875 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 7 Nov 2024 10:52:12 +0200 Subject: [PATCH 0819/2393] Nix: build aquamarine and hyprutils in debug when using hyprland-debug --- nix/default.nix | 4 +--- nix/overlays.nix | 8 +++++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index d463e271..29d31485 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -56,6 +56,7 @@ adapters = flatten [ stdenvAdapters.useMoldLinker + (lib.optional debug stdenvAdapters.keepDebugInfo) ]; customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters; @@ -147,9 +148,6 @@ in then "debugoptimized" else "release"; - # we want as much debug info as possible - dontStrip = debug; - mesonFlags = flatten [ (mapAttrsToList mesonEnable { "xwayland" = enableXWayland; diff --git a/nix/overlays.nix b/nix/overlays.nix index b1eb66ad..a7106315 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -40,7 +40,13 @@ in { inherit date; }; hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;}; - hyprland-debug = final.hyprland.override {debug = true;}; + + # Build major libs with debug to get as much info as possible in a stacktrace + hyprland-debug = final.hyprland.override { + aquamarine = final.aquamarine.override {debug = true;}; + hyprutils = final.hyprutils.override {debug = true;}; + debug = true; + }; hyprland-legacy-renderer = final.hyprland.override {legacyRenderer = true;}; # deprecated packages From 3b66351eeb76e802bac37cc892529549efc49905 Mon Sep 17 00:00:00 2001 From: nickodei <46863421+nickodei@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:25:37 +0100 Subject: [PATCH 0820/2393] input: Refocus window on scrolling if follows mouse (#8361) --- src/managers/input/InputManager.cpp | 36 ++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index af725927..b12a6e03 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -759,6 +759,7 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { static auto PINPUTSCROLLFACTOR = CConfigValue("input:scroll_factor"); static auto PTOUCHPADSCROLLFACTOR = CConfigValue("input:touchpad:scroll_factor"); static auto PEMULATEDISCRETE = CConfigValue("input:emulate_discrete_scroll"); + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR); @@ -774,24 +775,33 @@ void CInputManager::onMouseWheel(IPointer::SAxisEvent e) { const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); const auto PWINDOW = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); - if (PWINDOW && PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e)) - return; + if (PWINDOW) { + if (PWINDOW->checkInputOnDecos(INPUT_TYPE_AXIS, MOUSECOORDS, e)) + return; - if (PWINDOW && *POFFWINDOWAXIS != 1) { - const auto BOX = PWINDOW->getWindowMainSurfaceBox(); + if (*POFFWINDOWAXIS != 1) { + const auto BOX = PWINDOW->getWindowMainSurfaceBox(); - if (!BOX.containsPoint(MOUSECOORDS) && !PWINDOW->hasPopupAt(MOUSECOORDS)) { - if (*POFFWINDOWAXIS == 0) - return; + if (!BOX.containsPoint(MOUSECOORDS) && !PWINDOW->hasPopupAt(MOUSECOORDS)) { + if (*POFFWINDOWAXIS == 0) + return; - const auto TEMPCURX = std::clamp(MOUSECOORDS.x, BOX.x, BOX.x + BOX.w - 1); - const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1); + const auto TEMPCURX = std::clamp(MOUSECOORDS.x, BOX.x, BOX.x + BOX.w - 1); + const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1); - if (*POFFWINDOWAXIS == 3) - g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true); + if (*POFFWINDOWAXIS == 3) + g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true); - g_pSeatManager->sendPointerMotion(e.timeMs, Vector2D{TEMPCURX, TEMPCURY} - BOX.pos()); - g_pSeatManager->sendPointerFrame(); + g_pSeatManager->sendPointerMotion(e.timeMs, Vector2D{TEMPCURX, TEMPCURY} - BOX.pos()); + g_pSeatManager->sendPointerFrame(); + } + } + + if (g_pSeatManager->state.pointerFocus) { + const auto PCURRWINDOW = g_pCompositor->getWindowFromSurface(g_pSeatManager->state.pointerFocus.lock()); + + if (*PFOLLOWMOUSE == 1 && PCURRWINDOW && PWINDOW != PCURRWINDOW) + simulateMouseMovement(); } } } From 4c7a2faf85a2d74508cc8a95df42ebe52b47383b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 01:53:01 +0000 Subject: [PATCH 0821/2393] input: cleanup device naming logic ref #8301 --- src/devices/IHID.hpp | 2 +- src/devices/IKeyboard.hpp | 1 - src/devices/IPointer.hpp | 1 - src/devices/ITouch.hpp | 1 - src/devices/Tablet.hpp | 5 ----- src/managers/input/InputManager.cpp | 27 ++++----------------------- src/managers/input/Tablets.cpp | 6 ++++++ 7 files changed, 11 insertions(+), 32 deletions(-) diff --git a/src/devices/IHID.hpp b/src/devices/IHID.hpp index cac25112..4a0ff8fd 100644 --- a/src/devices/IHID.hpp +++ b/src/devices/IHID.hpp @@ -36,5 +36,5 @@ class IHID { CSignal destroy; } events; - std::string deviceName; + std::string deviceName, hlName; }; \ No newline at end of file diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index 76d2c31b..dce2127a 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -94,7 +94,6 @@ class IKeyboard : public IHID { std::array modIndexes = {XKB_MOD_INVALID}; uint32_t leds = 0; - std::string hlName = ""; std::string xkbFilePath = ""; std::string xkbKeymapString = ""; int xkbKeymapFD = -1; diff --git a/src/devices/IPointer.hpp b/src/devices/IPointer.hpp index f38ef55a..503a690e 100644 --- a/src/devices/IPointer.hpp +++ b/src/devices/IPointer.hpp @@ -104,7 +104,6 @@ class IPointer : public IHID { CSignal holdEnd; } pointerEvents; - std::string hlName; bool connected = false; // means connected to the cursor std::string boundOutput = ""; diff --git a/src/devices/ITouch.hpp b/src/devices/ITouch.hpp index bf969b2f..766c0510 100644 --- a/src/devices/ITouch.hpp +++ b/src/devices/ITouch.hpp @@ -44,7 +44,6 @@ class ITouch : public IHID { CSignal frame; } touchEvents; - std::string hlName = ""; std::string boundOutput = ""; WP self; diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index 01901721..4894ac8e 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -92,7 +92,6 @@ class CTablet : public IHID { WP self; bool relativeInput = false; - std::string hlName = ""; std::string boundOutput = ""; CBox activeArea; CBox boundBox; // output-local @@ -154,8 +153,6 @@ class CTabletPad : public IHID { WP self; WP parent; - std::string hlName; - private: CTabletPad(SP pad); @@ -210,8 +207,6 @@ class CTabletTool : public IHID { std::vector buttonsDown; Vector2D absolutePos; // last known absolute position. - std::string hlName; - private: CTabletTool(SP tool); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index b12a6e03..2787cbf7 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1655,31 +1655,12 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) { auto proposedNewName = deviceNameToInternalString(internalName); int dupeno = 0; - while (std::find_if(m_vKeyboards.begin(), m_vKeyboards.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vKeyboards.end()) + auto makeNewName = [&]() { return (proposedNewName.empty() ? "unknown-device" : proposedNewName) + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }; + + while (std::find_if(m_vHIDs.begin(), m_vHIDs.end(), [&](const auto& other) { return other->hlName == makeNewName(); }) != m_vHIDs.end()) dupeno++; - while (std::find_if(m_vPointers.begin(), m_vPointers.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vPointers.end()) - dupeno++; - - while (std::find_if(m_vTouches.begin(), m_vTouches.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTouches.end()) - dupeno++; - - while (std::find_if(m_vTabletPads.begin(), m_vTabletPads.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletPads.end()) - dupeno++; - - while (std::find_if(m_vTablets.begin(), m_vTablets.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTablets.end()) - dupeno++; - - while (std::find_if(m_vTabletTools.begin(), m_vTabletTools.end(), - [&](const auto& other) { return other->hlName == proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }) != m_vTabletTools.end()) - dupeno++; - - return proposedNewName + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); + return makeNewName(); } void CInputManager::releaseAllMouseButtons() { diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 9f80726e..3884afec 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -228,6 +228,12 @@ SP CInputManager::ensureTabletToolPresent(SPhlName = deviceNameToInternalString(pTool->getName()); + } catch (std::exception& e) { + Debug::log(ERR, "Tablet had no name???"); // logic error + } + PTOOL->events.destroy.registerStaticListener( [this](void* owner, std::any d) { auto TOOL = ((CTabletTool*)owner)->self; From f43d4a86383bc8a8251987552ad5a0e51dd85868 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 02:25:34 +0000 Subject: [PATCH 0822/2393] layershell: minor cleanups and improvements to focus ref #8293 --- src/desktop/LayerSurface.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index eb3cdfd2..31c2482a 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -222,7 +222,7 @@ void CLayerSurface::onUnmap() { const auto PMONITOR = monitor.lock(); - const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); + const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == surface->resource() || g_pSeatManager->state.pointerFocus == surface->resource(); if (!PMONITOR) return; @@ -231,7 +231,7 @@ void CLayerSurface::onUnmap() { // vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window if (WASLASTFOCUS || (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus->hlSurface && !g_pCompositor->m_pLastFocus->hlSurface->keyboardFocusable())) g_pInputManager->refocusLastWindow(PMONITOR); - else if (g_pCompositor->m_pLastFocus) + else if (g_pCompositor->m_pLastFocus && g_pCompositor->m_pLastFocus != surface->resource()) g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; @@ -320,8 +320,15 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (mapped) { - const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); + if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { + bool WASLASTFOCUS = false; + layerSurface->surface->breadthfirst( + [&WASLASTFOCUS](SP surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; }, + nullptr); + if (!WASLASTFOCUS && popupHead) { + popupHead->breadthfirst([&WASLASTFOCUS](CPopup* popup, void* data) { WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); }, + nullptr); + } const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; @@ -331,11 +338,13 @@ void CLayerSurface::onCommit() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); // if the surface was focused and interactive but now isn't, refocus - if (WASLASTFOCUS && !layerSurface->current.interactivity) { + if (WASLASTFOCUS && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) { // moveMouseUnified won't focus non interactive layers but it won't unfocus them either, // so unfocus the surface here. g_pCompositor->focusSurface(nullptr); g_pInputManager->refocusLastWindow(monitor.lock()); + } else if (WASLASTFOCUS && WASEXCLUSIVE && layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + g_pInputManager->simulateMouseMovement(); } else if (!WASEXCLUSIVE && ISEXCLUSIVE) { // if now exclusive and not previously g_pSeatManager->setGrab(nullptr); From 0ccc0ace88fab3969c2eca95deb1cc9b2ac0d16d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 02:25:54 +0000 Subject: [PATCH 0823/2393] input: ignore non-kb ls-es in refocusLastWindow ref #8293 --- src/managers/input/InputManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 2787cbf7..c190f589 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1388,13 +1388,19 @@ void CInputManager::refocusLastWindow(PHLMONITOR pMonitor) { foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource(); // then any surfaces above windows on the same monitor - if (!foundSurface) + if (!foundSurface) { foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &surfaceCoords, &pFoundLayerSurface); + if (pFoundLayerSurface && pFoundLayerSurface->interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) + foundSurface = nullptr; + } - if (!foundSurface) + if (!foundSurface) { foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); + if (pFoundLayerSurface && pFoundLayerSurface->interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) + foundSurface = nullptr; + } if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisibleNotCovered(g_pCompositor->m_pLastWindow->m_pWorkspace)) { // then the last focused window if we're on the same workspace as it From 726d69782124ffb5b609c0377cd21cfd4d6f6f88 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 02:26:24 +0000 Subject: [PATCH 0824/2393] popup: minor cleanups don't iterate over unmapped popups in breadthfirst, don't refocus if it wasnt in focus ref #8293 --- src/desktop/Popup.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 58995f00..ea6e877b 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -4,6 +4,8 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" +#include "../managers/SeatManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { @@ -106,6 +108,8 @@ void CPopup::onUnmap() { return; } + m_bMapped = false; + m_vLastSize = m_pResource->surface->surface->current.size; const auto COORDS = coordsGlobal(); @@ -116,8 +120,6 @@ void CPopup::onUnmap() { m_pSubsurfaceHead.reset(); - g_pInputManager->simulateMouseMovement(); - if (!m_pLayerOwner.expired() && m_pLayerOwner->layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP) g_pHyprOpenGL->markBlurDirtyForMonitor(g_pCompositor->getMonitorFromID(m_pLayerOwner->layer)); @@ -131,6 +133,11 @@ void CPopup::onUnmap() { g_pHyprRenderer->damageBox(&box); }, nullptr); + + const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource(); + + if (WASLASTFOCUS) + g_pInputManager->simulateMouseMovement(); } void CPopup::onCommit(bool ignoreSiblings) { @@ -317,7 +324,7 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); for (auto const& p : popups | std::views::reverse) { - if (!p->m_pResource) + if (!p->m_pResource || !p->m_bMapped) continue; if (!allowsInput) { From b9c439a55e5ecef563657da211bc10ddc3273a1c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 02:27:01 +0000 Subject: [PATCH 0825/2393] compositor: make sure we don't ret early on no surface if there is no implicit surface passed, make sure the current focus is not null, otherwise we nope early without focusing the window fixes #8293 --- src/Compositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 495a2d85..da20c5cf 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1062,7 +1062,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface return; } - if (m_pLastWindow.lock() == pWindow && g_pSeatManager->state.keyboardFocus == pSurface) + if (m_pLastWindow.lock() == pWindow && g_pSeatManager->state.keyboardFocus == pSurface && g_pSeatManager->state.keyboardFocus) return; if (pWindow->m_bPinned) From cca227a53e10b9101d2fbcfb99e6360b416d7168 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 02:34:04 +0000 Subject: [PATCH 0826/2393] tablet: use inputMgr unified naming scheme ref #8301 --- src/desktop/LayerSurface.cpp | 7 +++++-- src/managers/input/Tablets.cpp | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 31c2482a..cd1c4742 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -326,8 +326,11 @@ void CLayerSurface::onCommit() { [&WASLASTFOCUS](SP surf, const Vector2D& offset, void* data) { WASLASTFOCUS = WASLASTFOCUS || g_pSeatManager->state.keyboardFocus == surf; }, nullptr); if (!WASLASTFOCUS && popupHead) { - popupHead->breadthfirst([&WASLASTFOCUS](CPopup* popup, void* data) { WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); }, - nullptr); + popupHead->breadthfirst( + [&WASLASTFOCUS](CPopup* popup, void* data) { + WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); + }, + nullptr); } const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 3884afec..36bd5636 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -201,7 +201,7 @@ void CInputManager::newTablet(SP pDevice) { m_vHIDs.push_back(PNEWTABLET); try { - PNEWTABLET->hlName = deviceNameToInternalString(pDevice->getName()); + PNEWTABLET->hlName = g_pInputManager->getNameForNewDevice(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Tablet had no name???"); // logic error } @@ -229,7 +229,7 @@ SP CInputManager::ensureTabletToolPresent(SPhlName = deviceNameToInternalString(pTool->getName()); + PTOOL->hlName = g_pInputManager->getNameForNewDevice(pTool->getName()); } catch (std::exception& e) { Debug::log(ERR, "Tablet had no name???"); // logic error } @@ -249,7 +249,7 @@ void CInputManager::newTabletPad(SP pDevice) { m_vHIDs.push_back(PNEWPAD); try { - PNEWPAD->hlName = deviceNameToInternalString(pDevice->getName()); + PNEWPAD->hlName = g_pInputManager->getNameForNewDevice(pDevice->getName()); } catch (std::exception& e) { Debug::log(ERR, "Pad had no name???"); // logic error } From a425fbebe4cf4238e48a42f724ef2208959d66cf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 14:27:47 +0000 Subject: [PATCH 0827/2393] version: bump to 0.45.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a8ab6c96..bcce5d06 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.44.0 +0.45.0 From dca75db127fedc58fc85ae0e6e47162e3d5d16f9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 16:56:43 +0000 Subject: [PATCH 0828/2393] defaultConfig: fixup smart gaps rules --- example/hyprland.conf | 9 +++------ src/config/defaultConfig.hpp | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index edeeac01..fe1a831a 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -136,13 +136,10 @@ animations { # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ # "Smart gaps" / "No gaps when only" # uncomment all if you wish to use that. -# workspace = w[t1], gapsout:0, gapsin:0 -# workspace = w[tg1], gapsout:0, gapsin:0 +# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0 -# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1] -# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1] -# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1] -# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1] diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index 02781770..d680e92b 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -149,13 +149,10 @@ animations { # Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ # "Smart gaps" / "No gaps when only" # uncomment all if you wish to use that. -# workspace = w[t1], gapsout:0, gapsin:0 -# workspace = w[tg1], gapsout:0, gapsin:0 +# workspace = w[tv1], gapsout:0, gapsin:0 # workspace = f[1], gapsout:0, gapsin:0 -# windowrulev2 = bordersize 0, floating:0, onworkspace:w[t1] -# windowrulev2 = rounding 0, floating:0, onworkspace:w[t1] -# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tg1] -# windowrulev2 = rounding 0, floating:0, onworkspace:w[tg1] +# windowrulev2 = bordersize 0, floating:0, onworkspace:w[tv1] +# windowrulev2 = rounding 0, floating:0, onworkspace:w[tv1] # windowrulev2 = bordersize 0, floating:0, onworkspace:f[1] # windowrulev2 = rounding 0, floating:0, onworkspace:f[1] From a8ff3a452c1c445d24bdd9e7e4fcd66c8ef2a147 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 9 Nov 2024 17:11:38 +0000 Subject: [PATCH 0829/2393] core: move to os/Process from hyprutils nix bump too --- CMakeLists.txt | 2 +- flake.lock | 6 +++--- hyprpm/CMakeLists.txt | 2 +- hyprpm/src/core/PluginManager.cpp | 19 ++++++++----------- src/helpers/MiscFunctions.cpp | 20 ++++++++------------ 5 files changed, 21 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 877ba461..1ac2e10f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ else() endif() find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) -pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1) +pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2) diff --git a/flake.lock b/flake.lock index b9055015..47254052 100644 --- a/flake.lock +++ b/flake.lock @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1730968903, - "narHash": "sha256-zFvzLXcSm0Ia4XI1SE4FQ9KE63hlGrRWhLtwMolWuR8=", + "lastModified": 1731163338, + "narHash": "sha256-Qflei0JBeqQ0c8jxA8e982xAxJvfMwfx4Aci2eJi84s=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "3ce0cde8709cdacbfba471f8e828433b58a561e9", + "rev": "60d3dece30f98e8ad85131829c8529950630d6bc", "type": "github" }, "original": { diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index 692e8da1..65935638 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -9,7 +9,7 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") set(CMAKE_CXX_STANDARD 23) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4) add_executable(hyprpm ${SRCFILES}) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 57c67641..159b9cd6 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -23,22 +23,19 @@ #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; - std::array buffer; - std::string result; - using PcloseType = int (*)(FILE*); - const std::unique_ptr pipe(popen(cmd.c_str(), "r"), static_cast(pclose)); - if (!pipe) - return ""; - result.reserve(buffer.size()); - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { - result += buffer.data(); - } - return result; + CProcess proc("/bin/sh", {cmd}); + + if (!proc.runSync()) + return "error"; + + return proc.stdOut(); } SHyprlandVersion CPluginManager::getHyprlandVersion() { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 878f5ca1..75154796 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -17,7 +17,9 @@ #include #endif #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include @@ -583,18 +585,12 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve // Execute a shell command and get the output std::string execAndGet(const char* cmd) { - std::array buffer; - std::string result; - using PcloseType = int (*)(FILE*); - const std::unique_ptr pipe(popen(cmd, "r"), static_cast(pclose)); - if (!pipe) { - Debug::log(ERR, "execAndGet: failed in pipe"); - return ""; - } - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { - result += buffer.data(); - } - return result; + CProcess proc("/bin/sh", {cmd}); + + if (!proc.runSync()) + return "error"; + + return proc.stdOut(); } void logSystemInfo() { From 99b01c5d124d08648d4c9e6754485ea585c42707 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 10 Nov 2024 15:54:00 +0000 Subject: [PATCH 0830/2393] hyprpm: fix format --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 159b9cd6..ef77f540 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -31,7 +31,7 @@ static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; CProcess proc("/bin/sh", {cmd}); - + if (!proc.runSync()) return "error"; From 9e628067fc54851dc9138c2882abb21f72c5a5a6 Mon Sep 17 00:00:00 2001 From: WavyEbuilder Date: Sun, 10 Nov 2024 15:54:15 +0000 Subject: [PATCH 0831/2393] debug: clean up opening of files in HyprCtl (#8401) `std::ifstream` is more suited than `execAndGet` here. --- src/debug/HyprCtl.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 3e0c75a6..709d8b69 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1,6 +1,7 @@ #include "HyprCtl.hpp" #include +#include #include #include #include @@ -949,11 +950,27 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif result += "GPU information: \n" + GPUINFO; - if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) - result += execAndGet("cat /proc/driver/nvidia/version | grep NVRM"); + if (GPUINFO.contains("NVIDIA") && std::filesystem::exists("/proc/driver/nvidia/version")) { + std::ifstream file("/proc/driver/nvidia/version"); + std::string line; + if (file.is_open()) { + while (std::getline(file, line)) { + if (!line.contains("NVRM")) + continue; + result += line; + result += "\n"; + } + } else + result += "error"; + } result += "\n\n"; - result += "os-release: " + execAndGet("cat /etc/os-release") + "\n\n"; + if (std::ifstream file("/etc/os-release"); file.is_open()) { + std::stringstream buffer; + buffer << file.rdbuf(); + result += "os-release: " + buffer.str() + "\n\n"; + } else + result += "os-release: error\n\n"; result += "plugins:\n"; if (g_pPluginSystem) { From c10739e6e35c30ef5f273bfe5d219d361a31e226 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 10 Nov 2024 22:53:11 +0000 Subject: [PATCH 0832/2393] core: fixup execAndGet fixes #8410 --- hyprpm/src/core/PluginManager.cpp | 2 +- src/helpers/MiscFunctions.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index ef77f540..051ad500 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -30,7 +30,7 @@ using namespace Hyprutils::OS; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; - CProcess proc("/bin/sh", {cmd}); + CProcess proc("/bin/sh", {"-c", cmd}); if (!proc.runSync()) return "error"; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 75154796..7b4d63a7 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -585,7 +585,7 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve // Execute a shell command and get the output std::string execAndGet(const char* cmd) { - CProcess proc("/bin/sh", {cmd}); + CProcess proc("/bin/sh", {"-c", cmd}); if (!proc.runSync()) return "error"; From 1fa0cd7a7574c8e93c567bf0453c155285dd3960 Mon Sep 17 00:00:00 2001 From: WavyEbuilder Date: Mon, 11 Nov 2024 13:44:41 +0000 Subject: [PATCH 0833/2393] debug: clean up fetching of the contents of /proc/device-tree (#8413) --- src/debug/HyprCtl.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 709d8b69..6429e781 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1,7 +1,9 @@ #include "HyprCtl.hpp" +#include #include #include +#include #include #include #include @@ -945,7 +947,24 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); #elif defined(__arm__) || defined(__aarch64__) - const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); + std::string GPUINFO; + const std::filesystem::path dev_tree = "/proc/device-tree"; + try { + if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) { + std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) { + if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) { + std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) { + if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) { + std::filesystem::path file_path = sub_entry.path() / "compatible"; + std::ifstream file(file_path); + if (file) + GPUINFO.append(std::istreambuf_iterator(file), std::istreambuf_iterator()); + } + }); + } + }); + } + } catch (...) { GPUINFO = "error"; } #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif From 07052a515bea46e8b01d3ca5b2c284c272c5ed34 Mon Sep 17 00:00:00 2001 From: JManch <61563764+JManch@users.noreply.github.com> Date: Mon, 11 Nov 2024 13:45:33 +0000 Subject: [PATCH 0834/2393] pointer: map devices across all outputs by default (#8352) --- src/config/ConfigDescriptions.hpp | 10 +++- src/config/ConfigManager.cpp | 2 + src/devices/Tablet.hpp | 3 +- src/devices/VirtualPointer.cpp | 2 +- src/managers/PointerManager.cpp | 76 ++++++++++++++--------------- src/managers/input/InputManager.cpp | 3 ++ 6 files changed, 53 insertions(+), 43 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 12e81f2a..fde8173d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -620,16 +620,22 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "input:tablet:output", - .description = "the monitor to bind tablets. Empty means unbound..", + .description = "the monitor to bind tablets. Can be current or a monitor name. Leave empty to map across all monitors.", .type = CONFIG_OPTION_STRING_SHORT, .data = SConfigOptionDescription::SStringData{""}, //##TODO UNSET? }, SConfigOptionDescription{ .value = "input:tablet:region_position", - .description = "position of the mapped region in monitor layout.", + .description = "position of the mapped region in monitor layout relative to the top left corner of the bound monitor or all monitors.", .type = CONFIG_OPTION_VECTOR, .data = SConfigOptionDescription::SVectorData{{}, {-20000, -20000}, {20000, 20000}}, }, + SConfigOptionDescription{ + .value = "input:tablet:absolute_region_position", + .description = "whether to treat the region_position as an absolute position in monitor layout. Only applies when output is empty.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, SConfigOptionDescription{ .value = "input:tablet:region_size", .description = "size of the mapped region. When this variable is set, tablet input will be mapped to the region. [0, 0] or invalid size means unset.", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 769a7525..fbbc8dbd 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -516,6 +516,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("input:tablet:transform", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:tablet:output", {STRVAL_EMPTY}); m_pConfig->addConfigValue("input:tablet:region_position", Hyprlang::VEC2{0, 0}); + m_pConfig->addConfigValue("input:tablet:absolute_region_position", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:tablet:region_size", Hyprlang::VEC2{0, 0}); m_pConfig->addConfigValue("input:tablet:relative_input", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:tablet:left_handed", Hyprlang::INT{0}); @@ -625,6 +626,7 @@ CConfigManager::CConfigManager() { m_pConfig->addSpecialConfigValue("device", "output", {STRVAL_EMPTY}); m_pConfig->addSpecialConfigValue("device", "enabled", Hyprlang::INT{1}); // only for mice, touchpads, and touchdevices m_pConfig->addSpecialConfigValue("device", "region_position", Hyprlang::VEC2{0, 0}); // only for tablets + m_pConfig->addSpecialConfigValue("device", "absolute_region_position", Hyprlang::INT{0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "region_size", Hyprlang::VEC2{0, 0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "relative_input", Hyprlang::INT{0}); // only for tablets m_pConfig->addSpecialConfigValue("device", "active_area_position", Hyprlang::VEC2{0, 0}); // only for tablets diff --git a/src/devices/Tablet.hpp b/src/devices/Tablet.hpp index 4894ac8e..8f49c984 100644 --- a/src/devices/Tablet.hpp +++ b/src/devices/Tablet.hpp @@ -92,9 +92,10 @@ class CTablet : public IHID { WP self; bool relativeInput = false; + bool absolutePos = false; std::string boundOutput = ""; CBox activeArea; - CBox boundBox; // output-local + CBox boundBox; private: CTablet(SP tablet); diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 7ad18775..514c8c32 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -38,7 +38,7 @@ CVirtualPointer::CVirtualPointer(SP resource) : point listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); }); listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); }); - boundOutput = resource->boundOutput ? resource->boundOutput->szName : "entire"; + boundOutput = resource->boundOutput ? resource->boundOutput->szName : ""; deviceName = pointer->name; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index b309ba82..75be235f 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -668,9 +668,7 @@ void CPointerManager::move(const Vector2D& deltaLogical) { } void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { - - PHLMONITOR currentMonitor = g_pCompositor->m_pLastMonitor.lock(); - if (!currentMonitor || !dev) + if (!dev) return; if (!std::isnan(abs.x)) @@ -678,20 +676,44 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { if (!std::isnan(abs.y)) abs.y = std::clamp(abs.y, 0.0, 1.0); - // in logical global - CBox mappedArea = currentMonitor->logicalBox(); + // find x and y size of the entire space + const auto& MONITORS = g_pCompositor->m_vMonitors; + Vector2D topLeft = MONITORS.at(0)->vecPosition, bottomRight = MONITORS.at(0)->vecPosition + MONITORS.at(0)->vecSize; + for (size_t i = 1; i < MONITORS.size(); ++i) { + const auto EXTENT = MONITORS[i]->logicalBox().extent(); + const auto POS = MONITORS[i]->logicalBox().pos(); + if (EXTENT.x > bottomRight.x) + bottomRight.x = EXTENT.x; + if (EXTENT.y > bottomRight.y) + bottomRight.y = EXTENT.y; + if (POS.x < topLeft.x) + topLeft.x = POS.x; + if (POS.y < topLeft.y) + topLeft.y = POS.y; + } + CBox mappedArea = {topLeft, bottomRight - topLeft}; + + auto outputMappedArea = [&mappedArea](const std::string& output) { + if (output == "current") { + if (const auto PLASTMONITOR = g_pCompositor->m_pLastMonitor.lock(); PLASTMONITOR) + return PLASTMONITOR->logicalBox(); + } else if (const auto PMONITOR = g_pCompositor->getMonitorFromString(output); PMONITOR) + return PMONITOR->logicalBox(); + return mappedArea; + }; switch (dev->getType()) { case HID_TYPE_TABLET: { CTablet* TAB = reinterpret_cast(dev.get()); if (!TAB->boundOutput.empty()) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TAB->boundOutput); PMONITOR) { - currentMonitor = PMONITOR->self.lock(); - mappedArea = currentMonitor->logicalBox(); - } - } + mappedArea = outputMappedArea(TAB->boundOutput); + mappedArea.translate(TAB->boundBox.pos()); + } else if (TAB->absolutePos) { + mappedArea.x = TAB->boundBox.x; + mappedArea.y = TAB->boundBox.y; + } else + mappedArea.translate(TAB->boundBox.pos()); - mappedArea.translate(TAB->boundBox.pos()); if (!TAB->boundBox.empty()) { mappedArea.w = TAB->boundBox.w; mappedArea.h = TAB->boundBox.h; @@ -700,38 +722,14 @@ void CPointerManager::warpAbsolute(Vector2D abs, SP dev) { } case HID_TYPE_TOUCH: { ITouch* TOUCH = reinterpret_cast(dev.get()); - if (!TOUCH->boundOutput.empty()) { - if (const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput); PMONITOR) { - currentMonitor = PMONITOR->self.lock(); - mappedArea = currentMonitor->logicalBox(); - } - } + if (!TOUCH->boundOutput.empty()) + mappedArea = outputMappedArea(TOUCH->boundOutput); break; } case HID_TYPE_POINTER: { IPointer* POINTER = reinterpret_cast(dev.get()); - if (!POINTER->boundOutput.empty()) { - if (POINTER->boundOutput == "entire") { - // find x and y size of the entire space - Vector2D bottomRight = {-9999999, -9999999}, topLeft = {9999999, 9999999}; - for (auto const& m : g_pCompositor->m_vMonitors) { - const auto EXTENT = m->logicalBox().extent(); - const auto POS = m->logicalBox().pos(); - if (EXTENT.x > bottomRight.x) - bottomRight.x = EXTENT.x; - if (EXTENT.y > bottomRight.y) - bottomRight.y = EXTENT.y; - if (POS.x < topLeft.x) - topLeft.x = POS.x; - if (POS.y < topLeft.y) - topLeft.y = POS.y; - } - mappedArea = {topLeft, bottomRight - topLeft}; - } else if (const auto PMONITOR = g_pCompositor->getMonitorFromString(POINTER->boundOutput); PMONITOR) { - currentMonitor = PMONITOR->self.lock(); - mappedArea = currentMonitor->logicalBox(); - } - } + if (!POINTER->boundOutput.empty()) + mappedArea = outputMappedArea(POINTER->boundOutput); break; } default: break; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index c190f589..9110cd15 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1595,6 +1595,9 @@ void CInputManager::setTabletConfigs() { const auto REGION_SIZE = g_pConfigManager->getDeviceVec(NAME, "region_size", "input:tablet:region_size"); t->boundBox = {REGION_POS, REGION_SIZE}; + const auto ABSOLUTE_REGION_POS = g_pConfigManager->getDeviceInt(NAME, "absolute_region_position", "input:tablet:absolute_region_position"); + t->absolutePos = ABSOLUTE_REGION_POS; + const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(NAME, "active_area_size", "input:tablet:active_area_size"); const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(NAME, "active_area_position", "input:tablet:active_area_position"); if (ACTIVE_AREA_SIZE.x != 0 || ACTIVE_AREA_SIZE.y != 0) { From a551f85b9129eac76a5f295ecfe4fb39f96f435c Mon Sep 17 00:00:00 2001 From: dawsers <47487972+dawsers@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:48:50 +0100 Subject: [PATCH 0835/2393] renderer: scaled surfaces could have zero area (#8423) --- src/render/Renderer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 469acda9..d98e32a9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -222,6 +222,11 @@ static void renderSurface(SP surface, int x, int y, void* da windowBox.height = RDATA->h - y; } + const auto PROJSIZEUNSCALED = windowBox.size(); + + windowBox.scale(RDATA->pMonitor->scale); + windowBox.round(); + if (windowBox.width <= 1 || windowBox.height <= 1) { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { Debug::log(TRACE, "presentFeedback for invisible surface"); @@ -231,11 +236,6 @@ static void renderSurface(SP surface, int x, int y, void* da return; // invisible } - const auto PROJSIZEUNSCALED = windowBox.size(); - - windowBox.scale(RDATA->pMonitor->scale); - windowBox.round(); - const bool MISALIGNEDFSV1 = std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && windowBox.size() != surface->current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, surface->current.bufferSize.x, 3) && DELTALESSTHAN(windowBox.height, surface->current.bufferSize.y, 3) /* off by one-or-two */ && From 8fa4cfb7dfa0be52a66db5f3b13e0ecde3d78b41 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 11 Nov 2024 13:55:32 +0000 Subject: [PATCH 0836/2393] keybinds: don't animate fullscreen size/pos changes coming in when fullscreen, don't animate the pos/size when switching to another fullscreen window, as they can look weird and distracting. Ideally we would do it differently but it's not really possible to do well without reading minds --- src/managers/KeybindManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 5be6a1d9..f2fdab53 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -338,6 +338,10 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); + + // warp the position + size animation, otherwise it looks weird. + PWINDOWTOCHANGETO->m_vRealPosition.warp(); + PWINDOWTOCHANGETO->m_vRealSize.warp(); } else { updateRelativeCursorCoords(); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); @@ -2110,6 +2114,10 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { if (FSWINDOW != PWINDOW && !PWINDOW->m_bPinned) g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE); + + // warp the position + size animation, otherwise it looks weird. + PWINDOW->m_vRealPosition.warp(); + PWINDOW->m_vRealSize.warp(); } } else g_pCompositor->focusWindow(PWINDOW); From 430b5c302a358faf888a015a7a7009a824e62d99 Mon Sep 17 00:00:00 2001 From: izmyname <135810812+izmyname@users.noreply.github.com> Date: Thu, 7 Nov 2024 20:35:01 +0500 Subject: [PATCH 0837/2393] systemd: hyprland-systemd.desktop -> hyprland-uwsm.desktop Remove hyprland-session.service. --- systemd/hyprland-systemd.desktop | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/systemd/hyprland-systemd.desktop b/systemd/hyprland-systemd.desktop index 64ebbd47..2ed1031b 100644 --- a/systemd/hyprland-systemd.desktop +++ b/systemd/hyprland-systemd.desktop @@ -1,7 +1,6 @@ [Desktop Entry] -Name=Hyprland (systemd session) +Name=Hyprland (uwsm-managed) Comment=An intelligent dynamic tiling Wayland compositor -Exec=systemctl --user start --wait hyprland-session -Type=Application +Exec=uwsm start -N Hyprland -D Hyprland -C An_intelligent_dynamic_tiling_Wayland_compositor -- Hyprland DesktopNames=Hyprland -Keywords=tiling;wayland;compositor; +Type=Application From ccfae82ad1c1a97d06efe980d6ba0dd72be4116c Mon Sep 17 00:00:00 2001 From: Izmyname Date: Thu, 7 Nov 2024 21:01:12 +0500 Subject: [PATCH 0838/2393] rename hyprland-systemd.desktop and remove hyprland-session.service --- CMakeLists.txt | 10 ++-------- systemd/hyprland-session.service.in | 16 ---------------- ...and-systemd.desktop => hyprland-uwsm.desktop} | 0 systemd/meson.build | 14 +------------- 4 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 systemd/hyprland-session.service.in rename systemd/{hyprland-systemd.desktop => hyprland-uwsm.desktop} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ac2e10f..d337680f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,16 +222,10 @@ if(NO_SYSTEMD) else() message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...") add_compile_definitions(USES_SYSTEMD) - configure_file(systemd/hyprland-session.service.in - systemd/hyprland-session.service @ONLY) - # session file -systemd - install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-systemd.desktop + # session file -uwsm + install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) - - # install systemd service - install(FILES ${CMAKE_BINARY_DIR}/systemd/hyprland-session.service - DESTINATION ${CMAKE_INSTALL_LIBDIR}/systemd/user) endif() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) diff --git a/systemd/hyprland-session.service.in b/systemd/hyprland-session.service.in deleted file mode 100644 index dafdc141..00000000 --- a/systemd/hyprland-session.service.in +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Hyprland - Tiling compositor with the looks -Documentation=man:Hyprland(1) -BindsTo=graphical-session.target -Before=graphical-session.target -Wants=xdg-desktop-autostart.target -Wants=graphical-session-pre.target -After=graphical-session-pre.target - -[Service] -Type=notify -ExecStart=@PREFIX@/@BINDIR@/Hyprland -ExecStop=@PREFIX@/@BINDIR@/hyprctl dispatch exit -ExecStopPost=systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP -Restart=on-failure -Slice=session.slice diff --git a/systemd/hyprland-systemd.desktop b/systemd/hyprland-uwsm.desktop similarity index 100% rename from systemd/hyprland-systemd.desktop rename to systemd/hyprland-uwsm.desktop diff --git a/systemd/meson.build b/systemd/meson.build index 2cd5312a..731f04e3 100644 --- a/systemd/meson.build +++ b/systemd/meson.build @@ -1,17 +1,5 @@ install_data( - 'hyprland-systemd.desktop', + 'hyprland-uwsm.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime', ) - -conf_data = configuration_data() -conf_data.set('PREFIX', get_option('prefix')) -conf_data.set('BINDIR', get_option('bindir')) -user_unit_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir', - pkgconfig_define: ['prefix', get_option('prefix')]) - -configure_file( - configuration: conf_data, - input: 'hyprland-session.service.in', - output: '@BASENAME@', - install_dir: user_unit_dir ) From 943c7d18cc7c9300e1a6b4b859558b8c7ac540cd Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 11 Nov 2024 09:36:15 +0200 Subject: [PATCH 0839/2393] meson: autodetect systemd --- meson.build | 8 ++++++-- nix/default.nix | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 76765645..e4abad36 100644 --- a/meson.build +++ b/meson.build @@ -52,8 +52,12 @@ backtrace_dep = cpp_compiler.find_library('execinfo', required: false) epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs # Handle options -if get_option('systemd').enabled() - systemd = dependency('systemd') +systemd_option = get_option('systemd') +systemd = dependency('systemd', required: systemd_option) +systemd_option.enable_auto_if(systemd.found()) + +if (systemd_option.enabled()) + message('Enabling systemd integration') add_project_arguments('-DUSES_SYSTEMD', language: 'cpp') subdir('systemd') endif diff --git a/nix/default.nix b/nix/default.nix index 29d31485..90c92272 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -152,7 +152,6 @@ in (mapAttrsToList mesonEnable { "xwayland" = enableXWayland; "legacy_renderer" = legacyRenderer; - "systemd" = withSystemd; }) (mapAttrsToList mesonBool { "b_pch" = false; From ff411658e8b217cadf69887f7313d6fd2fc417f2 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 11 Nov 2024 10:05:01 +0200 Subject: [PATCH 0840/2393] Lock uwsm desktop file behind feature flag The file in the repo cannot be used in NixOS due to missing full paths, and the fact that `uwsm` does not have access to `PATH` to find the listed binaries. Might be useful in other situations as well. --- CMakeLists.txt | 9 +++++++-- meson_options.txt | 1 + systemd/meson.build | 12 +++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d337680f..117932d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,8 +224,13 @@ else() add_compile_definitions(USES_SYSTEMD) # session file -uwsm - install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + if(NO_UWSM) + message(STATUS "UWSM support is disabled...") + else() + message(STATUS "UWSM support is enabled (NO_UWSM not defined)...") + install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) + endif() endif() set(CPACK_PROJECT_NAME ${PROJECT_NAME}) diff --git a/meson_options.txt b/meson_options.txt index d8c9d5e6..9b64fb32 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,5 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') +option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') diff --git a/systemd/meson.build b/systemd/meson.build index 731f04e3..bc62e95a 100644 --- a/systemd/meson.build +++ b/systemd/meson.build @@ -1,5 +1,7 @@ -install_data( - 'hyprland-uwsm.desktop', - install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), - install_tag: 'runtime', -) +if (get_option('uwsm').allowed()) + install_data( + 'hyprland-uwsm.desktop', + install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), + install_tag: 'runtime', + ) +endif From b88e4a1a9a8a240d54a5006b35964c9e02f86f6b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 11 Nov 2024 10:15:58 +0200 Subject: [PATCH 0841/2393] Nix: disable uwsm desktop file installation Will be enabled in the NixOS module. --- nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/default.nix b/nix/default.nix index 90c92272..69174d4d 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -152,6 +152,7 @@ in (mapAttrsToList mesonEnable { "xwayland" = enableXWayland; "legacy_renderer" = legacyRenderer; + "uwsm" = false; }) (mapAttrsToList mesonBool { "b_pch" = false; From f5fa84554ffe55e29a397014964238be89ffa54d Mon Sep 17 00:00:00 2001 From: nnra <104775644+nnra6864@users.noreply.github.com> Date: Mon, 11 Nov 2024 16:49:35 +0100 Subject: [PATCH 0842/2393] config: Changed the default value of decoration:blur:ignore_opacity to true (#8418) This change is made in order to deliver the blur look majority of people expect by default. --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index fde8173d..27bc3c2d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -268,7 +268,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "blur:ignore_opacity", .description = "make the blur layer ignore the opacity of the window", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + .data = SConfigOptionDescription::SBoolData{true}, }, SConfigOptionDescription{ .value = "blur:new_optimizations", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fbbc8dbd..b768fda3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -417,7 +417,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("decoration:blur:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:blur:size", Hyprlang::INT{8}); m_pConfig->addConfigValue("decoration:blur:passes", Hyprlang::INT{1}); - m_pConfig->addConfigValue("decoration:blur:ignore_opacity", Hyprlang::INT{0}); + m_pConfig->addConfigValue("decoration:blur:ignore_opacity", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:blur:new_optimizations", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:blur:xray", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:blur:contrast", {0.8916F}); From a29cfa78431a054a093f3c843228bac6783a6d33 Mon Sep 17 00:00:00 2001 From: SoSeDiK Date: Tue, 12 Nov 2024 02:53:55 +0200 Subject: [PATCH 0843/2393] logging: Add some context to config error logs (#8326) --- src/config/ConfigManager.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b768fda3..e3d59874 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1851,7 +1851,7 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { if (it != flagsmap.end()) mode.flags |= it->second; else - Debug::log(ERR, "invalid flag {} in modeline", key); + Debug::log(ERR, "Invalid flag {} in modeline", key); } snprintf(mode.name, sizeof(mode.name), "%dx%d@%d", mode.hdisplay, mode.vdisplay, mode.vrefresh / 1000); @@ -1874,7 +1874,7 @@ std::optional CConfigManager::handleMonitor(const std::string& comm else if (ARGS[1] == "transform") { const auto TSF = std::stoi(ARGS[2]); if (std::clamp(TSF, 0, 7) != TSF) { - Debug::log(ERR, "invalid transform {} in monitor", TSF); + Debug::log(ERR, "Invalid transform {} in monitor", TSF); return "invalid transform"; } @@ -2027,7 +2027,7 @@ std::optional CConfigManager::handleMonitor(const std::string& comm m_dWorkspaceRules.emplace_back(wsRule); argno++; } else { - Debug::log(ERR, "Config error: invalid monitor syntax"); + Debug::log(ERR, "Config error: invalid monitor syntax at \"{}\"", ARGS[argno]); return "invalid syntax at \"" + ARGS[argno] + "\""; } @@ -2247,12 +2247,12 @@ std::optional CConfigManager::handleBind(const std::string& command const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(HANDLER); if (DISPATCHER == g_pKeybindManager->m_mDispatchers.end()) { - Debug::log(ERR, "Invalid dispatcher!"); + Debug::log(ERR, "Invalid dispatcher: {}", HANDLER); return "Invalid dispatcher, requested \"" + HANDLER + "\" does not exist"; } if (MOD == 0 && MODSTR != "") { - Debug::log(ERR, "Invalid mod!"); + Debug::log(ERR, "Invalid mod: {}", MODSTR); return "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod."; } @@ -2696,7 +2696,7 @@ std::optional CConfigManager::handleSubmap(const std::string& comma std::optional CConfigManager::handleSource(const std::string& command, const std::string& rawpath) { if (rawpath.length() < 2) { Debug::log(ERR, "source= path garbage"); - return "source path " + rawpath + " bogus!"; + return "source= path " + rawpath + " bogus!"; } std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }}; memset(glob_buf.get(), 0, sizeof(glob_t)); @@ -2718,8 +2718,8 @@ std::optional CConfigManager::handleSource(const std::string& comma continue; } - Debug::log(ERR, "source= file doesnt exist"); - return "source file " + value + " doesn't exist!"; + Debug::log(ERR, "source= file doesn't exist: {}", value); + return "source= file " + value + " doesn't exist!"; } configPaths.push_back(value); From bb160cfe377da2d2b2e4431a3399fa60114f3911 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 12 Nov 2024 15:26:25 +0000 Subject: [PATCH 0844/2393] makefile: add stub to discourage direct make --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 7cf21119..6c79b8db 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ PREFIX = /usr/local +stub: + @echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland." + legacyrenderer: cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` From 3fb47372b79265ebdabeeefdad10359d5b18377a Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 13 Nov 2024 21:34:52 +0200 Subject: [PATCH 0845/2393] flake.lock: update --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 47254052..c1fcb70d 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1730968822, - "narHash": "sha256-NocDjINsh6ismkhb0Xr6xPRksmhuB2WGf8ZmXMhxu7Y=", + "lastModified": 1731496216, + "narHash": "sha256-nlQrNN+tmJ+iP6Ck/czwZI0Hxz3oNvUyGkVruxJwgwA=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "a49bc3583ff223f426cb3526fdaa4bcaa247ec14", + "rev": "3b00e96f90cb0040de6d88ad99bf5f4d443f0c59", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1731163338, - "narHash": "sha256-Qflei0JBeqQ0c8jxA8e982xAxJvfMwfx4Aci2eJi84s=", + "lastModified": 1731518387, + "narHash": "sha256-aZZw1ZvTMLkcA6udlvkA3hrCkuipoWLy8s/JNnIclxY=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "60d3dece30f98e8ad85131829c8529950630d6bc", + "rev": "315fba5d21d87ddb756d4bebdb49f99d86b0ffe8", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1730785428, - "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", + "lastModified": 1731139594, + "narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", + "rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1730814269, - "narHash": "sha256-fWPHyhYE6xvMI1eGY3pwBTq85wcy1YXqdzTZF+06nOg=", + "lastModified": 1731363552, + "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "d70155fdc00df4628446352fc58adc640cd705c2", + "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", "type": "github" }, "original": { From 20031cea92417a852410827a5cdb4adbcaee4342 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 14 Nov 2024 20:15:51 +0000 Subject: [PATCH 0846/2393] pointer: add drm dumb buffers for cursors (#8399) --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 2 +- meson.build | 2 +- src/config/ConfigManager.cpp | 2 +- src/managers/PointerManager.cpp | 132 ++++++++++++++++++------------ src/protocols/core/Compositor.cpp | 26 ++++-- src/protocols/core/Compositor.hpp | 2 +- src/render/Texture.cpp | 21 ++++- src/render/Texture.hpp | 34 ++++---- 8 files changed, 142 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 117932d0..1cbd8b0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4) -pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2) +pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/meson.build b/meson.build index e4abad36..d825f184 100644 --- a/meson.build +++ b/meson.build @@ -31,7 +31,7 @@ if cpp_compiler.check_header('execinfo.h') add_project_arguments('-DHAS_EXECINFO', language: 'cpp') endif -aquamarine = dependency('aquamarine', version: '>=0.4.2') +aquamarine = dependency('aquamarine', version: '>=0.4.5') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') xcb_dep = dependency('xcb', required: get_option('xwayland')) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e3d59874..10299277 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -571,7 +571,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); - m_pConfig->addConfigValue("cursor:allow_dumb_copy", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:use_cpu_buffer", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 75be235f..0580c9be 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -375,6 +375,8 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->cursorPlaneSize(); auto const& cursorSize = currentCursorImage.size; + static auto PDUMB = CConfigValue("cursor:use_cpu_buffer"); + if (maxSize == Vector2D{}) return nullptr; @@ -386,10 +388,23 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size) { + if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size || + *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { - if (!state->monitor->cursorSwapchain) - state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(state->monitor->output->getBackend()->preferredAllocator(), state->monitor->output->getBackend()); + if (!state->monitor->cursorSwapchain || *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { + + auto allocator = state->monitor->output->getBackend()->preferredAllocator(); + if (*PDUMB) { + for (const auto& a : state->monitor->output->getBackend()->getAllocators()) { + if (a->type() == Aquamarine::AQ_ALLOCATOR_TYPE_DRM_DUMB) { + allocator = a; + break; + } + } + } + + state->monitor->cursorSwapchain = Aquamarine::CSwapchain::create(allocator, state->monitor->output->getBackend()); + } auto options = state->monitor->cursorSwapchain->currentOptions(); options.size = maxSize; @@ -397,8 +412,10 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; - // We do not set the format. If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, + // We do not set the format (unless shm). If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. + if (*PDUMB) + options.format = DRM_FORMAT_ARGB8888; if (!state->monitor->cursorSwapchain->reconfigure(options)) { Debug::log(TRACE, "Failed to reconfigure cursor swapchain"); @@ -420,60 +437,69 @@ SP CPointerManager::renderHWCursorBuffer(SPdataCopy(); + if (texData.empty()) { + if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) { + const auto SURFACE = currentCursorImage.surface->resource(); + auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE); + + bool flipRB = false; + + if (SURFACE->current.texture) { + Debug::log(TRACE, "Cursor CPU surface: format {}, expecting AR24", FormatUtils::drmFormatName(SURFACE->current.texture->m_iDrmFormat)); + if (SURFACE->current.texture->m_iDrmFormat == DRM_FORMAT_ABGR8888) { + Debug::log(TRACE, "Cursor CPU surface format AB24, will flip. WARNING: this will break on big endian!"); + flipRB = true; + } else if (SURFACE->current.texture->m_iDrmFormat != DRM_FORMAT_ARGB8888) { + Debug::log(TRACE, "Cursor CPU surface format rejected, falling back to sw"); + return nullptr; + } + } + + if (shmBuffer.data()) + texData = shmBuffer; + else { + texData.resize(texture->m_vSize.x * 4 * texture->m_vSize.y); + memset(texData.data(), 0x00, texData.size()); + } + + if (flipRB) { + for (size_t i = 0; i < shmBuffer.size(); i += 4) { + std::swap(shmBuffer.at(i), shmBuffer.at(i + 2)); // little-endian!!!!!! + } + } + } else { + Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers"); + return nullptr; + } + } + + // then, we just yeet it into the dumb buffer + + auto [data, fmt, size] = buf->beginDataPtr(0); + + memset(data, 0, size); + if (buf->dmabuf().size.x > texture->m_vSize.x) { + size_t STRIDE = 4 * texture->m_vSize.x; + for (int i = 0; i < texture->m_vSize.y; i++) + memcpy(data + i * buf->dmabuf().strides[0], texData.data() + i * STRIDE, STRIDE); + } else + memcpy(data, texData.data(), std::min(size, texData.size())); + + buf->endDataPtr(); + + return buf; + } + g_pHyprRenderer->makeEGLCurrent(); g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor; auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format); if (!RBO) { Debug::log(TRACE, "Failed to create cursor RB with format {}, mod {}", buf->dmabuf().format, buf->dmabuf().modifier); - static auto PDUMB = CConfigValue("cursor:allow_dumb_copy"); - if (!*PDUMB) - return nullptr; - - auto bufData = buf->beginDataPtr(0); - auto bufPtr = std::get<0>(bufData); - - // clear buffer - memset(bufPtr, 0, std::get<2>(bufData)); - - if (currentCursorImage.pBuffer) { - auto texAttrs = currentCursorImage.pBuffer->shm(); - - if (!texAttrs.success) { - Debug::log(TRACE, "Cannot use dumb copy on dmabuf cursor buffers"); - return nullptr; - } - - auto texData = currentCursorImage.pBuffer->beginDataPtr(GBM_BO_TRANSFER_WRITE); - auto texPtr = std::get<0>(texData); - Debug::log(TRACE, "cursor texture {}x{} {} {} {}", texAttrs.size.x, texAttrs.size.y, (void*)texPtr, texAttrs.format, texAttrs.stride); - // copy cursor texture - for (int i = 0; i < texAttrs.size.y; i++) - memcpy(bufPtr + i * buf->dmabuf().strides[0], texPtr + i * texAttrs.stride, texAttrs.stride); - } else if (currentCursorImage.surface && currentCursorImage.surface->resource()->role->role() == SURFACE_ROLE_CURSOR) { - const auto SURFACE = currentCursorImage.surface->resource(); - auto& shmBuffer = CCursorSurfaceRole::cursorPixelData(SURFACE); - Debug::log(TRACE, "cursor texture pixel data length: {}B", shmBuffer.size()); - - if (shmBuffer.data()) { - // copy cursor texture - // assume format is 32bpp - size_t STRIDE = 4 * SURFACE->current.bufferSize.x; - for (int i = 0; i < SURFACE->current.bufferSize.y; i++) - memcpy(bufPtr + i * buf->dmabuf().strides[0], shmBuffer.data() + i * STRIDE, STRIDE); - } else { - // if there is no data, hide the cursor - memset(bufPtr, '\0', buf->size.x * buf->size.y * 4 /* assume 32bpp */); - } - - } else { - Debug::log(TRACE, "Unsupported cursor buffer/surface, falling back to sw (can't dumb copy)"); - return nullptr; - } - - buf->endDataPtr(); - - return buf; + return nullptr; } RBO->bind(); @@ -773,7 +799,7 @@ SP CPointerManager::getCurrentCursorTexture() { if (currentCursorImage.pBuffer) { if (!currentCursorImage.bufferTex) - currentCursorImage.bufferTex = makeShared(currentCursorImage.pBuffer); + currentCursorImage.bufferTex = makeShared(currentCursorImage.pBuffer, true); return currentCursorImage.bufferTex; } diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 57f61f87..89f2a4cb 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -438,12 +438,13 @@ void CWLSurfaceResource::commitPendingState() { current.texture->m_eTransform = wlTransformToHyprutils(current.transform); if (current.buffer && current.buffer->buffer) { - current.buffer->buffer->update(accumulateCurrentBufferDamage()); + const auto DAMAGE = accumulateCurrentBufferDamage(); + current.buffer->buffer->update(DAMAGE); // if the surface is a cursor, update the shm buffer // TODO: don't update the entire texture - if (role->role() == SURFACE_ROLE_CURSOR) - updateCursorShm(); + if (role->role() == SURFACE_ROLE_CURSOR && !DAMAGE.empty()) + updateCursorShm(DAMAGE); // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. @@ -486,13 +487,12 @@ void CWLSurfaceResource::commitPendingState() { lastBuffer = current.buffer ? current.buffer->buffer : WP{}; } -void CWLSurfaceResource::updateCursorShm() { +void CWLSurfaceResource::updateCursorShm(CRegion damage) { auto buf = current.buffer ? current.buffer->buffer : lastBuffer; if (!buf) return; - // TODO: actually use damage auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock()); auto shmAttrs = buf->shm(); @@ -501,11 +501,25 @@ void CWLSurfaceResource::updateCursorShm() { return; } + damage.intersect(CBox{0, 0, buf->size.x, buf->size.y}); + // no need to end, shm. auto [pixelData, fmt, bufLen] = buf->beginDataPtr(0); shmData.resize(bufLen); - memcpy(shmData.data(), pixelData, bufLen); + + if (const auto RECTS = damage.getRects(); RECTS.size() == 1 && RECTS.at(0).x2 == buf->size.x && RECTS.at(0).y2 == buf->size.y) + memcpy(shmData.data(), pixelData, bufLen); + else { + for (auto& box : damage.getRects()) { + for (auto y = box.y1; y < box.y2; ++y) { + // bpp is 32 INSALLAH + auto begin = 4 * box.y1 * (box.x2 - box.x1) + box.x1; + auto len = 4 * (box.x2 - box.x1); + memcpy((uint8_t*)shmData.data() + begin, (uint8_t*)pixelData + begin, len); + } + } + } } void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index e5bdf082..c036041a 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -148,7 +148,7 @@ class CWLSurfaceResource { void dropCurrentBuffer(); void commitPendingState(); void bfHelper(std::vector> const& nodes, std::function, const Vector2D&, void*)> fn, void* data); - void updateCursorShm(); + void updateCursorShm(CRegion damage = CBox{0, 0, INT16_MAX, INT16_MAX}); friend class CWLPointerResource; }; diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp index 91e70afa..633f0212 100644 --- a/src/render/Texture.cpp +++ b/src/render/Texture.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "../protocols/types/Buffer.hpp" #include "../helpers/Format.hpp" +#include CTexture::CTexture() { // naffin' @@ -16,7 +17,7 @@ CTexture::~CTexture() { destroyTexture(); } -CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) { +CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_, bool keepDataCopy) : m_iDrmFormat(drmFormat), m_bKeepDataCopy(keepDataCopy) { createFromShm(drmFormat, pixels, stride, size_); } @@ -24,7 +25,7 @@ CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) { createFromDma(attrs, image); } -CTexture::CTexture(const SP buffer) { +CTexture::CTexture(const SP buffer, bool keepDataCopy) : m_bKeepDataCopy(keepDataCopy) { if (!buffer) return; @@ -43,6 +44,8 @@ CTexture::CTexture(const SP buffer) { auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0); + m_iDrmFormat = fmt; + createFromShm(fmt, pixelData, bufLen, shm.size); return; } @@ -80,6 +83,11 @@ void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t strid GLCALL(glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, size_.x, size_.y, 0, format->glFormat, format->glType, pixels)); GLCALL(glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0)); GLCALL(glBindTexture(GL_TEXTURE_2D, 0)); + + if (m_bKeepDataCopy) { + m_vDataCopy.resize(stride * size_.y); + memcpy(m_vDataCopy.data(), pixels, stride * size_.y); + } } void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) { @@ -135,6 +143,11 @@ void CTexture::update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, cons GLCALL(glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0)); glBindTexture(GL_TEXTURE_2D, 0); + + if (m_bKeepDataCopy) { + m_vDataCopy.resize(stride * m_vSize.y); + memcpy(m_vDataCopy.data(), pixels, stride * m_vSize.y); + } } void CTexture::destroyTexture() { @@ -152,3 +165,7 @@ void CTexture::allocate() { if (!m_iTexID) GLCALL(glGenTextures(1, &m_iTexID)); } + +const std::vector& CTexture::dataCopy() { + return m_vDataCopy; +} diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp index e0ef5503..ae949d5f 100644 --- a/src/render/Texture.hpp +++ b/src/render/Texture.hpp @@ -24,26 +24,32 @@ class CTexture { CTexture(const CTexture&&) = delete; CTexture(const CTexture&) = delete; - CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); + CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false); - CTexture(const SP buffer); + CTexture(const SP buffer, bool keepDataCopy = false); // this ctor takes ownership of the eglImage. CTexture(const Aquamarine::SDMABUFAttrs&, void* image); ~CTexture(); - void destroyTexture(); - void allocate(); - void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); + void destroyTexture(); + void allocate(); + void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage); + const std::vector& dataCopy(); - TEXTURETYPE m_iType = TEXTURE_RGBA; - GLenum m_iTarget = GL_TEXTURE_2D; - GLuint m_iTexID = 0; - Vector2D m_vSize = {}; - void* m_pEglImage = nullptr; - eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL; - bool m_bOpaque = false; + TEXTURETYPE m_iType = TEXTURE_RGBA; + GLenum m_iTarget = GL_TEXTURE_2D; + GLuint m_iTexID = 0; + Vector2D m_vSize = {}; + void* m_pEglImage = nullptr; + eTransform m_eTransform = HYPRUTILS_TRANSFORM_NORMAL; + bool m_bOpaque = false; + uint32_t m_iDrmFormat = 0; // for shm private: - void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); - void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); + void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size); + void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image); + + bool m_bKeepDataCopy = false; + + std::vector m_vDataCopy; }; \ No newline at end of file From 6f7280a6901aeba0fd1768ccf78fea152fe41f4f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 14 Nov 2024 20:20:51 +0000 Subject: [PATCH 0847/2393] descriptions: add use_cpu_buffer --- src/config/ConfigDescriptions.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 27bc3c2d..969ec66f 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1350,8 +1350,8 @@ inline static const std::vector CONFIG_OPTIONS = { .data = SConfigOptionDescription::SBoolData{true}, }, SConfigOptionDescription{ - .value = "cursor:allow_dumb_copy", - .description = "Makes HW cursors work on Nvidia, at the cost of a possible hitch whenever the image changes", + .value = "cursor:use_cpu_buffer", + .description = "Makes HW cursors use a CPU buffer. Required on Nvidia to have HW cursors. Experimental", .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, From 940ed3d525d838bc255070bd8cfc2f75df04229a Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 14 Nov 2024 21:38:16 +0100 Subject: [PATCH 0848/2393] xcursors: store themes in a std:set to order it (#8474) using a unordered_set means its store based on a hash_value meaning currently it can end up loading inherited themes before the actual theme itself depending on the hash of the theme name used, reason for using set at all over vector is to keep unique members and not foreverever looping broken inherit themeing. --- src/managers/XCursorManager.cpp | 8 ++++---- src/managers/XCursorManager.hpp | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 93ee7965..5c3053c7 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -197,7 +197,7 @@ SP CXCursorManager::createCursor(std::string const& shape, XcursorIma return xcursor; } -std::unordered_set CXCursorManager::themePaths(std::string const& theme) { +std::set CXCursorManager::themePaths(std::string const& theme) { auto const* path = XcursorLibraryPath(); auto expandTilde = [](std::string const& path) { @@ -276,10 +276,10 @@ std::unordered_set CXCursorManager::themePaths(std::string const& t return themes; }; - std::unordered_set paths; - std::unordered_set inherits; + std::set paths; + std::set inherits; - auto scanTheme = [&path, &paths, &expandTilde, &inherits, &getInheritThemes](auto const& t) { + auto scanTheme = [&path, &paths, &expandTilde, &inherits, &getInheritThemes](auto const& t) { std::stringstream ss(path); std::string line; diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 1f3c24db..2517e85e 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include #include #include #include @@ -34,16 +34,16 @@ class CXCursorManager { void syncGsettings(); private: - SP createCursor(std::string const& shape, XcursorImages* xImages); - std::unordered_set themePaths(std::string const& theme); - std::string getLegacyShapeName(std::string const& shape); - std::vector> loadStandardCursors(std::string const& name, int size); - std::vector> loadAllFromDir(std::string const& path, int size); + SP createCursor(std::string const& shape, XcursorImages* xImages); + std::set themePaths(std::string const& theme); + std::string getLegacyShapeName(std::string const& shape); + std::vector> loadStandardCursors(std::string const& name, int size); + std::vector> loadAllFromDir(std::string const& path, int size); - int lastLoadSize = 0; - float lastLoadScale = 0; - std::string themeName = ""; - SP defaultCursor; - SP hyprCursor; - std::vector> cursors; + int lastLoadSize = 0; + float lastLoadScale = 0; + std::string themeName = ""; + SP defaultCursor; + SP hyprCursor; + std::vector> cursors; }; From 967fe76a60ec6b2928b495ed202f772beca05275 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 15 Nov 2024 03:45:13 +0300 Subject: [PATCH 0849/2393] drm: enable explit out fence in AQ (#8431) --- src/render/Renderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d98e32a9..37e6f81e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1507,6 +1507,9 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { pMonitor->output->state->resetExplicitFences(); if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + auto explicitOptions = getExplicitSyncSettings(); + if (explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) + pMonitor->output->state->enableExplicitOutFenceForNextCommit(); if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; @@ -1530,8 +1533,6 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { } } - auto explicitOptions = getExplicitSyncSettings(); - if (!explicitOptions.explicitEnabled) return ok; From 098e491a43e8b26f4382b48651a4131464bf6a2f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 15 Nov 2024 00:47:34 +0000 Subject: [PATCH 0850/2393] protocols: mark primarySelection as not privileged fixes #8479 --- src/managers/ProtocolManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 601e564d..cf517b22 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -281,6 +281,7 @@ bool CProtocolManager::isGlobalPrivileged(const wl_global* global) { PROTO::xdgShell->getGlobal(), PROTO::xdgDialog->getGlobal(), PROTO::singlePixel->getGlobal(), + PROTO::primarySelection->getGlobal(), PROTO::sync ? PROTO::sync->getGlobal() : nullptr, PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr, PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr, From 7affc34ab43c5d5cbf670759b839a9e990d8bbea Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 16 Nov 2024 07:21:59 +0800 Subject: [PATCH 0851/2393] bind: new long press option (#8302) --------- Co-authored-by: Vaxry --- src/config/ConfigManager.cpp | 13 ++++++----- src/debug/HyprCtl.cpp | 7 +++--- src/managers/KeybindManager.cpp | 40 ++++++++++++++++++++++++++++++--- src/managers/KeybindManager.hpp | 5 ++++- 4 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 10299277..58db00e9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2171,6 +2171,7 @@ std::optional CConfigManager::handleBind(const std::string& command bool transparent = false; bool ignoreMods = false; bool multiKey = false; + bool longPress = false; bool hasDescription = false; bool dontInhibit = false; const auto BINDARGS = command.substr(4); @@ -2192,6 +2193,8 @@ std::optional CConfigManager::handleBind(const std::string& command ignoreMods = true; } else if (arg == 's') { multiKey = true; + } else if (arg == 'o') { + longPress = true; } else if (arg == 'd') { hasDescription = true; } else if (arg == 'p') { @@ -2201,8 +2204,8 @@ std::optional CConfigManager::handleBind(const std::string& command } } - if (release && repeat) - return "flags r and e are mutually exclusive"; + if ((longPress || release) && repeat) + return "flags e is mutually exclusive with r and o"; if (mouse && (repeat || release || locked)) return "flag m is exclusive"; @@ -2264,9 +2267,9 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{ - parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release, - repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit}); + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, + COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, release, repeat, longPress, + mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription, dontInhibit}); } return {}; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6429e781..c5eba0a7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -843,6 +843,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "mouse": {}, "release": {}, "repeat": {}, + "longPress": {}, "non_consuming": {}, "has_description": {}, "modmask": {}, @@ -854,9 +855,9 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "dispatcher": "{}", "arg": "{}" }},)#", - kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", - kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", - escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); + kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.longPress ? "true" : "false", + kb.nonConsuming ? "true" : "false", kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, + kb.catchAll ? "true" : "false", escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f2fdab53..b14637f7 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -13,6 +13,7 @@ #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" +#include "eventLoop/EventLoopManager.hpp" #include #include @@ -130,9 +131,25 @@ CKeybindManager::CKeybindManager() { m_tScrollTimer.reset(); + m_pLongPressTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + if (!m_pLastLongPressKeybind || g_pSeatManager->keyboard.expired()) + return; + + const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(m_pLastLongPressKeybind->handler); + + Debug::log(LOG, "Long press timeout passed, calling dispatcher."); + DISPATCHER->second(m_pLastLongPressKeybind->arg); + }, + nullptr); + + g_pEventLoopManager->addTimer(m_pLongPressTimer); + static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; m_vPressedSpecialBinds.clear(); }); } @@ -140,12 +157,17 @@ CKeybindManager::CKeybindManager() { CKeybindManager::~CKeybindManager() { if (m_pXKBTranslationState) xkb_state_unref(m_pXKBTranslationState); + if (m_pLongPressTimer && g_pEventLoopManager) { + g_pEventLoopManager->removeTimer(m_pLongPressTimer); + m_pLongPressTimer.reset(); + } } void CKeybindManager::addKeybind(SKeybind kb) { m_lKeybinds.push_back(kb); - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; } void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { @@ -158,7 +180,8 @@ void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { } } - m_pActiveKeybind = nullptr; + m_pActiveKeybind = nullptr; + m_pLastLongPressKeybind = nullptr; } uint32_t CKeybindManager::stringToModMask(std::string mods) { @@ -409,6 +432,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { m_pActiveKeybind = nullptr; } + m_pLastLongPressKeybind = nullptr; + bool suppressEvent = false; if (e.state == WL_KEYBOARD_KEY_STATE_PRESSED) { @@ -705,6 +730,15 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP } } + if (k.longPress) { + const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); + + m_pLongPressTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay)); + m_pLastLongPressKeybind = &k; + + continue; + } + const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler); if (SPECIALTRIGGERED && !pressed) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 24a09836..4a0af6e9 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -8,6 +8,7 @@ #include #include #include "../devices/IPointer.hpp" +#include "eventLoop/EventLoopTimer.hpp" class CInputManager; class CConfigManager; @@ -28,6 +29,7 @@ struct SKeybind { std::string description = ""; bool release = false; bool repeat = false; + bool longPress = false; bool mouse = false; bool nonConsuming = false; bool transparent = false; @@ -119,7 +121,8 @@ class CKeybindManager { inline static std::string m_szCurrentSelectedSubmap = ""; - SKeybind* m_pActiveKeybind = nullptr; + SKeybind * m_pActiveKeybind = nullptr, *m_pLastLongPressKeybind = nullptr; + SP m_pLongPressTimer; uint32_t m_uTimeLastMs = 0; uint32_t m_uLastCode = 0; From 83be2480c45bdead9110fdf137a1cd2f5a203378 Mon Sep 17 00:00:00 2001 From: sslater11 <43177940+sslater11@users.noreply.github.com> Date: Sat, 16 Nov 2024 16:39:58 +0000 Subject: [PATCH 0852/2393] workspace: fix missing name via focusworkspaceoncurrentmonitor (#8484) --- src/managers/KeybindManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index b14637f7..4d2f4dcc 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1887,7 +1887,7 @@ SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { } SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) { - auto workspaceID = getWorkspaceIDNameFromString(args).id; + auto [workspaceID, workspaceName] = getWorkspaceIDNameFromString(args); if (workspaceID == WORKSPACE_INVALID) { Debug::log(ERR, "focusWorkspaceOnCurrentMonitor invalid workspace!"); return {.success = false, .error = "focusWorkspaceOnCurrentMonitor invalid workspace!"}; @@ -1903,7 +1903,7 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args auto pWorkspace = g_pCompositor->getWorkspaceByID(workspaceID); if (!pWorkspace) { - pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID); + pWorkspace = g_pCompositor->createNewWorkspace(workspaceID, PCURRMONITOR->ID, workspaceName); // we can skip the moving, since it's already on the current monitor changeworkspace(pWorkspace->getConfigName()); return {}; From ec1e6be00377c26dd25497b1544091b3f643c4bc Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 16 Nov 2024 23:04:57 +0000 Subject: [PATCH 0853/2393] core: guard pmonitor in focuswindow may be null fixes #8483 --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index da20c5cf..fbbfd7e7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1077,7 +1077,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface PWORKSPACE->rememberPrevWorkspace(m_pLastMonitor->activeWorkspace); if (PWORKSPACE->m_bIsSpecialWorkspace) m_pLastMonitor->changeWorkspace(PWORKSPACE, false, true); // if special ws, open on current monitor - else + else if (PMONITOR) PMONITOR->changeWorkspace(PWORKSPACE, false, true); // changeworkspace already calls focusWindow return; @@ -1088,7 +1088,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface /* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which window focuses are "via keybinds" and which ones aren't. */ - if (PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH) + if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace != pWindow->m_pWorkspace && !pWindow->m_bPinned && !*PSPECIALFALLTHROUGH) PMONITOR->setSpecialWorkspace(nullptr); // we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window From cf18eca86d21c28b127d58938b3a1004800b85c9 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 16 Nov 2024 23:06:35 +0000 Subject: [PATCH 0854/2393] [gha] Nix: update inputs --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index c1fcb70d..969bc157 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1731496216, - "narHash": "sha256-nlQrNN+tmJ+iP6Ck/czwZI0Hxz3oNvUyGkVruxJwgwA=", + "lastModified": 1731774881, + "narHash": "sha256-1Dxryiw8u2ejntxrrv3sMtIE8WHKxmlN4KeH+uMGbmc=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "3b00e96f90cb0040de6d88ad99bf5f4d443f0c59", + "rev": "b31a6a4da8199ae3489057db7d36069a70749a56", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1731518387, - "narHash": "sha256-aZZw1ZvTMLkcA6udlvkA3hrCkuipoWLy8s/JNnIclxY=", + "lastModified": 1731702627, + "narHash": "sha256-+JeO9gevnXannQxMfR5xzZtF4sYmSlWkX/BPmPx0mWk=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "315fba5d21d87ddb756d4bebdb49f99d86b0ffe8", + "rev": "e911361a687753bbbdfe3b6a9eab755ecaf1d9e1", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1731139594, - "narHash": "sha256-IigrKK3vYRpUu+HEjPL/phrfh7Ox881er1UEsZvw9Q4=", + "lastModified": 1731676054, + "narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "76612b17c0ce71689921ca12d9ffdc9c23ce40b2", + "rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add", "type": "github" }, "original": { @@ -293,11 +293,11 @@ ] }, "locked": { - "lastModified": 1730743262, - "narHash": "sha256-iTLqj3lU8kFehPm5tXpctzkD274t/k1nwSSq3qCWXeg=", + "lastModified": 1731703417, + "narHash": "sha256-rheDc/7C+yI+QspYr9J2z9kQ5P9F4ATapI7qyFAe1XA=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "09b23cef06fe248e61cec8862c04b9bcb62f4b6d", + "rev": "8070f36deec723de71e7557441acb17e478204d3", "type": "github" }, "original": { From 9d37b1b07339b1b222ceab5952cd9b927fbf6d73 Mon Sep 17 00:00:00 2001 From: staz Date: Sun, 17 Nov 2024 04:07:33 +0500 Subject: [PATCH 0855/2393] workspacerules: Do not check 'on-created-empty' if using a workspace windowrule (#8486) --- src/events/Windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index f946ce03..77df7373 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -296,7 +296,7 @@ void Events::listener_mapWindow(void* owner, void* data) { auto pWorkspace = g_pCompositor->getWorkspaceByID(REQUESTEDWORKSPACEID); if (!pWorkspace) - pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName); + pWorkspace = g_pCompositor->createNewWorkspace(REQUESTEDWORKSPACEID, PWINDOW->monitorID(), requestedWorkspaceName, false); PWORKSPACE = pWorkspace; From af83c825138386d269d69b3ef755b844a2eacb22 Mon Sep 17 00:00:00 2001 From: Ruslan Date: Sun, 17 Nov 2024 02:18:30 +0300 Subject: [PATCH 0856/2393] hyprctl: add json output on hyprctl -j plugins list (#8480) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --------- Co-authored-by: Руслан Новокшонов --- src/debug/HyprCtl.cpp | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index c5eba0a7..964a193b 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1472,17 +1472,40 @@ std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string request) { g_pPluginSystem->unloadPlugin(PLUGIN); } else if (OPERATION == "list") { - const auto PLUGINS = g_pPluginSystem->getAllPlugins(); + const auto PLUGINS = g_pPluginSystem->getAllPlugins(); + std::string result = ""; - if (PLUGINS.size() == 0) - return "no plugins loaded"; + if (format == eHyprCtlOutputFormat::FORMAT_JSON) { + result += "["; - std::string list = ""; - for (auto const& p : PLUGINS) { - list += std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description); + if (PLUGINS.size() == 0) + return "[]"; + + for (auto const& p : PLUGINS) { + result += std::format( + R"#( +{{ + "name": "{}", + "author": "{}", + "handle": "{:x}", + "version": "{}", + "description": "{}" +}},)#", + escapeJSONStrings(p->name), escapeJSONStrings(p->author), (uintptr_t)p->m_pHandle, escapeJSONStrings(p->version), escapeJSONStrings(p->description)); + } + trimTrailingComma(result); + result += "]"; + } else { + if (PLUGINS.size() == 0) + return "no plugins loaded"; + + for (auto const& p : PLUGINS) { + result += + std::format("\nPlugin {} by {}:\n\tHandle: {:x}\n\tVersion: {}\n\tDescription: {}\n", p->name, p->author, (uintptr_t)p->m_pHandle, p->version, p->description); + } } - return list; + return result; } else { return "unknown opt"; } From 0ddbd1c3a40f921816a2c512f871f1e51aca8fe2 Mon Sep 17 00:00:00 2001 From: Alexandre Acebedo Date: Sun, 17 Nov 2024 15:58:18 +0000 Subject: [PATCH 0857/2393] renderer: add lockdead_screen_delay (#8467) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/managers/SessionLockManager.cpp | 10 ++++++++++ src/managers/SessionLockManager.hpp | 3 +++ src/render/Renderer.cpp | 9 +++++---- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 969ec66f..2e3a6720 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1121,6 +1121,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "misc:lockdead_screen_delay", + .description = "the delay in ms after the lockdead screen appears if the lock screen did not appear after a lock event occurred.", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1000, 0, 5000}, + }, /* * binds: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 58db00e9..1c025179 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -377,6 +377,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:middle_click_paste", Hyprlang::INT{1}); m_pConfig->addConfigValue("misc:render_unfocused_fps", Hyprlang::INT{15}); m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0}); + m_pConfig->addConfigValue("misc:lockdead_screen_delay", Hyprlang::INT{1000}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 1b28cc27..c7a5934a 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -57,6 +57,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { m_pSessionLock = std::make_unique(); m_pSessionLock->lock = pLock; + m_pSessionLock->mLockTimer.reset(); m_pSessionLock->listeners.newSurface = pLock->events.newLockSurface.registerListener([this](std::any data) { auto SURFACE = std::any_cast>(data); @@ -176,3 +177,12 @@ bool CSessionLockManager::isSessionLockPresent() { bool CSessionLockManager::anySessionLockSurfacesPresent() { return m_pSessionLock && std::ranges::any_of(m_pSessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; }); } + +bool CSessionLockManager::shallConsiderLockMissing() { + if (!m_pSessionLock) + return false; + + static auto LOCKDEAD_SCREEN_DELAY = CConfigValue("misc:lockdead_screen_delay"); + + return m_pSessionLock->mLockTimer.getMillis() > *LOCKDEAD_SCREEN_DELAY; +} \ No newline at end of file diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index 9b3b882c..59090605 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -29,6 +29,7 @@ struct SSessionLockSurface { struct SSessionLock { WP lock; + CTimer mLockTimer; std::vector> vSessionLockSurfaces; std::unordered_map mMonitorsWithoutMappedSurfaceTimers; @@ -61,6 +62,8 @@ class CSessionLockManager { void onLockscreenRenderedOnMonitor(uint64_t id); + bool shallConsiderLockMissing(); + private: UP m_pSessionLock; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 37e6f81e..3eba8458 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1045,9 +1045,10 @@ void CHyprRenderer::renderLockscreen(PHLMONITOR pMonitor, timespec* now, const C Vector2D translate = {geometry.x, geometry.y}; const auto PSLS = g_pSessionLockManager->getSessionLockSurfaceForMonitor(pMonitor->ID); - if (!PSLS) - renderSessionLockMissing(pMonitor); - else { + if (!PSLS) { + if (g_pSessionLockManager->shallConsiderLockMissing()) + renderSessionLockMissing(pMonitor); + } else { renderSessionLockSurface(PSLS, pMonitor, now); g_pSessionLockManager->onLockscreenRenderedOnMonitor(pMonitor->ID); } @@ -2726,7 +2727,7 @@ bool CHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMod return true; } - /* This is a constant expression, as we always use double-buffering in our swapchain + /* This is a constant expression, as we always use double-buffering in our swapchain TODO: Rewrite the CDamageRing to take advantage of that maybe? It's made to support longer swapchains atm because we used to do wlroots */ static constexpr const int HL_BUFFER_AGE = 2; From fb91c2550f5184785680f6af7b069cb857568104 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 16:16:49 +0000 Subject: [PATCH 0858/2393] renderer: don't render unmapped popups fixes #8485 --- src/desktop/Popup.hpp | 4 ++-- src/render/Renderer.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index f34b8a2c..e9b3e0f0 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -41,6 +41,7 @@ class CPopup { // SP m_pWLSurface; + bool m_bMapped = false; private: // T1 owners, each popup has to have one of these @@ -57,8 +58,7 @@ class CPopup { bool m_bRequestedReposition = false; - bool m_bInert = false; - bool m_bMapped = false; + bool m_bInert = false; // std::vector> m_vChildren; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 3eba8458..6067a7f2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -732,7 +732,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe pWindow->m_pPopupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource() || !popup->m_bMapped) return; auto pos = popup->coordsRelativeToParent(); auto rd = (SRenderData*)data; @@ -822,7 +822,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim if (popups) { pLayer->popupHead->breadthfirst( [](CPopup* popup, void* data) { - if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) + if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource() || !popup->m_bMapped) return; Vector2D pos = popup->coordsRelativeToParent(); From 4f591e807abe1865d8f8135a1a64932cc418d0f0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 16:42:30 +0000 Subject: [PATCH 0859/2393] renderer: simplify blur enabling logic --- src/render/OpenGL.cpp | 4 +--- src/render/Renderer.cpp | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 63a7e822..9c00daee 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2036,7 +2036,6 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, bool blockBlurOptimization, float blurA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); - static auto PBLURENABLED = CConfigValue("decoration:blur:enabled"); static auto PNOBLUROVERSIZED = CConfigValue("decoration:no_blur_on_oversized"); TRACY_GPU_ZONE("RenderTextureWithBlur"); @@ -2050,8 +2049,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.renderModif.applyToRegion(texDamage); - if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || - (m_pCurrentWindow.lock() && (m_pCurrentWindow->m_sWindowData.noBlur.valueOrDefault() || m_pCurrentWindow->m_sWindowData.RGBX.valueOrDefault()))) { + if (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { renderTexture(tex, pBox, a, round, false, true); return; } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6067a7f2..fc17ef9f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -174,6 +174,7 @@ static void renderSurface(SP surface, int x, int y, void* da } const auto RDATA = (SRenderData*)data; + const bool BLUR = RDATA->blur && !TEXTURE->m_bOpaque; const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; TRACY_GPU_ZONE("RenderSurface"); @@ -270,12 +271,12 @@ static void renderSurface(SP surface, int x, int y, void* da // is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) if (RDATA->surfaceCounter == 0 && !RDATA->popup) { - if (RDATA->blur) + if (BLUR) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, RDATA->blockBlurOptimization, RDATA->fadeAlpha); else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); } else { - if (RDATA->blur && RDATA->popup) + if (BLUR && RDATA->popup) g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, surface, rounding, true, RDATA->fadeAlpha); else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA, rounding, false, true); @@ -591,6 +592,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_iMonitorMovedFrom != -1 && !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace); + const bool DONT_BLUR = pWindow->m_sWindowData.noBlur.valueOrDefault() || pWindow->m_sWindowData.RGBX.valueOrDefault() || pWindow->opaque(); renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); @@ -599,7 +601,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry; // if it shouldn't, it will be ignored later + renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; renderdata.pWindow = pWindow; if (ignoreAllGeometry) { @@ -715,7 +717,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe static CConfigValue PBLURPOPUPS = CConfigValue("decoration:blur:popups"); static CConfigValue PBLURIGNOREA = CConfigValue("decoration:blur:popups_ignorealpha"); - renderdata.blur = *PBLURPOPUPS; + renderdata.blur = *PBLURPOPUPS && *PBLUR; const auto DM = g_pHyprOpenGL->m_RenderData.discardMode; const auto DA = g_pHyprOpenGL->m_RenderData.discardOpacity; @@ -734,13 +736,15 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe [](CPopup* popup, void* data) { if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource() || !popup->m_bMapped) return; - auto pos = popup->coordsRelativeToParent(); - auto rd = (SRenderData*)data; - Vector2D oldPos = {rd->x, rd->y}; + const auto pos = popup->coordsRelativeToParent(); + auto rd = (SRenderData*)data; + const Vector2D oldPos = {rd->x, rd->y}; rd->x += pos.x; rd->y += pos.y; + popup->m_pWLSurface->resource()->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, data); + rd->x = oldPos.x; rd->y = oldPos.y; }, @@ -785,6 +789,8 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim return; } + static auto PBLUR = CConfigValue("decoration:blur:enabled"); + TRACY_GPU_ZONE("RenderLayer"); const auto REALPOS = pLayer->realPosition.value(); @@ -792,7 +798,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim SRenderData renderdata = {pMonitor, time, REALPOS.x, REALPOS.y}; renderdata.fadeAlpha = pLayer->alpha.value(); - renderdata.blur = pLayer->forceBlur; + renderdata.blur = pLayer->forceBlur && *PBLUR; renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; renderdata.w = REALSIZ.x; From 8d5cdedbd350b4730a1aa57dc5491c88dff3415e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 16:46:49 +0000 Subject: [PATCH 0860/2393] hyprpm: fix format crash ref #8487 --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 051ad500..db315193 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -272,7 +272,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& } if (m_bVerbose) - std::println("{}", verboseString("shell returned: " + out)); + std::println("{}", verboseString("shell returned: {}", out)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/" + p.output)) { progress.printMessageAbove(failureString("Plugin {} failed to build.\n" From b735295d2b0025b26f88852c06f65514a963c711 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 19:31:54 +0000 Subject: [PATCH 0861/2393] windows/xdg: minor cleanup of min/max size calculations fixes #8495 --- src/desktop/Window.cpp | 26 ++++++++++++++++++++++++++ src/desktop/Window.hpp | 19 +++++++++---------- src/events/Windows.cpp | 8 ++++---- src/layout/DwindleLayout.cpp | 2 +- src/layout/IHyprLayout.cpp | 8 ++++---- src/layout/MasterLayout.cpp | 4 ++-- src/managers/XWaylandManager.cpp | 30 ------------------------------ src/managers/XWaylandManager.hpp | 2 -- src/protocols/XDGShell.cpp | 8 ++++++++ src/protocols/XDGShell.hpp | 3 +++ 10 files changed, 57 insertions(+), 53 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 20fed565..e74e13a2 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1601,3 +1601,29 @@ bool CWindow::isX11OverrideRedirect() { bool CWindow::isModal() { return (m_pXWaylandSurface && m_pXWaylandSurface->modal); } + +Vector2D CWindow::requestedMinSize() { + if ((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel)) + return Vector2D(1, 1); + + Vector2D minSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->min_width, m_pXWaylandSurface->sizeHints->min_height) : m_pXDGSurface->toplevel->layoutMinSize(); + + minSize = minSize.clamp({1, 1}); + + return minSize; +} + +Vector2D CWindow::requestedMaxSize() { + constexpr int NO_MAX_SIZE_LIMIT = 99999; + if (((m_bIsX11 && !m_pXWaylandSurface->sizeHints) || (!m_bIsX11 && !m_pXDGSurface->toplevel) || m_sWindowData.noMaxSize.valueOrDefault())) + return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT); + + Vector2D maxSize = m_bIsX11 ? Vector2D(m_pXWaylandSurface->sizeHints->max_width, m_pXWaylandSurface->sizeHints->max_height) : m_pXDGSurface->toplevel->layoutMaxSize(); + + if (maxSize.x < 5) + maxSize.x = NO_MAX_SIZE_LIMIT; + if (maxSize.y < 5) + maxSize.y = NO_MAX_SIZE_LIMIT; + + return maxSize; +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index b8dd3cf7..ac81e5ef 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -403,12 +403,9 @@ class CWindow { } // methods - CBox getFullWindowBoundingBox(); - SBoxExtents getFullWindowExtents(); - CBox getWindowBoxUnified(uint64_t props); - inline CBox getWindowMainSurfaceBox() const { - return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; - } + CBox getFullWindowBoundingBox(); + SBoxExtents getFullWindowExtents(); + CBox getWindowBoxUnified(uint64_t props); CBox getWindowIdealBoundingBoxIgnoreReserved(); void addWindowDeco(std::unique_ptr deco); void updateWindowDecos(); @@ -441,19 +438,15 @@ class CWindow { void activate(bool force = false); int surfacesCount(); void clampWindowSize(const std::optional minSize, const std::optional maxSize); - bool isFullscreen(); bool isEffectiveInternalFSMode(const eFullscreenMode); - int getRealBorderSize(); void updateWindowData(); void updateWindowData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(void* ptr); bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); int popupsCount(); - void applyGroupRules(); void createGroup(); void destroyGroup(); @@ -481,6 +474,12 @@ class CWindow { void unsetWindowData(eOverridePriority priority); bool isX11OverrideRedirect(); bool isModal(); + Vector2D requestedMinSize(); + Vector2D requestedMaxSize(); + + inline CBox getWindowMainSurfaceBox() const { + return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + } // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 77df7373..73ab45c1 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -346,7 +346,7 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + const auto MAXSIZE = PWINDOW->requestedMaxSize(); const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); @@ -469,7 +469,7 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(PWINDOW); + const auto MAXSIZE = PWINDOW->requestedMaxSize(); const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : stringToPercentage(SIZEXSTR, PMONITOR->vecSize.x); @@ -753,8 +753,8 @@ void Events::listener_commitWindow(void* owner, void* data) { PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; // apply pending size. We pinged, the window ponged. if (!PWINDOW->m_bIsX11 && !PWINDOW->isFullscreen() && PWINDOW->m_bIsFloating) { - const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->current.minSize; - const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->current.maxSize; + const auto MINSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMinSize(); + const auto MAXSIZE = PWINDOW->m_pXDGSurface->toplevel->layoutMaxSize(); PWINDOW->clampWindowSize(MINSIZE, MAXSIZE > Vector2D{1, 1} ? std::optional{MAXSIZE} : std::nullopt); g_pHyprRenderer->damageWindow(PWINDOW); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index e6e9090f..c3e394f3 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -283,7 +283,7 @@ void CHyprDwindleLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dir // first, check if OPENINGON isn't too big. const auto PREDSIZEMAX = OPENINGON ? Vector2D(OPENINGON->box.w, OPENINGON->box.h) : PMONITOR->vecSize; - if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) { + if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PREDSIZEMAX.x || MAXSIZE.y < PREDSIZEMAX.y) { // we can't continue. make it floating. pWindow->m_bIsFloating = true; m_lDwindleNodesData.remove(*PNODE); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index a312555f..af8b907c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -597,12 +597,12 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { - Vector2D MINSIZE = g_pXWaylandManager->getMinSizeForWindow(DRAGGINGWINDOW).clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20))); + Vector2D MINSIZE = DRAGGINGWINDOW->requestedMinSize().clamp(DRAGGINGWINDOW->m_sWindowData.minSize.valueOr(Vector2D(20, 20))); Vector2D MAXSIZE; if (DRAGGINGWINDOW->m_sWindowData.maxSize.hasValue()) - MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value()); + MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, DRAGGINGWINDOW->m_sWindowData.maxSize.value()); else - MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(DRAGGINGWINDOW).clamp({}, Vector2D(std::numeric_limits::max(), std::numeric_limits::max())); + MAXSIZE = DRAGGINGWINDOW->requestedMaxSize().clamp({}, Vector2D(std::numeric_limits::max(), std::numeric_limits::max())); Vector2D newSize = m_vBeginDragSizeXY; Vector2D newPos = m_vBeginDragPositionXY; @@ -884,7 +884,7 @@ Vector2D IHyprLayout::predictSizeForNewWindowFloating(PHLWINDOW pWindow) { // ge const auto SIZEXSTR = VALUE.substr(0, VALUE.find(' ')); const auto SIZEYSTR = VALUE.substr(VALUE.find(' ') + 1); - const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); + const auto MAXSIZE = pWindow->requestedMaxSize(); const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, g_pCompositor->m_pLastMonitor->vecSize.x) : stringToPercentage(SIZEXSTR, g_pCompositor->m_pLastMonitor->vecSize.x); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index b8b3efea..695dcc99 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -200,7 +200,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire PNODE->percMaster = lastSplitPercent; // first, check if it isn't too big. - if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) { + if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PMONITOR->vecSize.x * lastSplitPercent || MAXSIZE.y < PMONITOR->vecSize.y) { // we can't continue. make it floating. pWindow->m_bIsFloating = true; m_lMasterNodesData.remove(*PNODE); @@ -212,7 +212,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire PNODE->percMaster = lastSplitPercent; // first, check if it isn't too big. - if (const auto MAXSIZE = g_pXWaylandManager->getMaxSizeForWindow(pWindow); + if (const auto MAXSIZE = pWindow->requestedMaxSize(); MAXSIZE.x < PMONITOR->vecSize.x * (1 - lastSplitPercent) || MAXSIZE.y < PMONITOR->vecSize.y * (1.f / (WINDOWSONWORKSPACE - 1))) { // we can't continue. make it floating. pWindow->m_bIsFloating = true; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index d0dda8e6..832173eb 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -213,36 +213,6 @@ void CHyprXWaylandManager::setWindowFullscreen(PHLWINDOW pWindow, bool fullscree pWindow->m_pXDGSurface->toplevel->setFullscreen(fullscreen); } -Vector2D CHyprXWaylandManager::getMaxSizeForWindow(PHLWINDOW pWindow) { - constexpr int NO_MAX_SIZE_LIMIT = 99999; - if (!validMapped(pWindow) || - ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel) || - pWindow->m_sWindowData.noMaxSize.valueOrDefault())) - return Vector2D(NO_MAX_SIZE_LIMIT, NO_MAX_SIZE_LIMIT); - - Vector2D maxSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->max_width, pWindow->m_pXWaylandSurface->sizeHints->max_height) : - pWindow->m_pXDGSurface->toplevel->current.maxSize; - - if (maxSize.x < 5) - maxSize.x = NO_MAX_SIZE_LIMIT; - if (maxSize.y < 5) - maxSize.y = NO_MAX_SIZE_LIMIT; - - return maxSize; -} - -Vector2D CHyprXWaylandManager::getMinSizeForWindow(PHLWINDOW pWindow) { - if (!validMapped(pWindow) || ((pWindow->m_bIsX11 && !pWindow->m_pXWaylandSurface->sizeHints) || (!pWindow->m_bIsX11 && !pWindow->m_pXDGSurface->toplevel))) - return Vector2D(0, 0); - - Vector2D minSize = pWindow->m_bIsX11 ? Vector2D(pWindow->m_pXWaylandSurface->sizeHints->min_width, pWindow->m_pXWaylandSurface->sizeHints->min_height) : - pWindow->m_pXDGSurface->toplevel->current.minSize; - - minSize = minSize.clamp({1, 1}); - - return minSize; -} - Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index a9f95974..508a20d6 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -21,8 +21,6 @@ class CHyprXWaylandManager { void setWindowFullscreen(PHLWINDOW, bool); bool shouldBeFloated(PHLWINDOW, bool pending = false); void checkBorders(PHLWINDOW); - Vector2D getMaxSizeForWindow(PHLWINDOW); - Vector2D getMinSizeForWindow(PHLWINDOW); Vector2D xwaylandToWaylandCoords(const Vector2D&); }; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 25d8b1ba..932882e9 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -323,6 +323,14 @@ void CXDGToplevelResource::close() { resource->sendClose(); } +Vector2D CXDGToplevelResource::layoutMinSize() { + return owner ? current.minSize + owner->current.geometry.pos() : current.minSize; +} + +Vector2D CXDGToplevelResource::layoutMaxSize() { + return owner ? current.maxSize + owner->current.geometry.pos() : current.maxSize; +} + CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, SP surface_) : owner(owner_), surface(surface_), resource(resource_) { if (!good()) diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 9c766c20..ef847f3b 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -99,6 +99,9 @@ class CXDGToplevelResource { bool good(); + Vector2D layoutMinSize(); + Vector2D layoutMaxSize(); + // schedule a configure event uint32_t setSize(const Vector2D& size); uint32_t setMaximized(bool maximized); From 9b03307653c179a86a8dfdb4e5d16446d0cf6e23 Mon Sep 17 00:00:00 2001 From: Alessio Molinari Date: Sun, 17 Nov 2024 20:34:03 +0100 Subject: [PATCH 0862/2393] hooks: add pre connected/disconnected monitor events (#8503) --- src/helpers/Monitor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index bfab2fd3..9ac48220 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -39,6 +39,7 @@ CMonitor::~CMonitor() { } void CMonitor::onConnect(bool noRule) { + EMIT_HOOK_EVENT("preMonitorAdded", self.lock()); CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }}; if (output->supportsExplicit) { @@ -238,6 +239,7 @@ void CMonitor::onConnect(bool noRule) { } void CMonitor::onDisconnect(bool destroy) { + EMIT_HOOK_EVENT("preMonitorRemoved", self.lock()); CScopeGuard x = {[this]() { if (g_pCompositor->m_bIsShuttingDown) return; From e8717a4fce1eafa44d5b106b8159d56e8d368840 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 21:57:00 +0000 Subject: [PATCH 0863/2393] shell: don't use fgrep, prefer grep -F --- src/debug/CrashReporter.cpp | 2 +- src/debug/HyprCtl.cpp | 2 +- src/helpers/MiscFunctions.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index 000d8c5d..319c1414 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -159,7 +159,7 @@ void CrashReporter::createAndSaveCrash(int sig) { finalCrashReport += "GPU:\n\t"; #if defined(__DragonFly__) || defined(__FreeBSD__) - finalCrashReport.writeCmdOutput("pciconf -lv | fgrep -A4 vga"); + finalCrashReport.writeCmdOutput("pciconf -lv | grep -F -A4 vga"); #else finalCrashReport.writeCmdOutput("lspci -vnn | grep VGA"); #endif diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 964a193b..6c9c2b75 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -946,7 +946,7 @@ std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request) result += "\n\n"; #if defined(__DragonFly__) || defined(__FreeBSD__) - const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); + const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); #elif defined(__arm__) || defined(__aarch64__) std::string GPUINFO; const std::filesystem::path dev_tree = "/proc/device-tree"; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 7b4d63a7..cfaae542 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -606,7 +606,7 @@ void logSystemInfo() { Debug::log(NONE, "\n"); #if defined(__DragonFly__) || defined(__FreeBSD__) - const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga"); + const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); #elif defined(__arm__) || defined(__aarch64__) const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); #else From 1ba050d603dca644aca48872f62388d794c030b9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 17 Nov 2024 21:58:00 +0000 Subject: [PATCH 0864/2393] shell: propagate new machanism from hyprctl to miscfunctions --- src/helpers/MiscFunctions.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index cfaae542..6ad1b37a 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -608,7 +608,24 @@ void logSystemInfo() { #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); #elif defined(__arm__) || defined(__aarch64__) - const std::string GPUINFO = execAndGet("cat /proc/device-tree/soc*/gpu*/compatible"); + const std::string GPUINFO; + const std::filesystem::path dev_tree = "/proc/device-tree"; + try { + if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) { + std::for_each(std::filesystem::directory_iterator(dev_tree), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& entry) { + if (std::filesystem::is_directory(entry) && entry.path().filename().string().starts_with("soc")) { + std::for_each(std::filesystem::directory_iterator(entry.path()), std::filesystem::directory_iterator{}, [&](const std::filesystem::directory_entry& sub_entry) { + if (std::filesystem::is_directory(sub_entry) && sub_entry.path().filename().string().starts_with("gpu")) { + std::filesystem::path file_path = sub_entry.path() / "compatible"; + std::ifstream file(file_path); + if (file) + GPUINFO.append(std::istreambuf_iterator(file), std::istreambuf_iterator()); + } + }); + } + }); + } + } catch (...) { GPUINFO = "error"; } #else const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA"); #endif From 2259a885513e8ec793210ceb9d40ca096161849d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 18 Nov 2024 13:59:57 +0000 Subject: [PATCH 0865/2393] miscfunctions: add missing include --- src/helpers/MiscFunctions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 6ad1b37a..c7cd9ed4 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include From 6744bb57c639d5359a414eea2566328bb05c7065 Mon Sep 17 00:00:00 2001 From: johannes hanika Date: Mon, 18 Nov 2024 15:02:34 +0100 Subject: [PATCH 0866/2393] constraints: don't warp pointer position on release (#8491) this was annoying for nuklear properties/ui slider elements that grab the pointer via GLFW_CURSOR_DISABLE to allow more range and finer control. upon mouse release, the pointer is reset to the middle of the window without this patch, making long mouse movements necessary to go back to the original position for readjustments. fwiw the new behaviour is consistent with x11 and weston. --- src/protocols/PointerConstraints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 0f2dd991..7f08a7df 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -188,7 +188,7 @@ Vector2D CPointerConstraint::logicPositionHint() { const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); const auto CONSTRAINTPOS = SURFBOX.has_value() ? SURFBOX->pos() : Vector2D{}; - return hintSet ? CONSTRAINTPOS + positionHint : (locked ? CONSTRAINTPOS + SURFBOX->size() / 2.f : cursorPosOnActivate); + return hintSet ? CONSTRAINTPOS + positionHint : cursorPosOnActivate; } CPointerConstraintsProtocol::CPointerConstraintsProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { From 505c1f8f4a5a4a97534f1906a47c11de638d970d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 18 Nov 2024 14:35:09 +0000 Subject: [PATCH 0867/2393] miscfunctions: fix cross build --- src/helpers/MiscFunctions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index c7cd9ed4..c8b3bef4 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -609,7 +609,7 @@ void logSystemInfo() { #if defined(__DragonFly__) || defined(__FreeBSD__) const std::string GPUINFO = execAndGet("pciconf -lv | grep -F -A4 vga"); #elif defined(__arm__) || defined(__aarch64__) - const std::string GPUINFO; + std::string GPUINFO; const std::filesystem::path dev_tree = "/proc/device-tree"; try { if (std::filesystem::exists(dev_tree) && std::filesystem::is_directory(dev_tree)) { From 97493511f96af288e1f7b2bd3a119e47d75541fc Mon Sep 17 00:00:00 2001 From: Aqa-Ib Date: Mon, 18 Nov 2024 15:44:15 +0100 Subject: [PATCH 0868/2393] internal: fix changeWindowZOrder reordering incorrectly (#8494) --- src/Compositor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index fbbfd7e7..0e0c75a1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1389,6 +1389,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { if (!validMapped(pWindow)) return; + if (top) + pWindow->m_bCreatedOverFullscreen = true; + if (pWindow == (top ? m_vWindows.back() : m_vWindows.front())) return; @@ -1413,9 +1416,6 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { g_pHyprRenderer->damageMonitor(pw->m_pMonitor.lock()); }; - if (top) - pWindow->m_bCreatedOverFullscreen = true; - if (!pWindow->m_bIsX11) moveToZ(pWindow, top); else { From df9ff4489973afa9e29bb94ac47c946db745b460 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=BA=F0=9F=87=A6=20Sviatoslav=20Sydorenko=20=28?= =?UTF-8?q?=D0=A1=D0=B2=D1=8F=D1=82=D0=BE=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1?= =?UTF-8?q?=D0=B8=D0=B4=D0=BE=D1=80=D0=B5=D0=BD=D0=BA=D0=BE=29?= Date: Mon, 18 Nov 2024 16:54:18 +0100 Subject: [PATCH 0869/2393] Fix example config name in auto-generated cfg header (#8509) Previously, it was suggesting to find `hypr.conf` in the `examples/` folder which doesn't exist. This patch fixed that to point to the existing file. Additionally, the change updates `HYPR` to `HYPRLAND` in the same header. --- src/config/defaultConfig.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index d680e92b..c4eb3385 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -4,8 +4,8 @@ inline const std::string AUTOCONFIG = R"#( # ####################################################################################### -# AUTOGENERATED HYPR CONFIG. -# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hypr.conf AND EDIT IT, +# AUTOGENERATED HYPRLAND CONFIG. +# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT, # OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. # ####################################################################################### From cc923ad031579a5d1ebe07269d5ecb291331ee51 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:45:22 +0100 Subject: [PATCH 0870/2393] config: update the configStringToInt implementation (#8476) Copied from hyprlang and removed std::expected. --- src/helpers/MiscFunctions.cpp | 74 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index c8b3bef4..80681826 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -692,43 +692,79 @@ int64_t getPPIDof(int64_t pid) { } int64_t configStringToInt(const std::string& VALUE) { + auto parseHex = [](const std::string& value) -> int64_t { + try { + size_t position; + auto result = stoll(value, &position, 16); + if (position == value.size()) + return result; + } catch (const std::exception&) {} + throw std::invalid_argument("invalid hex " + value); + }; if (VALUE.starts_with("0x")) { // Values with 0x are hex - const auto VALUEWITHOUTHEX = VALUE.substr(2); - return stol(VALUEWITHOUTHEX, nullptr, 16); + return parseHex(VALUE); } else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) { - const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6); + const auto VALUEWITHOUTFUNC = trim(VALUE.substr(5, VALUE.length() - 6)); - if (trim(VALUEWITHOUTFUNC).length() != 8) { - Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length()); - throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)"); + // try doing it the comma way first + if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 3) { + // cool + std::string rolling = VALUEWITHOUTFUNC; + auto r = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + rolling = rolling.substr(rolling.find(',') + 1); + auto g = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + rolling = rolling.substr(rolling.find(',') + 1); + auto b = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + rolling = rolling.substr(rolling.find(',') + 1); + uint8_t a = 0; + try { + a = std::round(std::stof(trim(rolling.substr(0, rolling.find(',')))) * 255.f); + } catch (std::exception& e) { throw std::invalid_argument("failed parsing " + VALUEWITHOUTFUNC); } + + return a * (Hyprlang::INT)0x1000000 + r * (Hyprlang::INT)0x10000 + g * (Hyprlang::INT)0x100 + b; + } else if (VALUEWITHOUTFUNC.length() == 8) { + const auto RGBA = parseHex(VALUEWITHOUTFUNC); + // now we need to RGBA -> ARGB. The config holds ARGB only. + return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF); } - const auto RGBA = std::stol(VALUEWITHOUTFUNC, nullptr, 16); + throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values"); - // now we need to RGBA -> ARGB. The config holds ARGB only. - return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF); } else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) { - const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5); + const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5)); - if (trim(VALUEWITHOUTFUNC).length() != 6) { - Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length()); - throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)"); + // try doing it the comma way first + if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 2) { + // cool + std::string rolling = VALUEWITHOUTFUNC; + auto r = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + rolling = rolling.substr(rolling.find(',') + 1); + auto g = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + rolling = rolling.substr(rolling.find(',') + 1); + auto b = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); + + return (Hyprlang::INT)0xFF000000 + r * (Hyprlang::INT)0x10000 + g * (Hyprlang::INT)0x100 + b; + } else if (VALUEWITHOUTFUNC.length() == 6) { + return parseHex(VALUEWITHOUTFUNC) + 0xFF000000; } - const auto RGB = std::stol(VALUEWITHOUTFUNC, nullptr, 16); - - return RGB + 0xFF000000; // 0xFF for opaque + throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values"); } else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) { return 1; } else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) { return 0; } - if (VALUE.empty() || !isNumber(VALUE)) - return 0; + if (VALUE.empty() || !isNumber(VALUE, false)) + throw std::invalid_argument("cannot parse \"" + VALUE + "\" as an int."); - return std::stoll(VALUE); + try { + const auto RES = std::stoll(VALUE); + return RES; + } catch (std::exception& e) { throw std::invalid_argument(std::string{"stoll threw: "} + e.what()); } + + return 0; } Vector2D configStringToVector2D(const std::string& VALUE) { From 6113f4da7fa9839645525e57ff841db5bb00e475 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Mon, 18 Nov 2024 19:48:13 +0000 Subject: [PATCH 0871/2393] keybinds: allow repeating multiple binds (#8290) --- src/managers/KeybindManager.cpp | 69 +++++++++++++++------------------ src/managers/KeybindManager.hpp | 7 ++-- 2 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4d2f4dcc..a0cd01a9 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -144,11 +144,30 @@ CKeybindManager::CKeybindManager() { }, nullptr); + m_pRepeatKeyTimer = makeShared( + std::nullopt, + [this](SP self, void* data) { + if (m_vActiveKeybinds.size() == 0 || g_pSeatManager->keyboard.expired()) + return; + + for (SKeybind* k : m_vActiveKeybinds) { + const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(k->handler); + + Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); + DISPATCHER->second(k->arg); + } + + const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); + self->updateTimeout(std::chrono::milliseconds(1000 / PACTIVEKEEB->repeatRate)); + }, + nullptr); + g_pEventLoopManager->addTimer(m_pLongPressTimer); + g_pEventLoopManager->addTimer(m_pRepeatKeyTimer); static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd - m_pActiveKeybind = nullptr; + m_vActiveKeybinds.clear(); m_pLastLongPressKeybind = nullptr; m_vPressedSpecialBinds.clear(); }); @@ -161,12 +180,16 @@ CKeybindManager::~CKeybindManager() { g_pEventLoopManager->removeTimer(m_pLongPressTimer); m_pLongPressTimer.reset(); } + if (m_pRepeatKeyTimer && g_pEventLoopManager) { + g_pEventLoopManager->removeTimer(m_pRepeatKeyTimer); + m_pRepeatKeyTimer.reset(); + } } void CKeybindManager::addKeybind(SKeybind kb) { m_lKeybinds.push_back(kb); - m_pActiveKeybind = nullptr; + m_vActiveKeybinds.clear(); m_pLastLongPressKeybind = nullptr; } @@ -180,7 +203,7 @@ void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { } } - m_pActiveKeybind = nullptr; + m_vActiveKeybinds.clear(); m_pLastLongPressKeybind = nullptr; } @@ -426,11 +449,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { .submapAtPress = m_szCurrentSelectedSubmap, }; - if (m_pActiveKeybindEventSource) { - wl_event_source_remove(m_pActiveKeybindEventSource); - m_pActiveKeybindEventSource = nullptr; - m_pActiveKeybind = nullptr; - } + m_vActiveKeybinds.clear(); m_pLastLongPressKeybind = nullptr; @@ -482,11 +501,7 @@ bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) { m_tScrollTimer.reset(); - if (m_pActiveKeybindEventSource) { - wl_event_source_remove(m_pActiveKeybindEventSource); - m_pActiveKeybindEventSource = nullptr; - m_pActiveKeybind = nullptr; - } + m_vActiveKeybinds.clear(); bool found = false; if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { @@ -525,11 +540,7 @@ bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) { .modmaskAtPressTime = MODS, }; - if (m_pActiveKeybindEventSource) { - wl_event_source_remove(m_pActiveKeybindEventSource); - m_pActiveKeybindEventSource = nullptr; - m_pActiveKeybind = nullptr; - } + m_vActiveKeybinds.clear(); if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_dPressedKeys.push_back(KEY); @@ -580,22 +591,6 @@ void CKeybindManager::onSwitchOffEvent(const std::string& switchName) { handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:off:" + switchName}, true); } -int repeatKeyHandler(void* data) { - SKeybind** ppActiveKeybind = (SKeybind**)data; - - if (!*ppActiveKeybind || g_pSeatManager->keyboard.expired()) - return 0; - - const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find((*ppActiveKeybind)->handler); - - Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); - DISPATCHER->second((*ppActiveKeybind)->arg); - - wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate); - - return 0; -} - eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set keybindKeysyms, const std::set pressedKeysyms) { // Returns whether two sets of keysyms are equal, partially equal, or not // matching. (Partially matching means that pressed is a subset of bound) @@ -770,12 +765,10 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP } if (k.repeat) { - m_pActiveKeybind = &k; - m_pActiveKeybindEventSource = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, repeatKeyHandler, &m_pActiveKeybind); - const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); - wl_event_source_timer_update(m_pActiveKeybindEventSource, PACTIVEKEEB->repeatDelay); + m_vActiveKeybinds.push_back(&k); + m_pRepeatKeyTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay)); } if (!k.nonConsuming) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 4a0af6e9..d375db0f 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -102,8 +102,6 @@ class CKeybindManager { std::unordered_map> m_mDispatchers; - wl_event_source* m_pActiveKeybindEventSource = nullptr; - bool m_bGroupsLocked = false; std::list m_lKeybinds; @@ -121,8 +119,9 @@ class CKeybindManager { inline static std::string m_szCurrentSelectedSubmap = ""; - SKeybind * m_pActiveKeybind = nullptr, *m_pLastLongPressKeybind = nullptr; - SP m_pLongPressTimer; + std::vector m_vActiveKeybinds; + SKeybind* m_pLastLongPressKeybind = nullptr; + SP m_pLongPressTimer, m_pRepeatKeyTimer; uint32_t m_uTimeLastMs = 0; uint32_t m_uLastCode = 0; From 936dfedbadbae761cd307ba7509467b55ac5e1ae Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 18 Nov 2024 19:56:26 +0000 Subject: [PATCH 0872/2393] keybinds: move to managed pointers --- src/debug/HyprCtl.cpp | 26 ++++---- src/managers/KeybindManager.cpp | 107 +++++++++++++++----------------- src/managers/KeybindManager.hpp | 10 +-- 3 files changed, 68 insertions(+), 75 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6c9c2b75..1b94296f 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -814,28 +814,28 @@ std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::string requ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string ret = ""; if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto const& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_vKeybinds) { ret += "bind"; - if (kb.locked) + if (kb->locked) ret += "l"; - if (kb.mouse) + if (kb->mouse) ret += "m"; - if (kb.release) + if (kb->release) ret += "r"; - if (kb.repeat) + if (kb->repeat) ret += "e"; - if (kb.nonConsuming) + if (kb->nonConsuming) ret += "n"; - if (kb.hasDescription) + if (kb->hasDescription) ret += "d"; - ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, - kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg); + ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb->modmask, + kb->submap, kb->key, kb->keycode, kb->catchAll, kb->description, kb->handler, kb->arg); } } else { // json ret += "["; - for (auto const& kb : g_pKeybindManager->m_lKeybinds) { + for (auto const& kb : g_pKeybindManager->m_vKeybinds) { ret += std::format( R"#( {{ @@ -855,9 +855,9 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "dispatcher": "{}", "arg": "{}" }},)#", - kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.longPress ? "true" : "false", - kb.nonConsuming ? "true" : "false", kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, - kb.catchAll ? "true" : "false", escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); + kb->locked ? "true" : "false", kb->mouse ? "true" : "false", kb->release ? "true" : "false", kb->repeat ? "true" : "false", kb->longPress ? "true" : "false", + kb->nonConsuming ? "true" : "false", kb->hasDescription ? "true" : "false", kb->modmask, escapeJSONStrings(kb->submap), escapeJSONStrings(kb->key), kb->keycode, + kb->catchAll ? "true" : "false", escapeJSONStrings(kb->description), escapeJSONStrings(kb->handler), escapeJSONStrings(kb->arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index a0cd01a9..995fee17 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -150,7 +150,7 @@ CKeybindManager::CKeybindManager() { if (m_vActiveKeybinds.size() == 0 || g_pSeatManager->keyboard.expired()) return; - for (SKeybind* k : m_vActiveKeybinds) { + for (const auto& k : m_vActiveKeybinds) { const auto DISPATCHER = g_pKeybindManager->m_mDispatchers.find(k->handler); Debug::log(LOG, "Keybind repeat triggered, calling dispatcher."); @@ -168,7 +168,7 @@ CKeybindManager::CKeybindManager() { static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd m_vActiveKeybinds.clear(); - m_pLastLongPressKeybind = nullptr; + m_pLastLongPressKeybind.reset(); m_vPressedSpecialBinds.clear(); }); } @@ -187,24 +187,17 @@ CKeybindManager::~CKeybindManager() { } void CKeybindManager::addKeybind(SKeybind kb) { - m_lKeybinds.push_back(kb); + m_vKeybinds.emplace_back(makeShared(kb)); m_vActiveKeybinds.clear(); - m_pLastLongPressKeybind = nullptr; + m_pLastLongPressKeybind.reset(); } void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { - for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) { - if (it->modmask == mod && it->key == key.key && it->keycode == key.keycode && it->catchAll == key.catchAll) { - it = m_lKeybinds.erase(it); - - if (it == m_lKeybinds.end()) - break; - } - } + std::erase_if(m_vKeybinds, [&mod, &key](const auto& el) { return el->modmask == mod && el->key == key.key && el->keycode == key.keycode && el->catchAll == key.catchAll; }); m_vActiveKeybinds.clear(); - m_pLastLongPressKeybind = nullptr; + m_pLastLongPressKeybind.reset(); } uint32_t CKeybindManager::stringToModMask(std::string mods) { @@ -451,7 +444,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { m_vActiveKeybinds.clear(); - m_pLastLongPressKeybind = nullptr; + m_pLastLongPressKeybind.reset(); bool suppressEvent = false; if (e.state == WL_KEYBOARD_KEY_STATE_PRESSED) { @@ -612,11 +605,11 @@ eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set k return MK_NO_MATCH; } -eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { - if (mkKeysymSetMatches(keybind.sMkMods, m_sMkMods) != MK_FULL_MATCH) +eMultiKeyCase CKeybindManager::mkBindMatches(const SP keybind) { + if (mkKeysymSetMatches(keybind->sMkMods, m_sMkMods) != MK_FULL_MATCH) return MK_NO_MATCH; - return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); + return mkKeysymSetMatches(keybind->sMkKeys, m_sMkKeys); } std::string CKeybindManager::getCurrentSubmap() { @@ -640,35 +633,35 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP m_sMkKeys.erase(key.keysym); } - for (auto& k : m_lKeybinds) { - const bool SPECIALDISPATCHER = k.handler == "global" || k.handler == "pass" || k.handler == "sendshortcut" || k.handler == "mouse"; + for (auto& k : m_vKeybinds) { + const bool SPECIALDISPATCHER = k->handler == "global" || k->handler == "pass" || k->handler == "sendshortcut" || k->handler == "mouse"; const bool SPECIALTRIGGERED = - std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == &k; }) != m_vPressedSpecialBinds.end(); + std::find_if(m_vPressedSpecialBinds.begin(), m_vPressedSpecialBinds.end(), [&](const auto& other) { return other == k; }) != m_vPressedSpecialBinds.end(); const bool IGNORECONDITIONS = SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. - if (!k.dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) + if (!k->dontInhibit && !*PDISABLEINHIBIT && PROTO::shortcutsInhibit->isInhibited()) continue; - if (!k.locked && g_pSessionLockManager->isSessionLocked()) + if (!k->locked && g_pSessionLockManager->isSessionLocked()) continue; - if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) + if (!IGNORECONDITIONS && ((modmask != k->modmask && !k->ignoreMods) || k->submap != m_szCurrentSelectedSubmap || k->shadowed)) continue; - if (k.multiKey) { + if (k->multiKey) { switch (mkBindMatches(k)) { case MK_NO_MATCH: continue; case MK_PARTIAL_MATCH: found = true; continue; case MK_FULL_MATCH: found = true; } } else if (!key.keyName.empty()) { - if (key.keyName != k.key) + if (key.keyName != k->key) continue; - } else if (k.keycode != 0) { - if (key.keycode != k.keycode) + } else if (k->keycode != 0) { + if (key.keycode != k->keycode) continue; - } else if (k.catchAll) { + } else if (k->catchAll) { if (found || key.submapAtPress != m_szCurrentSelectedSubmap) continue; } else { @@ -679,8 +672,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs - const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_NO_FLAGS); - const auto KBKEYLOWER = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEY = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_NO_FLAGS); + const auto KBKEYLOWER = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); if (KBKEY == XKB_KEY_NoSymbol && KBKEYLOWER == XKB_KEY_NoSymbol) { // Keysym failed to resolve from the key name of the currently iterated bind. @@ -697,8 +690,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP continue; } - if (pressed && k.release && !SPECIALDISPATCHER) { - if (k.nonConsuming) + if (pressed && k->release && !SPECIALDISPATCHER) { + if (k->nonConsuming) continue; found = true; // suppress the event @@ -707,7 +700,7 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP if (!pressed) { // Require mods to be matching when the key was first pressed. - if (key.modmaskAtPressTime != modmask && !k.ignoreMods) { + if (key.modmaskAtPressTime != modmask && !k->ignoreMods) { // Handle properly `bindr` where a key is itself a bind mod for example: // "bindr = SUPER, SUPER_L, exec, $launcher". // This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set @@ -716,8 +709,8 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP if (keycodeToModifier(key.keycode) == key.modmaskAtPressTime) continue; - } else if (!k.release && !SPECIALDISPATCHER) { - if (k.nonConsuming) + } else if (!k->release && !SPECIALDISPATCHER) { + if (k->nonConsuming) continue; found = true; // suppress the event @@ -725,25 +718,25 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP } } - if (k.longPress) { + if (k->longPress) { const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); m_pLongPressTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay)); - m_pLastLongPressKeybind = &k; + m_pLastLongPressKeybind = k; continue; } - const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler); + const auto DISPATCHER = m_mDispatchers.find(k->mouse ? "mouse" : k->handler); if (SPECIALTRIGGERED && !pressed) - std::erase_if(m_vPressedSpecialBinds, [&](const auto& other) { return other == &k; }); + std::erase_if(m_vPressedSpecialBinds, [&](const auto& other) { return other == k; }); else if (SPECIALDISPATCHER && pressed) - m_vPressedSpecialBinds.push_back(&k); + m_vPressedSpecialBinds.push_back(k); // Should never happen, as we check in the ConfigManager, but oh well if (DISPATCHER == m_mDispatchers.end()) { - Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k.handler); + Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k->handler); } else { // call the dispatcher Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym); @@ -751,27 +744,27 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP m_iPassPressed = (int)pressed; // if the dispatchers says to pass event then we will - if (k.handler == "mouse") - res = DISPATCHER->second((pressed ? "1" : "0") + k.arg); + if (k->handler == "mouse") + res = DISPATCHER->second((pressed ? "1" : "0") + k->arg); else - res = DISPATCHER->second(k.arg); + res = DISPATCHER->second(k->arg); m_iPassPressed = -1; - if (k.handler == "submap") { + if (k->handler == "submap") { found = true; // don't process keybinds on submap change. break; } } - if (k.repeat) { + if (k->repeat) { const auto PACTIVEKEEB = g_pSeatManager->keyboard.lock(); - m_vActiveKeybinds.push_back(&k); + m_vActiveKeybinds.push_back(k); m_pRepeatKeyTimer->updateTimeout(std::chrono::milliseconds(PACTIVEKEEB->repeatDelay)); } - if (!k.nonConsuming) + if (!k->nonConsuming) found = true; } @@ -792,17 +785,17 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) { // shadow disables keybinds after one has been triggered - for (auto& k : m_lKeybinds) { + for (auto& k : m_vKeybinds) { bool shadow = false; - if (k.handler == "global" || k.transparent) + if (k->handler == "global" || k->transparent) continue; // can't be shadowed - if (k.multiKey && (mkBindMatches(k) == MK_FULL_MATCH)) + if (k->multiKey && (mkBindMatches(k) == MK_FULL_MATCH)) shadow = true; else { - const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEY = xkb_keysym_from_name(k->key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); for (auto const& pk : m_dPressedKeys) { @@ -815,7 +808,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 } } - if (pk.keycode != 0 && pk.keycode == k.keycode) { + if (pk.keycode != 0 && pk.keycode == k->keycode) { shadow = true; if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { @@ -826,7 +819,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 } } - k.shadowed = shadow; + k->shadowed = shadow; } } @@ -1004,7 +997,7 @@ SDispatchResult CKeybindManager::kill(std::string args) { } void CKeybindManager::clearKeybinds() { - m_lKeybinds.clear(); + m_vKeybinds.clear(); } static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional floatState) { @@ -2182,8 +2175,8 @@ SDispatchResult CKeybindManager::setSubmap(std::string submap) { return {}; } - for (auto const& k : g_pKeybindManager->m_lKeybinds) { - if (k.submap == submap) { + for (const auto& k : g_pKeybindManager->m_vKeybinds) { + if (k->submap == submap) { m_szCurrentSelectedSubmap = submap; Debug::log(LOG, "Changed keybind submap to {}", submap); g_pEventManager->postEvent(SHyprIPCEvent{"submap", submap}); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index d375db0f..1f60fdd2 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -104,7 +104,7 @@ class CKeybindManager { bool m_bGroupsLocked = false; - std::list m_lKeybinds; + std::vector> m_vKeybinds; //since we cant find keycode through keyname in xkb: //on sendshortcut call, we once search for keyname (e.g. "g") the correct keycode (e.g. 42) @@ -119,15 +119,15 @@ class CKeybindManager { inline static std::string m_szCurrentSelectedSubmap = ""; - std::vector m_vActiveKeybinds; - SKeybind* m_pLastLongPressKeybind = nullptr; + std::vector> m_vActiveKeybinds; + WP m_pLastLongPressKeybind; SP m_pLongPressTimer, m_pRepeatKeyTimer; uint32_t m_uTimeLastMs = 0; uint32_t m_uLastCode = 0; uint32_t m_uLastMouseCode = 0; - std::vector m_vPressedSpecialBinds; + std::vector> m_vPressedSpecialBinds; int m_iPassPressed = -1; // used for pass @@ -137,7 +137,7 @@ class CKeybindManager { std::set m_sMkKeys = {}; std::set m_sMkMods = {}; - eMultiKeyCase mkBindMatches(const SKeybind); + eMultiKeyCase mkBindMatches(const SP); eMultiKeyCase mkKeysymSetMatches(const std::set, const std::set); bool handleInternalKeybinds(xkb_keysym_t); From 47a1650c4810ad3cb3e9f125cb0addf18aa7395c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 18 Nov 2024 23:53:38 +0000 Subject: [PATCH 0873/2393] miscfunctions: move configStringToInt to std::expected --- src/config/ConfigManager.cpp | 54 +++++++++++++++++++++------------ src/debug/HyprCtl.cpp | 4 +-- src/desktop/LayerSurface.cpp | 2 +- src/desktop/Window.cpp | 8 ++--- src/helpers/MiscFunctions.cpp | 37 ++++++++++++++-------- src/helpers/MiscFunctions.hpp | 45 +++++++++++++-------------- src/managers/KeybindManager.cpp | 15 +++++---- src/plugins/HookSystem.cpp | 13 +++++--- 8 files changed, 106 insertions(+), 72 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1c025179..fe80a5ab 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -67,7 +67,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** } try { - DATA->m_vColors.push_back(CColor(configStringToInt(var))); + DATA->m_vColors.push_back(CColor(*configStringToInt(var))); } catch (std::exception& e) { Debug::log(WARN, "Error parsing gradient {}", V); parseError = "Error parsing gradient " + V + ": " + e.what(); @@ -2615,7 +2615,14 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin const static std::string ruleOnCreatedEmpty = "on-created-empty:"; const static auto ruleOnCreatedEmptyLen = ruleOnCreatedEmpty.length(); - auto assignRule = [&](std::string rule) -> std::optional { +#define CHECK_OR_THROW(expr) \ + \ + auto X = expr; \ + if (!X) { \ + return "Failed parsing a workspace rule"; \ + } + + auto assignRule = [&](std::string rule) -> std::optional { size_t delim = std::string::npos; if ((delim = rule.find("gapsin:")) != std::string::npos) { CVarList varlist = CVarList(rule.substr(delim + 7), 0, ' '); @@ -2633,25 +2640,32 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin try { wsRule.borderSize = std::stoi(rule.substr(delim + 11)); } catch (...) { return "Error parsing workspace rule bordersize: {}", rule.substr(delim + 11); } - else if ((delim = rule.find("border:")) != std::string::npos) - wsRule.noBorder = !configStringToInt(rule.substr(delim + 7)); - else if ((delim = rule.find("shadow:")) != std::string::npos) - wsRule.noShadow = !configStringToInt(rule.substr(delim + 7)); - else if ((delim = rule.find("rounding:")) != std::string::npos) - wsRule.noRounding = !configStringToInt(rule.substr(delim + 9)); - else if ((delim = rule.find("decorate:")) != std::string::npos) - wsRule.decorate = configStringToInt(rule.substr(delim + 9)); - else if ((delim = rule.find("monitor:")) != std::string::npos) + else if ((delim = rule.find("border:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 7))) + wsRule.noBorder = !*X; + } else if ((delim = rule.find("shadow:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 7))) + wsRule.noShadow = !*X; + } else if ((delim = rule.find("rounding:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 9))) + wsRule.noRounding = !*X; + } else if ((delim = rule.find("decorate:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 9))) + wsRule.decorate = *X; + } else if ((delim = rule.find("monitor:")) != std::string::npos) wsRule.monitor = rule.substr(delim + 8); - else if ((delim = rule.find("default:")) != std::string::npos) - wsRule.isDefault = configStringToInt(rule.substr(delim + 8)); - else if ((delim = rule.find("persistent:")) != std::string::npos) - wsRule.isPersistent = configStringToInt(rule.substr(delim + 11)); - else if ((delim = rule.find("defaultName:")) != std::string::npos) + else if ((delim = rule.find("default:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 8))) + wsRule.isDefault = *X; + } else if ((delim = rule.find("persistent:")) != std::string::npos) { + CHECK_OR_THROW(configStringToInt(rule.substr(delim + 11))) + wsRule.isPersistent = *X; + } else if ((delim = rule.find("defaultName:")) != std::string::npos) wsRule.defaultName = rule.substr(delim + 12); - else if ((delim = rule.find(ruleOnCreatedEmpty)) != std::string::npos) - wsRule.onCreatedEmptyRunCmd = cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmptyLen)); - else if ((delim = rule.find("layoutopt:")) != std::string::npos) { + else if ((delim = rule.find(ruleOnCreatedEmpty)) != std::string::npos) { + CHECK_OR_THROW(cleanCmdForWorkspace(name, rule.substr(delim + ruleOnCreatedEmptyLen))) + wsRule.onCreatedEmptyRunCmd = *X; + } else if ((delim = rule.find("layoutopt:")) != std::string::npos) { std::string opt = rule.substr(delim + 10); if (!opt.contains(":")) { // invalid @@ -2668,6 +2682,8 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin return {}; }; +#undef CHECK_OR_THROW + CVarList rulesList{rules, 0, ',', true}; for (auto const& r : rulesList) { const auto R = assignRule(r); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 1b94296f..4d3c2be4 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1286,7 +1286,7 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) { return "ok"; } - const CColor COLOR = configStringToInt(vars[1]); + const CColor COLOR = configStringToInt(vars[1]).value_or(0); for (size_t i = 2; i < vars.size(); ++i) errorMessage += vars[i] + ' '; @@ -1539,7 +1539,7 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) { time = std::stoi(TIME); } catch (std::exception& e) { return "invalid arg 2"; } - CColor color = configStringToInt(vars[3]); + CColor color = configStringToInt(vars[3]).value_or(0); size_t msgidx = 4; float fontsize = 13.f; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index cd1c4742..40491123 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -400,7 +400,7 @@ void CLayerSurface::applyRules() { } else if (rule.rule.starts_with("xray")) { CVarList vars{rule.rule, 0, ' '}; try { - xray = configStringToInt(vars[1]); + xray = configStringToInt(vars[1]).value_or(false); } catch (...) {} } else if (rule.rule.starts_with("animation")) { CVarList vars{rule.rule, 2, 's'}; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e74e13a2..33e6a5f8 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -672,8 +672,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { // Basic form has only two colors, everything else can be parsed as a gradient if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { - m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]))), priority); - m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]))), priority); + m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority); + m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority); return; } @@ -685,9 +685,9 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { } else if (token.contains("deg")) inactiveBorderGradient.m_fAngle = std::stoi(token.substr(0, token.size() - 3)) * (PI / 180.0); else if (active) - activeBorderGradient.m_vColors.push_back(configStringToInt(token)); + activeBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0)); else - inactiveBorderGradient.m_vColors.push_back(configStringToInt(token)); + inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0)); } // Includes sanity checks for the number of colors in each gradient diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 80681826..fa2f84ab 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -691,15 +691,15 @@ int64_t getPPIDof(int64_t pid) { #endif } -int64_t configStringToInt(const std::string& VALUE) { - auto parseHex = [](const std::string& value) -> int64_t { +std::expected configStringToInt(const std::string& VALUE) { + auto parseHex = [](const std::string& value) -> std::expected { try { size_t position; auto result = stoll(value, &position, 16); if (position == value.size()) return result; } catch (const std::exception&) {} - throw std::invalid_argument("invalid hex " + value); + return std::unexpected("invalid hex " + value); }; if (VALUE.starts_with("0x")) { // Values with 0x are hex @@ -718,18 +718,25 @@ int64_t configStringToInt(const std::string& VALUE) { auto b = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); rolling = rolling.substr(rolling.find(',') + 1); uint8_t a = 0; + + if (!r || !g || !b) + return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); + try { a = std::round(std::stof(trim(rolling.substr(0, rolling.find(',')))) * 255.f); - } catch (std::exception& e) { throw std::invalid_argument("failed parsing " + VALUEWITHOUTFUNC); } + } catch (std::exception& e) { return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); } - return a * (Hyprlang::INT)0x1000000 + r * (Hyprlang::INT)0x10000 + g * (Hyprlang::INT)0x100 + b; + return a * (Hyprlang::INT)0x1000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b; } else if (VALUEWITHOUTFUNC.length() == 8) { const auto RGBA = parseHex(VALUEWITHOUTFUNC); + + if (!RGBA) + return RGBA; // now we need to RGBA -> ARGB. The config holds ARGB only. - return (RGBA >> 8) + 0x1000000 * (RGBA & 0xFF); + return (*RGBA >> 8) + 0x1000000 * (*RGBA & 0xFF); } - throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values"); + return std::unexpected("rgba() expects length of 8 characters (4 bytes) or 4 comma separated values"); } else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) { const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5)); @@ -744,12 +751,16 @@ int64_t configStringToInt(const std::string& VALUE) { rolling = rolling.substr(rolling.find(',') + 1); auto b = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); - return (Hyprlang::INT)0xFF000000 + r * (Hyprlang::INT)0x10000 + g * (Hyprlang::INT)0x100 + b; + if (!r || !g || !b) + return std::unexpected("failed parsing " + VALUEWITHOUTFUNC); + + return (Hyprlang::INT)0xFF000000 + *r * (Hyprlang::INT)0x10000 + *g * (Hyprlang::INT)0x100 + *b; } else if (VALUEWITHOUTFUNC.length() == 6) { - return parseHex(VALUEWITHOUTFUNC) + 0xFF000000; + auto r = parseHex(VALUEWITHOUTFUNC); + return r ? *r + 0xFF000000 : r; } - throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values"); + return std::unexpected("rgb() expects length of 6 characters (3 bytes) or 3 comma separated values"); } else if (VALUE.starts_with("true") || VALUE.starts_with("on") || VALUE.starts_with("yes")) { return 1; } else if (VALUE.starts_with("false") || VALUE.starts_with("off") || VALUE.starts_with("no")) { @@ -757,14 +768,14 @@ int64_t configStringToInt(const std::string& VALUE) { } if (VALUE.empty() || !isNumber(VALUE, false)) - throw std::invalid_argument("cannot parse \"" + VALUE + "\" as an int."); + return std::unexpected("cannot parse \"" + VALUE + "\" as an int."); try { const auto RES = std::stoll(VALUE); return RES; - } catch (std::exception& e) { throw std::invalid_argument(std::string{"stoll threw: "} + e.what()); } + } catch (std::exception& e) { return std::unexpected(std::string{"stoll threw: "} + e.what()); } - return 0; + return std::unexpected("parse error"); } Vector2D configStringToVector2D(const std::string& VALUE) { diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 34b23746..bb686df4 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -6,6 +6,7 @@ #include "math/Math.hpp" #include #include +#include #include "../SharedDefs.hpp" #include "../macros.hpp" @@ -19,28 +20,28 @@ struct SWorkspaceIDName { std::string name; }; -std::string absolutePath(const std::string&, const std::string&); -void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); -void removeWLSignal(wl_listener*); -std::string escapeJSONStrings(const std::string& str); -bool isDirection(const std::string&); -bool isDirection(const char&); -SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&); -std::optional cleanCmdForWorkspace(const std::string&, std::string); -float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); -void logSystemInfo(); -std::string execAndGet(const char*); -int64_t getPPIDof(int64_t pid); -int64_t configStringToInt(const std::string&); -Vector2D configStringToVector2D(const std::string&); -std::optional getPlusMinusKeywordResult(std::string in, float relative); -double normalizeAngleRad(double ang); -std::vector getBacktrace(); -void throwError(const std::string& err); -bool envEnabled(const std::string& env); -int allocateSHMFile(size_t len); -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); -float stringToPercentage(const std::string& VALUE, const float REL); +std::string absolutePath(const std::string&, const std::string&); +void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); +void removeWLSignal(wl_listener*); +std::string escapeJSONStrings(const std::string& str); +bool isDirection(const std::string&); +bool isDirection(const char&); +SWorkspaceIDName getWorkspaceIDNameFromString(const std::string&); +std::optional cleanCmdForWorkspace(const std::string&, std::string); +float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2); +void logSystemInfo(); +std::string execAndGet(const char*); +int64_t getPPIDof(int64_t pid); +std::expected configStringToInt(const std::string&); +Vector2D configStringToVector2D(const std::string&); +std::optional getPlusMinusKeywordResult(std::string in, float relative); +double normalizeAngleRad(double ang); +std::vector getBacktrace(); +void throwError(const std::string& err); +bool envEnabled(const std::string& env); +int allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +float stringToPercentage(const std::string& VALUE, const float REL); template [[deprecated("use std::format instead")]] std::string getFormat(std::format_string fmt, Args&&... args) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 995fee17..c9ca90e5 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2972,11 +2972,14 @@ SDispatchResult CKeybindManager::setProp(std::string args) { const auto TOKEN = vars[i]; if (TOKEN.ends_with("deg")) colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); - else - colorData.m_vColors.push_back(configStringToInt(TOKEN)); + else if (const auto V = configStringToInt(TOKEN); V) + colorData.m_vColors.push_back(*V); } - } else if (VAL != "-1") - colorData.m_vColors.push_back(configStringToInt(VAL)); + } else if (VAL != "-1") { + const auto V = configStringToInt(VAL); + if (V) + colorData.m_vColors.push_back(*V); + } if (PROP == "activebordercolor") PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); @@ -2993,8 +2996,8 @@ SDispatchResult CKeybindManager::setProp(std::string args) { } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) { if (VAL == "unset") search->second(PWINDOW)->unset(PRIORITY_SET_PROP); - else - *(search->second(PWINDOW)) = CWindowOverridableVar((int)configStringToInt(VAL), PRIORITY_SET_PROP); + else if (const auto V = configStringToInt(VAL); V) + *(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP); } else { return {.success = false, .error = "Prop not found"}; } diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 745b2593..69ca81cb 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -90,11 +90,14 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline); if (code.contains("%rip")) { - CVarList tokens{code, 0, 's'}; - size_t plusPresent = tokens[1][0] == '+' ? 1 : 0; - size_t minusPresent = tokens[1][0] == '-' ? 1 : 0; - std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent)); - const int32_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr); + CVarList tokens{code, 0, 's'}; + size_t plusPresent = tokens[1][0] == '+' ? 1 : 0; + size_t minusPresent = tokens[1][0] == '-' ? 1 : 0; + std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent)); + auto addrResult = configStringToInt(addr); + if (!addrResult) + return {}; + const int32_t OFFSET = (minusPresent ? -1 : 1) * *addrResult; if (OFFSET == 0) return {}; const uint64_t DESTINATION = currentAddress + OFFSET + len; From 67cee430061626ccd73dc6d30eed9db289053608 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 19 Nov 2024 01:16:11 +0000 Subject: [PATCH 0874/2393] internal: minor cleanups for color results --- src/debug/HyprCtl.cpp | 8 +++++--- src/managers/KeybindManager.cpp | 23 ++++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 4d3c2be4..7c0a9417 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1529,9 +1529,8 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) { icon = std::stoi(ICON); } catch (std::exception& e) { return "invalid arg 1"; } - if (icon > ICON_NONE || icon < 0) { + if (icon > ICON_NONE || icon < 0) icon = ICON_NONE; - } const auto TIME = vars[2]; int time = 0; @@ -1539,7 +1538,10 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) { time = std::stoi(TIME); } catch (std::exception& e) { return "invalid arg 2"; } - CColor color = configStringToInt(vars[3]).value_or(0); + const auto COLOR_RESULT = configStringToInt(vars[3]); + if (!COLOR_RESULT) + return "invalid arg 3"; + CColor color = *COLOR_RESULT; size_t msgidx = 4; float fontsize = 13.f; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c9ca90e5..75e2a7b3 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2920,6 +2920,9 @@ SDispatchResult CKeybindManager::event(std::string args) { return {}; } +#include +#include + SDispatchResult CKeybindManager::setProp(std::string args) { CVarList vars(args, 3, ' '); @@ -2972,14 +2975,17 @@ SDispatchResult CKeybindManager::setProp(std::string args) { const auto TOKEN = vars[i]; if (TOKEN.ends_with("deg")) colorData.m_fAngle = std::stoi(TOKEN.substr(0, TOKEN.size() - 3)) * (PI / 180.0); - else if (const auto V = configStringToInt(TOKEN); V) - colorData.m_vColors.push_back(*V); + else + configStringToInt(TOKEN).and_then([&colorData](const auto& e) { + colorData.m_vColors.push_back(e); + return std::result_of::type(1); + }); } - } else if (VAL != "-1") { - const auto V = configStringToInt(VAL); - if (V) - colorData.m_vColors.push_back(*V); - } + } else if (VAL != "-1") + configStringToInt(VAL).and_then([&colorData](const auto& e) { + colorData.m_vColors.push_back(e); + return std::result_of::type(1); + }); if (PROP == "activebordercolor") PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); @@ -2998,9 +3004,8 @@ SDispatchResult CKeybindManager::setProp(std::string args) { search->second(PWINDOW)->unset(PRIORITY_SET_PROP); else if (const auto V = configStringToInt(VAL); V) *(search->second(PWINDOW)) = CWindowOverridableVar((int)*V, PRIORITY_SET_PROP); - } else { + } else return {.success = false, .error = "Prop not found"}; - } } catch (std::exception& e) { return {.success = false, .error = std::format("Error parsing prop value: {}", std::string(e.what()))}; } g_pCompositor->updateAllWindowsAnimatedDecorationValues(); From aa067a4cf12522ede1752dd2048ce67d07e903f1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 19 Nov 2024 21:40:16 +0000 Subject: [PATCH 0875/2393] xdg-shell: don't report invalid min/max sizes on unset fixes #8522 --- src/protocols/XDGShell.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 932882e9..f121070d 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -324,10 +324,14 @@ void CXDGToplevelResource::close() { } Vector2D CXDGToplevelResource::layoutMinSize() { + if (current.minSize.x <= 1 && current.minSize.y <= 1) + return {0, 0}; return owner ? current.minSize + owner->current.geometry.pos() : current.minSize; } Vector2D CXDGToplevelResource::layoutMaxSize() { + if (current.maxSize.x <= 1 && current.maxSize.y <= 1) + return {0, 0}; return owner ? current.maxSize + owner->current.geometry.pos() : current.maxSize; } From c4eda46d0ef022a17348623beec4154ba34af691 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 19 Nov 2024 22:07:25 +0000 Subject: [PATCH 0876/2393] xdg-shell: even more robust layout min/max size although I don't think any apps use this, but better safe than sorry --- src/protocols/XDGShell.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index f121070d..688d0006 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -324,15 +324,21 @@ void CXDGToplevelResource::close() { } Vector2D CXDGToplevelResource::layoutMinSize() { - if (current.minSize.x <= 1 && current.minSize.y <= 1) - return {0, 0}; - return owner ? current.minSize + owner->current.geometry.pos() : current.minSize; + Vector2D minSize; + if (current.minSize.x > 1) + minSize.x = owner ? current.minSize.x + owner->current.geometry.pos().x : current.minSize.x; + if (current.minSize.y > 1) + minSize.y = owner ? current.minSize.y + owner->current.geometry.pos().y : current.minSize.y; + return minSize; } Vector2D CXDGToplevelResource::layoutMaxSize() { - if (current.maxSize.x <= 1 && current.maxSize.y <= 1) - return {0, 0}; - return owner ? current.maxSize + owner->current.geometry.pos() : current.maxSize; + Vector2D maxSize; + if (current.maxSize.x > 1) + maxSize.x = owner ? current.maxSize.x + owner->current.geometry.pos().x : current.maxSize.x; + if (current.maxSize.y > 1) + maxSize.y = owner ? current.maxSize.y + owner->current.geometry.pos().y : current.maxSize.y; + return maxSize; } CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, SP surface_) : From e5fa017172156fa5c70fedeaee5f51eace9577c0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 20 Nov 2024 10:32:50 +0000 Subject: [PATCH 0877/2393] internal: fix some misused configStringToInt conversions fixes #8523 --- src/config/ConfigManager.cpp | 4 ++-- src/desktop/Window.cpp | 2 +- src/desktop/Workspace.cpp | 4 ++-- src/managers/KeybindManager.cpp | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fe80a5ab..357e7a60 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2101,13 +2101,13 @@ std::optional CConfigManager::handleAnimation(const std::string& co PANIM->second.pValues = &PANIM->second; // This helper casts strings like "1", "true", "off", "yes"... to int. - int64_t enabledInt = configStringToInt(ARGS[1]) == 1; + int64_t enabledInt = configStringToInt(ARGS[1]).value_or(0) == 1; // Checking that the int is 1 or 0 because the helper can return integers out of range. if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; - PANIM->second.internalEnabled = configStringToInt(ARGS[1]) == 1; + PANIM->second.internalEnabled = configStringToInt(ARGS[1]).value_or(0) == 1; if (PANIM->second.internalEnabled) { // speed diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 33e6a5f8..117d301c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -707,7 +707,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { *(search->second(m_pSelf.lock())) = CWindowOverridableVar(true, priority); } else { try { - *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]), priority); + *(search->second(m_pSelf.lock())) = CWindowOverridableVar((bool)configStringToInt(VARS[1]).value_or(0), priority); } catch (...) {} } } else if (auto search = g_pConfigManager->miWindowProperties.find(VARS[0]); search != g_pConfigManager->miWindowProperties.end()) { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 2e1e91f2..8cddbb6b 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -332,7 +332,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { const auto SHOULDBESPECIAL = configStringToInt(prop); - if ((bool)SHOULDBESPECIAL != m_bIsSpecialWorkspace) + if (SHOULDBESPECIAL && (bool)*SHOULDBESPECIAL != m_bIsSpecialWorkspace) return false; continue; } @@ -367,7 +367,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { const auto WANTSNAMED = configStringToInt(prop); - if (WANTSNAMED != (m_iID <= -1337)) + if (WANTSNAMED && *WANTSNAMED != (m_iID <= -1337)) return false; continue; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 75e2a7b3..be1e9534 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2961,13 +2961,13 @@ SDispatchResult CKeybindManager::setProp(std::string args) { CWindowOverridableVar(SAlphaValue{std::stof(VAL), PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_bOverride}, PRIORITY_SET_PROP); } else if (PROP == "alphaoverride") { PWINDOW->m_sWindowData.alpha = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alpha.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP); } else if (PROP == "alphainactiveoverride") { PWINDOW->m_sWindowData.alphaInactive = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaInactive.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP); } else if (PROP == "alphafullscreenoverride") { PWINDOW->m_sWindowData.alphaFullscreen = - CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL)}, PRIORITY_SET_PROP); + CWindowOverridableVar(SAlphaValue{PWINDOW->m_sWindowData.alphaFullscreen.valueOrDefault().m_fAlpha, (bool)configStringToInt(VAL).value_or(0)}, PRIORITY_SET_PROP); } else if (PROP == "activebordercolor" || PROP == "inactivebordercolor") { CGradientValueData colorData = {}; if (vars.size() > 4) { @@ -2998,7 +2998,7 @@ SDispatchResult CKeybindManager::setProp(std::string args) { else if (VAL == "unset") pWindowDataElement->unset(PRIORITY_SET_PROP); else - *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL), PRIORITY_SET_PROP); + *pWindowDataElement = CWindowOverridableVar((bool)configStringToInt(VAL).value_or(0), PRIORITY_SET_PROP); } else if (auto search = g_pConfigManager->miWindowProperties.find(PROP); search != g_pConfigManager->miWindowProperties.end()) { if (VAL == "unset") search->second(PWINDOW)->unset(PRIORITY_SET_PROP); From 940f7aa990dbc99815bab8d355999d8277534b17 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 20 Nov 2024 11:02:21 +0000 Subject: [PATCH 0878/2393] renderer: fixup blur optimization considitons fixes #8531 --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index fc17ef9f..42545bc1 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -174,7 +174,6 @@ static void renderSurface(SP surface, int x, int y, void* da } const auto RDATA = (SRenderData*)data; - const bool BLUR = RDATA->blur && !TEXTURE->m_bOpaque; const auto INTERACTIVERESIZEINPROGRESS = RDATA->pWindow && g_pInputManager->currentlyDraggedWindow && g_pInputManager->dragMode == MBIND_RESIZE; TRACY_GPU_ZONE("RenderSurface"); @@ -183,6 +182,7 @@ static void renderSurface(SP surface, int x, int y, void* da auto PSURFACE = CWLSurface::fromResource(surface); const float ALPHA = RDATA->alpha * RDATA->fadeAlpha * (PSURFACE ? PSURFACE->m_pAlphaModifier : 1.F); + const bool BLUR = RDATA->blur && (!TEXTURE->m_bOpaque || ALPHA < 1.F); CBox windowBox; if (RDATA->surface && surface == RDATA->surface) { From 943b3d467b0a77a6b67df01e78f5e4977486824f Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Fri, 22 Nov 2024 02:47:51 +0100 Subject: [PATCH 0879/2393] bezier: optimize setup of bezier curves (#8528) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit avoid reallocations by resizing and copy the pVec into the resized m_dPoints, reduce the amount of calculations in baking to only do it once per iteration instead of twice. precompute in getYforT and getXforT return early in getYForPoint if x is equal or below 0. and use const references where we can. these changes we are now down to an average of "time to bake: 2.50µs." on my machine compared to before average of "time to bake: 11.15µs" --- src/helpers/BezierCurve.cpp | 39 ++++++++++++++++++++++++------------- src/helpers/BezierCurve.hpp | 8 ++++---- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp index ea567ad6..23fcd691 100644 --- a/src/helpers/BezierCurve.cpp +++ b/src/helpers/BezierCurve.cpp @@ -6,24 +6,27 @@ #include void CBezierCurve::setup(std::vector* pVec) { - m_dPoints.clear(); - const auto BEGIN = std::chrono::high_resolution_clock::now(); - m_dPoints.emplace_back(Vector2D(0, 0)); - - for (auto const& p : *pVec) { - m_dPoints.push_back(p); + // Avoid reallocations by reserving enough memory upfront + m_dPoints.resize(pVec->size() + 2); + m_dPoints[0] = Vector2D(0, 0); // Start point + size_t index = 1; // Start after the first element + for (const auto& vec : *pVec) { + if (index < m_dPoints.size() - 1) { // Bounds check to ensure safety + m_dPoints[index] = vec; + ++index; + } } - - m_dPoints.emplace_back(Vector2D(1, 1)); + m_dPoints.back() = Vector2D(1, 1); // End point RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size()); // bake BAKEDPOINTS points for faster lookups // T -> X ( / BAKEDPOINTS ) for (int i = 0; i < BAKEDPOINTS; ++i) { - m_aPointsBaked[i] = Vector2D(getXForT((i + 1) / (float)BAKEDPOINTS), getYForT((i + 1) / (float)BAKEDPOINTS)); + float const t = (i + 1) / (float)BAKEDPOINTS; + m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t)); } const auto ELAPSEDUS = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f; @@ -40,18 +43,26 @@ void CBezierCurve::setup(std::vector* pVec) { ELAPSEDUS, ELAPSEDCALCAVG); } -float CBezierCurve::getYForT(float t) { - return 3 * t * pow(1 - t, 2) * m_dPoints[1].y + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].y + pow(t, 3); +float CBezierCurve::getXForT(float const& t) { + float t2 = t * t; + float t3 = t2 * t; + + return 3 * t * (1 - t) * (1 - t) * m_dPoints[1].x + 3 * t2 * (1 - t) * m_dPoints[2].x + t3 * m_dPoints[3].x; } -float CBezierCurve::getXForT(float t) { - return 3 * t * pow(1 - t, 2) * m_dPoints[1].x + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].x + pow(t, 3); +float CBezierCurve::getYForT(float const& t) { + float t2 = t * t; + float t3 = t2 * t; + + return 3 * t * (1 - t) * (1 - t) * m_dPoints[1].y + 3 * t2 * (1 - t) * m_dPoints[2].y + t3 * m_dPoints[3].y; } // Todo: this probably can be done better and faster -float CBezierCurve::getYForPoint(float x) { +float CBezierCurve::getYForPoint(float const& x) { if (x >= 1.f) return 1.f; + if (x <= 0.f) + return 0.f; int index = 0; bool below = true; diff --git a/src/helpers/BezierCurve.hpp b/src/helpers/BezierCurve.hpp index 54af46a6..1a842f5a 100644 --- a/src/helpers/BezierCurve.hpp +++ b/src/helpers/BezierCurve.hpp @@ -16,13 +16,13 @@ class CBezierCurve { // this EXCLUDES the 0,0 and 1,1 points, void setup(std::vector* points); - float getYForT(float t); - float getXForT(float t); - float getYForPoint(float x); + float getYForT(float const& t); + float getXForT(float const& t); + float getYForPoint(float const& x); private: // this INCLUDES the 0,0 and 1,1 points. - std::deque m_dPoints; + std::vector m_dPoints; std::array m_aPointsBaked; }; From b1003445953474b967464d4d0878955d37498647 Mon Sep 17 00:00:00 2001 From: may <63159454+m4rch3n1ng@users.noreply.github.com> Date: Fri, 22 Nov 2024 03:31:42 +0100 Subject: [PATCH 0880/2393] keybinds: actually suppress internal keybinds instead of passing them along (#8538) --- src/managers/KeybindManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index be1e9534..8cf39c1b 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -423,8 +423,10 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); + // handleInternalKeybinds returns true when the key should be suppressed, + // while this function returns true when the key event should be sent if (handleInternalKeybinds(internalKeysym)) - return true; + return false; const auto MODS = g_pInputManager->accumulateModsFromAllKBs(); From a847bc67b1efcf3a0fa9c8a3a1da1a79743940c1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 22 Nov 2024 15:22:28 +0000 Subject: [PATCH 0881/2393] monitor: fix default focus when switching to a fs workspace --- src/helpers/Monitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9ac48220..63268c8a 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -629,7 +629,7 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); - auto pWindow = pWorkspace->getLastFocusedWindow(); + auto pWindow = pWorkspace->m_bHasFullscreenWindow ? g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID) : pWorkspace->getLastFocusedWindow(); if (!pWindow) { if (*PFOLLOWMOUSE == 1) From 745a82ce8ab19d958e344f5925bb1dc8ea7d6a53 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 22 Nov 2024 16:01:02 +0000 Subject: [PATCH 0882/2393] core: workspace-related function cleanup / refactor CCompositor is massive, and has a lot of functions that could be better optimized if in CWorkspace --- src/Compositor.cpp | 182 ++++----------------------- src/Compositor.hpp | 13 -- src/config/ConfigManager.cpp | 4 +- src/debug/HyprCtl.cpp | 10 +- src/desktop/Window.cpp | 38 +++--- src/desktop/Workspace.cpp | 149 ++++++++++++++++++++-- src/desktop/Workspace.hpp | 20 +-- src/events/Windows.cpp | 12 +- src/helpers/MiscFunctions.cpp | 2 +- src/helpers/Monitor.cpp | 6 +- src/layout/DwindleLayout.cpp | 6 +- src/layout/IHyprLayout.cpp | 10 +- src/layout/MasterLayout.cpp | 2 +- src/managers/AnimationManager.cpp | 2 +- src/managers/KeybindManager.cpp | 30 +++-- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.cpp | 8 +- src/managers/input/Swipe.cpp | 13 +- src/render/Renderer.cpp | 18 +-- 19 files changed, 267 insertions(+), 260 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0e0c75a1..3fe5acec 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -833,6 +833,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special && !w->onSpecialWorkspace()) // because special floating may creep up into regular continue; + if (!w->m_pWorkspace) + continue; + const auto PWINDOWMONITOR = w->m_pMonitor.lock(); // to avoid focusing windows behind special workspaces from other monitors @@ -844,7 +847,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper continue; } - if (w->m_bIsFloating && w->m_bIsMapped && isWorkspaceVisible(w->m_pWorkspace) && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && + if (w->m_bIsFloating && w->m_bIsMapped && w->m_pWorkspace->isVisible() && !w->isHidden() && !w->m_bPinned && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow && (!aboveFullscreen || w->m_bCreatedOverFullscreen)) { // OR windows should add focus to parent if (w->m_bX11ShouldntFocus && !w->isX11OverrideRedirect()) @@ -887,7 +890,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper const auto PWORKSPACE = getWorkspaceByID(WSPID); if (PWORKSPACE->m_bHasFullscreenWindow) - return getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + return PWORKSPACE->getFullscreenWindow(); auto found = floating(false); if (found) @@ -898,6 +901,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special != w->onSpecialWorkspace()) continue; + if (!w->m_pWorkspace) + continue; + if (!w->m_bIsX11 && !w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { if (w->hasPopupAt(pos)) @@ -909,6 +915,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (special != w->onSpecialWorkspace()) continue; + if (!w->m_pWorkspace) + continue; + if (!w->m_bIsFloating && w->m_bIsMapped && w->workspaceID() == WSPID && !w->isHidden() && !w->m_bX11ShouldntFocus && !w->m_sWindowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { CBox box = (properties & USE_PROP_TILED) ? w->getWindowBoxUnified(properties) : CBox{w->m_vPosition, w->m_vSize}; @@ -1070,7 +1079,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface const auto PMONITOR = pWindow->m_pMonitor.lock(); - if (!isWorkspaceVisible(pWindow->m_pWorkspace)) { + if (!pWindow->m_pWorkspace || !pWindow->m_pWorkspace->isVisible()) { const auto PWORKSPACE = pWindow->m_pWorkspace; // This is to fix incorrect feedback on the focus history. PWORKSPACE->m_pLastFocusedWindow = pWindow; @@ -1247,30 +1256,6 @@ PHLWINDOW CCompositor::getWindowFromHandle(uint32_t handle) { return nullptr; } -PHLWINDOW CCompositor::getFullscreenWindowOnWorkspace(const WORKSPACEID& ID) { - for (auto const& w : m_vWindows) { - if (w->workspaceID() == ID && w->isFullscreen()) - return w; - } - - return nullptr; -} - -bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) { - return valid(w) && w->m_bVisible; -} - -bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { - if (!valid(w)) - return false; - - const auto PMONITOR = w->m_pMonitor.lock(); - if (PMONITOR->activeSpecialWorkspace) - return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID; - - return PMONITOR->activeWorkspace->m_iID == w->m_iID; -} - PHLWORKSPACE CCompositor::getWorkspaceByID(const WORKSPACEID& id) { for (auto const& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) @@ -1295,37 +1280,6 @@ void CCompositor::sanityCheckWorkspaces() { } } -int CCompositor::getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { - int no = 0; - for (auto const& w : m_vWindows) { - if (w->workspaceID() != id || !w->m_bIsMapped) - continue; - if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) - continue; - if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) - continue; - no++; - } - - return no; -} - -int CCompositor::getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled, std::optional onlyVisible) { - int no = 0; - for (auto const& w : m_vWindows) { - if (w->workspaceID() != id || !w->m_bIsMapped) - continue; - if (!w->m_sGroupData.head) - continue; - if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) - continue; - if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) - continue; - no++; - } - return no; -} - PHLWINDOW CCompositor::getUrgentWindow() { for (auto const& w : m_vWindows) { if (w->m_bIsMapped && w->m_bIsUrgent) @@ -1335,44 +1289,6 @@ PHLWINDOW CCompositor::getUrgentWindow() { return nullptr; } -bool CCompositor::hasUrgentWindowOnWorkspace(const WORKSPACEID& id) { - for (auto const& w : m_vWindows) { - if (w->workspaceID() == id && w->m_bIsMapped && w->m_bIsUrgent) - return true; - } - - return false; -} - -PHLWINDOW CCompositor::getFirstWindowOnWorkspace(const WORKSPACEID& id) { - for (auto const& w : m_vWindows) { - if (w->workspaceID() == id && w->m_bIsMapped && !w->isHidden()) - return w; - } - - return nullptr; -} - -PHLWINDOW CCompositor::getTopLeftWindowOnWorkspace(const WORKSPACEID& id) { - const auto PWORKSPACE = getWorkspaceByID(id); - - if (!PWORKSPACE) - return nullptr; - - const auto PMONITOR = PWORKSPACE->m_pMonitor.lock(); - - for (auto const& w : m_vWindows) { - if (w->workspaceID() != id || !w->m_bIsMapped || w->isHidden()) - continue; - - const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); - - if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1) - return w; - } - return nullptr; -} - bool CCompositor::isWindowActive(PHLWINDOW pWindow) { if (m_pLastWindow.expired() && !m_pLastFocus) return false; @@ -1560,7 +1476,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { // for tiled windows, we calc edges for (auto const& w : m_vWindows) { - if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) + if (w == pWindow || !w->m_pWorkspace || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) continue; if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) @@ -1652,7 +1568,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { constexpr float THRESHOLD = 0.3 * M_PI; for (auto const& w : m_vWindows) { - if (w == pWindow || !w->m_bIsMapped || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !isWorkspaceVisible(w->m_pWorkspace)) + if (w == pWindow || !w->m_bIsMapped || !w->m_pWorkspace || w->isHidden() || (!w->isFullscreen() && !w->m_bIsFloating) || !w->m_pWorkspace->isVisible()) continue; if (pWindow->m_pMonitor == w->m_pMonitor && pWindow->m_pWorkspace != w->m_pWorkspace) @@ -1678,7 +1594,7 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) { } if (!leaderWindow && PWORKSPACE->m_bHasFullscreenWindow) - leaderWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + leaderWindow = PWORKSPACE->getFullscreenWindow(); } if (leaderValue != -1) @@ -1871,15 +1787,6 @@ void CCompositor::updateAllWindowsAnimatedDecorationValues() { } } -void CCompositor::updateWorkspaceWindows(const int64_t& id) { - for (auto const& w : m_vWindows) { - if (!w->m_bIsMapped || w->workspaceID() != id) - continue; - - w->updateDynamicRules(); - } -} - void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // optimization static auto PACTIVECOL = CConfigValue("general:col.active_border"); @@ -2391,7 +2298,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); - forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID()); + PWORKSPACE->forceReportSizesToWindows(); g_pInputManager->recheckIdleInhibitorStatus(); @@ -2422,27 +2329,6 @@ PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) { return nullptr; } -void CCompositor::updateWorkspaceWindowDecos(const WORKSPACEID& id) { - for (auto const& w : m_vWindows) { - if (w->workspaceID() != id) - continue; - - w->updateWindowDecos(); - } -} - -void CCompositor::updateWorkspaceWindowData(const WORKSPACEID& id) { - const auto PWORKSPACE = getWorkspaceByID(id); - const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; - - for (auto const& w : m_vWindows) { - if (w->workspaceID() != id) - continue; - - w->updateWindowData(WORKSPACERULE); - } -} - void CCompositor::scheduleFrameForMonitor(PHLMONITOR pMonitor, IOutput::scheduleFrameReason reason) { if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive) return; @@ -2654,14 +2540,6 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con return Vector2D(X, Y); } -void CCompositor::forceReportSizesToWindowsOnWorkspace(const WORKSPACEID& wid) { - for (auto const& w : m_vWindows) { - if (w->workspaceID() == wid && w->m_bIsMapped && !w->isHidden()) { - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); - } - } -} - PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITORID& monid, const std::string& name, bool isEmpty) { const auto NAME = name == "" ? std::to_string(id) : name; auto monID = monid; @@ -2679,21 +2557,6 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO return PWORKSPACE; } -void CCompositor::renameWorkspace(const WORKSPACEID& id, const std::string& name) { - const auto PWORKSPACE = getWorkspaceByID(id); - - if (!PWORKSPACE) - return; - - if (isWorkspaceSpecial(id)) - return; - - Debug::log(LOG, "renameWorkspace: Renaming workspace {} to '{}'", id, name); - PWORKSPACE->m_szName = name; - - g_pEventManager->postEvent({"renameworkspace", std::to_string(PWORKSPACE->m_iID) + "," + PWORKSPACE->m_szName}); -} - void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) { if (m_pLastMonitor == pMonitor) return; @@ -2758,8 +2621,8 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor if (FULLSCREEN) setWindowFullscreenInternal(pWindow, FSMODE_NONE); - const PHLWINDOW pFirstWindowOnWorkspace = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID); - const int visibleWindowsOnWorkspace = g_pCompositor->getWindowsOnWorkspace(pWorkspace->m_iID, std::nullopt, true); + const PHLWINDOW pFirstWindowOnWorkspace = pWorkspace->getFirstWindow(); + const int visibleWindowsOnWorkspace = pWorkspace->getWindows(std::nullopt, true); const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock(); const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock(); @@ -2817,14 +2680,15 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor if (FULLSCREEN) setWindowFullscreenInternal(pWindow, FULLSCREENMODE); - g_pCompositor->updateWorkspaceWindows(pWorkspace->m_iID); - g_pCompositor->updateWorkspaceWindows(pWindow->workspaceID()); + pWorkspace->updateWindows(); + if (pWindow->m_pWorkspace) + pWindow->m_pWorkspace->updateWindows(); g_pCompositor->updateSuspendedStates(); } PHLWINDOW CCompositor::getForceFocus() { for (auto const& w : m_vWindows) { - if (!w->m_bIsMapped || w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace)) + if (!w->m_bIsMapped || w->isHidden() || !w->m_pWorkspace || !w->m_pWorkspace->isVisible()) continue; if (!w->m_bStayFocused) @@ -3002,7 +2866,7 @@ void CCompositor::updateSuspendedStates() { if (!w->m_bIsMapped) continue; - w->setSuspended(w->isHidden() || !isWorkspaceVisible(w->m_pWorkspace)); + w->setSuspended(w->isHidden() || !w->m_pWorkspace || !w->m_pWorkspace->isVisible()); } } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 208b6ecf..c02be579 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -115,21 +115,11 @@ class CCompositor { PHLMONITOR getRealMonitorFromOutput(SP); PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); - bool isWorkspaceVisible(PHLWORKSPACE); - bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); PHLWORKSPACE getWorkspaceByID(const WORKSPACEID&); PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&); void sanityCheckWorkspaces(); - void updateWorkspaceWindowDecos(const WORKSPACEID&); - void updateWorkspaceWindowData(const WORKSPACEID&); - int getWindowsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroupsOnWorkspace(const WORKSPACEID& id, std::optional onlyTiled = {}, std::optional onlyVisible = {}); PHLWINDOW getUrgentWindow(); - bool hasUrgentWindowOnWorkspace(const WORKSPACEID&); - PHLWINDOW getFirstWindowOnWorkspace(const WORKSPACEID&); - PHLWINDOW getTopLeftWindowOnWorkspace(const WORKSPACEID&); - PHLWINDOW getFullscreenWindowOnWorkspace(const WORKSPACEID&); bool isWindowActive(PHLWINDOW); void changeWindowZOrder(PHLWINDOW, bool); void cleanupFadingOut(const MONITORID& monid); @@ -142,7 +132,6 @@ class CCompositor { PHLMONITOR getMonitorInDirection(const char&); PHLMONITOR getMonitorInDirection(PHLMONITOR, const char&); void updateAllWindowsAnimatedDecorationValues(); - void updateWorkspaceWindows(const WORKSPACEID& id); void updateWindowAnimatedDecorationValues(PHLWINDOW); MONITORID getNextAvailableMonitorID(std::string const& name); void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false); @@ -165,10 +154,8 @@ class CCompositor { PHLLS getLayerSurfaceFromSurface(SP); void closeWindow(PHLWINDOW); Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&); - void forceReportSizesToWindowsOnWorkspace(const WORKSPACEID&); PHLWORKSPACE createNewWorkspace(const WORKSPACEID&, const MONITORID&, const std::string& name = "", bool isEmpty = true); // will be deleted next frame if left empty and unfocused! - void renameWorkspace(const WORKSPACEID&, const std::string& name = ""); void setActiveMonitor(PHLMONITOR); bool isWorkspaceSpecial(const WORKSPACEID&); WORKSPACEID getNewSpecialID(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 357e7a60..f6734011 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -927,8 +927,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { for (auto const& w : g_pCompositor->m_vWorkspaces) { if (w->inert()) continue; - g_pCompositor->updateWorkspaceWindows(w->m_iID); - g_pCompositor->updateWorkspaceWindowData(w->m_iID); + w->updateWindows(); + w->updateWindowData(); } // Update window border colors diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 7c0a9417..11c16f0e 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -306,12 +306,12 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form "lastwindowtitle": "{}" }})#", w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), - escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), g_pCompositor->getWindowsOnWorkspace(w->m_iID), - ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); + escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), + (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); } else { return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, - w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", g_pCompositor->getWindowsOnWorkspace(w->m_iID), - (int)w->m_bHasFullscreenWindow, (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : ""); + w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, + (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : ""); } } @@ -1764,7 +1764,7 @@ std::string CHyprCtl::getReply(std::string request) { } for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || !g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) + if (!w->m_bIsMapped || !w->m_pWorkspace || !w->m_pWorkspace->isVisible()) continue; w->updateDynamicRules(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 117d301c..12e81b76 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -413,12 +413,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { setAnimationsToMove(); - g_pCompositor->updateWorkspaceWindows(OLDWORKSPACE->m_iID); - g_pCompositor->updateWorkspaceWindowData(OLDWORKSPACE->m_iID); + OLDWORKSPACE->updateWindows(); + OLDWORKSPACE->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID()); - g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceWindowData(workspaceID()); + pWorkspace->updateWindows(); + pWorkspace->updateWindowData(); g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -437,7 +437,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { // update xwayland coords g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); - if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && g_pCompositor->getWindowsOnWorkspace(OLDWORKSPACE->m_iID) == 0 && *PCLOSEONLASTSPECIAL) { + if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); } @@ -516,7 +516,7 @@ void CWindow::onUnmap() { std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); - if (*PCLOSEONLASTSPECIAL && g_pCompositor->getWindowsOnWorkspace(workspaceID()) == 0 && onSpecialWorkspace()) { + if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) { const auto PMONITOR = m_pMonitor.lock(); if (PMONITOR && PMONITOR->activeSpecialWorkspace && PMONITOR->activeSpecialWorkspace == m_pWorkspace) PMONITOR->setSpecialWorkspace(nullptr); @@ -527,8 +527,10 @@ void CWindow::onUnmap() { if (PMONITOR && PMONITOR->solitaryClient.lock().get() == this) PMONITOR->solitaryClient.reset(); - g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceWindowData(workspaceID()); + if (m_pWorkspace) { + m_pWorkspace->updateWindows(); + m_pWorkspace->updateWindowData(); + } g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -855,8 +857,10 @@ void CWindow::createGroup() { addWindowDeco(std::make_unique(m_pSelf.lock())); - g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceWindowData(workspaceID()); + if (m_pWorkspace) { + m_pWorkspace->updateWindows(); + m_pWorkspace->updateWindowData(); + } g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -873,8 +877,10 @@ void CWindow::destroyGroup() { m_sGroupData.pNextWindow.reset(); m_sGroupData.head = false; updateWindowDecos(); - g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceWindowData(workspaceID()); + if (m_pWorkspace) { + m_pWorkspace->updateWindows(); + m_pWorkspace->updateWindowData(); + } g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -909,8 +915,10 @@ void CWindow::destroyGroup() { } g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV; - g_pCompositor->updateWorkspaceWindows(workspaceID()); - g_pCompositor->updateWorkspaceWindowData(workspaceID()); + if (m_pWorkspace) { + m_pWorkspace->updateWindows(); + m_pWorkspace->updateWindowData(); + } g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -1507,7 +1515,7 @@ void CWindow::onX11Configure(CBox box) { updateWindowDecos(); - if (!g_pCompositor->isWorkspaceVisible(m_pWorkspace)) + if (!m_pWorkspace || !m_pWorkspace->isVisible()) return; // further things are only for visible windows m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 8cddbb6b..7c3d47d7 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -422,11 +422,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { int count; if (wantsCountGroup) - count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else - count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (count != from) return false; @@ -456,11 +456,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { WORKSPACEID count; if (wantsCountGroup) - count = g_pCompositor->getGroupsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else - count = g_pCompositor->getWindowsOnWorkspace(m_iID, wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (std::clamp(count, from, to) != count) return false; @@ -525,3 +525,136 @@ bool CWorkspace::inert() { MONITORID CWorkspace::monitorID() { return m_pMonitor ? m_pMonitor->ID : MONITOR_INVALID; } + +PHLWINDOW CWorkspace::getFullscreenWindow() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace == m_pSelf && w->isFullscreen()) + return w; + } + + return nullptr; +} + +bool CWorkspace::isVisible() { + return m_bVisible; +} + +bool CWorkspace::isVisibleNotCovered() { + const auto PMONITOR = m_pMonitor.lock(); + if (PMONITOR->activeSpecialWorkspace) + return PMONITOR->activeSpecialWorkspace->m_iID == m_iID; + + return PMONITOR->activeWorkspace->m_iID == m_iID; +} + +int CWorkspace::getWindows(std::optional onlyTiled, std::optional onlyVisible) { + int no = 0; + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->workspaceID() != m_iID || !w->m_bIsMapped) + continue; + if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) + continue; + if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) + continue; + no++; + } + + return no; +} + +int CWorkspace::getGroups(std::optional onlyTiled, std::optional onlyVisible) { + int no = 0; + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->workspaceID() != m_iID || !w->m_bIsMapped) + continue; + if (!w->m_sGroupData.head) + continue; + if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) + continue; + if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) + continue; + no++; + } + return no; +} + +PHLWINDOW CWorkspace::getFirstWindow() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && !w->isHidden()) + return w; + } + + return nullptr; +} + +PHLWINDOW CWorkspace::getTopLeftWindow() { + const auto PMONITOR = m_pMonitor.lock(); + + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) + continue; + + const auto WINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved(); + + if (WINDOWIDEALBB.x <= PMONITOR->vecPosition.x + 1 && WINDOWIDEALBB.y <= PMONITOR->vecPosition.y + 1) + return w; + } + return nullptr; +} + +bool CWorkspace::hasUrgentWindow() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace == m_pSelf && w->m_bIsMapped && w->m_bIsUrgent) + return true; + } + + return false; +} + +void CWorkspace::updateWindowDecos() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace != m_pSelf) + continue; + + w->updateWindowDecos(); + } +} + +void CWorkspace::updateWindowData() { + const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock()); + + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace != m_pSelf) + continue; + + w->updateWindowData(WORKSPACERULE); + } +} + +void CWorkspace::forceReportSizesToWindows() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) + continue; + + g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); + } +} + +void CWorkspace::rename(const std::string& name) { + if (g_pCompositor->isWorkspaceSpecial(m_iID)) + return; + + Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name); + m_szName = name; + + g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName}); +} + +void CWorkspace::updateWindows() { + for (auto const& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_pWorkspace != m_pSelf) + continue; + + w->updateDynamicRules(); + } +} diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 3ed9f50c..606485a2 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -63,23 +63,29 @@ class CWorkspace { // Inert: destroyed and invalid. If this is true, release the ptr you have. bool inert(); - void startAnim(bool in, bool left, bool instant = false); void setActive(bool on); - void moveToMonitor(const MONITORID&); MONITORID monitorID(); - PHLWINDOW getLastFocusedWindow(); void rememberPrevWorkspace(const PHLWORKSPACE& prevWorkspace); - std::string getConfigName(); - bool matchesStaticSelector(const std::string& selector); - void markInert(); - SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const; + void updateWindowDecos(); + void updateWindowData(); + int getWindows(std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getGroups(std::optional onlyTiled = {}, std::optional onlyVisible = {}); + bool hasUrgentWindow(); + PHLWINDOW getFirstWindow(); + PHLWINDOW getTopLeftWindow(); + PHLWINDOW getFullscreenWindow(); + bool isVisible(); + bool isVisibleNotCovered(); + void rename(const std::string& name = ""); + void forceReportSizesToWindows(); + void updateWindows(); private: void init(PHLWORKSPACE self); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 73ab45c1..a607d7ce 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -509,7 +509,7 @@ void Events::listener_mapWindow(void* owner, void* data) { else if (*PNEWTAKESOVERFS == 1) requestedInternalFSMode = PWINDOW->m_pWorkspace->m_efFullscreenMode; else if (*PNEWTAKESOVERFS == 2) - g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE); + g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); } if (!PWINDOW->m_sWindowData.noFocus.valueOrDefault() && !PWINDOW->m_bNoInitialFocus && @@ -531,7 +531,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (!PWINDOW->m_bNoInitialFocus && (requestedInternalFSMode.has_value() || requestedClientFSMode.has_value() || requestedFSState.has_value())) { // fix fullscreen on requested (basically do a switcheroo) if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) - g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWINDOW->m_pWorkspace->m_iID), FSMODE_NONE); + g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); PWINDOW->m_vRealPosition.warp(); PWINDOW->m_vRealSize.warp(); @@ -603,7 +603,8 @@ void Events::listener_mapWindow(void* owner, void* data) { // fix some xwayland apps that don't behave nicely PWINDOW->m_vReportedSize = PWINDOW->m_vPendingReportedSize; - g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); + if (PWINDOW->m_pWorkspace) + PWINDOW->m_pWorkspace->updateWindows(); if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; @@ -699,7 +700,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->setWindowFullscreenInternal(PWINDOWCANDIDATE, CURRENTFSMODE); } - if (!PWINDOWCANDIDATE && g_pCompositor->getWindowsOnWorkspace(PWINDOW->workspaceID()) == 0) + if (!PWINDOWCANDIDATE && PWINDOW->m_pWorkspace && PWINDOW->m_pWorkspace->getWindows() == 0) g_pInputManager->refocus(); g_pInputManager->sendMotionEventsToFocused(); @@ -729,7 +730,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pInputManager->recheckIdleInhibitorStatus(); // force report all sizes (QT sometimes has an issue with this) - g_pCompositor->forceReportSizesToWindowsOnWorkspace(PWINDOW->workspaceID()); + if (PWINDOW->m_pWorkspace) + PWINDOW->m_pWorkspace->forceReportSizesToWindows(); // update lastwindow after focus PWINDOW->onUnmap(); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index fa2f84ab..dc181d4f 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -264,7 +264,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { WORKSPACEID id = next ? g_pCompositor->m_pLastMonitor->activeWorkspaceID() : 0; while (++id < LONG_MAX) { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(id); - if (!invalidWSes.contains(id) && (!PWORKSPACE || g_pCompositor->getWindowsOnWorkspace(id) == 0)) { + if (!invalidWSes.contains(id) && (!PWORKSPACE || PWORKSPACE->getWindows() == 0)) { result.id = id; return result; } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 63268c8a..cbad959e 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -629,17 +629,17 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo if (!noFocus && !g_pCompositor->m_pLastMonitor->activeSpecialWorkspace && !(g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_bPinned && g_pCompositor->m_pLastWindow->m_pMonitor == self)) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); - auto pWindow = pWorkspace->m_bHasFullscreenWindow ? g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID) : pWorkspace->getLastFocusedWindow(); + auto pWindow = pWorkspace->m_bHasFullscreenWindow ? pWorkspace->getFullscreenWindow() : pWorkspace->getLastFocusedWindow(); if (!pWindow) { if (*PFOLLOWMOUSE == 1) pWindow = g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!pWindow) - pWindow = g_pCompositor->getTopLeftWindowOnWorkspace(pWorkspace->m_iID); + pWindow = pWorkspace->getTopLeftWindow(); if (!pWindow) - pWindow = g_pCompositor->getFirstWindowOnWorkspace(pWorkspace->m_iID); + pWindow = pWorkspace->getFirstWindow(); } g_pCompositor->focusWindow(pWindow); diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index c3e394f3..864c8564 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -514,7 +514,7 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { if (pWorkspace->m_bHasFullscreenWindow) { // massive hack from the fullscreen func - const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); + const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; @@ -1054,7 +1054,7 @@ void CHyprDwindleLayout::moveToRoot(PHLWINDOW pWindow, bool stable) { std::swap(pRoot->children[0], pRoot->children[1]); // if the workspace is visible, recalculate layout - if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + if (pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible()) pRoot->recalcSizePosRecursive(); } @@ -1094,7 +1094,7 @@ Vector2D CHyprDwindleLayout::predictSizeForNewWindowTiled() { PHLWINDOW candidate = g_pCompositor->m_pLastWindow.lock(); if (!candidate) - candidate = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID); + candidate = g_pCompositor->m_pLastMonitor->activeWorkspace->getFirstWindow(); // create a fake node SDwindleNodeData node; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index af8b907c..22e1d947 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -187,7 +187,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { static auto PAUTOGROUP = CConfigValue("group:auto_group"); const PHLWINDOW OPENINGON = g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace == pWindow->m_pWorkspace ? g_pCompositor->m_pLastWindow.lock() : - g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + (pWindow->m_pWorkspace ? pWindow->m_pWorkspace->getFirstWindow() : nullptr); const bool FLOATEDINTOTILED = pWindow->m_bIsFloating && !OPENINGON->m_bIsFloating; const bool SWALLOWING = pWindow->m_pSwallowed || pWindow->m_bGroupSwallowed; @@ -714,7 +714,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { const auto PWORKSPACE = PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace; if (PWORKSPACE->m_bHasFullscreenWindow) - g_pCompositor->setWindowFullscreenInternal(g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID), FSMODE_NONE); + g_pCompositor->setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); // save real pos cuz the func applies the default 5,5 mid const auto PSAVEDPOS = pWindow->m_vRealPosition.goal(); @@ -803,7 +803,7 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { // first of all, if this is a fullscreen workspace, if (PWORKSPACE->m_bHasFullscreenWindow) - return g_pCompositor->getFullscreenWindowOnWorkspace(pWindow->workspaceID()); + return PWORKSPACE->getFullscreenWindow(); if (pWindow->m_bIsFloating) { @@ -842,10 +842,10 @@ PHLWINDOW IHyprLayout::getNextWindowCandidate(PHLWINDOW pWindow) { auto pWindowCandidate = g_pCompositor->vectorToWindowUnified(pWindow->middle(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!pWindowCandidate) - pWindowCandidate = g_pCompositor->getTopLeftWindowOnWorkspace(pWindow->workspaceID()); + pWindowCandidate = PWORKSPACE->getTopLeftWindow(); if (!pWindowCandidate) - pWindowCandidate = g_pCompositor->getFirstWindowOnWorkspace(pWindow->workspaceID()); + pWindowCandidate = PWORKSPACE->getFirstWindow(); if (!pWindowCandidate || pWindow == pWindowCandidate || !pWindowCandidate->m_bIsMapped || pWindowCandidate->isHidden() || pWindowCandidate->m_bX11ShouldntFocus || pWindowCandidate->isX11OverrideRedirect() || pWindowCandidate->m_pMonitor != g_pCompositor->m_pLastMonitor) diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 695dcc99..bf808627 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -298,7 +298,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (pWorkspace->m_bHasFullscreenWindow) { // massive hack from the fullscreen func - const auto PFULLWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID); + const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index ceb594aa..68dbdda1 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -149,7 +149,7 @@ void CAnimationManager::tick() { animationsDisabled = animationsDisabled || PLAYER->noAnimations; } - const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? g_pCompositor->isWorkspaceVisible(PWINDOW->m_pWorkspace) : true; + const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? PWINDOW->m_pWorkspace->isVisible() : true; // beziers are with a switch unforto // TODO: maybe do something cleaner diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8cf39c1b..a5327149 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1036,8 +1036,12 @@ static SDispatchResult toggleActiveFloatingCore(std::string args, std::optional< g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(PWINDOW); } - g_pCompositor->updateWorkspaceWindows(PWINDOW->workspaceID()); - g_pCompositor->updateWorkspaceWindowData(PWINDOW->workspaceID()); + + if (PWINDOW->m_pWorkspace) { + PWINDOW->m_pWorkspace->updateWindows(); + PWINDOW->m_pWorkspace->updateWindowData(); + } + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->monitorID()); g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -1305,7 +1309,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } - POLDWS->m_pLastFocusedWindow = g_pCompositor->getFirstWindowOnWorkspace(POLDWS->m_iID); + POLDWS->m_pLastFocusedWindow = POLDWS->getFirstWindow(); if (pWorkspace->m_bIsSpecialWorkspace) pMonitor->setSpecialWorkspace(pWorkspace); @@ -1799,10 +1803,14 @@ SDispatchResult CKeybindManager::renameWorkspace(std::string args) { if (FIRSTSPACEPOS != std::string::npos) { int workspace = std::stoi(args.substr(0, FIRSTSPACEPOS)); std::string name = args.substr(FIRSTSPACEPOS + 1); - g_pCompositor->renameWorkspace(workspace, name); - } else { - g_pCompositor->renameWorkspace(std::stoi(args), ""); - } + if (const auto& PWS = g_pCompositor->getWorkspaceByID(workspace); PWS) + PWS->rename(name); + else + return {.success = false, .error = "No such workspace"}; + } else if (const auto& PWS = g_pCompositor->getWorkspaceByID(std::stoi(args)); PWS) + PWS->rename(""); + else + return {.success = false, .error = "No such workspace"}; } catch (std::exception& e) { Debug::log(ERR, "Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what()); return {.success = false, .error = std::format("Invalid arg in renameWorkspace, expected numeric id only or a numeric id and string name. \"{}\": \"{}\"", args, e.what())}; @@ -2069,9 +2077,9 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) { if (g_pCompositor->m_pLastWindow.expired()) { // if we have a clear focus, find the first window and get the next focusable. - if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) > 0) { - const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()); - + const auto PWS = g_pCompositor->m_pLastMonitor->activeWorkspace; + if (PWS && PWS->getWindows() > 0) { + const auto PWINDOW = PWS->getFirstWindow(); switchToWindow(PWINDOW); } @@ -2117,7 +2125,7 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { } if (PWORKSPACE->m_bHasFullscreenWindow) { - const auto FSWINDOW = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + const auto FSWINDOW = PWORKSPACE->getFullscreenWindow(); const auto FSMODE = PWORKSPACE->m_efFullscreenMode; if (PWINDOW->m_bIsFloating) { diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index a6f25142..7c91258e 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -63,7 +63,7 @@ void CInputManager::recheckIdleInhibitorStatus() { return; } - if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->isFullscreen() && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) { + if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->isFullscreen() && w->m_pWorkspace && w->m_pWorkspace->isVisible()) { PROTO::idle->setInhibit(true); return; } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 9110cd15..525ca954 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -294,7 +294,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { const auto PWORKSPACE = PMONITOR->activeWorkspace; const auto PWINDOWIDEAL = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (PWORKSPACE->m_bHasFullscreenWindow && !foundSurface && PWORKSPACE->m_efFullscreenMode == FSMODE_FULLSCREEN) { - pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + pFoundWindow = PWORKSPACE->getFullscreenWindow(); if (!pFoundWindow) { // what the fuck, somehow happens occasionally?? @@ -325,7 +325,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (pFoundWindow && !pFoundWindow->onSpecialWorkspace()) { - pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + pFoundWindow = PWORKSPACE->getFullscreenWindow(); } } else { // if we have a maximized window, allow focusing on a bar or something if in reserved area. @@ -339,7 +339,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING); if (!(pFoundWindow && pFoundWindow->m_bIsFloating && pFoundWindow->m_bCreatedOverFullscreen)) - pFoundWindow = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + pFoundWindow = PWORKSPACE->getFullscreenWindow(); } } } @@ -1402,7 +1402,7 @@ void CInputManager::refocusLastWindow(PHLMONITOR pMonitor) { foundSurface = nullptr; } - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisibleNotCovered(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->m_pLastWindow->m_pWorkspace && g_pCompositor->m_pLastWindow->m_pWorkspace->isVisibleNotCovered()) { // then the last focused window if we're on the same workspace as it const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); g_pCompositor->focusWindow(PLASTWINDOW); diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index ba0783fa..6cfe5a24 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -243,8 +243,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { m_sActiveSwipe.delta = std::clamp(m_sActiveSwipe.delta, (double)-SWIPEDISTANCE, (double)SWIPEDISTANCE); if ((m_sActiveSwipe.pWorkspaceBegin->m_iID == workspaceIDLeft && *PSWIPENEW && (m_sActiveSwipe.delta < 0)) || - (m_sActiveSwipe.delta > 0 && g_pCompositor->getWindowsOnWorkspace(m_sActiveSwipe.pWorkspaceBegin->m_iID) == 0 && - workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID) || + (m_sActiveSwipe.delta > 0 && m_sActiveSwipe.pWorkspaceBegin->getWindows() == 0 && workspaceIDRight <= m_sActiveSwipe.pWorkspaceBegin->m_iID) || (m_sActiveSwipe.delta < 0 && m_sActiveSwipe.pWorkspaceBegin->m_iID <= workspaceIDLeft)) { m_sActiveSwipe.delta = 0; @@ -270,7 +269,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { else m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); + m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; } m_sActiveSwipe.delta = 0; @@ -297,7 +296,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } - g_pCompositor->updateWorkspaceWindowDecos(workspaceIDLeft); + PWORKSPACE->updateWindowDecos(); } else { const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); @@ -310,7 +309,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) { else m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); + m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; } m_sActiveSwipe.delta = 0; @@ -337,12 +336,12 @@ void CInputManager::updateWorkspaceSwipe(double delta) { m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } - g_pCompositor->updateWorkspaceWindowDecos(workspaceIDRight); + PWORKSPACE->updateWindowDecos(); } g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); - g_pCompositor->updateWorkspaceWindowDecos(m_sActiveSwipe.pWorkspaceBegin->m_iID); + m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); if (*PSWIPEFOREVER) { if (abs(m_sActiveSwipe.delta) >= SWIPEDISTANCE) { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 42545bc1..57490d23 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -310,8 +310,8 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it. - if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && - !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && pWindow->m_pWorkspace && + !pWindow->m_pWorkspace->isVisible()) return true; const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; @@ -324,18 +324,18 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { pWindow->m_fAlpha.value() == 0) return false; - if (!PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() && !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + if (!PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() && !PWINDOWWORKSPACE->isVisible()) return false; } if (pWindow->m_pMonitor == pMonitor) return true; - if (!g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace) && pWindow->m_pMonitor != pMonitor) + if (!(!pWindow->m_pWorkspace || !pWindow->m_pWorkspace->isVisible()) && pWindow->m_pMonitor != pMonitor) return false; // if not, check if it maybe is active on a different monitor. - if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace) && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */) + if (pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible() && pWindow->m_bIsFloating /* tiled windows can't be multi-ws */) return !pWindow->isFullscreen(); // Do not draw fullscreen windows on other monitors if (pMonitor->activeSpecialWorkspace == pWindow->m_pWorkspace) @@ -376,7 +376,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { if (pWindow->m_bPinned || PWORKSPACE->m_bForceRendering) return true; - if (g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace)) + if (PWORKSPACE && PWORKSPACE->isVisible()) return true; for (auto const& m : g_pCompositor->m_vMonitors) { @@ -591,7 +591,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe decorate = false; // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws - const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_iMonitorMovedFrom != -1 && !g_pCompositor->isWorkspaceVisible(pWindow->m_pWorkspace); + const bool USE_WORKSPACE_FADE_ALPHA = pWindow->m_iMonitorMovedFrom != -1 && (!PWORKSPACE || !PWORKSPACE->isVisible()); const bool DONT_BLUR = pWindow->m_sWindowData.noBlur.valueOrDefault() || pWindow->m_sWindowData.RGBX.valueOrDefault() || pWindow->opaque(); renderdata.surface = pWindow->m_pWLSurface->resource(); @@ -933,7 +933,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // Render layer surfaces below windows for monitor // if we have a fullscreen, opaque window that convers the screen, we can skip this. // TODO: check better with solitary after MR for tearing. - const auto PFULLWINDOW = pWorkspace ? g_pCompositor->getFullscreenWindowOnWorkspace(pWorkspace->m_iID) : nullptr; + const auto PFULLWINDOW = pWorkspace ? pWorkspace->getFullscreenWindow() : nullptr; if (!pWorkspace->m_bHasFullscreenWindow || pWorkspace->m_efFullscreenMode != FSMODE_FULLSCREEN || !PFULLWINDOW || PFULLWINDOW->m_vRealSize.isBeingAnimated() || !PFULLWINDOW->opaque() || pWorkspace->m_vRenderOffset.value() != Vector2D{} || g_pHyprOpenGL->preBlurQueued()) { @@ -2639,7 +2639,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) return; - const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID); + const auto PCANDIDATE = PWORKSPACE->getFullscreenWindow(); if (!PCANDIDATE) return; // ???? From 00d6261cc06716eac6bdfc9d4426c3a54597098c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 23 Nov 2024 14:18:13 +0000 Subject: [PATCH 0883/2393] hyprpm: move temp files to XDG_RUNTIME_DIR avoid /tmp, it's cringe --- hyprpm/src/core/PluginManager.cpp | 44 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index db315193..fb3065b4 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -38,6 +38,18 @@ static std::string execAndGet(std::string cmd) { return proc.stdOut(); } +static std::string getTempRoot() { + static auto ENV = getenv("XDG_RUNTIME_DIR"); + if (!ENV) { + std::cerr << "\nERROR: XDG_RUNTIME_DIR not set!\n"; + exit(1); + } + + const auto STR = ENV + std::string{"/hyprpm/"}; + + return STR; +} + SHyprlandVersion CPluginManager::getHyprlandVersion() { static SHyprlandVersion ver; static bool once = false; @@ -84,7 +96,7 @@ SHyprlandVersion CPluginManager::getHyprlandVersion() { } bool CPluginManager::createSafeDirectory(const std::string& path) { - if (path.empty() || !path.starts_with("/tmp")) + if (path.empty() || !path.starts_with(getTempRoot())) return false; if (std::filesystem::exists(path)) @@ -142,17 +154,17 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.print(); - if (!std::filesystem::exists("/tmp/hyprpm")) { - std::filesystem::create_directory("/tmp/hyprpm"); - std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); - } else if (!std::filesystem::is_directory("/tmp/hyprpm")) { + if (!std::filesystem::exists(getTempRoot())) { + std::filesystem::create_directory(getTempRoot()); + std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); + } else if (!std::filesystem::is_directory(getTempRoot())) { std::println(stderr, "\n{}", failureString("Could not prepare working dir for hyprpm")); return false; } const std::string USERNAME = getpwuid(getuid())->pw_name; - m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; + m_szWorkingPluginDirectory = getTempRoot() + USERNAME; if (!createSafeDirectory(m_szWorkingPluginDirectory)) { std::println(stderr, "\n{}", failureString("Could not prepare working dir for repo")); @@ -161,7 +173,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(infoString("Cloning {}", url)); - std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + url + " " + USERNAME); + std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), url, USERNAME)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. shell returned:\n{}", ret)); @@ -413,9 +425,9 @@ bool CPluginManager::updateHeaders(bool force) { return false; } - if (!std::filesystem::exists("/tmp/hyprpm")) { - std::filesystem::create_directory("/tmp/hyprpm"); - std::filesystem::permissions("/tmp/hyprpm", std::filesystem::perms::all, std::filesystem::perm_options::replace); + if (!std::filesystem::exists(getTempRoot())) { + std::filesystem::create_directory(getTempRoot()); + std::filesystem::permissions(getTempRoot(), std::filesystem::perms::owner_all, std::filesystem::perm_options::replace); } if (!force && headersValid() == HEADERS_OK) { @@ -430,7 +442,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.print(); const std::string USERNAME = getpwuid(getuid())->pw_name; - const auto WORKINGDIR = "/tmp/hyprpm/hyprland-" + USERNAME; + const auto WORKINGDIR = getTempRoot() + "hyprland-" + USERNAME; if (!createSafeDirectory(WORKINGDIR)) { std::println("\n{}", failureString("Could not prepare working dir for hl")); @@ -448,12 +460,12 @@ bool CPluginManager::updateHeaders(bool force) { if (m_bVerbose && bShallow) progress.printMessageAbove(verboseString("will shallow since: {}", SHALLOW_DATE)); - std::string ret = - execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-" + USERNAME + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : "")); + std::string ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/Hyprland hyprland-{}{}", getTempRoot(), USERNAME, + (bShallow ? " --shallow-since='" + SHALLOW_DATE + "'" : ""))); if (!std::filesystem::exists(WORKINGDIR)) { progress.printMessageAbove(failureString("Clone failed. Retrying without shallow.")); - ret = execAndGet("cd /tmp/hyprpm && git clone --recursive https://github.com/hyprwm/hyprland hyprland-" + USERNAME); + ret = execAndGet(std::format("cd {} && git clone --recursive https://github.com/hyprwm/hyprland hyprland-{}", getTempRoot(), USERNAME)); } if (!std::filesystem::exists(WORKINGDIR + "/.git")) { @@ -577,7 +589,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.print(); const std::string USERNAME = getpwuid(getuid())->pw_name; - m_szWorkingPluginDirectory = "/tmp/hyprpm/" + USERNAME; + m_szWorkingPluginDirectory = getTempRoot() + USERNAME; for (auto const& repo : REPOS) { bool update = forceUpdateAll; @@ -592,7 +604,7 @@ bool CPluginManager::updatePlugins(bool forceUpdateAll) { progress.printMessageAbove(infoString("Cloning {}", repo.url)); - std::string ret = execAndGet("cd /tmp/hyprpm && git clone --recursive " + repo.url + " " + USERNAME); + std::string ret = execAndGet(std::format("cd {} && git clone --recursive {} {}", getTempRoot(), repo.url, USERNAME)); if (!std::filesystem::exists(m_szWorkingPluginDirectory + "/.git")) { std::println("{}", failureString("could not clone repo: shell returned: {}", ret)); From 451d7a41fc87529854c4116c96a7c6a46568a1ee Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 23 Nov 2024 09:29:29 -0500 Subject: [PATCH 0884/2393] renderer: add option to blur IME popups (#8521) --- src/config/ConfigDescriptions.hpp | 12 ++++++++++++ src/config/ConfigManager.cpp | 2 ++ src/render/Renderer.cpp | 11 ++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 2e3a6720..45379140 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -331,6 +331,18 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_FLOAT, .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, }, + SConfigOptionDescription{ + .value = "blur:input_methods", + .description = "whether to blur input methods (e.g. fcitx5)", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "blur:input_methods_ignorealpha", + .description = "works like ignorealpha in layer rules. If pixel opacity is below set value, will not blur. [0.0 - 1.0]", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{0.2, 0, 1}, + }, /* * animations: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f6734011..32f64f0a 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -429,6 +429,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("decoration:blur:special", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:blur:popups", Hyprlang::INT{0}); m_pConfig->addConfigValue("decoration:blur:popups_ignorealpha", {0.2F}); + m_pConfig->addConfigValue("decoration:blur:input_methods", Hyprlang::INT{0}); + m_pConfig->addConfigValue("decoration:blur:input_methods_ignorealpha", {0.2F}); m_pConfig->addConfigValue("decoration:active_opacity", {1.F}); m_pConfig->addConfigValue("decoration:inactive_opacity", {1.F}); m_pConfig->addConfigValue("decoration:fullscreen_opacity", {1.F}); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 57490d23..dae62851 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -850,12 +850,21 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, tim const auto SURF = pPopup->getSurface(); - renderdata.blur = false; renderdata.surface = SURF; renderdata.decorate = false; renderdata.w = SURF->current.size.x; renderdata.h = SURF->current.size.y; + static auto PBLUR = CConfigValue("decoration:blur:enabled"); + static auto PBLURIMES = CConfigValue("decoration:blur:input_methods"); + static auto PBLURIGNOREA = CConfigValue("decoration:blur:input_methods_ignorealpha"); + + renderdata.blur = *PBLURIMES && *PBLUR; + if (renderdata.blur) { + g_pHyprOpenGL->m_RenderData.discardMode |= DISCARD_ALPHA; + g_pHyprOpenGL->m_RenderData.discardOpacity = *PBLURIGNOREA; + } + SURF->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); } From 65f66dcf0d38533a383212ca440fdea0163be276 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 23 Nov 2024 22:32:13 +0800 Subject: [PATCH 0885/2393] binds: add option to allow fullscreening a pinned window (#8526) --- src/Compositor.cpp | 15 +++++++++++++-- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/desktop/Window.hpp | 3 +++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3fe5acec..53eaa467 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2245,7 +2245,8 @@ void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFull } void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) { - static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); + static auto PALLOWPINFULLSCREEN = CConfigValue("binds:allow_pin_fullscreen"); if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState) return; @@ -2259,7 +2260,17 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS const eFullscreenMode CURRENT_EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)PWINDOW->m_sFullscreenState.internal); const eFullscreenMode EFFECTIVE_MODE = (eFullscreenMode)std::bit_floor((uint8_t)state.internal); - const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE || (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen())); + if (*PALLOWPINFULLSCREEN && !PWINDOW->m_bPinFullscreened && !PWINDOW->isFullscreen() && PWINDOW->m_bPinned) { + PWINDOW->m_bPinned = false; + PWINDOW->m_bPinFullscreened = true; + } + + const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE || (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen())); + + if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) { + PWINDOW->m_bPinned = true; + PWINDOW->m_bPinFullscreened = false; + } // TODO: update the state on syncFullscreen changes if (!CHANGEINTERNAL && PWINDOW->m_sWindowData.syncFullscreen.valueOrDefault()) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 45379140..bb3d4e0e 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1206,6 +1206,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "binds:allow_pin_fullscreen", + .description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * xwayland: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 32f64f0a..3429db24 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -536,6 +536,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:window_direction_monitor_fallback", Hyprlang::INT{1}); + m_pConfig->addConfigValue("binds:allow_pin_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe", Hyprlang::INT{0}); m_pConfig->addConfigValue("gestures:workspace_swipe_fingers", Hyprlang::INT{3}); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ac81e5ef..5dd59437 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -332,6 +332,9 @@ class CWindow { // For pinned (sticky) windows bool m_bPinned = false; + // For preserving pinned state when fullscreening a pinned window + bool m_bPinFullscreened = false; + // urgency hint bool m_bIsUrgent = false; From 54f57797e9d025db72777ccf4adb0ddb25125016 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Sat, 23 Nov 2024 09:36:28 -0500 Subject: [PATCH 0886/2393] snap: account for position of multiple monitors (#8543) --- src/layout/IHyprLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 22e1d947..8ff55d10 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -484,8 +484,8 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA const double BORDERDIFF = DRAGGINGBORDERSIZE - BORDERSIZE; const auto MON = DRAGGINGWINDOW->m_pMonitor.lock(); - SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecSize.x - BORDERSIZE}; - SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecSize.y - BORDERSIZE}; + SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecPosition.x + MON->vecSize.x - BORDERSIZE}; + SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecPosition.y + MON->vecSize.y - BORDERSIZE}; if (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE)) { SNAP(sourceX.start, sourceX.end, monX.start); From 55ec8bd512605a014cc322d3419a9cfa72178340 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 24 Nov 2024 02:46:24 +0000 Subject: [PATCH 0887/2393] config: throw an error explicitly when parsing colors in gradients ref #8552 --- src/config/ConfigManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3429db24..ba0fdd9d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -67,7 +67,10 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** } try { - DATA->m_vColors.push_back(CColor(*configStringToInt(var))); + const auto COL = configStringToInt(var); + if (!COL) + throw std::runtime_error(std::format("failed to parse {} as a color", var)); + DATA->m_vColors.push_back(CColor(COL.value())); } catch (std::exception& e) { Debug::log(WARN, "Error parsing gradient {}", V); parseError = "Error parsing gradient " + V + ": " + e.what(); From cc38e7e18fd762d5cdb34d06335223b7d7874106 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 24 Nov 2024 14:53:36 +0000 Subject: [PATCH 0888/2393] config: don't overwrite errors in gradients --- src/config/ConfigManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ba0fdd9d..c0f212cf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -79,7 +79,8 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** if (DATA->m_vColors.size() == 0) { Debug::log(WARN, "Error parsing gradient {}", V); - parseError = "Error parsing gradient " + V + ": No colors?"; + if (parseError.empty()) + parseError = "Error parsing gradient " + V + ": No colors?"; DATA->m_vColors.push_back(0); // transparent } From 1930a95000d336b76d18c0c95ef77e138c9a4cd0 Mon Sep 17 00:00:00 2001 From: Nabil Otsmane <44232317+nabil-otsmane@users.noreply.github.com> Date: Mon, 25 Nov 2024 01:50:35 +0100 Subject: [PATCH 0889/2393] shm: fix shm fd size check before creating or resizing shm_pool (#8572) * protocols: fix shm fd size check before creating or resizing shm_pool * added static to function --- src/protocols/core/Shm.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index a8c98bb0..708d41c3 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -1,6 +1,7 @@ #include "Shm.hpp" #include #include +#include #include #include "../../render/Texture.hpp" #include "../types/WLBuffer.hpp" @@ -99,10 +100,25 @@ void CSHMPool::resize(size_t size_) { LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); } +static int shmIsSizeValid(int fd, size_t size) { + struct stat st; + if (fstat(fd, &st) == -1) { + LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); + return 0; + } + + return (size_t)st.st_size >= size; +} + CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { if (!good()) return; + if (!shmIsSizeValid(fd_, size_)) { + resource_->error(-1, "The size of the file is not big enough for the shm pool"); + return; + } + pool = makeShared(fd_, size_); resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); @@ -113,6 +129,11 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t r->error(-1, "Shrinking a shm pool is illegal"); return; } + if (!shmIsSizeValid(pool->fd, size_)) { + r->error(-1, "The size of the file is not big enough for the shm pool"); + return; + } + pool->resize(size_); }); From 0ddb952d7a3d102e160eea93c68f0d366186cf73 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:18:50 +0300 Subject: [PATCH 0890/2393] hyprland-uwsm.desktop: Just reference plain entry (#8553) --- systemd/hyprland-uwsm.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/systemd/hyprland-uwsm.desktop b/systemd/hyprland-uwsm.desktop index 2ed1031b..e00f4aa2 100644 --- a/systemd/hyprland-uwsm.desktop +++ b/systemd/hyprland-uwsm.desktop @@ -1,6 +1,6 @@ [Desktop Entry] Name=Hyprland (uwsm-managed) Comment=An intelligent dynamic tiling Wayland compositor -Exec=uwsm start -N Hyprland -D Hyprland -C An_intelligent_dynamic_tiling_Wayland_compositor -- Hyprland +Exec=uwsm start -- hyprland.desktop DesktopNames=Hyprland Type=Application From 268778823676ef2bbda42050d78946e1fc27fc31 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 25 Nov 2024 14:42:06 +0000 Subject: [PATCH 0891/2393] hyprctl: verify runtime dir exists in instances() ref #8579 --- hyprctl/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 1f7f8d74..4ee2d598 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -66,6 +66,11 @@ std::string getRuntimeDir() { std::vector instances() { std::vector result; + try { + if (!std::filesystem::exists(getRuntimeDir())) + return {}; + } catch (std::exception& e) { return {}; } + for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) { if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock")) continue; From 1fb720b62aeb474873ba43426ddc53afde1e6cdd Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Tue, 26 Nov 2024 07:52:43 -0600 Subject: [PATCH 0892/2393] seat: fix double scrolling in some applications (#8583) --- src/managers/SeatManager.cpp | 6 ++++-- src/protocols/core/Seat.cpp | 4 ++++ src/protocols/core/Seat.hpp | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index b40d6cad..665805f6 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -332,8 +332,10 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double p->sendAxisRelativeDirection(axis, relative); if (source == 0) { - p->sendAxisValue120(axis, value120); - p->sendAxisDiscrete(axis, discrete); + if (p->version() >= 8) + p->sendAxisValue120(axis, value120); + else + p->sendAxisDiscrete(axis, discrete); } else if (value == 0) p->sendAxisStop(timeMs, axis); } diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index d95e0e12..7c31b67c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -136,6 +136,10 @@ CWLPointerResource::CWLPointerResource(SP resource_, SPstate.pointerFocus.lock(), {-1, -1} /* Coords don't really matter that much, they will be updated next move */); } +int CWLPointerResource::version() { + return resource->version(); +} + bool CWLPointerResource::good() { return resource->resource(); } diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 1b43dd04..b5670237 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -73,6 +73,7 @@ class CWLPointerResource { CWLPointerResource(SP resource_, SP owner_); bool good(); + int version(); void sendEnter(SP surface, const Vector2D& local); void sendLeave(); void sendMotion(uint32_t timeMs, const Vector2D& local); From e9a7fb8f91d23f1ac2671e55f74234dcec2ee1c6 Mon Sep 17 00:00:00 2001 From: Agent00Ming <107314235+Agent00Ming@users.noreply.github.com> Date: Wed, 27 Nov 2024 09:17:45 -0500 Subject: [PATCH 0893/2393] renderer: fix incorrect early return (#8590) Co-authored-by: Agent_00Ming --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index dae62851..ca6ceba1 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -331,7 +331,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { if (pWindow->m_pMonitor == pMonitor) return true; - if (!(!pWindow->m_pWorkspace || !pWindow->m_pWorkspace->isVisible()) && pWindow->m_pMonitor != pMonitor) + if ((!pWindow->m_pWorkspace || !pWindow->m_pWorkspace->isVisible()) && pWindow->m_pMonitor != pMonitor) return false; // if not, check if it maybe is active on a different monitor. From 5329298b522e3cc1201894909443775b00aeb336 Mon Sep 17 00:00:00 2001 From: Andre Toerien Date: Wed, 27 Nov 2024 21:59:00 +0200 Subject: [PATCH 0894/2393] sessionLock: don't send motion events on every surface commit (#8584) --- src/managers/SessionLockManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index c7a5934a..b7110990 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -31,7 +31,7 @@ SSessionLockSurface::SSessionLockSurface(SP surface_) : sur listeners.commit = surface_->events.commit.registerListener([this](std::any data) { const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); - if (mapped && pWlrSurface != g_pCompositor->m_pLastFocus) + if (mapped && !g_pCompositor->m_pLastFocus) g_pInputManager->simulateMouseMovement(); if (PMONITOR) From 8b51eeb7aef8b25de35a0d460f28f4d67c017866 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 28 Nov 2024 14:31:38 +0000 Subject: [PATCH 0895/2393] core: fix compilation outside stdlibc++ fixes #8603 --- src/managers/KeybindManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index a5327149..7f10249a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2988,13 +2988,13 @@ SDispatchResult CKeybindManager::setProp(std::string args) { else configStringToInt(TOKEN).and_then([&colorData](const auto& e) { colorData.m_vColors.push_back(e); - return std::result_of::type(1); + return std::invoke_result_t(1); }); } } else if (VAL != "-1") configStringToInt(VAL).and_then([&colorData](const auto& e) { colorData.m_vColors.push_back(e); - return std::result_of::type(1); + return std::invoke_result_t(1); }); if (PROP == "activebordercolor") From 5963970be54c92fdebdbcebdeb76cf6de5e7e717 Mon Sep 17 00:00:00 2001 From: nyx Date: Thu, 28 Nov 2024 10:25:24 -0500 Subject: [PATCH 0896/2393] descriptions: change allow_pin_fullscreen value to false (#8592) --- src/config/ConfigDescriptions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index bb3d4e0e..e5918691 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1210,7 +1210,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "binds:allow_pin_fullscreen", .description = "Allows fullscreen to pinned windows, and restore their pinned status afterwards", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, /* From 22bf2853e6271932f073961f3dbeb0f9ff48493e Mon Sep 17 00:00:00 2001 From: Daringcuteseal Date: Thu, 28 Nov 2024 21:21:55 +0700 Subject: [PATCH 0897/2393] hyprpm: fix incomplete unmet dependencies message --- hyprpm/src/core/PluginManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index fb3065b4..db3893b5 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -115,7 +115,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); + std::println(stderr, "\n{}", failureString("Could not clone the plugin repository. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); return false; } @@ -421,7 +421,7 @@ bool CPluginManager::updateHeaders(bool force) { const auto HLVER = getHyprlandVersion(); if (!hasDeps()) { - std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio")); + std::println("\n{}", failureString("Could not update. Dependencies not satisfied. Hyprpm requires: cmake, meson, cpio, pkg-config")); return false; } From 8f83d29f00bfa89d1e8fe94b4dda98fe898b6b0e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 28 Nov 2024 23:51:53 +0000 Subject: [PATCH 0898/2393] renderer: restore discard mode after IME render pass ref #8555 --- src/render/Renderer.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index ca6ceba1..bba133d9 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -859,6 +859,10 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, tim static auto PBLURIMES = CConfigValue("decoration:blur:input_methods"); static auto PBLURIGNOREA = CConfigValue("decoration:blur:input_methods_ignorealpha"); + // TODO: make push/pop methods for this. + const auto DM = g_pHyprOpenGL->m_RenderData.discardMode; + const auto DA = g_pHyprOpenGL->m_RenderData.discardOpacity; + renderdata.blur = *PBLURIMES && *PBLUR; if (renderdata.blur) { g_pHyprOpenGL->m_RenderData.discardMode |= DISCARD_ALPHA; @@ -866,6 +870,9 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, tim } SURF->breadthfirst([](SP s, const Vector2D& offset, void* data) { renderSurface(s, offset.x, offset.y, data); }, &renderdata); + + g_pHyprOpenGL->m_RenderData.discardMode = DM; + g_pHyprOpenGL->m_RenderData.discardOpacity = DA; } void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, PHLMONITOR pMonitor, timespec* time) { From ef6b0c81c914bdc9b56c2674273698f065518993 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sun, 1 Dec 2024 00:40:23 +0800 Subject: [PATCH 0899/2393] cleanup: remove leftover var in ThreadManager.cpp (#8611) --- src/managers/ThreadManager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/managers/ThreadManager.cpp b/src/managers/ThreadManager.cpp index 6f8e0c9a..8666b3a6 100644 --- a/src/managers/ThreadManager.cpp +++ b/src/managers/ThreadManager.cpp @@ -3,8 +3,6 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" -int slowUpdate = 0; - int handleTimer(void* data) { const auto PTM = (CThreadManager*)data; @@ -27,4 +25,4 @@ CThreadManager::CThreadManager() { CThreadManager::~CThreadManager() { if (m_esConfigTimer) wl_event_source_remove(m_esConfigTimer); -} \ No newline at end of file +} From d26439a0fe5594fb26d5a3c01571f9490a9a2d2c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 30 Nov 2024 17:42:40 +0000 Subject: [PATCH 0900/2393] nix: update flake --- flake.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/flake.lock b/flake.lock index 969bc157..0db2ee60 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1731774881, - "narHash": "sha256-1Dxryiw8u2ejntxrrv3sMtIE8WHKxmlN4KeH+uMGbmc=", + "lastModified": 1731959031, + "narHash": "sha256-TGcvIjftziC1CjuiHCzrYDwmOoSFYIhdiKmLetzB5L0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "b31a6a4da8199ae3489057db7d36069a70749a56", + "rev": "4468981c1c50999f315baa1508f0e53c4ee70c52", "type": "github" }, "original": { @@ -151,11 +151,11 @@ ] }, "locked": { - "lastModified": 1731702627, - "narHash": "sha256-+JeO9gevnXannQxMfR5xzZtF4sYmSlWkX/BPmPx0mWk=", + "lastModified": 1732288281, + "narHash": "sha256-XTU9B53IjGeJiJ7LstOhuxcRjCOFkQFl01H78sT9Lg4=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "e911361a687753bbbdfe3b6a9eab755ecaf1d9e1", + "rev": "b26f33cc1c8a7fd5076e19e2cce3f062dca6351c", "type": "github" }, "original": { @@ -189,11 +189,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1731676054, - "narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=", + "lastModified": 1732758367, + "narHash": "sha256-RzaI1RO0UXqLjydtz3GAXSTzHkpb/lLD1JD8a0W4Wpo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add", + "rev": "fa42b5a5f401aab8a32bd33c9a4de0738180dc59", "type": "github" }, "original": { @@ -229,11 +229,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1731363552, - "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=", + "lastModified": 1732021966, + "narHash": "sha256-mnTbjpdqF0luOkou8ZFi2asa1N3AA2CchR/RqCNmsGE=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", + "rev": "3308484d1a443fc5bc92012435d79e80458fe43c", "type": "github" }, "original": { From 6d7544458d0fafcae410c1978a0cabce2fb4a346 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Sun, 1 Dec 2024 11:14:35 -0600 Subject: [PATCH 0901/2393] cleanup: use doLater instead of adding idle event handlers (#8624) --- src/protocols/Tablet.cpp | 26 ++++++++++++-------------- src/protocols/Tablet.hpp | 7 +++---- src/protocols/XDGShell.cpp | 18 +++++++++--------- src/protocols/XDGShell.hpp | 8 ++++---- src/xwayland/Server.cpp | 12 ++++-------- 5 files changed, 32 insertions(+), 39 deletions(-) diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index d7f741b9..7768402b 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -2,6 +2,7 @@ #include "../devices/Tablet.hpp" #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include @@ -162,11 +163,6 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP< }); } -CTabletToolV2Resource::~CTabletToolV2Resource() { - if (frameSource) - wl_event_source_remove(frameSource); -} - bool CTabletToolV2Resource::good() { return resource->resource(); } @@ -205,20 +201,22 @@ void CTabletToolV2Resource::sendData() { } void CTabletToolV2Resource::queueFrame() { - if (frameSource) + if (frameQueued) return; - frameSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this); + frameQueued = true; + g_pEventLoopManager->doLater([this]() { + if (!frameQueued || tool.expired() || inert) + return; + + sendFrame(); + }); } -void CTabletToolV2Resource::sendFrame(bool removeSource) { - if (frameSource) { - if (removeSource) - wl_event_source_remove(frameSource); - frameSource = nullptr; - } +void CTabletToolV2Resource::sendFrame() { + frameQueued = false; - if (!current) + if (!current || !resource) return; timespec now; diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 1ebcb1e5..8c99bee0 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -112,21 +112,20 @@ class CTabletV2Resource { class CTabletToolV2Resource { public: CTabletToolV2Resource(SP resource_, SP tool_, SP seat_); - ~CTabletToolV2Resource(); bool good(); void sendData(); void queueFrame(); - void sendFrame(bool removeSource = true); + void sendFrame(); bool current = false; WP lastSurf; WP tool; WP seat; - wl_event_source* frameSource = nullptr; - bool inert = false; // removed was sent + bool frameQueued = false; + bool inert = false; // removed was sent private: SP resource; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 688d0006..a542c394 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include @@ -469,8 +470,6 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPresetRole(); } @@ -484,22 +483,23 @@ SP CXDGSurfaceResource::fromResource(wl_resource* res) { return data ? data->self.lock() : nullptr; } -static void onConfigure(void* data) { - ((CXDGSurfaceResource*)data)->configure(); -} - uint32_t CXDGSurfaceResource::scheduleConfigure() { - if (configureSource) + if (configureScheduled) return scheduledSerial; - configureSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, onConfigure, this); scheduledSerial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); + configureScheduled = true; + g_pEventLoopManager->doLater([this]() { configure(); }); + return scheduledSerial; } void CXDGSurfaceResource::configure() { - configureSource = nullptr; + if (!resource) + return; + + configureScheduled = false; resource->sendConfigure(scheduledSerial); } diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index ef847f3b..3b7d2d11 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -199,12 +199,12 @@ class CXDGSurfaceResource { void configure(); private: - SP resource; + SP resource; - uint32_t lastConfigureSerial = 0; - uint32_t scheduledSerial = 0; + uint32_t lastConfigureSerial = 0; + uint32_t scheduledSerial = 0; - wl_event_source* configureSource = nullptr; + bool configureScheduled = false; // std::vector> popups; diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index f356af18..390ce1f6 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -176,11 +176,6 @@ static bool openSockets(std::array& sockets, int display) { return true; } -static void startServer(void* data) { - if (!g_pXWayland->pServer->start()) - Debug::log(ERR, "The XWayland server could not start! XWayland will not work..."); -} - static int xwaylandReady(int fd, uint32_t mask, void* data) { return g_pXWayland->pServer->ready(fd, mask); } @@ -308,9 +303,10 @@ bool CXWaylandServer::create() { setenv("DISPLAY", displayName.c_str(), true); - // TODO: lazy mode - - idleSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::startServer, nullptr); + g_pEventLoopManager->doLater([this]() { + if (!start()) + Debug::log(ERR, "The XWayland server could not start! XWayland will not work..."); + }); return true; } From 10a9fec7fc8e77479a599985c776a8a184311cd6 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:32:32 +0300 Subject: [PATCH 0902/2393] master: make center ignore reserved areas (#8625) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/layout/MasterLayout.cpp | 13 +++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index e5918691..b95eeab1 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1596,6 +1596,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "master:center_ignores_reserved", + .description = "centers the master window on monitor ignoring reserved areas", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, SConfigOptionDescription{ .value = "master:smart_resizing", .description = diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c0f212cf..07de8c24 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -470,6 +470,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:mfact", {0.55f}); m_pConfig->addConfigValue("master:new_status", {"slave"}); m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); + m_pConfig->addConfigValue("master:center_ignores_reserved", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:orientation", {"left"}); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index bf808627..4f761973 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -328,6 +328,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { eOrientation orientation = getDynamicOrientation(pWorkspace); bool centerMasterWindow = false; static auto ALWAYSCENTER = CConfigValue("master:always_center_master"); + static auto PIGNORERESERVED = CConfigValue("master:center_ignores_reserved"); static auto PSMARTRESIZING = CConfigValue("master:smart_resizing"); const auto MASTERS = getMastersOnWorkspace(pWorkspace->m_iID); @@ -402,7 +403,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { nextX += WIDTH; } } else { // orientation left, right or center - float WIDTH = WSSIZE.x; + float WIDTH = *PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecSize.x : WSSIZE.x; float heightLeft = WSSIZE.y; int mastersLeft = MASTERS; float nextX = 0; @@ -414,7 +415,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (orientation == ORIENTATION_RIGHT) { nextX = WSSIZE.x - WIDTH; } else if (centerMasterWindow) { - nextX = (WSSIZE.x - WIDTH) / 2; + nextX = ((*PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecSize.x : WSSIZE.x) - WIDTH) / 2; } for (auto& nd : m_lMasterNodesData) { @@ -431,7 +432,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { } nd.size = Vector2D(WIDTH, HEIGHT); - nd.position = WSPOS + Vector2D(nextX, nextY); + nd.position = (*PIGNORERESERVED && centerMasterWindow ? PMONITOR->vecPosition : WSPOS) + Vector2D(nextX, nextY); applyNodeDataToWindow(&nd); mastersLeft--; @@ -506,7 +507,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { nextY += HEIGHT; } } else { // slaves for centered master window(s) - const float WIDTH = (WSSIZE.x - PMASTERNODE->size.x) / 2.0; + const float WIDTH = ((*PIGNORERESERVED ? PMONITOR->vecSize.x : WSSIZE.x) - PMASTERNODE->size.x) / 2.0; float heightLeft = 0; float heightLeftL = WSSIZE.y; float heightLeftR = WSSIZE.y; @@ -543,7 +544,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { continue; if (onRight) { - nextX = WIDTH + PMASTERNODE->size.x; + nextX = WIDTH + PMASTERNODE->size.x - (*PIGNORERESERVED ? PMONITOR->vecReservedTopLeft.x : 0); nextY = nextYR; heightLeft = heightLeftR; slavesLeft = slavesLeftR; @@ -568,7 +569,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { } } - nd.size = Vector2D(WIDTH, HEIGHT); + nd.size = Vector2D(*PIGNORERESERVED ? (WIDTH - (onRight ? PMONITOR->vecReservedBottomRight.x : PMONITOR->vecReservedTopLeft.x)) : WIDTH, HEIGHT); nd.position = WSPOS + Vector2D(nextX, nextY); applyNodeDataToWindow(&nd); From 92186898c0ca1b3f72922b72c4af1723f0d9b888 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 2 Dec 2024 16:31:22 +0000 Subject: [PATCH 0903/2393] version: add link versions for other utils (#8619) --------- Co-authored-by: Mihai Fufezan --- CMakeLists.txt | 13 ++++++++----- hyprpm/CMakeLists.txt | 4 ++-- meson.build | 6 ++++++ src/debug/HyprCtl.cpp | 10 +++++++--- src/meson.build | 6 +++--- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cbd8b0a..7e2a1fe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,8 +104,14 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) +pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) +pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") +add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") +add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") +add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") pkg_check_modules( deps @@ -123,10 +129,7 @@ pkg_check_modules( libdrm libinput gbm - gio-2.0 - hyprlang>=0.3.2 - hyprcursor>=0.1.7 - hyprutils>=0.2.3) + gio-2.0) find_package(hyprwayland-scanner 0.3.10 REQUIRED) @@ -244,7 +247,7 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::deps) +target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::deps) if(udis_dep_FOUND) target_link_libraries(Hyprland PkgConfig::udis_dep) else() diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index 65935638..22cb8caa 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") set(CMAKE_CXX_STANDARD 23) -pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4) +pkg_check_modules(hyprpm_deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.2.4) add_executable(hyprpm ${SRCFILES}) -target_link_libraries(hyprpm PUBLIC PkgConfig::deps) +target_link_libraries(hyprpm PUBLIC PkgConfig::hyprpm_deps) # binary install(TARGETS hyprpm) diff --git a/meson.build b/meson.build index d825f184..39a5a6d0 100644 --- a/meson.build +++ b/meson.build @@ -32,7 +32,13 @@ if cpp_compiler.check_header('execinfo.h') endif aquamarine = dependency('aquamarine', version: '>=0.4.5') +hyprcursor = dependency('hyprcursor', version: '>=0.1.7') +hyprlang = dependency('hyprlang', version: '>= 0.3.2') +hyprutils = dependency('hyprutils', version: '>= 0.2.3') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') +add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') +add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') +add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp') xcb_dep = dependency('xcb', required: get_option('xwayland')) xcb_composite_dep = dependency('xcb-composite', required: get_option('xwayland')) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 11c16f0e..6b62ec8d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -875,8 +875,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" "Date: {}\n" "Tag: {}, commits: {}\n" - "built against aquamarine {}\n\n\n", - HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION); + "built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n\n\n", + HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION, + HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION); #if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND)) result += "no flags were set\n"; @@ -905,9 +906,12 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "tag": "{}", "commits": "{}", "buildAquamarine": "{}", + "buildHyprlang": "{}", + "buildHyprutils": "{}", + "buildHyprcursor": "{}", "flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, - GIT_COMMITS, AQUAMARINE_VERSION); + GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; diff --git a/src/meson.build b/src/meson.build index 2dbe2f44..61ca06d5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,14 +9,14 @@ executable( dependencies: [ server_protos, aquamarine, + hyprcursor, + hyprlang, + hyprutils, dependency('gbm'), dependency('xcursor'), dependency('wayland-server'), dependency('wayland-client'), dependency('cairo'), - dependency('hyprcursor', version: '>=0.1.7'), - dependency('hyprlang', version: '>= 0.3.2'), - dependency('hyprutils', version: '>= 0.2.3'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), From 320144ae7288fe23686935ebb235d9fe0c900862 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:58:24 +0000 Subject: [PATCH 0904/2393] core: move colorspace handling to oklab (#8635) * Meson: add hyprgraphics * Nix: add hyprgraphics * CI/setup_base: get hyprgraphics-git --------- Co-authored-by: Mihai Fufezan --- .github/actions/setup_base/action.yml | 7 + CMakeLists.txt | 4 +- flake.lock | 27 +++ flake.nix | 7 + meson.build | 2 + nix/default.nix | 2 + nix/overlays.nix | 1 + src/Compositor.cpp | 10 +- src/config/ConfigDataValues.hpp | 22 ++- src/config/ConfigManager.cpp | 23 +-- src/config/ConfigManager.hpp | 2 +- src/debug/HyprCtl.cpp | 15 +- src/debug/HyprNotificationOverlay.cpp | 4 +- src/debug/HyprNotificationOverlay.hpp | 18 +- src/desktop/Window.cpp | 4 +- src/desktop/Window.hpp | 2 +- src/helpers/AnimatedVariable.hpp | 4 +- src/helpers/Color.cpp | 56 +++++-- src/helpers/Color.hpp | 48 ++++-- src/hyprerror/HyprError.cpp | 6 +- src/hyprerror/HyprError.hpp | 4 +- src/managers/AnimationManager.cpp | 55 +++++- src/managers/AnimationManager.hpp | 4 +- src/managers/KeybindManager.cpp | 2 +- src/managers/PointerManager.cpp | 2 +- src/meson.build | 1 + src/plugins/PluginAPI.cpp | 4 +- src/plugins/PluginAPI.hpp | 4 +- src/protocols/SinglePixel.cpp | 8 +- src/protocols/SinglePixel.hpp | 4 +- src/protocols/ToplevelExport.cpp | 4 +- src/render/OpenGL.cpp | 157 +++++++++++++++--- src/render/OpenGL.hpp | 13 +- src/render/Renderer.cpp | 20 +-- src/render/Shader.hpp | 10 +- .../decorations/CHyprBorderDecoration.cpp | 11 +- .../decorations/CHyprDropShadowDecoration.cpp | 10 +- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 24 +-- src/render/shaders/Border.hpp | 62 ++++++- 40 files changed, 492 insertions(+), 173 deletions(-) diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index 26660ce6..e22f514e 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -33,7 +33,9 @@ runs: libfontenc \ libglvnd \ libinput \ + libjxl \ libliftoff \ + libwebp \ libxcursor \ libxcvt \ libxfont2 \ @@ -69,6 +71,11 @@ runs: cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --install build + - name: Get hyprgraphics-git + shell: bash + run: | + git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build + - name: Get hyprutils-git shell: bash run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e2a1fe6..aa0d4b03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,11 +107,13 @@ pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3) +pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") +add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}") pkg_check_modules( deps @@ -247,7 +249,7 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::deps) +target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps) if(udis_dep_FOUND) target_link_libraries(Hyprland PkgConfig::udis_dep) else() diff --git a/flake.lock b/flake.lock index 0db2ee60..23bd37a9 100644 --- a/flake.lock +++ b/flake.lock @@ -92,6 +92,32 @@ "type": "github" } }, + "hyprgraphics": { + "inputs": { + "hyprutils": [ + "hyprutils" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1733248371, + "narHash": "sha256-FFLJzFTyNhS7tBEEECx0B8Ye/bpmxhFVEKlECgMLc6c=", + "owner": "hyprwm", + "repo": "hyprgraphics", + "rev": "cc95e5babc6065bc3ab4cd195429a9900836ef13", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprgraphics", + "type": "github" + } + }, "hyprland-protocols": { "inputs": { "nixpkgs": [ @@ -246,6 +272,7 @@ "inputs": { "aquamarine": "aquamarine", "hyprcursor": "hyprcursor", + "hyprgraphics": "hyprgraphics", "hyprland-protocols": "hyprland-protocols", "hyprlang": "hyprlang", "hyprutils": "hyprutils", diff --git a/flake.nix b/flake.nix index e3419ef8..f26f1c31 100644 --- a/flake.nix +++ b/flake.nix @@ -22,6 +22,13 @@ inputs.hyprlang.follows = "hyprlang"; }; + hyprgraphics = { + url = "github:hyprwm/hyprgraphics"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + }; + hyprland-protocols = { url = "github:hyprwm/hyprland-protocols"; inputs.nixpkgs.follows = "nixpkgs"; diff --git a/meson.build b/meson.build index 39a5a6d0..c46b199c 100644 --- a/meson.build +++ b/meson.build @@ -33,10 +33,12 @@ endif aquamarine = dependency('aquamarine', version: '>=0.4.5') hyprcursor = dependency('hyprcursor', version: '>=0.1.7') +hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprutils = dependency('hyprutils', version: '>= 0.2.3') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') +add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') add_project_arguments(['-DHYPRUTILS_VERSION="@0@"'.format(hyprutils.version())], language: 'cpp') diff --git a/nix/default.nix b/nix/default.nix index 69174d4d..dbe4879e 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -12,6 +12,7 @@ cairo, git, hyprcursor, + hyprgraphics, hyprland-protocols, hyprlang, hyprutils, @@ -113,6 +114,7 @@ in cairo git hyprcursor + hyprgraphics hyprland-protocols hyprlang hyprutils diff --git a/nix/overlays.nix b/nix/overlays.nix index a7106315..c2103f31 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -22,6 +22,7 @@ in { # Dependencies inputs.aquamarine.overlays.default inputs.hyprcursor.overlays.default + inputs.hyprgraphics.overlays.default inputs.hyprland-protocols.overlays.default inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 53eaa467..3573996d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1873,11 +1873,11 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (pWindow == m_pLastWindow) - pWindow->m_cRealShadowColor = CColor(*PSHADOWCOL); + pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL); else - pWindow->m_cRealShadowColor = CColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); + pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); } else { - pWindow->m_cRealShadowColor.setValueAndWarp(CColor(0, 0, 0, 0)); // no shadow + pWindow->m_cRealShadowColor.setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow } pWindow->updateWindowDecos(); @@ -2608,14 +2608,14 @@ void CCompositor::performUserChecks() { g_pHyprNotificationOverlay->addNotification( std::format("Your XDG_CURRENT_DESKTOP environment seems to be managed externally, and the current value is {}.\nThis might cause issues unless it's intentional.", CURRENT_DESKTOP_ENV ? CURRENT_DESKTOP_ENV : "unset"), - CColor{}, 15000, ICON_WARNING); + CHyprColor{}, 15000, ICON_WARNING); } } if (g_pHyprOpenGL->failedAssetsNo > 0) { g_pHyprNotificationOverlay->addNotification(std::format("Hyprland failed to load {} essential asset{}, blame your distro's packager for doing a bad job at packaging!", g_pHyprOpenGL->failedAssetsNo, g_pHyprOpenGL->failedAssetsNo > 1 ? "s" : ""), - CColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR); + CHyprColor{1.0, 0.1, 0.1, 1.0}, 15000, ICON_ERROR); } } diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 37c9fc92..212f26fa 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -21,8 +21,9 @@ class ICustomConfigValueData { class CGradientValueData : public ICustomConfigValueData { public: CGradientValueData() {}; - CGradientValueData(CColor col) { + CGradientValueData(CHyprColor col) { m_vColors.push_back(col); + updateColorsOk(); }; virtual ~CGradientValueData() {}; @@ -30,14 +31,29 @@ class CGradientValueData : public ICustomConfigValueData { return CVD_TYPE_GRADIENT; } - void reset(CColor col) { + void reset(CHyprColor col) { m_vColors.clear(); m_vColors.emplace_back(col); m_fAngle = 0; + updateColorsOk(); + } + + void updateColorsOk() { + m_vColorsOkLabA.clear(); + for (auto& c : m_vColors) { + const auto OKLAB = c.asOkLab(); + m_vColorsOkLabA.emplace_back(OKLAB.l); + m_vColorsOkLabA.emplace_back(OKLAB.a); + m_vColorsOkLabA.emplace_back(OKLAB.b); + m_vColorsOkLabA.emplace_back(c.a); + } } /* Vector containing the colors */ - std::vector m_vColors; + std::vector m_vColors; + + /* Vector containing pure colors for shoving into opengl */ + std::vector m_vColorsOkLabA; /* Float corresponding to the angle (rad) */ float m_fAngle = 0; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 07de8c24..820844eb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -70,7 +70,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** const auto COL = configStringToInt(var); if (!COL) throw std::runtime_error(std::format("failed to parse {} as a color", var)); - DATA->m_vColors.push_back(CColor(COL.value())); + DATA->m_vColors.push_back(CHyprColor(COL.value())); } catch (std::exception& e) { Debug::log(WARN, "Error parsing gradient {}", V); parseError = "Error parsing gradient " + V + ": " + e.what(); @@ -85,6 +85,8 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** DATA->m_vColors.push_back(0); // transparent } + DATA->updateColorsOk(); + Hyprlang::CParseResult result; if (!parseError.empty()) result.setError(parseError.c_str()); @@ -676,7 +678,7 @@ CConfigManager::CConfigManager() { Debug::disableTime = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr()); if (ERR.has_value()) - g_pHyprError->queueCreate(ERR.value(), CColor{1.0, 0.1, 0.1, 1.0}); + g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); } std::optional CConfigManager::generateConfig(std::string configPath) { @@ -883,14 +885,14 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { m_szConfigErrors = ""; if (result.error && !std::any_cast(m_pConfig->getConfigValue("debug:suppress_errors"))) - g_pHyprError->queueCreate(result.getError(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); + g_pHyprError->queueCreate(result.getError(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) g_pHyprError->queueCreate( "Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland", - CColor(1.0, 1.0, 70.0 / 255.0, 1.0)); + CHyprColor(1.0, 1.0, 70.0 / 255.0, 1.0)); else if (*PENABLEEXPLICIT != prevEnabledExplicit) - g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CHyprColor(0.9, 0.76, 0.221, 1.0)); else g_pHyprError->destroy(); @@ -948,7 +950,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { // manual crash if (std::any_cast(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) { m_bManualCrashInitiated = true; - g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, ICON_INFO); + g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CHyprColor(0), 5000, + ICON_INFO); } else if (m_bManualCrashInitiated && !std::any_cast(m_pConfig->getConfigValue("debug:manual_crash"))) { // cowabunga it is g_pHyprRenderer->initiateManualCrash(); @@ -1015,7 +1018,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: if (COMMAND.contains("explicit")) { if (*PENABLEEXPLICIT != prevEnabledExplicit) - g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0)); + g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CHyprColor(0.9, 0.76, 0.221, 1.0)); else g_pHyprError->destroy(); } @@ -1027,7 +1030,7 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: if (std::any_cast(m_pConfig->getConfigValue("debug:manual_crash")) && !m_bManualCrashInitiated) { m_bManualCrashInitiated = true; if (g_pHyprNotificationOverlay) { - g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CColor(0), 5000, + g_pHyprNotificationOverlay->addNotification("Manual crash has been set up. Set debug:manual_crash back to 0 in order to crash the compositor.", CHyprColor(0), 5000, ICON_INFO); } } else if (m_bManualCrashInitiated && !std::any_cast(m_pConfig->getConfigValue("debug:manual_crash"))) { @@ -1671,7 +1674,7 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std:: } void CConfigManager::addParseError(const std::string& err) { - g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); + g_pHyprError->queueCreate(err + "\nHyprland may not work correctly.", CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); } PHLMONITOR CConfigManager::getBoundMonitorForWS(const std::string& wsname) { @@ -1716,7 +1719,7 @@ void CConfigManager::handlePluginLoads() { error << "\n" << path; } - g_pHyprError->queueCreate(error.str(), CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); + g_pHyprError->queueCreate(error.str(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); } if (pluginsChanged) { diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 88b74b6e..a3b86e69 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -119,7 +119,7 @@ struct SConfigOptionDescription { }; struct SColorData { - CColor color; + CHyprColor color; }; struct SChoiceData { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6b62ec8d..74b2a3a1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -875,9 +875,9 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" "Date: {}\n" "Tag: {}, commits: {}\n" - "built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n\n\n", + "built against:\n aquamarine {}\n hyprlang {}\n hyprutils {}\n hyprcursor {}\n hyprgraphics {}\n\n\n", HYPRLAND_VERSION, GIT_BRANCH, GIT_COMMIT_HASH, GIT_DIRTY, commitMsg, GIT_COMMIT_DATE, GIT_TAG, GIT_COMMITS, AQUAMARINE_VERSION, - HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION); + HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION); #if (!defined(LEGACY_RENDERER) && !defined(ISDEBUG) && !defined(NO_XWAYLAND)) result += "no flags were set\n"; @@ -909,9 +909,10 @@ std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { "buildHyprlang": "{}", "buildHyprutils": "{}", "buildHyprcursor": "{}", + "buildHyprgraphics": "{}", "flags": [)#", GIT_BRANCH, GIT_COMMIT_HASH, HYPRLAND_VERSION, (strcmp(GIT_DIRTY, "dirty") == 0 ? "true" : "false"), escapeJSONStrings(commitMsg), GIT_COMMIT_DATE, GIT_TAG, - GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION); + GIT_COMMITS, AQUAMARINE_VERSION, HYPRLANG_VERSION, HYPRUTILS_VERSION, HYPRCURSOR_VERSION, HYPRGRAPHICS_VERSION); #ifdef LEGACY_RENDERER result += "\"legacyrenderer\","; @@ -1290,7 +1291,7 @@ std::string dispatchSeterror(eHyprCtlOutputFormat format, std::string request) { return "ok"; } - const CColor COLOR = configStringToInt(vars[1]).value_or(0); + const CHyprColor COLOR = configStringToInt(vars[1]).value_or(0); for (size_t i = 2; i < vars.size(); ++i) errorMessage += vars[i] + ' '; @@ -1545,10 +1546,10 @@ std::string dispatchNotify(eHyprCtlOutputFormat format, std::string request) { const auto COLOR_RESULT = configStringToInt(vars[3]); if (!COLOR_RESULT) return "invalid arg 3"; - CColor color = *COLOR_RESULT; + CHyprColor color = *COLOR_RESULT; - size_t msgidx = 4; - float fontsize = 13.f; + size_t msgidx = 4; + float fontsize = 13.f; if (vars[msgidx].length() > 9 && vars[msgidx].compare(0, 9, "fontsize:") == 0) { const auto FONTSIZE = vars[msgidx].substr(9); diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index e46999e6..482db541 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -34,11 +34,11 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() { cairo_surface_destroy(m_pCairoSurface); } -void CHyprNotificationOverlay::addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon, const float fontSize) { +void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { const auto PNOTIF = m_dNotifications.emplace_back(std::make_unique()).get(); PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; - PNOTIF->color = color == CColor(0) ? ICONS_COLORS[icon] : color; + PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; PNOTIF->started.reset(); PNOTIF->timeMs = timeMs; PNOTIF->icon = icon; diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 0bba8b04..67603e49 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -19,17 +19,17 @@ enum eIconBackend { static const std::array, 3 /* backends */> ICONS_ARRAY = { std::array{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array{"", "", "", "", "", "󰸞", ""}, std::array{"", "", "", "", "", ""}}; -static const std::array ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0}, - CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0}, - CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0}, - CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0}, - CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0}, - CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0}, - CColor{0, 0, 0, 1.0}}; +static const std::array ICONS_COLORS = {CHyprColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0}, + CHyprColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0}, + CHyprColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0}, + CHyprColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0}, + CHyprColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0}, + CHyprColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0}, + CHyprColor{0, 0, 0, 1.0}}; struct SNotification { std::string text = ""; - CColor color; + CHyprColor color; CTimer started; float timeMs = 0; eIcons icon = ICON_NONE; @@ -42,7 +42,7 @@ class CHyprNotificationOverlay { ~CHyprNotificationOverlay(); void draw(PHLMONITOR pMonitor); - void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); + void addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon = ICON_NONE, const float fontSize = 13.f); void dismissNotifications(const int amount); bool hasAny(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 12e81b76..b015d61f 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -674,8 +674,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { // Basic form has only two colors, everything else can be parsed as a gradient if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { - m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority); - m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority); + m_sWindowData.activeBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[0]).value_or(0))), priority); + m_sWindowData.inactiveBorderColor = CWindowOverridableVar(CGradientValueData(CHyprColor(configStringToInt(colorsAndAngles[1]).value_or(0))), priority); return; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 5dd59437..672ff6ec 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -356,7 +356,7 @@ class CWindow { CAnimatedVariable m_fActiveInactiveAlpha; // animated shadow color - CAnimatedVariable m_cRealShadowColor; + CAnimatedVariable m_cRealShadowColor; // animated tint CAnimatedVariable m_fDimPercent; diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index 6310afb7..7cea72a0 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -34,7 +34,7 @@ struct typeToANIMATEDVARTYPE_t { }; template <> -struct typeToANIMATEDVARTYPE_t { +struct typeToANIMATEDVARTYPE_t { static constexpr ANIMATEDVARTYPE value = AVARTYPE_COLOR; }; @@ -63,7 +63,7 @@ concept OneOf = (... or std::same_as); // This is mainly to get better errors if we put a type that's not supported // Otherwise template errors are ugly template -concept Animable = OneOf; +concept Animable = OneOf; class CBaseAnimatedVariable { public: diff --git a/src/helpers/Color.cpp b/src/helpers/Color.cpp index f9a207bb..fe217c0f 100644 --- a/src/helpers/Color.cpp +++ b/src/helpers/Color.cpp @@ -5,22 +5,52 @@ #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0) #define BLUE(c) ((double)(((c)) & 0xff) / 255.0) -CColor::CColor() {} +CHyprColor::CHyprColor() {} -CColor::CColor(float r, float g, float b, float a) { - this->r = r; - this->g = g; - this->b = b; - this->a = a; +CHyprColor::CHyprColor(float r_, float g_, float b_, float a_) { + r = r_; + g = g_; + b = b_; + a = a_; + + okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab(); } -CColor::CColor(uint64_t hex) { - this->r = RED(hex); - this->g = GREEN(hex); - this->b = BLUE(hex); - this->a = ALPHA(hex); +CHyprColor::CHyprColor(uint64_t hex) { + r = RED(hex); + g = GREEN(hex); + b = BLUE(hex); + a = ALPHA(hex); + + okLab = Hyprgraphics::CColor(Hyprgraphics::CColor::SSRGB{r, g, b}).asOkLab(); } -uint32_t CColor::getAsHex() const { +CHyprColor::CHyprColor(const Hyprgraphics::CColor& color, float a_) { + const auto SRGB = color.asRgb(); + r = SRGB.r; + g = SRGB.g; + b = SRGB.b; + a = a_; + + okLab = color.asOkLab(); +} + +uint32_t CHyprColor::getAsHex() const { return (uint32_t)(a * 255.f) * 0x1000000 + (uint32_t)(r * 255.f) * 0x10000 + (uint32_t)(g * 255.f) * 0x100 + (uint32_t)(b * 255.f) * 0x1; -} \ No newline at end of file +} + +Hyprgraphics::CColor::SSRGB CHyprColor::asRGB() const { + return {r, g, b}; +} + +Hyprgraphics::CColor::SOkLab CHyprColor::asOkLab() const { + return okLab; +} + +Hyprgraphics::CColor::SHSL CHyprColor::asHSL() const { + return Hyprgraphics::CColor(okLab).asHSL(); +} + +CHyprColor CHyprColor::stripA() const { + return {r, g, b, 1.F}; +} diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 32ed39ee..cf7f7943 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -1,35 +1,47 @@ #pragma once #include +#include +#include "../debug/Log.hpp" +#include "../macros.hpp" -class CColor { +class CHyprColor { public: - CColor(); - CColor(float r, float g, float b, float a); - CColor(uint64_t); - - float r = 0, g = 0, b = 0, a = 1.f; + CHyprColor(); + CHyprColor(float r, float g, float b, float a); + CHyprColor(const Hyprgraphics::CColor& col, float a); + CHyprColor(uint64_t); // AR32 - uint32_t getAsHex() const; + uint32_t getAsHex() const; + Hyprgraphics::CColor::SSRGB asRGB() const; + Hyprgraphics::CColor::SOkLab asOkLab() const; + Hyprgraphics::CColor::SHSL asHSL() const; + CHyprColor stripA() const; - CColor operator-(const CColor& c2) const { - return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a); + // + bool operator==(const CHyprColor& c2) const { + return c2.r == r && c2.g == g && c2.b == b && c2.a == a; } - CColor operator+(const CColor& c2) const { - return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a); + // stubs for the AnimationMgr + CHyprColor operator-(const CHyprColor& c2) const { + RASSERT(false, "CHyprColor: - is a STUB"); + return {}; } - CColor operator*(const float& v) const { - return CColor(r * v, g * v, b * v, a * v); + CHyprColor operator+(const CHyprColor& c2) const { + RASSERT(false, "CHyprColor: + is a STUB"); + return {}; } - bool operator==(const CColor& c2) const { - return r == c2.r && g == c2.g && b == c2.b && a == c2.a; + CHyprColor operator*(const float& c2) const { + RASSERT(false, "CHyprColor: * is a STUB"); + return {}; } - CColor stripA() const { - return {r, g, b, 1}; - } + double r = 0, g = 0, b = 0, a = 0; + + private: + Hyprgraphics::CColor::SOkLab okLab; // cache for the OkLab representation }; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 4761346e..74a3030c 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -33,7 +33,7 @@ CHyprError::~CHyprError() { m_fFadeOpacity.unregister(); } -void CHyprError::queueCreate(std::string message, const CColor& color) { +void CHyprError::queueCreate(std::string message, const CHyprColor& color) { m_szQueued = message; m_cQueued = color; } @@ -98,7 +98,7 @@ void CHyprError::createQueued() { cairo_stroke(CAIRO); // draw the text with a common font - const CColor textColor = CColor(0.9, 0.9, 0.9, 1.0); + const CHyprColor textColor = CHyprColor(0.9, 0.9, 0.9, 1.0); cairo_set_source_rgba(CAIRO, textColor.r, textColor.g, textColor.b, textColor.a); static auto fontFamily = CConfigValue("misc:font_family"); @@ -160,7 +160,7 @@ void CHyprError::createQueued() { m_bIsCreated = true; m_szQueued = ""; - m_cQueued = CColor(); + m_cQueued = CHyprColor(); g_pHyprRenderer->damageMonitor(PMONITOR); diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index a553614c..042dccd0 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -11,7 +11,7 @@ class CHyprError { CHyprError(); ~CHyprError(); - void queueCreate(std::string message, const CColor& color); + void queueCreate(std::string message, const CHyprColor& color); void draw(); void destroy(); @@ -21,7 +21,7 @@ class CHyprError { private: void createQueued(); std::string m_szQueued = ""; - CColor m_cQueued; + CHyprColor m_cQueued; bool m_bQueuedDestroy = false; bool m_bIsCreated = false; SP m_pTexture; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 68dbdda1..7525bf6b 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -8,6 +8,8 @@ #include "eventLoop/EventLoopManager.hpp" #include "../helpers/varlist/VarList.hpp" +#include + int wlTick(SP self, void* data) { if (g_pAnimationManager) g_pAnimationManager->onTicked(); @@ -154,7 +156,7 @@ void CAnimationManager::tick() { // beziers are with a switch unforto // TODO: maybe do something cleaner - auto updateVariable = [&](CAnimatedVariable& av) { + static const auto updateVariable = [&](CAnimatedVariable& av) { // for disabled anims just warp if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) { av.warp(false); @@ -166,13 +168,50 @@ void CAnimationManager::tick() { return; } - const auto DELTA = av.m_Goal - av.m_Begun; const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); + const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER->second.getYForPoint(SPENT); + + const auto DELTA = av.m_Goal - av.m_Begun; if (BEZIER != m_mBezierCurves.end()) - av.m_Value = av.m_Begun + DELTA * BEZIER->second.getYForPoint(SPENT); + av.m_Value = av.m_Begun + DELTA * POINTY; else - av.m_Value = av.m_Begun + DELTA * DEFAULTBEZIER->second.getYForPoint(SPENT); + av.m_Value = av.m_Begun + DELTA * POINTY; + }; + + static const auto updateColorVariable = [&](CAnimatedVariable& av) { + // for disabled anims just warp + if (av.m_pConfig->pValues->internalEnabled == 0 || animationsDisabled) { + av.warp(false); + return; + } + + if (SPENT >= 1.f || av.m_Begun == av.m_Goal) { + av.warp(false); + return; + } + + const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); + const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER->second.getYForPoint(SPENT); + + // convert both to OkLab, then lerp that, and convert back. + // This is not as fast as just lerping rgb, but it's WAY more precise... + // Use the CHyprColor cache for OkLab + + const auto& L1 = av.m_Begun.asOkLab(); + const auto& L2 = av.m_Goal.asOkLab(); + + static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; + + const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{ + .l = lerp(L1.l, L2.l, POINTY), + .a = lerp(L1.a, L2.a, POINTY), + .b = lerp(L1.b, L2.b, POINTY), + }; + + av.m_Value = {lerped, lerp(av.m_Begun.a, av.m_Goal.a, POINTY)}; + + return; }; switch (av->m_Type) { @@ -187,8 +226,8 @@ void CAnimationManager::tick() { break; } case AVARTYPE_COLOR: { - auto typedAv = static_cast*>(av); - updateVariable(*typedAv); + auto typedAv = static_cast*>(av); + updateColorVariable(*typedAv); break; } default: UNREACHABLE(); @@ -272,7 +311,7 @@ bool CAnimationManager::deltaSmallToFlip(const Vector2D& a, const Vector2D& b) { return std::abs(a.x - b.x) < 0.5f && std::abs(a.y - b.y) < 0.5f; } -bool CAnimationManager::deltaSmallToFlip(const CColor& a, const CColor& b) { +bool CAnimationManager::deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b) { return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f; } @@ -288,7 +327,7 @@ bool CAnimationManager::deltazero(const float& a, const float& b) { return a == b; } -bool CAnimationManager::deltazero(const CColor& a, const CColor& b) { +bool CAnimationManager::deltazero(const CHyprColor& a, const CHyprColor& b) { return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; } diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 601a38b3..3960f261 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -39,10 +39,10 @@ class CAnimationManager { private: bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b); - bool deltaSmallToFlip(const CColor& a, const CColor& b); + bool deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b); bool deltaSmallToFlip(const float& a, const float& b); bool deltazero(const Vector2D& a, const Vector2D& b); - bool deltazero(const CColor& a, const CColor& b); + bool deltazero(const CHyprColor& a, const CHyprColor& b); bool deltazero(const float& a, const float& b); std::unordered_map m_mBezierCurves; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 7f10249a..cfb7453c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -275,7 +275,7 @@ void CKeybindManager::updateXKBTranslationState() { if (!PKEYMAP) { g_pHyprError->queueCreate("[Runtime Error] Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS + ", layout: " + LAYOUT + " )", - CColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); + CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); Debug::log(ERR, "[XKBTranslationState] Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model, rules.options); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 0580c9be..c0c190dd 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -505,7 +505,7 @@ SP CPointerManager::renderHWCursorBuffer(SPbind(); g_pHyprOpenGL->beginSimple(state->monitor.lock(), {0, 0, INT16_MAX, INT16_MAX}, RBO); - g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F}); + g_pHyprOpenGL->clear(CHyprColor{0.F, 0.F, 0.F, 0.F}); CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()}; Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize, diff --git a/src/meson.build b/src/meson.build index 61ca06d5..754cd55a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -10,6 +10,7 @@ executable( server_protos, aquamarine, hyprcursor, + hyprgraphics, hyprlang, hyprutils, dependency('gbm'), diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index ef3ae06a..1a7f25ab 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -71,7 +71,7 @@ APICALL bool HyprlandAPI::reloadConfig() { return true; } -APICALL bool HyprlandAPI::addNotification(HANDLE handle, const std::string& text, const CColor& color, const float timeMs) { +APICALL bool HyprlandAPI::addNotification(HANDLE handle, const std::string& text, const CHyprColor& color, const float timeMs) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) @@ -244,7 +244,7 @@ APICALL bool addNotificationV2(HANDLE handle, const std::unordered_map(iterator->second); + const auto COLOR = std::any_cast(iterator->second); // optional eIcons icon = ICON_NONE; diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index 4dcf4ba5..bd257699 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -187,7 +187,7 @@ namespace HyprlandAPI { returns: true on success. False otherwise. */ - APICALL bool addNotification(HANDLE handle, const std::string& text, const CColor& color, const float timeMs); + APICALL bool addNotification(HANDLE handle, const std::string& text, const CHyprColor& color, const float timeMs); /* Creates a trampoline function hook to an internal hl func. @@ -251,7 +251,7 @@ namespace HyprlandAPI { data has to contain: - text: std::string or const char* - time: uint64_t - - color: CColor -> CColor(0) will apply the default color for the notification icon + - color: CHyprColor -> CHyprColor(0) will apply the default color for the notification icon data may contain: - icon: eIcons diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index d800539d..41771ce2 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -2,7 +2,7 @@ #include #include "render/Renderer.hpp" -CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col_) { +CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col_) { LOGM(LOG, "New single-pixel buffer with color 0x{:x}", col_.getAsHex()); color = col_.getAsHex(); @@ -59,7 +59,7 @@ bool CSinglePixelBuffer::good() { return resource->good(); } -CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color) { +CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color) { buffer = makeShared(id, client, color); if (!buffer->good()) @@ -89,8 +89,8 @@ CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SPsetOnDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); resource->setCreateU32RgbaBuffer([this](CWpSinglePixelBufferManagerV1* res, uint32_t id, uint32_t r, uint32_t g, uint32_t b, uint32_t a) { - CColor color{r / (float)std::numeric_limits::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), - a / (float)std::numeric_limits::max()}; + CHyprColor color{r / (float)std::numeric_limits::max(), g / (float)std::numeric_limits::max(), b / (float)std::numeric_limits::max(), + a / (float)std::numeric_limits::max()}; const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared(id, resource->client(), color)); if (!RESOURCE->good()) { diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp index ab74825c..b20f582a 100644 --- a/src/protocols/SinglePixel.hpp +++ b/src/protocols/SinglePixel.hpp @@ -9,7 +9,7 @@ class CSinglePixelBuffer : public IHLBuffer { public: - CSinglePixelBuffer(uint32_t id, wl_client* client, CColor col); + CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col); virtual ~CSinglePixelBuffer(); virtual Aquamarine::eBufferCapability caps(); @@ -33,7 +33,7 @@ class CSinglePixelBuffer : public IHLBuffer { class CSinglePixelBufferResource { public: - CSinglePixelBufferResource(uint32_t id, wl_client* client, CColor color); + CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color); ~CSinglePixelBufferResource(); bool good(); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 04c089d7..d00e9dce 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -255,7 +255,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &outFB)) return false; - g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); + g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0)); // render client at 0,0 g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible @@ -308,7 +308,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) { if (!g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_TO_BUFFER, buffer.lock())) return false; - g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0)); + g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0)); g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(pWindow); // block the feedback to avoid spamming the surface if it's visible g_pHyprRenderer->renderWindow(pWindow, PMONITOR, now, false, RENDER_PASS_ALL, true, true); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 9c00daee..9b878317 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -566,7 +566,11 @@ void CHyprOpenGLImpl::logShaderError(const GLuint& shader, bool program) { glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data()); std::string errorStr(errorLog.begin(), errorLog.end()); - g_pConfigManager->addParseError((program ? "Screen shader parser: Error linking program:" : "Screen shader parser: Error compiling shader: ") + errorStr); + const auto FULLERROR = (program ? "Screen shader parser: Error linking program:" : "Screen shader parser: Error compiling shader: ") + errorStr; + + Debug::log(ERR, "Failed to link shader: {}", FULLERROR); + + g_pConfigManager->addParseError(FULLERROR); } GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) { @@ -604,6 +608,8 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string return 0; } } else { + if (ok != GL_TRUE) + logShaderError(prog, true); RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!"); } @@ -627,6 +633,8 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool return 0; } } else { + if (ok != GL_TRUE) + logShaderError(shader, false); RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!"); } @@ -1114,8 +1122,12 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); + m_RenderData.pCurrentMonData->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2"); m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); + m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length = glGetUniformLocation(prog, "gradient2Length"); m_RenderData.pCurrentMonData->m_shBORDER1.angle = glGetUniformLocation(prog, "angle"); + m_RenderData.pCurrentMonData->m_shBORDER1.angle2 = glGetUniformLocation(prog, "angle2"); + m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp = glGetUniformLocation(prog, "gradientLerp"); m_RenderData.pCurrentMonData->m_shBORDER1.alpha = glGetUniformLocation(prog, "alpha"); m_RenderData.pCurrentMonData->m_bShadersInitialized = true; @@ -1167,7 +1179,7 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos"); } -void CHyprOpenGLImpl::clear(const CColor& color) { +void CHyprOpenGLImpl::clear(const CHyprColor& color) { RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!"); TRACY_GPU_ZONE("RenderClear"); @@ -1231,12 +1243,12 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h scissor(&box, transform); } -void CHyprOpenGLImpl::renderRect(CBox* box, const CColor& col, int round) { +void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round) { if (!m_RenderData.damage.empty()) renderRectWithDamage(box, col, &m_RenderData.damage, round); } -void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round, float blurA, bool xray) { +void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float blurA, bool xray) { if (m_RenderData.damage.empty()) return; @@ -1258,7 +1270,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - renderRect(box, CColor(0, 0, 0, 0), round); + renderRect(box, CHyprColor(0, 0, 0, 0), round); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -1283,7 +1295,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CColor& col, int round renderRectWithDamage(box, col, &m_RenderData.damage, round); } -void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion* damage, int round) { +void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, CRegion* damage, int round) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -1981,7 +1993,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->blurFB.bind(); - clear(CColor(0, 0, 0, 0)); + clear(CHyprColor(0, 0, 0, 0)); m_bEndFrame = true; // fix transformed renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, &fakeDamage, 0, false, true, false); @@ -2100,7 +2112,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHA)) - renderRect(pBox, CColor(0, 0, 0, 0), round); + renderRect(pBox, CHyprColor(0, 0, 0, 0), round); else renderTexture(tex, pBox, a, round, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -2184,12 +2196,107 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); #endif - static_assert(sizeof(CColor) == 4 * sizeof(float)); // otherwise the line below this will fail - - glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColors.size(), (float*)grad.m_vColors.data()); - glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColors.size()); + glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad.m_vColorsOkLabA.size(), (float*)grad.m_vColorsOkLabA.data()); + glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad.m_vColorsOkLabA.size() / 4); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); + glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, 0); + + CBox transformedBox = *box; + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + m_RenderData.pMonitor->vecTransformedSize.y); + + const auto TOPLEFT = Vector2D(transformedBox.x, transformedBox.y); + const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height); + + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); + + glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); + glEnableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + + if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { + CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; + damageClip.intersect(m_RenderData.damage); + + if (!damageClip.empty()) { + for (auto const& RECT : damageClip.getRects()) { + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + } else { + for (auto const& RECT : m_RenderData.damage.getRects()) { + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib); + glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shBORDER1.texAttrib); + + blend(BLEND); +} + +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, int borderSize, float a, int outerRound) { + RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); + RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); + + TRACY_GPU_ZONE("RenderBorder2"); + + if (m_RenderData.damage.empty() || (m_pCurrentWindow.lock() && m_pCurrentWindow->m_sWindowData.noBorder.valueOrDefault())) + return; + + CBox newBox = *box; + m_RenderData.renderModif.applyToBox(newBox); + + box = &newBox; + + if (borderSize < 1) + return; + + int scaledBorderSize = std::round(borderSize * m_RenderData.pMonitor->scale); + scaledBorderSize = std::round(scaledBorderSize * m_RenderData.renderModif.combinedScale()); + + // adjust box + box->x -= scaledBorderSize; + box->y -= scaledBorderSize; + box->width += 2 * scaledBorderSize; + box->height += 2 * scaledBorderSize; + + round += round == 0 ? 0 : scaledBorderSize; + + Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( + newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); + Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); + + const auto BLEND = m_bBlend; + blend(true); + + glUseProgram(m_RenderData.pCurrentMonData->m_shBORDER1.program); + +#ifndef GLES2 + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_TRUE, glMatrix.getMatrix().data()); +#else + glMatrix.transpose(); + glUniformMatrix3fv(m_RenderData.pCurrentMonData->m_shBORDER1.proj, 1, GL_FALSE, glMatrix.getMatrix().data()); +#endif + + glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient, grad1.m_vColorsOkLabA.size(), (float*)grad1.m_vColorsOkLabA.data()); + glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength, grad1.m_vColorsOkLabA.size() / 4); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle, (int)(grad1.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); + glUniform4fv(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2, grad2.m_vColorsOkLabA.size(), (float*)grad2.m_vColorsOkLabA.data()); + glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, grad2.m_vColorsOkLabA.size() / 4); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.angle2, (int)(grad2.m_fAngle / (PI / 180.0)) % 360 * (PI / 180.0)); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp, lerp); CBox transformedBox = *box; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, @@ -2253,7 +2360,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, pFramebuffer); - clear(CColor(0, 0, 0, 0)); // JIC + clear(CHyprColor(0, 0, 0, 0)); // JIC timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -2272,7 +2379,7 @@ void CHyprOpenGLImpl::makeRawWindowSnapshot(PHLWINDOW pWindow, CFramebuffer* pFr m_RenderData.currentFB = pFramebuffer; - clear(CColor(0, 0, 0, 0)); // JIC + clear(CHyprColor(0, 0, 0, 0)); // JIC g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, false, RENDER_PASS_ALL, true); @@ -2308,7 +2415,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { g_pHyprRenderer->m_bRenderingSnapshot = true; - clear(CColor(0, 0, 0, 0)); // JIC + clear(CHyprColor(0, 0, 0, 0)); // JIC timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -2322,7 +2429,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(PHLWINDOW pWindow) { const auto BLURVAL = **PBLUR; **PBLUR = 0; - clear(CColor(0, 0, 0, 0)); // JIC + clear(CHyprColor(0, 0, 0, 0)); // JIC g_pHyprRenderer->renderWindow(pWindow, PMONITOR, &now, !pWindow->m_bX11DoesntWantBorders, RENDER_PASS_ALL); @@ -2355,7 +2462,7 @@ void CHyprOpenGLImpl::makeLayerSnapshot(PHLLS pLayer) { g_pHyprRenderer->m_bRenderingSnapshot = true; - clear(CColor(0, 0, 0, 0)); // JIC + clear(CHyprColor(0, 0, 0, 0)); // JIC timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -2405,7 +2512,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLWINDOW pWindow) { if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault()) { CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y}; - g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value())); + g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value())); g_pHyprRenderer->damageMonitor(PMONITOR); } @@ -2449,7 +2556,7 @@ void CHyprOpenGLImpl::renderSnapshot(PHLLS pLayer) { m_bEndFrame = false; } -void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CColor& color, float a) { +void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CHyprColor& color, float a) { RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); RASSERT(m_pCurrentWindow.lock(), "Tried to render shadow without a window!"); @@ -2568,7 +2675,7 @@ void CHyprOpenGLImpl::renderMirrored() { .translate(-monitor->vecTransformedSize / 2.0); // clear stuff outside of mirrored area (e.g. when changing to mirrored) - clear(CColor(0, 0, 0, 0)); + clear(CHyprColor(0, 0, 0, 0)); renderTexture(PFB->getTexture(), &monbox, 1.f, 0, false, false); @@ -2583,7 +2690,7 @@ void CHyprOpenGLImpl::renderSplash(cairo_t* const CAIRO, cairo_surface_t* const const auto FONTFAMILY = *PSPLASHFONT != STRVAL_EMPTY ? *PSPLASHFONT : *FALLBACKFONT; const auto FONTSIZE = (int)(size.y / 76); - const auto COLOR = CColor(*PSPLASHCOLOR); + const auto COLOR = CHyprColor(*PSPLASHCOLOR); PangoLayout* layoutText = pango_cairo_create_layout(CAIRO); PangoFontDescription* pangoFD = pango_font_description_new(); @@ -2671,7 +2778,7 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { return tex; } -SP CHyprOpenGLImpl::renderText(const std::string& text, CColor col, int pt, bool italic) { +SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic) { SP tex = makeShared(); static auto FONT = CConfigValue("misc:font_family"); @@ -2804,7 +2911,7 @@ void CHyprOpenGLImpl::initAssets() { g_pCompositor->m_pAqBackend->hasSession() && g_pCompositor->m_pAqBackend->session->vt > 0 ? std::to_string(g_pCompositor->m_pAqBackend->session->vt) : "unknown"), - CColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); + CHyprColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); // create the default background texture { @@ -2889,7 +2996,7 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; blend(true); - clear(CColor{0, 0, 0, 1}); + clear(CHyprColor{0, 0, 0, 1}); // first render the background if (m_pBackgroundTexture) { @@ -2981,7 +3088,7 @@ void CHyprOpenGLImpl::restoreMatrix() { void CHyprOpenGLImpl::bindOffMain() { m_RenderData.pCurrentMonData->offMainFB.bind(); - clear(CColor(0, 0, 0, 0)); + clear(CHyprColor(0, 0, 0, 0)); m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index c594a7cc..6c0632dd 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -153,15 +153,16 @@ class CHyprOpenGLImpl { void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); void end(); - void renderRect(CBox*, const CColor&, int round = 0); - void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0); + void renderRect(CBox*, const CHyprColor&, int round = 0); + void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CHyprColor&, CRegion* damage, int round = 0); void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithDamage(SP, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0); + void renderRoundedShadow(CBox*, int round, int range, const CHyprColor& color, float a = 1.0); void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); void setMonitorTransformEnabled(bool enabled); @@ -180,7 +181,7 @@ class CHyprOpenGLImpl { void renderSnapshot(PHLLS); bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CColor&); + void clear(const CHyprColor&); void clearWithTex(); void scissor(const CBox*, bool transform = true); void scissor(const pixman_box32*, bool transform = true); @@ -289,7 +290,7 @@ class CHyprOpenGLImpl { void initEGL(bool gbm); EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); SP loadAsset(const std::string& file); - SP renderText(const std::string& text, CColor col, int pt, bool italic = false); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false); void initAssets(); void initMissingAssetTexture(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index bba133d9..7e44e64e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -619,7 +619,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe if (*PDIMAROUND && pWindow->m_sWindowData.dimAround.valueOrDefault() && !m_bRenderingSnapshot && mode != RENDER_PASS_POPUP) { CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y}; - g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha)); + g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * renderdata.alpha * renderdata.fadeAlpha)); } renderdata.x += pWindow->m_vFloatingOffset.x; @@ -668,7 +668,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe if (!pWindow->m_sWindowData.noBlur.valueOrDefault() && pWindow->m_pWLSurface->small() && !pWindow->m_pWLSurface->m_bFillIgnoreSmall && renderdata.blur && *PBLUR) { CBox wb = {renderdata.x - pMonitor->vecPosition.x, renderdata.y - pMonitor->vecPosition.y, renderdata.w, renderdata.h}; wb.scale(pMonitor->scale).round(); - g_pHyprOpenGL->renderRectWithBlur(&wb, CColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, + g_pHyprOpenGL->renderRectWithBlur(&wb, CHyprColor(0, 0, 0, 0), renderdata.dontRound ? 0 : renderdata.rounding - 1, renderdata.fadeAlpha, g_pHyprOpenGL->shouldUseNewBlurOptimizations(nullptr, pWindow)); renderdata.blur = false; } @@ -780,7 +780,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) { CBox monbox = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y}; - g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value())); + g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value())); } if (pLayer->fadingOut) { @@ -919,7 +919,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA g_pHyprOpenGL->blend(false); if (!canSkipBackBufferClear(pMonitor)) { if (*PRENDERTEX /* inverted cfg flag */) - g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR)); + g_pHyprOpenGL->clear(CHyprColor(*PBACKGROUNDCOLOR)); else g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" } @@ -959,7 +959,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA g_pHyprOpenGL->blend(false); if (!canSkipBackBufferClear(pMonitor)) { if (*PRENDERTEX /* inverted cfg flag */) - g_pHyprOpenGL->clear(CColor(*PBACKGROUNDCOLOR)); + g_pHyprOpenGL->clear(CHyprColor(*PBACKGROUNDCOLOR)); else g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" } @@ -995,12 +995,12 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA if (*PDIMSPECIAL != 0.f) { CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale}; - g_pHyprOpenGL->renderRect(&monbox, CColor(0, 0, 0, *PDIMSPECIAL * (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS))); + g_pHyprOpenGL->renderRect(&monbox, CHyprColor(0, 0, 0, *PDIMSPECIAL * (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS))); } if (*PBLURSPECIAL && *PBLUR) { CBox monbox = {translate.x, translate.y, pMonitor->vecTransformedSize.x * scale, pMonitor->vecTransformedSize.y * scale}; - g_pHyprOpenGL->renderRectWithBlur(&monbox, CColor(0, 0, 0, 0), 0, (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS)); + g_pHyprOpenGL->renderRectWithBlur(&monbox, CHyprColor(0, 0, 0, 0), 0, (ANIMOUT ? (1.0 - SPECIALANIMPROGRS) : SPECIALANIMPROGRS)); } break; @@ -1447,7 +1447,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { if (*PDAMAGEBLINK && damageBlinkCleanup == 0) { CBox monrect = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}; - g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0); + g_pHyprOpenGL->renderRect(&monrect, CHyprColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0); damageBlinkCleanup = 1; } else if (*PDAMAGEBLINK) { damageBlinkCleanup++; @@ -2526,7 +2526,7 @@ std::tuple CHyprRenderer::getRenderTimes(PHLMONITOR pMonito static int handleCrashLoop(void* data) { - g_pHyprNotificationOverlay->addNotification("Hyprland will crash in " + std::to_string(10 - (int)(g_pHyprRenderer->m_fCrashingDistort * 2.f)) + "s.", CColor(0), 5000, + g_pHyprNotificationOverlay->addNotification("Hyprland will crash in " + std::to_string(10 - (int)(g_pHyprRenderer->m_fCrashingDistort * 2.f)) + "s.", CHyprColor(0), 5000, ICON_INFO); g_pHyprRenderer->m_fCrashingDistort += 0.5f; @@ -2540,7 +2540,7 @@ static int handleCrashLoop(void* data) { } void CHyprRenderer::initiateManualCrash() { - g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CColor(0), 5000, ICON_INFO); + g_pHyprNotificationOverlay->addNotification("Manual crash initiated. Farewell...", CHyprColor(0), 5000, ICON_INFO); m_pCrashingLoop = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleCrashLoop, nullptr); wl_event_source_timer_update(m_pCrashingLoop, 1000); diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index d5a312c3..eaf9da96 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -38,9 +38,13 @@ class CShader { GLint applyTint = -1; GLint tint = -1; - GLint gradient = -1; - GLint gradientLength = -1; - GLint angle = -1; + GLint gradient = -1; + GLint gradientLength = -1; + GLint angle = -1; + GLint gradient2 = -1; + GLint gradient2Length = -1; + GLint angle2 = -1; + GLint gradientLerp = -1; float initialTime = 0; GLint time = -1; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index d62e67c4..b0de4a64 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -60,7 +60,6 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { auto grad = m_pWindow->m_cRealBorderColor; const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated(); - float a1 = a * (ANIMATED ? m_pWindow->m_fBorderFadeAnimationProgress.value() : 1.f); if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) { grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.value() * M_PI * 2; @@ -70,12 +69,10 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { int borderSize = m_pWindow->getRealBorderSize(); const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; - g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a1); - - if (ANIMATED) { - float a2 = a * (1.f - m_pWindow->m_fBorderFadeAnimationProgress.value()); - g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, ROUNDING, borderSize, a2); - } + if (ANIMATED) + g_pHyprOpenGL->renderBorder(&windowBox, m_pWindow->m_cRealBorderColorPrevious, grad, m_pWindow->m_fBorderFadeAnimationProgress.value(), ROUNDING, borderSize, a); + else + g_pHyprOpenGL->renderBorder(&windowBox, grad, ROUNDING, borderSize, a); } eDecorationType CHyprBorderDecoration::getDecorationType() { diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 893ad498..39398878 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -93,7 +93,7 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (!validMapped(PWINDOW)) return; - if (PWINDOW->m_cRealShadowColor.value() == CColor(0, 0, 0, 0)) + if (PWINDOW->m_cRealShadowColor.value() == CHyprColor(0, 0, 0, 0)) return; // don't draw invisible shadows if (!PWINDOW->m_sWindowData.decorate.valueOrDefault()) @@ -181,13 +181,13 @@ void CHyprDropShadowDecoration::draw(PHLMONITOR pMonitor, float const& a) { // build the matte // 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest. // first, clear region of interest with black (fully transparent) - g_pHyprOpenGL->renderRect(&fullBox, CColor(0, 0, 0, 1), 0); + g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); + g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); alphaSwapFB.bind(); @@ -215,7 +215,7 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { return DECORATION_LAYER_BOTTOM; } -void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CColor color, float a) { +void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a) { static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); g_pHyprOpenGL->blend(true); diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 933ee0ef..650f8c92 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -34,7 +34,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; - void drawShadowInternal(CBox* box, int round, int range, CColor color, float a); + void drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a); CBox m_bLastWindowBox = {0}; CBox m_bLastWindowBoxWithDecos = {0}; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index b5189be5..937c913d 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -147,7 +147,7 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; - CColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; + CHyprColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); @@ -205,19 +205,19 @@ void CHyprGroupBarDecoration::invalidateTextures() { } CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale) { - tex = makeShared(); - szContent = pWindow->m_szTitle; - pWindowOwner = pWindow; - const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); - const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE); + tex = makeShared(); + szContent = pWindow->m_szTitle; + pWindowOwner = pWindow; + const auto LAYOUTSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); + const auto LAYOUTCAIRO = cairo_create(LAYOUTSURFACE); - static auto FALLBACKFONT = CConfigValue("misc:font_family"); - static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); - static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); - static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); + static auto FALLBACKFONT = CConfigValue("misc:font_family"); + static auto PTITLEFONTFAMILY = CConfigValue("group:groupbar:font_family"); + static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); + static auto PTEXTCOLOR = CConfigValue("group:groupbar:text_color"); - const CColor COLOR = CColor(*PTEXTCOLOR); - const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; + const CHyprColor COLOR = CHyprColor(*PTEXTCOLOR); + const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; cairo_surface_destroy(LAYOUTSURFACE); diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp index 1f4a1d97..acd3f3ff 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/Border.hpp @@ -17,12 +17,32 @@ uniform float radius; uniform float radiusOuter; uniform float thick; +// Gradients are in OkLabA!!!! {l, a, b, alpha} uniform vec4 gradient[10]; +uniform vec4 gradient2[10]; uniform int gradientLength; +uniform int gradient2Length; uniform float angle; +uniform float angle2; +uniform float gradientLerp; uniform float alpha; -vec4 getColorForCoord(vec2 normalizedCoord) { +float linearToGamma(float x) { + return x >= 0.0031308 ? 1.055 * pow(x, 0.416666666) - 0.055 : 12.92 * x; +} + +vec4 okLabAToSrgb(vec4 lab) { + float l = pow(lab[0] + lab[1] * 0.3963377774 + lab[2] * 0.2158037573, 3.0); + float m = pow(lab[0] + lab[1] * (-0.1055613458) + lab[2] * (-0.0638541728), 3.0); + float s = pow(lab[0] + lab[1] * (-0.0894841775) + lab[2] * (-1.2914855480), 3.0); + + return vec4(linearToGamma(l * 4.0767416621 + m * -3.3077115913 + s * 0.2309699292), + linearToGamma(l * (-1.2684380046) + m * 2.6097574011 + s * (-0.3413193965)), + linearToGamma(l * (-0.0041960863) + m * (-0.7034186147) + s * 1.7076147010), + lab[3]); +} + +vec4 getOkColorForCoordArray1(vec2 normalizedCoord) { if (gradientLength < 2) return gradient[0]; @@ -51,6 +71,46 @@ vec4 getColorForCoord(vec2 normalizedCoord) { return gradient[top] * (progress - float(bottom)) + gradient[bottom] * (float(top) - progress); } +vec4 getOkColorForCoordArray2(vec2 normalizedCoord) { + if (gradient2Length < 2) + return gradient2[0]; + + float finalAng = 0.0; + + if (angle2 > 4.71 /* 270 deg */) { + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = 6.28 - angle; + } else if (angle2 > 3.14 /* 180 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + normalizedCoord[1] = 1.0 - normalizedCoord[1]; + finalAng = angle - 3.14; + } else if (angle2 > 1.57 /* 90 deg */) { + normalizedCoord[0] = 1.0 - normalizedCoord[0]; + finalAng = 3.14 - angle2; + } else { + finalAng = angle2; + } + + float sine = sin(finalAng); + + float progress = (normalizedCoord[1] * sine + normalizedCoord[0] * (1.0 - sine)) * float(gradient2Length - 1); + int bottom = int(floor(progress)); + int top = bottom + 1; + + return gradient2[top] * (progress - float(bottom)) + gradient2[bottom] * (float(top) - progress); +} + +vec4 getColorForCoord(vec2 normalizedCoord) { + vec4 result1 = getOkColorForCoordArray1(normalizedCoord); + + if (gradient2Length <= 0) + return okLabAToSrgb(result1); + + vec4 result2 = getOkColorForCoordArray2(normalizedCoord); + + return okLabAToSrgb(mix(result1, result2, gradientLerp)); +} + void main() { highp vec2 pixCoord = vec2(gl_FragCoord); From f6ac755cf76750b8ee53389c54ef653590462c1c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 3 Dec 2024 21:15:25 +0000 Subject: [PATCH 0905/2393] cleanup: Revert use doLater instead of adding idle event handlers (#8624) This reverts commit 6d7544458d0fafcae410c1978a0cabce2fb4a346. --- src/protocols/Tablet.cpp | 26 ++++++++++++++------------ src/protocols/Tablet.hpp | 7 ++++--- src/protocols/XDGShell.cpp | 18 +++++++++--------- src/protocols/XDGShell.hpp | 8 ++++---- src/xwayland/Server.cpp | 12 ++++++++---- 5 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 7768402b..d7f741b9 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -2,7 +2,6 @@ #include "../devices/Tablet.hpp" #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" -#include "../managers/eventLoop/EventLoopManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include @@ -163,6 +162,11 @@ CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP< }); } +CTabletToolV2Resource::~CTabletToolV2Resource() { + if (frameSource) + wl_event_source_remove(frameSource); +} + bool CTabletToolV2Resource::good() { return resource->resource(); } @@ -201,22 +205,20 @@ void CTabletToolV2Resource::sendData() { } void CTabletToolV2Resource::queueFrame() { - if (frameQueued) + if (frameSource) return; - frameQueued = true; - g_pEventLoopManager->doLater([this]() { - if (!frameQueued || tool.expired() || inert) - return; - - sendFrame(); - }); + frameSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, [](void* data) { ((CTabletToolV2Resource*)data)->sendFrame(false); }, this); } -void CTabletToolV2Resource::sendFrame() { - frameQueued = false; +void CTabletToolV2Resource::sendFrame(bool removeSource) { + if (frameSource) { + if (removeSource) + wl_event_source_remove(frameSource); + frameSource = nullptr; + } - if (!current || !resource) + if (!current) return; timespec now; diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 8c99bee0..1ebcb1e5 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -112,20 +112,21 @@ class CTabletV2Resource { class CTabletToolV2Resource { public: CTabletToolV2Resource(SP resource_, SP tool_, SP seat_); + ~CTabletToolV2Resource(); bool good(); void sendData(); void queueFrame(); - void sendFrame(); + void sendFrame(bool removeSource = true); bool current = false; WP lastSurf; WP tool; WP seat; + wl_event_source* frameSource = nullptr; - bool frameQueued = false; - bool inert = false; // removed was sent + bool inert = false; // removed was sent private: SP resource; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index a542c394..688d0006 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,7 +3,6 @@ #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" -#include "../managers/eventLoop/EventLoopManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include @@ -470,6 +469,8 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPresetRole(); } @@ -483,23 +484,22 @@ SP CXDGSurfaceResource::fromResource(wl_resource* res) { return data ? data->self.lock() : nullptr; } +static void onConfigure(void* data) { + ((CXDGSurfaceResource*)data)->configure(); +} + uint32_t CXDGSurfaceResource::scheduleConfigure() { - if (configureScheduled) + if (configureSource) return scheduledSerial; + configureSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, onConfigure, this); scheduledSerial = wl_display_next_serial(g_pCompositor->m_sWLDisplay); - configureScheduled = true; - g_pEventLoopManager->doLater([this]() { configure(); }); - return scheduledSerial; } void CXDGSurfaceResource::configure() { - if (!resource) - return; - - configureScheduled = false; + configureSource = nullptr; resource->sendConfigure(scheduledSerial); } diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 3b7d2d11..ef847f3b 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -199,12 +199,12 @@ class CXDGSurfaceResource { void configure(); private: - SP resource; + SP resource; - uint32_t lastConfigureSerial = 0; - uint32_t scheduledSerial = 0; + uint32_t lastConfigureSerial = 0; + uint32_t scheduledSerial = 0; - bool configureScheduled = false; + wl_event_source* configureSource = nullptr; // std::vector> popups; diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 390ce1f6..f356af18 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -176,6 +176,11 @@ static bool openSockets(std::array& sockets, int display) { return true; } +static void startServer(void* data) { + if (!g_pXWayland->pServer->start()) + Debug::log(ERR, "The XWayland server could not start! XWayland will not work..."); +} + static int xwaylandReady(int fd, uint32_t mask, void* data) { return g_pXWayland->pServer->ready(fd, mask); } @@ -303,10 +308,9 @@ bool CXWaylandServer::create() { setenv("DISPLAY", displayName.c_str(), true); - g_pEventLoopManager->doLater([this]() { - if (!start()) - Debug::log(ERR, "The XWayland server could not start! XWayland will not work..."); - }); + // TODO: lazy mode + + idleSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::startServer, nullptr); return true; } From 3c617ce33c64cb43049489598b6391911eed7070 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 3 Dec 2024 22:58:30 +0000 Subject: [PATCH 0906/2393] internal: fixup some missed updateColorsOk() calls --- src/desktop/Window.cpp | 2 ++ src/managers/KeybindManager.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b015d61f..34682b32 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -692,6 +692,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { inactiveBorderGradient.m_vColors.push_back(configStringToInt(token).value_or(0)); } + activeBorderGradient.updateColorsOk(); + // Includes sanity checks for the number of colors in each gradient if (activeBorderGradient.m_vColors.size() > 10 || inactiveBorderGradient.m_vColors.size() > 10) Debug::log(WARN, "Bordercolor rule \"{}\" has more than 10 colors in one gradient, ignoring", r.szRule); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index cfb7453c..153c3c0d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2997,6 +2997,8 @@ SDispatchResult CKeybindManager::setProp(std::string args) { return std::invoke_result_t(1); }); + colorData.updateColorsOk(); + if (PROP == "activebordercolor") PWINDOW->m_sWindowData.activeBorderColor = CWindowOverridableVar(colorData, PRIORITY_SET_PROP); else From f9e4998a6d7713b19947b0db2c43ad88c5b71d80 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Wed, 4 Dec 2024 13:12:04 -0500 Subject: [PATCH 0907/2393] snap: check which corner is being grabbed for monitor snapping (#8637) --- src/layout/IHyprLayout.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 8ff55d10..cb1f064b 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -487,19 +487,23 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA SRange monX = {MON->vecPosition.x + BORDERSIZE, MON->vecPosition.x + MON->vecSize.x - BORDERSIZE}; SRange monY = {MON->vecPosition.y + BORDERSIZE, MON->vecPosition.y + MON->vecSize.y - BORDERSIZE}; - if (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE)) { + if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && + (canSnap(sourceX.start, monX.start, GAPSIZE) || canSnap(sourceX.start, (monX.start += MON->vecReservedTopLeft.x + BORDERDIFF), GAPSIZE))) { SNAP(sourceX.start, sourceX.end, monX.start); snaps |= SNAP_LEFT; } - if (canSnap(sourceX.end, monX.end, GAPSIZE) || canSnap(sourceX.end, (monX.end -= MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE)) { + if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && + (canSnap(sourceX.end, monX.end, GAPSIZE) || canSnap(sourceX.end, (monX.end -= MON->vecReservedBottomRight.x + BORDERDIFF), GAPSIZE))) { SNAP(sourceX.end, sourceX.start, monX.end); snaps |= SNAP_RIGHT; } - if (canSnap(sourceY.start, monY.start, GAPSIZE) || canSnap(sourceY.start, (monY.start += MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE)) { + if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && + (canSnap(sourceY.start, monY.start, GAPSIZE) || canSnap(sourceY.start, (monY.start += MON->vecReservedTopLeft.y + BORDERDIFF), GAPSIZE))) { SNAP(sourceY.start, sourceY.end, monY.start); snaps |= SNAP_UP; } - if (canSnap(sourceY.end, monY.end, GAPSIZE) || canSnap(sourceY.end, (monY.end -= MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE)) { + if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && + (canSnap(sourceY.end, monY.end, GAPSIZE) || canSnap(sourceY.end, (monY.end -= MON->vecReservedBottomRight.y + BORDERDIFF), GAPSIZE))) { SNAP(sourceY.end, sourceY.start, monY.end); snaps |= SNAP_DOWN; } From 22f7d6f1424c296b297df87bf2accdfefac4af33 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 5 Dec 2024 01:59:29 +0000 Subject: [PATCH 0908/2393] core: add a few festive splashes adds two new 'special' splash types for xmas and new years. Activated based on local time. --- src/Compositor.cpp | 14 ++- src/helpers/Splashes.hpp | 184 +++++++++++++++++++++++---------------- 2 files changed, 120 insertions(+), 78 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3573996d..1261d003 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -206,11 +206,21 @@ CCompositor::~CCompositor() { } void CCompositor::setRandomSplash() { + auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + auto local = *localtime(&tt); + + const auto* SPLASHES = &NSplashes::SPLASHES; + + if (local.tm_mon + 1 == 12 && local.tm_mday >= 23 && local.tm_mday <= 27) // dec 23-27 + SPLASHES = &NSplashes::SPLASHES_CHRISTMAS; + if ((local.tm_mon + 1 == 12 && local.tm_mday >= 29) || (local.tm_mon + 1 == 1 && local.tm_mday <= 3)) + SPLASHES = &NSplashes::SPLASHES_NEWYEAR; + std::random_device dev; std::mt19937 engine(dev()); - std::uniform_int_distribution<> distribution(0, SPLASHES.size() - 1); + std::uniform_int_distribution<> distribution(0, SPLASHES->size() - 1); - m_szCurrentSplash = SPLASHES[distribution(engine)]; + m_szCurrentSplash = SPLASHES->at(distribution(engine)); } static std::vector> pendingOutputs; diff --git a/src/helpers/Splashes.hpp b/src/helpers/Splashes.hpp index 4a4fd022..2c74abb1 100644 --- a/src/helpers/Splashes.hpp +++ b/src/helpers/Splashes.hpp @@ -3,80 +3,112 @@ #include #include -inline const std::vector SPLASHES = { - // clang-format off - "Woo, animations!", - "It's like Hypr, but better.", - "Release 1.0 when?", - "It's not awesome, it's Hyprland!", - "\"I commit too often, people can't catch up lmao\" - Vaxry", - "This text is random.", - "\"There are reasons to not use rust.\" - Boga", - "Read the wiki.", - "\"Hello everyone this is YOUR daily dose of ‘read the wiki’\" - Vaxry", - "h", - "\"‘why no work’, bro I haven't hacked your pc to get live feeds yet\" - Vaxry", - "Compile, wait for 20 minutes, notice a new commit, compile again.", - "To rice, or not to rice, that is the question.", - "Now available on Fedora!", - "\"Hyprland is so good it starts with a capital letter\" - Hazel", - "\"please make this message a splash\" - eriedaberrie", - "\"the only wayland compositor powered by fried chicken\" - raf", - "\"This will never get into Hyprland\" - Flafy", - "\"Hyprland only gives you up on -git\" - fazzi", - "Segmentation fault (core dumped)", - "\"disabling hyprland logo is a war crime\" - vaxry", - "some basic startup code", - "\"I think I am addicted to hyprland\" - mathisbuilder", - "\"hyprland is the most important package in the arch repos\" - jacekpoz", - "Thanks Brodie!", - "Thanks fufexan!", - "Thanks raf!", - "You can't use --splash to change this message :)", - "Hyprland will overtake Gnome in popularity by [insert year]", - // music reference / quote section - "J'remue le ciel, le jour, la nuit.", - "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", - "Wir sind schon sehr lang zusammen...", - "I see a red door and I want it painted black.", - "Take on me, take me on...", - "You spin me right round baby right round", - "Stayin' alive, stayin' alive", - "Say no way, say no way ya, no way!", - "Ground control to Major Tom...", - "Alors on danse", - "And all that I can see, is just a yellow lemon tree.", - "Got a one-way ticket to the blues", - "Is this the real life, is this just fantasy", - "What's in your head, in your head?", - "We're all living in America, America, America.", - "I'm still standing, better than I ever did", - "Here comes the sun, bringing you love and shining on everyone", - "Two trailer park girls go round the outside", - "With the lights out, it's less dangerous", - "Here we go back, this is the moment, tonight is the night", - "Now you're just somebody that I used to know...", - "Black bird, black moon, black sky", - "Some legends are told, some turn to dust or to gold", - "Your brain gets smart, but your head gets dumb.", - "Save your mercy for someone who needs it more", - "You're gonna hear my voice when I shout it out loud", - "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm", - "Súbeme la radio que esta es mi canción", - "I'm beggin', beggin' you", - "Never gonna let you down (I am trying!)", - "\"I use Arch, btw\" - John Cena", - "\"Hyper\".replace(\"e\", \"\")", - "\"my win11 install runs hyprland that is true\" - raf", - "\"stop playing league loser\" - hyprBot", - "\"If it ain't broke, don't fix it\" - Lucascito_03", - "\"@vaxry how do i learn c++\" - flicko", - // - "Join the discord server!", - "Thanks ThatOneCalculator!", - "The AUR packages always work, except for the times they don't.", - "Funny animation compositor woo", - // - "2 years!" - // clang-format on +namespace NSplashes { + inline const std::vector SPLASHES = { + // clang-format off + "Woo, animations!", + "It's like Hypr, but better.", + "Release 1.0 when?", + "It's not awesome, it's Hyprland!", + "\"I commit too often, people can't catch up lmao\" - Vaxry", + "This text is random.", + "\"There are reasons to not use rust.\" - Boga", + "Read the wiki.", + "\"Hello everyone this is YOUR daily dose of ‘read the wiki’\" - Vaxry", + "h", + "\"‘why no work’, bro I haven't hacked your pc to get live feeds yet\" - Vaxry", + "Compile, wait for 20 minutes, notice a new commit, compile again.", + "To rice, or not to rice, that is the question.", + "Now available on Fedora!", + "\"Hyprland is so good it starts with a capital letter\" - Hazel", + "\"please make this message a splash\" - eriedaberrie", + "\"the only wayland compositor powered by fried chicken\" - raf", + "\"This will never get into Hyprland\" - Flafy", + "\"Hyprland only gives you up on -git\" - fazzi", + "Segmentation fault (core dumped)", + "\"disabling hyprland logo is a war crime\" - vaxry", + "some basic startup code", + "\"I think I am addicted to hyprland\" - mathisbuilder", + "\"hyprland is the most important package in the arch repos\" - jacekpoz", + "Thanks Brodie!", + "Thanks fufexan!", + "Thanks raf!", + "You can't use --splash to change this message :)", + "Hyprland will overtake Gnome in popularity by [insert year]", + // music reference / quote section + "J'remue le ciel, le jour, la nuit.", + "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!", + "Wir sind schon sehr lang zusammen...", + "I see a red door and I want it painted black.", + "Take on me, take me on...", + "You spin me right round baby right round", + "Stayin' alive, stayin' alive", + "Say no way, say no way ya, no way!", + "Ground control to Major Tom...", + "Alors on danse", + "And all that I can see, is just a yellow lemon tree.", + "Got a one-way ticket to the blues", + "Is this the real life, is this just fantasy", + "What's in your head, in your head?", + "We're all living in America, America, America.", + "I'm still standing, better than I ever did", + "Here comes the sun, bringing you love and shining on everyone", + "Two trailer park girls go round the outside", + "With the lights out, it's less dangerous", + "Here we go back, this is the moment, tonight is the night", + "Now you're just somebody that I used to know...", + "Black bird, black moon, black sky", + "Some legends are told, some turn to dust or to gold", + "Your brain gets smart, but your head gets dumb.", + "Save your mercy for someone who needs it more", + "You're gonna hear my voice when I shout it out loud", + "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm", + "Súbeme la radio que esta es mi canción", + "I'm beggin', beggin' you", + "Never gonna let you down (I am trying!)", + "\"I use Arch, btw\" - John Cena", + "\"Hyper\".replace(\"e\", \"\")", + "\"my win11 install runs hyprland that is true\" - raf", + "\"stop playing league loser\" - hyprBot", + "\"If it ain't broke, don't fix it\" - Lucascito_03", + "\"@vaxry how do i learn c++\" - flicko", + // + "Join the discord server!", + "Thanks ThatOneCalculator!", + "The AUR packages always work, except for the times they don't.", + "Funny animation compositor woo", + // + "2 years!" + // clang-format on + }; + + inline const std::vector SPLASHES_CHRISTMAS = { + // clang-format off + "Merry Christmas!", + "Merry Xmas!", + "Ho ho ho", + "Santa was here", + // clang-format on + }; + + // ONLY valid near new years. + inline static int newYear = []() -> int { + auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + auto local = *localtime(&tt); + + if (local.tm_mon < 8 /* decided with a fair die I promise. */) + return local.tm_year + 1900; + return local.tm_year + 1901; + }(); + + inline const std::vector SPLASHES_NEWYEAR = { + // clang-format off + "Happy new Year!", + "[New year] will be the year of the Linux desktop!", + "[New year] will be the year of the Hyprland desktop!", + std::format("{} will be the year of the Linux desktop!", newYear), + std::format("{} will be the year of the Hyprland desktop!", newYear), + std::format("Let's make {} even better than {}!", newYear, newYear - 1), + // clang-format on + }; }; \ No newline at end of file From ceef4fb3a5efe1617790f56e2701846a21c2533d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 5 Dec 2024 03:36:50 +0000 Subject: [PATCH 0909/2393] core: feeling a bit quirky today. --- src/helpers/Splashes.hpp | 49 +++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/helpers/Splashes.hpp b/src/helpers/Splashes.hpp index 2c74abb1..3ae59956 100644 --- a/src/helpers/Splashes.hpp +++ b/src/helpers/Splashes.hpp @@ -35,6 +35,30 @@ namespace NSplashes { "Thanks raf!", "You can't use --splash to change this message :)", "Hyprland will overtake Gnome in popularity by [insert year]", + "Designed in California - Assembled in China", + "\"something
System/Version info - ```sh - - + ``` + + ``` @@ -61,15 +62,56 @@ body: attributes: label: How to reproduce description: "How can someone else reproduce the issue?" + placeholder: | + 1. ... + 2. ... + 3. ... + validations: required: true + - type: markdown + attributes: + value: | + ## Additional info section + + In the section below you will be asked to upload some files. + + When including text files (such as logs or config), please **always ATTACH** them, and not paste them directly. + + This is important to avoid clutter, spam, and make the issues more readable. + Thanks for your understanding. + + # The main reason to disallow pasting directly or in a dropdown, is to not clutter + # the issue with unnecessary keywords, making the github issue search useless. + - type: checkboxes + attributes: + label: Attach not paste + options: + - label: I understand that all text files must be *attached*, and not pasted directly. If not respected, this issue will likely get closed as spam + required: true + + - type: markdown + attributes: + value: >- + Please be sure to upload the following files below if they are relevant to the issue: + + - Logs can be found in $XDG_RUNTIME_DIR/hypr (sort by date to grab the latest) + - Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland + - Hyprland config files - `hyprctl systeminfo -c > /tmp/hyprland_config_dump.txt` use this command to dump full configuration to a single file. + + - type: checkboxes + attributes: + label: Checklist of files to include below + options: + - label: Hyprland config - `hyprctl systeminfo -c` (always include) + - label: Crash report (always include in case of crash) + - label: Video (always include in case of a visual bug) + - label: Logs (might contain useful info such as errors) + - type: textarea id: logs attributes: - label: Crash reports, logs, images, videos + label: Additional info & File uploads description: | - Anything that can help. Please always ATTACH and not paste them. - Logs can be found in $XDG_RUNTIME_DIR/hypr - Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland - + Tip: You can attach files by clicking this area to highlight it and then dragging files in. From f69e72eca1a31e4780d06018fc7e09767a50969d Mon Sep 17 00:00:00 2001 From: davc0n Date: Fri, 3 Jan 2025 23:43:48 +0100 Subject: [PATCH 1017/2393] socket2: add focusedmonv2 event (#8921) * socket2: add focusedmonv2 event * socket2: remove workspace name from focusedmonv2 --- src/Compositor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c8ed22df..aa6faa16 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2588,7 +2588,12 @@ void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) { const auto PWORKSPACE = pMonitor->activeWorkspace; - g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")}); + const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_iID) : std::to_string(WORKSPACE_INVALID); + const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_szName : "?"; + + g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + WORKSPACE_NAME}); + g_pEventManager->postEvent(SHyprIPCEvent{"focusedmonv2", pMonitor->szName + "," + WORKSPACE_ID}); + EMIT_HOOK_EVENT("focusedMon", pMonitor); m_pLastMonitor = pMonitor->self; } From 2e6e0e9278614406979f63692cdb3a015e54c248 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 4 Jan 2025 00:10:10 +0100 Subject: [PATCH 1018/2393] core: guard workspace and monitor in moveWorkspaceToMonitor ref #7822 --- src/Compositor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index aa6faa16..c80f05e6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2076,7 +2076,8 @@ PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) { void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) { - // We trust the monitor to be correct. + if (!pWorkspace || !pMonitor) + return; if (pWorkspace->m_pMonitor == pMonitor) return; From 60f069d54015fec66e63f1ff7e6ff26ddb349976 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 4 Jan 2025 00:25:01 +0100 Subject: [PATCH 1019/2393] groupbar: fix missing ellipsize for text fixes #8938 --- src/render/OpenGL.cpp | 8 +++- src/render/OpenGL.hpp | 38 +++++++++---------- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 68baf48e..1b51acbf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2555,7 +2555,7 @@ SP CHyprOpenGLImpl::loadAsset(const std::string& filename) { return tex; } -SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily) { +SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col, int pt, bool italic, const std::string& fontFamily, int maxWidth) { SP tex = makeShared(); static auto FONT = CConfigValue("misc:font_family"); @@ -2580,6 +2580,12 @@ SP CHyprOpenGLImpl::renderText(const std::string& text, CHyprColor col int textW = 0, textH = 0; pango_layout_set_text(layoutText, text.c_str(), -1); + + if (maxWidth > 0) { + pango_layout_set_width(layoutText, maxWidth * PANGO_SCALE); + pango_layout_set_ellipsize(layoutText, PANGO_ELLIPSIZE_END); + } + pango_layout_get_size(layoutText, &textW, &textH); textW /= PANGO_SCALE; textH /= PANGO_SCALE; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 281ee09a..713816bc 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -217,32 +217,32 @@ class CHyprOpenGLImpl { void renderOffToMain(CFramebuffer* off); void bindBackOnMain(); - SP loadAsset(const std::string& file); - SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = ""); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); - void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void setDamage(const CRegion& damage, std::optional finalDamage = {}); - uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; - uint failedAssetsNo = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; + uint failedAssetsNo = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; std::map m_mMonitorRenderResources; std::map m_mMonitorBGFBs; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 53d35a64..c6dc5779 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -223,7 +223,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float const CHyprColor COLOR = CHyprColor(*PTEXTCOLOR); const auto FONTFAMILY = *PTITLEFONTFAMILY != STRVAL_EMPTY ? *PTITLEFONTFAMILY : *FALLBACKFONT; - tex = g_pHyprOpenGL->renderText(pWindow->m_szTitle, COLOR, *PTITLEFONTSIZE, false, FONTFAMILY); + tex = g_pHyprOpenGL->renderText(pWindow->m_szTitle, COLOR, *PTITLEFONTSIZE, false, FONTFAMILY, bufferSize.x - 2 /* some padding yk */); if (tex) texSize = tex->m_vSize; From a25d228840dfac88160b6f6c9513b5a587119f67 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 4 Jan 2025 17:21:02 +0100 Subject: [PATCH 1020/2393] windows: minor initial workspace improvements ref #8942 --- src/events/Windows.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index c17c425b..a20cbcad 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -121,16 +121,6 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bX11ShouldntFocus = PWINDOW->m_bX11ShouldntFocus || (PWINDOW->m_bIsX11 && PWINDOW->isX11OverrideRedirect() && !PWINDOW->m_pXWaylandSurface->wantsFocus()); - if (PWORKSPACE->m_bDefaultFloating) - PWINDOW->m_bIsFloating = true; - - if (PWORKSPACE->m_bDefaultPseudo) { - PWINDOW->m_bIsPseudotiled = true; - CBox desiredGeometry = {0}; - g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry); - PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); - } - // window rules PWINDOW->m_vMatchedRules = g_pConfigManager->getMatchingRules(PWINDOW, false); std::optional requestedInternalFSMode, requestedClientFSMode; @@ -171,6 +161,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PMONITOR = PMONITORFROMID; } PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; + PWORKSPACE = PWINDOW->m_pWorkspace; Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); } @@ -180,11 +171,10 @@ void Events::listener_mapWindow(void* owner, void* data) { // check if it isnt unset const auto WORKSPACERQ = r->szRule.substr(r->szRule.find_first_of(' ') + 1); - if (WORKSPACERQ == "unset") { + if (WORKSPACERQ == "unset") requestedWorkspace = ""; - } else { + else requestedWorkspace = WORKSPACERQ; - } const auto JUSTWORKSPACE = WORKSPACERQ.contains(' ') ? WORKSPACERQ.substr(0, WORKSPACERQ.find_first_of(' ')) : WORKSPACERQ; @@ -347,6 +337,16 @@ void Events::listener_mapWindow(void* owner, void* data) { workspaceSilent = false; } + if (PWORKSPACE->m_bDefaultFloating) + PWINDOW->m_bIsFloating = true; + + if (PWORKSPACE->m_bDefaultPseudo) { + PWINDOW->m_bIsPseudotiled = true; + CBox desiredGeometry = {0}; + g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry); + PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + } + PWINDOW->updateWindowData(); // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. From e8317ae34d635b6055c4ab3e42325a9e50b6f5a0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sat, 4 Jan 2025 17:35:11 +0100 Subject: [PATCH 1021/2393] xwayland: don't define atoms on no_xwayland builds fixes #8661 --- src/xwayland/XWayland.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index 96253d19..113ca4d4 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -34,6 +34,7 @@ class CXWayland { inline std::unique_ptr g_pXWayland; inline std::unordered_map HYPRATOMS = { +#ifndef NO_XWAYLAND HYPRATOM("_NET_SUPPORTED"), HYPRATOM("_NET_SUPPORTING_WM_CHECK"), HYPRATOM("_NET_WM_NAME"), @@ -126,4 +127,5 @@ inline std::unordered_map HYPRATOMS = { HYPRATOM("DELETE"), HYPRATOM("TEXT"), HYPRATOM("INCR"), +#endif }; From b0bae15499ad57bbfeae8be958df8c022201e583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Migu=C3=A9ns?= Date: Sat, 4 Jan 2025 17:40:33 +0100 Subject: [PATCH 1022/2393] master: make loop around optional when cycling (#8926) --- src/layout/MasterLayout.cpp | 21 ++++++++++++++++----- src/layout/MasterLayout.hpp | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 05a2a707..fb7df84f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -978,7 +978,7 @@ void CHyprMasterLayout::alterSplitRatio(PHLWINDOW pWindow, float ratio, bool exa recalculateMonitor(pWindow->monitorID()); } -PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next) { +PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next, bool loop) { if (!isWindowTiled(pWindow)) return nullptr; @@ -997,6 +997,13 @@ PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next) { CANDIDATE = std::find_if(nodes.begin(), nodes.end(), [&](const auto& other) { return other != *PNODE && ISMASTER != other.isMaster && other.workspaceID == PNODE->workspaceID; }); + if (CANDIDATE != nodes.end() && !loop) { + if (CANDIDATE->isMaster && next) + return nullptr; + if (!CANDIDATE->isMaster && ISMASTER && !next) + return nullptr; + } + return CANDIDATE == nodes.end() ? nullptr : CANDIDATE->pWindow.lock(); } @@ -1110,7 +1117,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!PWINDOW) return 0; - const auto PNEXTWINDOW = getNextWindow(PWINDOW, true); + const bool NOLOOP = vars.size() >= 2 && vars[1] == "noloop"; + const auto PNEXTWINDOW = getNextWindow(PWINDOW, true, !NOLOOP); switchToWindow(PNEXTWINDOW); } else if (command == "cycleprev") { const auto PWINDOW = header.pWindow; @@ -1118,7 +1126,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!PWINDOW) return 0; - const auto PPREVWINDOW = getNextWindow(PWINDOW, false); + const bool NOLOOP = vars.size() >= 2 && vars[1] == "noloop"; + const auto PPREVWINDOW = getNextWindow(PWINDOW, false, !NOLOOP); switchToWindow(PPREVWINDOW); } else if (command == "swapnext") { if (!validMapped(header.pWindow)) @@ -1129,7 +1138,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri return 0; } - const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true); + const bool NOLOOP = vars.size() >= 2 && vars[1] == "noloop"; + const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, true, !NOLOOP); if (PWINDOWTOSWAPWITH) { g_pCompositor->setWindowFullscreenInternal(header.pWindow, FSMODE_NONE); @@ -1145,7 +1155,8 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri return 0; } - const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false); + const bool NOLOOP = vars.size() >= 2 && vars[1] == "noloop"; + const auto PWINDOWTOSWAPWITH = getNextWindow(header.pWindow, false, !NOLOOP); if (PWINDOWTOSWAPWITH) { g_pCompositor->setWindowFullscreenClient(header.pWindow, FSMODE_NONE); diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 4841ef08..03ca3c3b 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -87,7 +87,7 @@ class CHyprMasterLayout : public IHyprLayout { SMasterNodeData* getMasterNodeOnWorkspace(const WORKSPACEID&); SMasterWorkspaceData* getMasterWorkspaceData(const WORKSPACEID&); void calculateWorkspace(PHLWORKSPACE); - PHLWINDOW getNextWindow(PHLWINDOW, bool); + PHLWINDOW getNextWindow(PHLWINDOW, bool, bool); int getMastersOnWorkspace(const WORKSPACEID&); friend struct SMasterNodeData; From a5c14370c11287cbf520c8f427179c665ac9c891 Mon Sep 17 00:00:00 2001 From: Pollux Date: Sun, 5 Jan 2025 12:38:49 -0600 Subject: [PATCH 1023/2393] renderer: Add supercircular window corners (#8943) renderer: Add supercircular shadows and borders config: Add rounding_power to default and example configs rule: add `roundingpower` window rule --- example/hyprland.conf | 1 + src/config/ConfigDescriptions.hpp | 6 + src/config/ConfigManager.cpp | 1 + src/config/ConfigManager.hpp | 1 + src/config/defaultConfig.hpp | 1 + src/desktop/Window.cpp | 23 ++-- src/desktop/Window.hpp | 2 + src/desktop/WindowRule.cpp | 6 +- src/render/OpenGL.cpp | 106 +++++++++------- src/render/OpenGL.hpp | 119 +++++++++--------- src/render/Renderer.cpp | 11 +- src/render/Shader.hpp | 1 + .../decorations/CHyprBorderDecoration.cpp | 16 +-- .../decorations/CHyprDropShadowDecoration.cpp | 14 ++- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- src/render/pass/BorderPassElement.cpp | 6 +- src/render/pass/BorderPassElement.hpp | 1 + src/render/pass/RectPassElement.cpp | 4 +- src/render/pass/RectPassElement.hpp | 5 +- src/render/pass/SurfacePassElement.cpp | 17 +-- src/render/pass/SurfacePassElement.hpp | 5 +- src/render/pass/TexPassElement.cpp | 3 +- src/render/pass/TexPassElement.hpp | 7 +- src/render/shaders/Border.hpp | 7 +- src/render/shaders/Shadow.hpp | 13 +- src/render/shaders/Textures.hpp | 23 ++-- 26 files changed, 228 insertions(+), 173 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index fe1a831a..c2b1a071 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -81,6 +81,7 @@ general { # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { rounding = 10 + rounding_power = 2 # Change transparency of focused and unfocused windows active_opacity = 1.0 diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 17657983..46f91a21 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -139,6 +139,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{0, 0, 20}, }, + SConfigOptionDescription{ + .value = "decoration:rounding_power", + .description = "rouding power of corners (2 is a circle)", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{2, 2, 10}, + }, SConfigOptionDescription{ .value = "decoration:active_opacity", .description = "opacity of active windows. [0.0 - 1.0]", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bdce573f..732d12e5 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -427,6 +427,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("debug:colored_stdout_logs", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:rounding", Hyprlang::INT{0}); + m_pConfig->addConfigValue("decoration:rounding_power", {2.F}); m_pConfig->addConfigValue("decoration:blur:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("decoration:blur:size", Hyprlang::INT{8}); m_pConfig->addConfigValue("decoration:blur:passes", Hyprlang::INT{1}); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 0cd0a0a4..436362ae 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -259,6 +259,7 @@ class CConfigManager { }; std::unordered_map*(PHLWINDOW)>> mfWindowProperties = { + {"roundingpower", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.roundingPower; }}, {"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }}, {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}}; diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index c4eb3385..851e11f2 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -94,6 +94,7 @@ general { # https://wiki.hyprland.org/Configuring/Variables/#decoration decoration { rounding = 10 + rounding_power = 2 # Change transparency of focused and unfocused windows active_opacity = 1.0 diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 4104c737..60914198 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -824,7 +824,8 @@ void CWindow::updateDynamicRules() { // it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize) // otherwise behaviour is undefined bool CWindow::isInCurvedCorner(double x, double y) { - const int ROUNDING = rounding(); + const int ROUNDING = rounding(); + const int ROUNDINGPOWER = roundingPower(); if (getRealBorderSize() >= ROUNDING) return false; @@ -835,16 +836,16 @@ bool CWindow::isInCurvedCorner(double x, double y) { double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING; if (x < x0 && y < y0) { - return Vector2D{x0, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x > x1 && y < y0) { - return Vector2D{x1, y0}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x < x0 && y > y1) { - return Vector2D{x0, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } if (x > x1 && y > y1) { - return Vector2D{x1, y1}.distance(Vector2D{x, y}) > (double)ROUNDING; + return std::pow(x - x1, ROUNDINGPOWER) + std::pow(y - y1, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); } return false; @@ -1164,13 +1165,21 @@ bool CWindow::opaque() { } float CWindow::rounding() { - static auto PROUNDING = CConfigValue("decoration:rounding"); + static auto PROUNDING = CConfigValue("decoration:rounding"); + static auto PROUNDINGPOWER = CConfigValue("decoration:rounding_power"); - float rounding = m_sWindowData.rounding.valueOr(*PROUNDING); + float roundingPower = m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER); + float rounding = m_sWindowData.rounding.valueOr(*PROUNDING) * (roundingPower / 2.0); /* Make perceived roundness consistent. */ return m_sWindowData.noRounding.valueOrDefault() ? 0 : rounding; } +float CWindow::roundingPower() { + static auto PROUNDINGPOWER = CConfigValue("decoration:rounding_power"); + + return m_sWindowData.roundingPower.valueOr(*PROUNDINGPOWER); +} + void CWindow::updateWindowData() { const auto PWORKSPACE = m_pWorkspace; const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE) : SWorkspaceRule{}; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 6ed9a525..3ceaf594 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -183,6 +183,7 @@ struct SWindowData { CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar rounding; + CWindowOverridableVar roundingPower; CWindowOverridableVar borderSize; CWindowOverridableVar scrollMouse; @@ -414,6 +415,7 @@ class CWindow { Vector2D middle(); bool opaque(); float rounding(); + float roundingPower(); bool canBeTorn(); void setSuspended(bool suspend); bool visibleOnMonitor(PHLMONITOR pMonitor); diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp index 7db6c3db..306a25ce 100644 --- a/src/desktop/WindowRule.cpp +++ b/src/desktop/WindowRule.cpp @@ -8,8 +8,8 @@ static const auto RULES = std::unordered_set{ "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto RULES_PREFIX = std::unordered_set{ - "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", - "plugin:", "prop", "pseudo", "rounding", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", + "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", + "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", }; CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) { @@ -88,4 +88,4 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool ruleType = RULE_INVALID; } } -} \ No newline at end of file +} diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 1b51acbf..94b70acf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -971,14 +971,15 @@ void CHyprOpenGLImpl::setDamage(const CRegion& damage_, std::optional f } void CHyprOpenGLImpl::initShaders() { - GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); - m_RenderData.pCurrentMonData->m_shQUAD.program = prog; - m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); - m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); + GLuint prog = createProgram(QUADVERTSRC, QUADFRAGSRC); + m_RenderData.pCurrentMonData->m_shQUAD.program = prog; + m_RenderData.pCurrentMonData->m_shQUAD.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shQUAD.color = glGetUniformLocation(prog, "color"); + m_RenderData.pCurrentMonData->m_shQUAD.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shQUAD.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shQUAD.fullSize = glGetUniformLocation(prog, "fullSize"); + m_RenderData.pCurrentMonData->m_shQUAD.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shQUAD.roundingPower = glGetUniformLocation(prog, "roundingPower"); prog = createProgram(TEXVERTSRC, TEXFRAGSRCRGBA); m_RenderData.pCurrentMonData->m_shRGBA.program = prog; @@ -995,6 +996,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBA.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBA.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBA.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBA.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shRGBA.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBA.tint = glGetUniformLocation(prog, "tint"); m_RenderData.pCurrentMonData->m_shRGBA.useAlphaMatte = glGetUniformLocation(prog, "useAlphaMatte"); @@ -1037,6 +1039,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shRGBX.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shRGBX.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shRGBX.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shRGBX.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shRGBX.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shRGBX.tint = glGetUniformLocation(prog, "tint"); @@ -1053,6 +1056,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shEXT.topLeft = glGetUniformLocation(prog, "topLeft"); m_RenderData.pCurrentMonData->m_shEXT.fullSize = glGetUniformLocation(prog, "fullSize"); m_RenderData.pCurrentMonData->m_shEXT.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shEXT.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shEXT.applyTint = glGetUniformLocation(prog, "applyTint"); m_RenderData.pCurrentMonData->m_shEXT.tint = glGetUniformLocation(prog, "tint"); @@ -1097,18 +1101,19 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBLURFINISH.brightness = glGetUniformLocation(prog, "brightness"); m_RenderData.pCurrentMonData->m_shBLURFINISH.noise = glGetUniformLocation(prog, "noise"); - prog = createProgram(QUADVERTSRC, FRAGSHADOW); - m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; - m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); - m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); - m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); - m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); - m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); - m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); - m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); - m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); - m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); - m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); + prog = createProgram(QUADVERTSRC, FRAGSHADOW); + m_RenderData.pCurrentMonData->m_shSHADOW.program = prog; + m_RenderData.pCurrentMonData->m_shSHADOW.proj = glGetUniformLocation(prog, "proj"); + m_RenderData.pCurrentMonData->m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); + m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + m_RenderData.pCurrentMonData->m_shSHADOW.topLeft = glGetUniformLocation(prog, "topLeft"); + m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight = glGetUniformLocation(prog, "bottomRight"); + m_RenderData.pCurrentMonData->m_shSHADOW.fullSize = glGetUniformLocation(prog, "fullSize"); + m_RenderData.pCurrentMonData->m_shSHADOW.radius = glGetUniformLocation(prog, "radius"); + m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower = glGetUniformLocation(prog, "roundingPower"); + m_RenderData.pCurrentMonData->m_shSHADOW.range = glGetUniformLocation(prog, "range"); + m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower = glGetUniformLocation(prog, "shadowPower"); + m_RenderData.pCurrentMonData->m_shSHADOW.color = glGetUniformLocation(prog, "color"); prog = createProgram(QUADVERTSRC, FRAGBORDER1); m_RenderData.pCurrentMonData->m_shBORDER1.program = prog; @@ -1122,6 +1127,7 @@ void CHyprOpenGLImpl::initShaders() { m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed = glGetUniformLocation(prog, "fullSizeUntransformed"); m_RenderData.pCurrentMonData->m_shBORDER1.radius = glGetUniformLocation(prog, "radius"); m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter = glGetUniformLocation(prog, "radiusOuter"); + m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower = glGetUniformLocation(prog, "roundingPower"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient = glGetUniformLocation(prog, "gradient"); m_RenderData.pCurrentMonData->m_shBORDER1.gradient2 = glGetUniformLocation(prog, "gradient2"); m_RenderData.pCurrentMonData->m_shBORDER1.gradientLength = glGetUniformLocation(prog, "gradientLength"); @@ -1244,12 +1250,12 @@ void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h scissor(&box, transform); } -void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round) { +void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round, float roundingPower) { if (!m_RenderData.damage.empty()) - renderRectWithDamage(box, col, m_RenderData.damage, round); + renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float blurA, bool xray) { +void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float roundingPower, float blurA, bool xray) { if (m_RenderData.damage.empty()) return; @@ -1271,7 +1277,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - renderRect(box, CHyprColor(0, 0, 0, 0), round); + renderRect(box, CHyprColor(0, 0, 0, 0), round, roundingPower); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -1282,7 +1288,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r m_bEndFrame = true; // fix transformed const auto SAVEDRENDERMODIF = m_RenderData.renderModif; m_RenderData.renderModif = {}; // fix shit - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, damage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, damage, 0, 2.0f, false, false, false); m_bEndFrame = false; m_RenderData.renderModif = SAVEDRENDERMODIF; @@ -1293,10 +1299,10 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); - renderRectWithDamage(box, col, m_RenderData.damage, round); + renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, const CRegion& damage, int round) { +void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, const CRegion& damage, int round, float roundingPower) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -1334,6 +1340,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shQUAD.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.radius, round); + glUniform1f(m_RenderData.pCurrentMonData->m_shQUAD.roundingPower, roundingPower); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -1361,25 +1368,25 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.damage, round, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, const CRegion& damage, float alpha, int round, bool discardActive, bool allowCustomUV, - SP waitTimeline, uint64_t waitPoint) { +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, const CRegion& damage, float alpha, int round, float roundingPower, bool discardActive, + bool allowCustomUV, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); + renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, const CRegion& damage, int round, bool discardActive, bool noAA, - bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, + bool noAA, bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1506,6 +1513,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y); glUniform1f(shader->radius, round); + glUniform1f(shader->roundingPower, roundingPower); if (allowDim && m_RenderData.currentWindow) { glUniform1i(shader->applyTint, 1); @@ -1997,7 +2005,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { clear(CHyprColor(0, 0, 0, 0)); m_bEndFrame = true; // fix transformed - renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, fakeDamage, 0, false, true, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, fakeDamage, 0, 2.0f, false, true, false); m_bEndFrame = false; m_RenderData.currentFB->bind(); @@ -2045,8 +2053,8 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, bool blockBlurOptimization, float blurA, - float overallA) { +void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, float roundingPower, bool blockBlurOptimization, + float blurA, float overallA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto PNOBLUROVERSIZED = CConfigValue("decoration:no_blur_on_oversized"); @@ -2063,7 +2071,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.renderModif.applyToRegion(texDamage); if (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, round, roundingPower, false, true); return; } @@ -2076,7 +2084,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { - renderTexture(tex, pBox, a, round, false, true); + renderTexture(tex, pBox, a, round, roundingPower, false, true); return; } } else { @@ -2112,9 +2120,9 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHA)) - renderRect(pBox, CHyprColor(0, 0, 0, 0), round); + renderRect(pBox, CHyprColor(0, 0, 0, 0), round, roundingPower); else - renderTexture(tex, pBox, a, round, true, true); // discard opaque + renderTexture(tex, pBox, a, round, roundingPower, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -2127,7 +2135,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float setMonitorTransformEnabled(true); if (!USENEWOPTIMIZE) setRenderModifEnabled(false); - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, 0, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, 0, 2.0f, false, false, false); if (!USENEWOPTIMIZE) setRenderModifEnabled(true); setMonitorTransformEnabled(false); @@ -2138,14 +2146,14 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a * overallA, texDamage, round, false, false, true, true); + renderTextureInternalWithDamage(tex, pBox, a * overallA, texDamage, round, roundingPower, false, false, true, true); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); scissor((CBox*)nullptr); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, int borderSize, float a, int outerRound) { +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, float roundingPower, int borderSize, float a, int outerRound) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -2207,6 +2215,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -2238,7 +2247,8 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in blend(BLEND); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, int borderSize, float a, int outerRound) { +void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, float roundingPower, int borderSize, float a, + int outerRound) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); @@ -2304,6 +2314,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); + glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.thick, scaledBorderSize); glVertexAttribPointer(m_RenderData.pCurrentMonData->m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -2335,7 +2346,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c blend(BLEND); } -void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const CHyprColor& color, float a) { +void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPower, int range, const CHyprColor& color, float a) { RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); RASSERT(m_RenderData.currentWindow, "Tried to render shadow without a window!"); @@ -2381,6 +2392,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.bottomRight, (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.radius, range + round); + glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.roundingPower, roundingPower); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.range, range); glUniform1f(m_RenderData.pCurrentMonData->m_shSHADOW.shadowPower, SHADOWPOWER); @@ -2421,7 +2433,7 @@ void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { blend(false); - renderTexture(m_RenderData.currentFB->getTexture(), box, 1.f, 0, false, false); + renderTexture(m_RenderData.currentFB->getTexture(), box, 1.f, 0, 2.0f, false, false); blend(true); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 713816bc..3f117a5a 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -166,83 +166,84 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); ~CHyprOpenGLImpl(); - void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); + void end(); - void renderRect(CBox*, const CHyprColor&, int round = 0); - void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CHyprColor&, const CRegion& damage, int round = 0); - void renderTexture(SP, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, const CRegion& damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false, - SP waitTimeline = nullptr, uint64_t waitPoint = 0); - void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f, - float overallA = 1.f); - void renderRoundedShadow(CBox*, int round, int range, const CHyprColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); + void renderRect(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f); + void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(CBox*, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); + void renderTexture(SP, CBox*, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, CBox*, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, + bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); + void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, + float blurA = 1.f, float overallA = 1.f); + void renderRoundedShadow(CBox*, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); + void renderBorder(CBox*, const CGradientValueData&, int round, float roundingPower, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, float roundingPower, int borderSize, float a = 1.0, + int outerRound = -1 /* use round */); + void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CHyprColor&); - void clearWithTex(); - void scissor(const CBox*, bool transform = true); - void scissor(const pixman_box32*, bool transform = true); - void scissor(const int x, const int y, const int w, const int h, bool transform = true); + void clear(const CHyprColor&); + void clearWithTex(); + void scissor(const CBox*, bool transform = true); + void scissor(const pixman_box32*, bool transform = true); + void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(PHLMONITOR); + void destroyMonitorResources(PHLMONITOR); - void markBlurDirtyForMonitor(PHLMONITOR); + void markBlurDirtyForMonitor(PHLMONITOR); - void preWindowPass(); - bool preBlurQueued(); - void preRender(PHLMONITOR); + void preWindowPass(); + bool preBlurQueued(); + void preRender(PHLMONITOR); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(CBox*); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - SP loadAsset(const std::string& file); - SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); - void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void setDamage(const CRegion& damage, std::optional finalDamage = {}); - uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; - uint failedAssetsNo = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; + uint failedAssetsNo = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; std::map m_mMonitorRenderResources; std::map m_mMonitorBGFBs; @@ -311,8 +312,8 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(SP, CBox* pBox, float a, const CRegion& damage, int round = 0, bool discardOpaque = false, bool noAA = false, - bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); + void renderTextureInternalWithDamage(SP, CBox* pBox, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, + bool noAA = false, bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); void renderTexturePrimitive(SP tex, CBox* pBox); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 35150ce2..d154e64a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -460,11 +460,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha.value(); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; - renderdata.pWindow = pWindow; + renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); + renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; + renderdata.roundingPower = ignoreAllGeometry || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); + renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; + renderdata.pWindow = pWindow; if (ignoreAllGeometry) { renderdata.alpha = 1.f; diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index eaf9da96..666ee9d4 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -26,6 +26,7 @@ class CShader { GLint fullSizeUntransformed = -1; GLint radius = -1; GLint radiusOuter = -1; + GLfloat roundingPower = -1; GLint thick = -1; diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 4a793eab..2bc894ef 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -67,15 +67,17 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); } - int borderSize = m_pWindow->getRealBorderSize(); - const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; + int borderSize = m_pWindow->getRealBorderSize(); + const auto ROUNDING = m_pWindow->rounding() * pMonitor->scale; + const auto ROUNDINGPOWER = m_pWindow->roundingPower(); CBorderPassElement::SBorderData data; - data.box = windowBox; - data.grad1 = grad; - data.round = ROUNDING; - data.a = a; - data.borderSize = borderSize; + data.box = windowBox; + data.grad1 = grad; + data.round = ROUNDING; + data.roundingPower = ROUNDINGPOWER; + data.a = a; + data.borderSize = borderSize; if (ANIMATED) { data.hasGrad2 = true; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 21242b57..07dbb436 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -55,6 +55,7 @@ void CHyprDropShadowDecoration::damageEntire() { static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); const auto ROUNDING = PWINDOW->rounding(); + const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; CRegion shadowRegion(shadowBox); @@ -119,6 +120,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { return; // disabled const auto ROUNDINGBASE = PWINDOW->rounding(); + const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + PWINDOW->getRealBorderSize() : 0; const auto PWORKSPACE = PWINDOW->m_pWorkspace; const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); @@ -192,10 +194,10 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale); + g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); alphaSwapFB.bind(); @@ -214,7 +216,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); @@ -226,7 +228,7 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { return DECORATION_LAYER_BOTTOM; } -void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a) { +void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a) { static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); g_pHyprOpenGL->blend(true); @@ -234,7 +236,7 @@ void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, int ran color.a *= a; if (*PSHADOWSHARP) - g_pHyprOpenGL->renderRect(box, color, round); + g_pHyprOpenGL->renderRect(box, color, round, roundingPower); else - g_pHyprOpenGL->renderRoundedShadow(box, round, range, color, 1.F); + g_pHyprOpenGL->renderRoundedShadow(box, round, roundingPower, range, color, 1.F); } diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index fe0f8952..93fa3d1a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -36,7 +36,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; - void drawShadowInternal(CBox* box, int round, int range, CHyprColor color, float a); + void drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a); CBox m_bLastWindowBox = {0}; CBox m_bLastWindowBoxWithDecos = {0}; diff --git a/src/render/pass/BorderPassElement.cpp b/src/render/pass/BorderPassElement.cpp index 635533d0..ceeec6f3 100644 --- a/src/render/pass/BorderPassElement.cpp +++ b/src/render/pass/BorderPassElement.cpp @@ -7,9 +7,9 @@ CBorderPassElement::CBorderPassElement(const CBorderPassElement::SBorderData& da void CBorderPassElement::draw(const CRegion& damage) { if (data.hasGrad2) - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.grad2, data.lerp, data.round, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.grad2, data.lerp, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); else - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.round, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); } bool CBorderPassElement::needsLiveBlur() { @@ -18,4 +18,4 @@ bool CBorderPassElement::needsLiveBlur() { bool CBorderPassElement::needsPrecomputeBlur() { return false; -} \ No newline at end of file +} diff --git a/src/render/pass/BorderPassElement.hpp b/src/render/pass/BorderPassElement.hpp index 3a529640..785653ab 100644 --- a/src/render/pass/BorderPassElement.hpp +++ b/src/render/pass/BorderPassElement.hpp @@ -12,6 +12,7 @@ class CBorderPassElement : public IPassElement { bool hasGrad2 = false; float lerp = 0.F, a = 1.F; int round = 0, borderSize = 1, outerRound = -1; + float roundingPower = 2.F; }; CBorderPassElement(const SBorderData& data_); diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index 25a550b3..a57c959e 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -10,9 +10,9 @@ void CRectPassElement::draw(const CRegion& damage) { return; if (data.color.a == 1.F || !data.blur) - g_pHyprOpenGL->renderRectWithDamage(&data.box, data.color, damage, data.round); + g_pHyprOpenGL->renderRectWithDamage(&data.box, data.color, damage, data.round, data.roundingPower); else - g_pHyprOpenGL->renderRectWithBlur(&data.box, data.color, data.round, data.blurA, data.xray); + g_pHyprOpenGL->renderRectWithBlur(&data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); } bool CRectPassElement::needsLiveBlur() { diff --git a/src/render/pass/RectPassElement.hpp b/src/render/pass/RectPassElement.hpp index 32111a43..d27abdcc 100644 --- a/src/render/pass/RectPassElement.hpp +++ b/src/render/pass/RectPassElement.hpp @@ -6,7 +6,8 @@ class CRectPassElement : public IPassElement { struct SRectData { CBox box; CHyprColor color; - int round = 0; + int round = 0; + float roundingPower = 2.0f; bool blur = false, xray = false; float blurA = 1.F; }; @@ -26,4 +27,4 @@ class CRectPassElement : public IPassElement { private: SRectData data; -}; \ No newline at end of file +}; diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index bdb21338..13e9e741 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -88,12 +88,15 @@ void CSurfacePassElement::draw(const CRegion& damage) { if (MISALIGNEDFSV1) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; - float rounding = data.rounding; + float rounding = data.rounding; + float roundingPower = data.roundingPower; rounding -= 1; // to fix a border issue - if (data.dontRound) - rounding = 0; + if (data.dontRound) { + rounding = 0; + roundingPower = 2.0f; + } const bool WINDOWOPAQUE = data.pWindow && data.pWindow->m_pWLSurface->resource() == data.surface ? data.pWindow->opaque() : false; const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding == 0 && WINDOWOPAQUE; @@ -108,14 +111,14 @@ void CSurfacePassElement::draw(const CRegion& damage) { // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) if (data.surfaceCounter == 0 && !data.popup) { if (BLUR) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } else { if (BLUR && data.popup) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, true, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, true, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index 746c5a64..14d8ef14 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -35,6 +35,9 @@ class CSurfacePassElement : public IPassElement { // for custom round values int rounding = -1; // -1 means not set + // for custom rounding powers + float roundingPower = 2.0f; + // for blurring bool blur = false; bool blockBlurOptimization = false; @@ -79,4 +82,4 @@ class CSurfacePassElement : public IPassElement { SRenderData data; CBox getTexBox(); -}; \ No newline at end of file +}; diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index 05f756dc..0624a786 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -18,7 +18,8 @@ void CTexPassElement::draw(const CRegion& damage) { if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection; - g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, &data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.syncTimeline, data.syncPoint); + g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, &data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, + data.syncPoint); if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = g_pHyprOpenGL->m_RenderData.pMonitor->projMatrix; } diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index bf896951..036b89fe 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -13,8 +13,9 @@ class CTexPassElement : public IPassElement { CBox box; float a = 1.F; CRegion damage; - int round = 0; - bool flipEndFrame = false; + int round = 0; + float roundingPower = 2.0f; + bool flipEndFrame = false; SP syncTimeline; int64_t syncPoint = 0; std::optional replaceProjection; @@ -36,4 +37,4 @@ class CTexPassElement : public IPassElement { private: SRenderData data; -}; \ No newline at end of file +}; diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp index acd3f3ff..3b9a91f0 100644 --- a/src/render/shaders/Border.hpp +++ b/src/render/shaders/Border.hpp @@ -15,6 +15,7 @@ uniform vec2 fullSize; uniform vec2 fullSizeUntransformed; uniform float radius; uniform float radiusOuter; +uniform float roundingPower; uniform float thick; // Gradients are in OkLabA!!!! {l, a, b, alpha} @@ -138,9 +139,9 @@ void main() { const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - float dist = length(pixCoord); - float distOuter = length(pixCoordOuter); - float h = (thick / 2.0); + float dist = pow(pow(pixCoord.x,roundingPower)+pow(pixCoord.y,roundingPower),1.0/roundingPower); + float distOuter = pow(pow(pixCoordOuter.x,roundingPower)+pow(pixCoordOuter.y,roundingPower),1.0/roundingPower); + float h = (thick / 2.0); if (dist < radius - h) { // lower diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp index 0acab6b7..c04d4bf3 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/Shadow.hpp @@ -11,6 +11,7 @@ uniform vec2 topLeft; uniform vec2 bottomRight; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform float range; uniform float shadowPower; @@ -26,6 +27,10 @@ float pixAlphaRoundedDistance(float distanceToCorner) { return 1.0; } +float modifiedLength(vec2 a) { + return pow(pow(abs(a.x),roundingPower)+pow(abs(a.y),roundingPower),1.0/roundingPower); +} + void main() { vec4 pixColor = v_color; @@ -40,21 +45,21 @@ void main() { if (pixCoord[0] < topLeft[0]) { if (pixCoord[1] < topLeft[1]) { // top left - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, topLeft)); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - topLeft)); done = true; } else if (pixCoord[1] > bottomRight[1]) { // bottom left - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(topLeft[0], bottomRight[1]))); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(topLeft[0], bottomRight[1]))); done = true; } } else if (pixCoord[0] > bottomRight[0]) { if (pixCoord[1] < topLeft[1]) { // top right - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, vec2(bottomRight[0], topLeft[1]))); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - vec2(bottomRight[0], topLeft[1]))); done = true; } else if (pixCoord[1] > bottomRight[1]) { // bottom right - pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(distance(pixCoord, bottomRight)); + pixColor[3] = pixColor[3] * pixAlphaRoundedDistance(modifiedLength(pixCoord - bottomRight)); done = true; } } diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index b203ad04..49d27b4c 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -19,23 +19,18 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - if (pixCoord.x + pixCoord.y > radius) { + //if (pixCoord.x + pixCoord.y > radius) { - float dist = length(pixCoord); + float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); - if (dist > radius + SMOOTHING_CONSTANT * 2.0) - discard; + if (dist > radius + SMOOTHING_CONSTANT) + discard; - if (dist > radius - SMOOTHING_CONSTANT * 2.0) { - float dist = length(pixCoord); + float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - float normalized = 1.0 - smoothstep(0.0, 1.0, (dist - radius + SMOOTHING_CONSTANT) / (SMOOTHING_CONSTANT * 2.0)); - - )#" + + )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; - } - - } + //} )#"; }; @@ -63,6 +58,7 @@ varying vec4 v_color; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; void main() { @@ -107,6 +103,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; @@ -167,6 +164,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; @@ -440,6 +438,7 @@ uniform float alpha; uniform vec2 topLeft; uniform vec2 fullSize; uniform float radius; +uniform float roundingPower; uniform int discardOpaque; uniform int discardAlpha; From 391ff29110e3fb9711b98e92cee44182dda2e2ba Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 19:49:27 +0100 Subject: [PATCH 1024/2393] pass: improve pass debug mode --- src/render/pass/Pass.cpp | 42 +++++++++++++++++++++++++++++++++++----- src/render/pass/Pass.hpp | 6 +++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 3e1282f0..0489e985 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -88,7 +88,7 @@ void CRenderPass::simplify() { } newDamage.subtract(opaque); if (*PDEBUGPASS) - occludedRegion.add(opaque); + occludedRegions.emplace_back(opaque); } } @@ -114,9 +114,11 @@ CRegion CRenderPass::render(const CRegion& damage_) { const auto WILLBLUR = std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->needsLiveBlur(); }); - damage = *PDEBUGPASS ? CRegion{CBox{{}, {INT32_MAX, INT32_MAX}}} : damage_.copy(); - occludedRegion = CRegion{}; - totalLiveBlurRegion = CRegion{}; + damage = *PDEBUGPASS ? CRegion{CBox{{}, {INT32_MAX, INT32_MAX}}} : damage_.copy(); + if (*PDEBUGPASS) { + occludedRegions.clear(); + totalLiveBlurRegion = CRegion{}; + } if (damage.empty()) { g_pHyprOpenGL->m_RenderData.damage = damage; @@ -198,7 +200,9 @@ CRegion CRenderPass::render(const CRegion& damage_) { void CRenderPass::renderDebugData() { CBox box = {{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize}; - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::RED.modifyA(0.1F), occludedRegion); + for (const auto& rg : occludedRegions) { + g_pHyprOpenGL->renderRectWithDamage(&box, Colors::RED.modifyA(0.1F), rg); + } g_pHyprOpenGL->renderRectWithDamage(&box, Colors::GREEN.modifyA(0.1F), totalLiveBlurRegion); std::unordered_map offsets; @@ -239,6 +243,34 @@ void CRenderPass::renderDebugData() { renderHLSurface(debugData.pointerFocusText, g_pSeatManager->state.pointerFocus.lock(), Colors::ORANGE.modifyA(0.1F)); if (g_pCompositor->m_pLastWindow) renderHLSurface(debugData.lastWindowText, g_pCompositor->m_pLastWindow->m_pWLSurface->resource(), Colors::LIGHT_BLUE.modifyA(0.1F)); + + const auto DISCARDED_ELEMENTS = std::count_if(m_vPassElements.begin(), m_vPassElements.end(), [](const auto& e) { return e->discard; }); + auto tex = g_pHyprOpenGL->renderText(std::format("occlusion layers: {}\npass elements: {} ({} discarded)\nviewport: {:X0}", occludedRegions.size(), m_vPassElements.size(), + DISCARDED_ELEMENTS, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize), + Colors::WHITE, 12); + + if (tex) { + box = CBox{{0.F, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale); + g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + } + + std::string passStructure; + auto yn = [](const bool val) -> const char* { return val ? "yes" : "no"; }; + auto tick = [](const bool val) -> const char* { return val ? "✔" : "✖"; }; + for (const auto& el : m_vPassElements | std::views::reverse) { + passStructure += std::format("{} {} (bb: {} op: {})\n", tick(!el->discard), el->element->passName(), yn(el->element->boundingBox().has_value()), + yn(!el->element->opaqueRegion().empty())); + } + + if (!passStructure.empty()) + passStructure.pop_back(); + + tex = g_pHyprOpenGL->renderText(passStructure, Colors::WHITE, 12); + if (tex) { + box = CBox{{g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.x - tex->m_vSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale( + g_pHyprOpenGL->m_RenderData.pMonitor->scale); + g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + } } float CRenderPass::oneBlurRadius() { diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp index 5fa25fc3..a0810155 100644 --- a/src/render/pass/Pass.hpp +++ b/src/render/pass/Pass.hpp @@ -19,9 +19,9 @@ class CRenderPass { CRegion render(const CRegion& damage_); private: - CRegion damage; - CRegion occludedRegion; - CRegion totalLiveBlurRegion; + CRegion damage; + std::vector occludedRegions; + CRegion totalLiveBlurRegion; struct SPassElementData { CRegion elementDamage; From 1b06d222cf5abfc9802f7787315a8190f011d43e Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 20:35:24 +0100 Subject: [PATCH 1025/2393] pass/surface: fixup invalid expansion by old -1 rounding param fixes #8889 --- src/render/pass/SurfacePassElement.hpp | 36 +++++++------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index 14d8ef14..12387367 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -9,38 +9,22 @@ class CSyncTimeline; class CSurfacePassElement : public IPassElement { public: struct SRenderData { - PHLMONITORREF pMonitor; - timespec* when = nullptr; - Vector2D pos, localPos; + PHLMONITORREF pMonitor; + timespec* when = nullptr; + Vector2D pos, localPos; - // for iters void* data = nullptr; SP surface = nullptr; SP texture = nullptr; bool mainSurface = true; double w = 0, h = 0; - - // for rounding - bool dontRound = true; - - // for fade - float fadeAlpha = 1.f; - - // for alpha settings - float alpha = 1.f; - - // for decorations (border) - bool decorate = false; - - // for custom round values - int rounding = -1; // -1 means not set - - // for custom rounding powers - float roundingPower = 2.0f; - - // for blurring - bool blur = false; - bool blockBlurOptimization = false; + int rounding = 0; + bool dontRound = true; + float roundingPower = 2.0F; + bool decorate = false; + float alpha = 1.F, fadeAlpha = 1.F; + bool blur = false; + bool blockBlurOptimization = false; // only for windows, not popups bool squishOversized = true; From f390f48a07d117e24acec59dcf6791bcb3a81110 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 5 Jan 2025 23:19:13 +0100 Subject: [PATCH 1026/2393] pass: fixup debug mode rendering of input boxes --- src/render/pass/Pass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 0489e985..b72248c2 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -226,12 +226,13 @@ void CRenderPass::renderDebugData() { if (box.intersection(CBox{{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize}).empty()) return; + g_pHyprOpenGL->renderRectWithDamage(&box, color, CRegion{0, 0, INT32_MAX, INT32_MAX}); + if (offsets.contains(surface.get())) box.translate(Vector2D{0.F, offsets[surface.get()]}); else offsets[surface.get()] = 0; - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::PURPLE.modifyA(0.1F), CRegion{0, 0, INT32_MAX, INT32_MAX}); box = {box.pos(), texture->m_vSize}; g_pHyprOpenGL->renderRectWithDamage(&box, CHyprColor{0.F, 0.F, 0.F, 0.2F}, CRegion{0, 0, INT32_MAX, INT32_MAX}, std::min(5.0, box.size().y)); g_pHyprOpenGL->renderTexture(texture, &box, 1.F); From f1a7a7497e9b058092e915acd5164dcc162a8260 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 6 Jan 2025 15:27:57 +0100 Subject: [PATCH 1027/2393] datadevice: guard XWayland server against crashes The server might be dead or restarting, and we'd deref null ref #7822 --- src/protocols/core/DataDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 6ad17d7b..722eb9fd 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -417,7 +417,7 @@ void CWLDataDeviceProtocol::destroyResource(CWLDataOfferResource* resource) { SP CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) { #ifndef NO_XWAYLAND - if (c == g_pXWayland->pServer->xwaylandClient) + if (g_pXWayland->pServer && c == g_pXWayland->pServer->xwaylandClient) return g_pXWayland->pWM->getDataDevice(); #endif From 780e3dd542c9706dd37b715f95eb1134b14e6624 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 6 Jan 2025 14:29:29 +0000 Subject: [PATCH 1028/2393] [gha] Nix: update inputs --- flake.lock | 73 +++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/flake.lock b/flake.lock index 76d371bc..f16ecaa7 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1734906446, - "narHash": "sha256-6OWluVE2A8xi+8V3jN9KA72RCgJjYdyyuLBUjxZ2q2U=", + "lastModified": 1736102453, + "narHash": "sha256-5qb4kb7Xbt8jJFL/oDqOor9Z2+E+A+ql3PiyDvsfWZ0=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "eecb74dc79bb6752a2a507e6edee3042390a6091", + "rev": "4846091641f3be0ad7542086d52769bb7932bde6", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1734906236, - "narHash": "sha256-vH/ysV2ONGQgYZPtcJKwc8jJivzyVxru2aaOxC20ZOE=", + "lastModified": 1736115290, + "narHash": "sha256-Jcn6yAzfUMcxy3tN/iZRbi/QgrYm7XLyVRl9g/nbUl4=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "6dea3fba08fd704dd624b6d4b261638fb4003c9c", + "rev": "52202272d89da32a9f866c0d10305a5e3d954c50", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1735734474, - "narHash": "sha256-9OV4lOqrEJVLdOrpNN/9msNwAhI6FQTu4N7fufilG08=", + "lastModified": 1735774328, + "narHash": "sha256-vIRwLS9w+N99EU1aJ+XNOU6mJTxrUBa31i1r82l0V7s=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "271df559dd30e4bc5ec6af02d017ac0aaabd63a7", + "rev": "e3b6af97ddcfaafbda8e2828c719a5af84f662cb", "type": "github" }, "original": { @@ -154,11 +154,11 @@ ] }, "locked": { - "lastModified": 1734906472, - "narHash": "sha256-pWPRv/GA/X/iAwoE6gMNUqn/ZeJX1IeLPRpZI0tTPK0=", + "lastModified": 1736114838, + "narHash": "sha256-FxbuGQExtN37ToWYnGmO6weOYN6WPHN/RAqbr7gNPek=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "c77109d7e1ddbcdb87cafd32ce411f76328ae152", + "rev": "6997fe382dcf396704227d2b98ffdd5066da6959", "type": "github" }, "original": { @@ -180,11 +180,11 @@ ] }, "locked": { - "lastModified": 1734906259, - "narHash": "sha256-P79t/7HbACO4/PuJBroGpTptvCWJtXTv+gWsF+sM6MI=", + "lastModified": 1735393019, + "narHash": "sha256-NPpqA8rtmDLsEmZOmz+qR67zsB6Y503Jnv+nSFLKJZ8=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "0404833ea18d543df44df935ebf1b497310eb046", + "rev": "55608efdaa387af7bfdc0eddb404c409958efa43", "type": "github" }, "original": { @@ -203,11 +203,11 @@ ] }, "locked": { - "lastModified": 1735316583, - "narHash": "sha256-AiiUwHWHfEdpFzXy7l1x3zInCUa1xcRMrbZ1XRSkzwU=", + "lastModified": 1736164519, + "narHash": "sha256-1LimBKvDpBbeX+qW7T240WEyw+DBVpDotZB4JYm8Aps=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "8f15d45b120b33712f6db477fe5ffb18034d0ea8", + "rev": "3c895da64b0eb19870142196fa48c07090b441c4", "type": "github" }, "original": { @@ -226,11 +226,11 @@ ] }, "locked": { - "lastModified": 1734793513, - "narHash": "sha256-rrrHcXapXJvGFqX+L/Bb0182L25jofAZ0fm1FInvrTQ=", + "lastModified": 1735493474, + "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "4d7367b6eee87397e2dbca2e78078dd0a4ef4c61", + "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", "type": "github" }, "original": { @@ -241,11 +241,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1735291276, - "narHash": "sha256-NYVcA06+blsLG6wpAbSPTCyLvxD/92Hy4vlY9WxFI1M=", + "lastModified": 1736012469, + "narHash": "sha256-/qlNWm/IEVVH7GfgAIyP6EsVZI6zjAx1cV5zNyrs+rI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "634fd46801442d760e09493a794c4f15db2d0cbb", + "rev": "8f3e1f807051e32d8c95cd12b9b421623850a34d", "type": "github" }, "original": { @@ -255,37 +255,20 @@ "type": "github" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1730741070, - "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, "pre-commit-hooks": { "inputs": { "flake-compat": "flake-compat", "gitignore": "gitignore", "nixpkgs": [ "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" + ] }, "locked": { - "lastModified": 1734797603, - "narHash": "sha256-ulZN7ps8nBV31SE+dwkDvKIzvN6hroRY8sYOT0w+E28=", + "lastModified": 1735882644, + "narHash": "sha256-3FZAG+pGt3OElQjesCAWeMkQ7C/nB1oTHLRQ8ceP110=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "f0f0dc4920a903c3e08f5bdb9246bb572fcae498", + "rev": "a5a961387e75ae44cc20f0a57ae463da5e959656", "type": "github" }, "original": { From 602d6b73563e56fe003bbf3d25b45a53c51bad24 Mon Sep 17 00:00:00 2001 From: Mike Will Date: Mon, 6 Jan 2025 11:37:13 -0500 Subject: [PATCH 1029/2393] snap: don't snap to any windows if workspace has a fullscreen window (#8870) --- src/layout/IHyprLayout.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index e90ab0f0..f875b99c 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -421,11 +421,13 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA SRange sourceY = {sourcePos.y, sourcePos.y + sourceSize.y}; if (*SNAPWINDOWGAP) { - const double GAPSIZE = *SNAPWINDOWGAP; - const auto WSID = DRAGGINGWINDOW->workspaceID(); + const double GAPSIZE = *SNAPWINDOWGAP; + const auto WSID = DRAGGINGWINDOW->workspaceID(); + const bool HASFULLSCREEN = DRAGGINGWINDOW->m_pWorkspace && DRAGGINGWINDOW->m_pWorkspace->m_bHasFullscreenWindow; for (auto& other : g_pCompositor->m_vWindows) { - if (other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || other->isX11OverrideRedirect()) + if ((HASFULLSCREEN && !other->m_bCreatedOverFullscreen) || other == DRAGGINGWINDOW || other->workspaceID() != WSID || !other->m_bIsMapped || other->m_bFadingOut || + other->isX11OverrideRedirect()) continue; const int OTHERBORDERSIZE = other->getRealBorderSize(); From 6a90b505456cc708ec2779e0943eb9764e7630a5 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Mon, 6 Jan 2025 19:52:35 +0300 Subject: [PATCH 1030/2393] core/compositor: fix too early buffer release (#8966) --- src/protocols/core/Compositor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index ee1e6224..6213f987 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -428,6 +428,7 @@ void CWLSurfaceResource::commitPendingState() { pending.damage.clear(); pending.bufferDamage.clear(); pending.newBuffer = false; + dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore events.roleCommit.emit(); @@ -448,10 +449,9 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. - if (current.buffer->buffer->isSynchronous()) { - dropCurrentBuffer(); - dropPendingBuffer(); // pending atm is just a copied ref of the current, drop it too to send a release - } + // Some clients aren't ready to receive a release this early. Should be fine to release it on the next commitPendingState. + // if (current.buffer->buffer->isSynchronous()) + // dropCurrentBuffer(); } // TODO: we should _accumulate_ and not replace above if sync From 1bf4937b0292dc156e2530185c231608280be27f Mon Sep 17 00:00:00 2001 From: Byso Date: Mon, 6 Jan 2025 17:52:59 +0100 Subject: [PATCH 1031/2393] hyprctl: fix hyprctl --batch not working with exec rules (#8952) --- src/debug/HyprCtl.cpp | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index b946da6e..8724d2c7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1150,34 +1150,26 @@ static std::string cursorPosRequest(eHyprCtlOutputFormat format, std::string req } static std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { - // split by ; - - request = request.substr(9); - std::string curitem = ""; - std::string reply = ""; - - auto nextItem = [&]() { - auto idx = request.find_first_of(';'); - - if (idx != std::string::npos) { - curitem = request.substr(0, idx); - request = request.substr(idx + 1); - } else { - curitem = request; - request = ""; - } - - curitem = trim(curitem); - }; - - nextItem(); + // split by ; ignores ; inside [] and adds ; on last command + request = request.substr(9); + std::string reply = ""; const std::string DELIMITER = "\n\n\n"; + int bracket = 0; + size_t idx = 0; - while (curitem != "" || request != "") { - reply += g_pHyprCtl->getReply(curitem) + DELIMITER; - - nextItem(); + for (size_t i = 0; i <= request.size(); ++i) { + char ch = (i < request.size()) ? request[i] : ';'; + if (ch == '[') + ++bracket; + else if (ch == ']') + --bracket; + else if (ch == ';' && bracket == 0) { + if (idx < i) + reply += g_pHyprCtl->getReply(trim(request.substr(idx, i - idx))).append(DELIMITER); + idx = i + 1; + continue; + } } return reply.substr(0, std::max(static_cast(reply.size() - DELIMITER.size()), 0)); From b9f110ef8726fcba2b4ee69856027731e73003a5 Mon Sep 17 00:00:00 2001 From: Pollux Date: Mon, 6 Jan 2025 13:30:57 -0600 Subject: [PATCH 1032/2393] shaders: fix blank windows when using corner rounding (#8969) (#8971) --- src/render/shaders/Textures.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/shaders/Textures.hpp b/src/render/shaders/Textures.hpp index 49d27b4c..78845322 100644 --- a/src/render/shaders/Textures.hpp +++ b/src/render/shaders/Textures.hpp @@ -19,7 +19,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar const float SMOOTHING_CONSTANT = )#" + std::format("{:.7f}", SHADER_ROUNDED_SMOOTHING_FACTOR) + R"#(; - //if (pixCoord.x + pixCoord.y > radius) { + if (pixCoord.x + pixCoord.y > radius) { float dist = pow(pow(pixCoord.x, roundingPower) + pow(pixCoord.y, roundingPower), 1.0/roundingPower); @@ -30,7 +30,7 @@ inline static constexpr auto ROUNDED_SHADER_FUNC = [](const std::string colorVar )#" + colorVarName + R"#( = )#" + colorVarName + R"#( * normalized; - //} + } )#"; }; From c7086f936a06abebcc863c35f634760ca1ee90c0 Mon Sep 17 00:00:00 2001 From: Zetta1 Reid0 <79805086+Zetta1Reid0@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:50:34 +0200 Subject: [PATCH 1033/2393] master: add option to show slaves on left in center orientation (#8940) Co-authored-by: Zetta1_Reid0 <11255-Zetta1_Reid0@users.noreply.gitlab.xfce.org> --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/layout/MasterLayout.cpp | 20 +++++++++++++++----- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 46f91a21..8c35a3b1 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1632,6 +1632,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{2, 0, 10}, //##TODO RANGE? }, + SConfigOptionDescription{ + .value = "master:center_master_slaves_on_right", + .description = "set if the slaves should appear on right of master when slave_count_for_center_master > 2", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "master:center_ignores_reserved", .description = "centers the master window on monitor ignoring reserved areas", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 732d12e5..927cee9f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -479,6 +479,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:mfact", {0.55f}); m_pConfig->addConfigValue("master:new_status", {"slave"}); m_pConfig->addConfigValue("master:slave_count_for_center_master", Hyprlang::INT{2}); + m_pConfig->addConfigValue("master:center_master_slaves_on_right", Hyprlang::INT{1}); m_pConfig->addConfigValue("master:center_ignores_reserved", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index fb7df84f..225246f0 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -328,6 +328,7 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { eOrientation orientation = getDynamicOrientation(pWorkspace); bool centerMasterWindow = false; static auto SLAVECOUNTFORCENTER = CConfigValue("master:slave_count_for_center_master"); + static auto CMSLAVESONRIGHT = CConfigValue("master:center_master_slaves_on_right"); static auto PIGNORERESERVED = CConfigValue("master:center_ignores_reserved"); static auto PSMARTRESIZING = CConfigValue("master:smart_resizing"); @@ -341,7 +342,10 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { if (STACKWINDOWS >= *SLAVECOUNTFORCENTER) { centerMasterWindow = true; } else { - orientation = ORIENTATION_LEFT; + if (*CMSLAVESONRIGHT) + orientation = ORIENTATION_LEFT; + else + orientation = ORIENTATION_RIGHT; } } @@ -515,15 +519,20 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { float nextY = 0; float nextYL = 0; float nextYR = 0; - bool onRight = true; + bool onRight = *CMSLAVESONRIGHT; + int slavesLeftL = 1 + (slavesLeft - 1) / 2; + int slavesLeftR = slavesLeft - slavesLeftL; - int slavesLeftR = 1 + (slavesLeft - 1) / 2; - int slavesLeftL = slavesLeft - slavesLeftR; + if (*CMSLAVESONRIGHT) { + slavesLeftR = 1 + (slavesLeft - 1) / 2; + slavesLeftL = slavesLeft - slavesLeftR; + } const float slaveAverageHeightL = WSSIZE.y / slavesLeftL; const float slaveAverageHeightR = WSSIZE.y / slavesLeftR; float slaveAccumulatedHeightL = 0; float slaveAccumulatedHeightR = 0; + if (*PSMARTRESIZING) { for (auto const& nd : m_lMasterNodesData) { if (nd.workspaceID != pWorkspace->m_iID || nd.isMaster) @@ -536,7 +545,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { } onRight = !onRight; } - onRight = true; + + onRight = *CMSLAVESONRIGHT; } for (auto& nd : m_lMasterNodesData) { From 5642ed331df56375c55cd8d56a14054af8bdf8f2 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:55:14 +0000 Subject: [PATCH 1034/2393] core: move parts of the animation system to hyprutils (#8868) * core: change animation manager to use Hyprutils::Animation * config: move animation config to hyprutils animation tree * use g_pAnimationManager->createAnimation and the new PHLANIMVAR template * core: use CGenericAnimatedVariabled::{enabled,setConfig,getStyle} and adapt callbacks * core: adapt animated variable usage (dereference the shared pointer) * misc: bump CMakeLists to hyprutils 0.3.3 --- CMakeLists.txt | 2 +- src/Compositor.cpp | 78 +-- src/config/ConfigManager.cpp | 156 ++--- src/config/ConfigManager.hpp | 87 ++- src/debug/HyprCtl.cpp | 23 +- src/desktop/LayerSurface.cpp | 88 ++- src/desktop/LayerSurface.hpp | 18 +- src/desktop/Popup.cpp | 4 +- src/desktop/Subsurface.cpp | 2 +- src/desktop/WLSurface.cpp | 2 +- src/desktop/Window.cpp | 198 +++--- src/desktop/Window.hpp | 42 +- src/desktop/Workspace.cpp | 99 ++- src/desktop/Workspace.hpp | 6 +- src/events/Windows.cpp | 100 +-- src/helpers/AnimatedVariable.cpp | 87 --- src/helpers/AnimatedVariable.hpp | 275 +-------- src/helpers/BezierCurve.cpp | 90 --- src/helpers/BezierCurve.hpp | 28 - src/helpers/Monitor.cpp | 8 +- src/helpers/WLClasses.hpp | 1 - src/hyprerror/HyprError.cpp | 30 +- src/hyprerror/HyprError.hpp | 20 +- src/layout/DwindleLayout.cpp | 38 +- src/layout/IHyprLayout.cpp | 100 +-- src/layout/MasterLayout.cpp | 36 +- src/managers/AnimationManager.cpp | 584 +++++++----------- src/managers/AnimationManager.hpp | 75 ++- src/managers/KeybindManager.cpp | 64 +- src/managers/XWaylandManager.cpp | 6 +- src/managers/input/InputManager.cpp | 12 +- src/managers/input/Swipe.cpp | 120 ++-- src/managers/input/Tablets.cpp | 2 +- src/managers/input/Touch.cpp | 16 +- src/protocols/CTMControl.cpp | 14 +- src/protocols/CTMControl.hpp | 4 +- src/protocols/ToplevelExport.cpp | 8 +- src/render/OpenGL.cpp | 8 +- src/render/Renderer.cpp | 94 +-- .../decorations/CHyprBorderDecoration.cpp | 14 +- .../decorations/CHyprDropShadowDecoration.cpp | 28 +- .../decorations/CHyprGroupBarDecoration.cpp | 10 +- .../decorations/DecorationPositioner.cpp | 6 +- src/render/pass/SurfacePassElement.cpp | 12 +- 44 files changed, 1031 insertions(+), 1664 deletions(-) delete mode 100644 src/helpers/AnimatedVariable.cpp delete mode 100644 src/helpers/BezierCurve.cpp delete mode 100644 src/helpers/BezierCurve.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d5c58b7..aa746d2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.2.3) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.3.3) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c80f05e6..5805eff9 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -569,7 +569,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pKeybindManager = std::make_unique(); Debug::log(LOG, "Creating the AnimationManager!"); - g_pAnimationManager = std::make_unique(); + g_pAnimationManager = std::make_unique(); Debug::log(LOG, "Creating the ConfigManager!"); g_pConfigManager = std::make_unique(); @@ -964,11 +964,11 @@ SP CCompositor::vectorWindowToSurface(const Vector2D& pos, P if (PPOPUP) { const auto OFF = PPOPUP->coordsRelativeToParent(); - sl = pos - pWindow->m_vRealPosition.goal() - OFF; + sl = pos - pWindow->m_vRealPosition->goal() - OFF; return PPOPUP->m_pWLSurface->resource(); } - auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition.goal(), true); + auto [surf, local] = pWindow->m_pWLSurface->resource()->at(pos - pWindow->m_vRealPosition->goal(), true); if (surf) { sl = local; return surf; @@ -982,7 +982,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo return {}; if (pWindow->m_bIsX11) - return vec - pWindow->m_vRealPosition.goal(); + return vec - pWindow->m_vRealPosition->goal(); const auto PPOPUP = pWindow->m_pPopupHead->at(vec); if (PPOPUP) @@ -1001,9 +1001,9 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo CBox geom = pWindow->m_pXDGSurface->current.geometry; if (std::get<1>(iterData) == Vector2D{-1337, -1337}) - return vec - pWindow->m_vRealPosition.goal(); + return vec - pWindow->m_vRealPosition->goal(); - return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; + return vec - pWindow->m_vRealPosition->goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y}; } PHLMONITOR CCompositor::getMonitorFromOutput(SP out) { @@ -1211,7 +1211,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) continue; auto SURFACEAT = ls->popupHead->at(pos, true); @@ -1229,7 +1229,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& ls : *layerSurfaces | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) + if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) continue; auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); @@ -1378,7 +1378,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { if (w->monitorID() != monid && w->m_pMonitor) continue; - if (!w->m_bFadingOut || w->m_fAlpha.value() == 0.f) { + if (!w->m_bFadingOut || w->m_fAlpha->value() == 0.f) { w->m_bFadingOut = false; @@ -1831,8 +1831,8 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { pWindow->m_cRealBorderColorPrevious = pWindow->m_cRealBorderColor; pWindow->m_cRealBorderColor = grad; - pWindow->m_fBorderFadeAnimationProgress.setValueAndWarp(0.f); - pWindow->m_fBorderFadeAnimationProgress = 1.f; + pWindow->m_fBorderFadeAnimationProgress->setValueAndWarp(0.f); + *pWindow->m_fBorderFadeAnimationProgress = 1.f; }; const bool IS_SHADOWED_BY_MODAL = pWindow->m_pXDGSurface && pWindow->m_pXDGSurface->toplevel && pWindow->m_pXDGSurface->toplevel->anyChildModal(); @@ -1855,18 +1855,18 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // tick angle if it's not running (aka dead) - if (!pWindow->m_fBorderAngleAnimationProgress.isBeingAnimated()) - pWindow->m_fBorderAngleAnimationProgress.setValueAndWarp(0.f); + if (!pWindow->m_fBorderAngleAnimationProgress->isBeingAnimated()) + pWindow->m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); // opacity const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { if (pWindow == m_pLastWindow) - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alpha.valueOrDefault().applyAlpha(*PACTIVEALPHA); else - pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA); + *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaInactive.valueOrDefault().applyAlpha(*PINACTIVEALPHA); } // dim @@ -1879,16 +1879,16 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { if (IS_SHADOWED_BY_MODAL) goalDim += (1.F - goalDim) / 2.F; - pWindow->m_fDimPercent = goalDim; + *pWindow->m_fDimPercent = goalDim; // shadow if (!pWindow->isX11OverrideRedirect() && !pWindow->m_bX11DoesntWantBorders) { if (pWindow == m_pLastWindow) - pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL); + *pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOL); else - pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); + *pWindow->m_cRealShadowColor = CHyprColor(*PSHADOWCOLINACTIVE != INT64_MAX ? *PSHADOWCOLINACTIVE : *PSHADOWCOL); } else { - pWindow->m_cRealShadowColor.setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow + pWindow->m_cRealShadowColor->setValueAndWarp(CHyprColor(0, 0, 0, 0)); // no shadow } pWindow->updateWindowDecos(); @@ -1932,11 +1932,11 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor // additionally, move floating and fs windows manually if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - pMonitorA->vecPosition + pMonitorB->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitorB->vecPosition; - w->m_vRealSize = pMonitorB->vecSize; + *w->m_vRealPosition = pMonitorB->vecPosition; + *w->m_vRealSize = pMonitorB->vecSize; } w->updateToplevel(); @@ -1957,11 +1957,11 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor // additionally, move floating and fs windows manually if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - pMonitorB->vecPosition + pMonitorA->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitorA->vecPosition; - w->m_vRealSize = pMonitorA->vecSize; + *w->m_vRealPosition = pMonitorA->vecPosition; + *w->m_vRealSize = pMonitorA->vecSize; } w->updateToplevel(); @@ -2135,14 +2135,14 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo if (w->m_bIsMapped && !w->isHidden()) { if (POLDMON) { if (w->m_bIsFloating) - w->m_vRealPosition = w->m_vRealPosition.goal() - POLDMON->vecPosition + pMonitor->vecPosition; + *w->m_vRealPosition = w->m_vRealPosition->goal() - POLDMON->vecPosition + pMonitor->vecPosition; if (w->isFullscreen()) { - w->m_vRealPosition = pMonitor->vecPosition; - w->m_vRealSize = pMonitor->vecSize; + *w->m_vRealPosition = pMonitor->vecPosition; + *w->m_vRealSize = pMonitor->vecSize; } } else { - w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition.goal().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition.goal().y % (int)pMonitor->vecSize.y}; + *w->m_vRealPosition = Vector2D{(int)w->m_vRealPosition->goal().x % (int)pMonitor->vecSize.x, (int)w->m_vRealPosition->goal().y % (int)pMonitor->vecSize.y}; } } @@ -2216,9 +2216,9 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { continue; if (!FULLSCREEN) - w->m_fAlpha = 1.f; + *w->m_fAlpha = 1.f; else if (!w->isFullscreen()) - w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; + *w->m_fAlpha = !w->m_bCreatedOverFullscreen ? 0.f : 1.f; } } @@ -2227,7 +2227,7 @@ void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { if (pWorkspace->m_iID == PMONITOR->activeWorkspaceID() || pWorkspace->m_iID == PMONITOR->activeSpecialWorkspaceID()) { for (auto const& ls : PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { if (!ls->fadingOut) - ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + *ls->alpha = FULLSCREEN && pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } } @@ -2317,7 +2317,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS updateFullscreenFadeOnWorkspace(PWORKSPACE); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); PWORKSPACE->forceReportSizesToWindows(); @@ -2573,7 +2573,7 @@ PHLWORKSPACE CCompositor::createNewWorkspace(const WORKSPACEID& id, const MONITO const auto PWORKSPACE = m_vWorkspaces.emplace_back(CWorkspace::create(id, getMonitorFromID(monID), NAME, SPECIAL, isEmpty)); - PWORKSPACE->m_fAlpha.setValueAndWarp(0); + PWORKSPACE->m_fAlpha->setValueAndWarp(0); return PWORKSPACE; } @@ -2659,7 +2659,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor const PHLWINDOW pFirstWindowOnWorkspace = pWorkspace->getFirstWindow(); const int visibleWindowsOnWorkspace = pWorkspace->getWindows(std::nullopt, true); const auto PWINDOWMONITOR = pWindow->m_pMonitor.lock(); - const auto POSTOMON = pWindow->m_vRealPosition.goal() - PWINDOWMONITOR->vecPosition; + const auto POSTOMON = pWindow->m_vRealPosition->goal() - PWINDOWMONITOR->vecPosition; const auto PWORKSPACEMONITOR = pWorkspace->m_pMonitor.lock(); if (!pWindow->m_bIsFloating) @@ -2696,7 +2696,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pLayoutManager->getCurrentLayout()->onWindowCreatedTiling(pWindow); if (pWindow->m_bIsFloating) - pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; + *pWindow->m_vRealPosition = POSTOMON + PWORKSPACEMONITOR->vecPosition; } pWindow->updateToplevel(); @@ -2721,8 +2721,8 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pCompositor->updateSuspendedStates(); if (!WASVISIBLE && pWindow->m_pWorkspace && pWindow->m_pWorkspace->isVisible()) { - pWindow->m_fMovingFromWorkspaceAlpha.setValueAndWarp(0.F); - pWindow->m_fMovingFromWorkspaceAlpha = 1.F; + pWindow->m_fMovingFromWorkspaceAlpha->setValueAndWarp(0.F); + *pWindow->m_fMovingFromWorkspaceAlpha = 1.F; } } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 927cee9f..1ab29b1f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -11,6 +11,7 @@ #include "../protocols/LayerShell.hpp" #include "../xwayland/XWayland.hpp" #include "../protocols/OutputManagement.hpp" +#include "managers/AnimationManager.hpp" #include #include @@ -32,6 +33,7 @@ #include #include using namespace Hyprutils::String; +using namespace Hyprutils::Animation; //NOLINTNEXTLINE extern "C" char** environ; @@ -681,7 +683,6 @@ CConfigManager::CConfigManager() { m_pConfig->commence(); - setDefaultAnimationVars(); resetHLConfig(); Debug::log(INFO, @@ -780,76 +781,46 @@ void CConfigManager::reload() { } void CConfigManager::setDefaultAnimationVars() { - if (isFirstLaunch) { - INITANIMCFG("__internal_fadeCTM"); + m_AnimationTree.createNode("__internal_fadeCTM"); + m_AnimationTree.createNode("global"); - INITANIMCFG("global"); - INITANIMCFG("windows"); - INITANIMCFG("layers"); - INITANIMCFG("fade"); - INITANIMCFG("border"); - INITANIMCFG("borderangle"); + // global + m_AnimationTree.createNode("windows", "global"); + m_AnimationTree.createNode("layers", "global"); + m_AnimationTree.createNode("fade", "global"); + m_AnimationTree.createNode("border", "global"); + m_AnimationTree.createNode("borderangle", "global"); + m_AnimationTree.createNode("workspaces", "global"); - // windows - INITANIMCFG("windowsIn"); - INITANIMCFG("windowsOut"); - INITANIMCFG("windowsMove"); + // layer + m_AnimationTree.createNode("layersIn", "layers"); + m_AnimationTree.createNode("layersOut", "layers"); - // layers - INITANIMCFG("layersIn"); - INITANIMCFG("layersOut"); + // windows + m_AnimationTree.createNode("windowsIn", "windows"); + m_AnimationTree.createNode("windowsOut", "windows"); + m_AnimationTree.createNode("windowsMove", "windows"); - // fade - INITANIMCFG("fadeIn"); - INITANIMCFG("fadeOut"); - INITANIMCFG("fadeSwitch"); - INITANIMCFG("fadeShadow"); - INITANIMCFG("fadeDim"); + // fade + m_AnimationTree.createNode("fadeIn", "fade"); + m_AnimationTree.createNode("fadeOut", "fade"); + m_AnimationTree.createNode("fadeSwitch", "fade"); + m_AnimationTree.createNode("fadeShadow", "fade"); + m_AnimationTree.createNode("fadeDim", "fade"); + m_AnimationTree.createNode("fadeLayers", "fade"); + m_AnimationTree.createNode("fadeLayersIn", "fadeLayers"); + m_AnimationTree.createNode("fadeLayersOut", "fadeLayers"); - // border + // workspaces + m_AnimationTree.createNode("workspacesIn", "workspaces"); + m_AnimationTree.createNode("workspacesOut", "workspaces"); + m_AnimationTree.createNode("specialWorkspace", "workspaces"); + m_AnimationTree.createNode("specialWorkspaceIn", "specialWorkspace"); + m_AnimationTree.createNode("specialWorkspaceOut", "specialWorkspace"); - // workspaces - INITANIMCFG("workspaces"); - INITANIMCFG("workspacesIn"); - INITANIMCFG("workspacesOut"); - INITANIMCFG("specialWorkspace"); - INITANIMCFG("specialWorkspaceIn"); - INITANIMCFG("specialWorkspaceOut"); - } - - // init the values - animationConfig["global"] = {false, "default", "", 8.f, 1, &animationConfig["general"], nullptr}; - - animationConfig["__internal_fadeCTM"] = {false, "linear", "", 5.F, 1, &animationConfig["__internal_fadeCTM"], nullptr}; - - CREATEANIMCFG("windows", "global"); - CREATEANIMCFG("layers", "global"); - CREATEANIMCFG("fade", "global"); - CREATEANIMCFG("border", "global"); - CREATEANIMCFG("borderangle", "global"); - CREATEANIMCFG("workspaces", "global"); - - CREATEANIMCFG("layersIn", "layers"); - CREATEANIMCFG("layersOut", "layers"); - - CREATEANIMCFG("windowsIn", "windows"); - CREATEANIMCFG("windowsOut", "windows"); - CREATEANIMCFG("windowsMove", "windows"); - - CREATEANIMCFG("fadeIn", "fade"); - CREATEANIMCFG("fadeOut", "fade"); - CREATEANIMCFG("fadeSwitch", "fade"); - CREATEANIMCFG("fadeShadow", "fade"); - CREATEANIMCFG("fadeDim", "fade"); - CREATEANIMCFG("fadeLayers", "fade"); - CREATEANIMCFG("fadeLayersIn", "fadeLayers"); - CREATEANIMCFG("fadeLayersOut", "fadeLayers"); - - CREATEANIMCFG("workspacesIn", "workspaces"); - CREATEANIMCFG("workspacesOut", "workspaces"); - CREATEANIMCFG("specialWorkspace", "workspaces"); - CREATEANIMCFG("specialWorkspaceIn", "specialWorkspace"); - CREATEANIMCFG("specialWorkspaceOut", "specialWorkspace"); + // init the root nodes + m_AnimationTree.setConfigForNode("global", 1, 8.f, "", "default"); + m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "", "linear"); } std::optional CConfigManager::resetHLConfig() { @@ -857,6 +828,8 @@ std::optional CConfigManager::resetHLConfig() { m_vWindowRules.clear(); g_pKeybindManager->clearKeybinds(); g_pAnimationManager->removeAllBeziers(); + g_pAnimationManager->addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); + m_mAdditionalReservedAreas.clear(); m_dBlurLSNamespaces.clear(); m_vWorkspaceRules.clear(); @@ -1647,8 +1620,8 @@ void CConfigManager::ensureVRR(PHLMONITOR pMonitor) { } } -SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::string& name) { - return &animationConfig[name]; +SP CConfigManager::getAnimationPropertyConfig(const std::string& name) { + return m_AnimationTree.getConfig(name); } void CConfigManager::addParseError(const std::string& err) { @@ -1711,8 +1684,8 @@ ICustomConfigValueData::~ICustomConfigValueData() { ; // empty } -std::unordered_map CConfigManager::getAnimationConfig() { - return animationConfig; +const std::unordered_map>& CConfigManager::getAnimationConfig() { + return m_AnimationTree.getFullConfig(); } void CConfigManager::addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value) { @@ -2058,17 +2031,6 @@ std::optional CConfigManager::handleBezier(const std::string& comma return {}; } -void CConfigManager::setAnimForChildren(SAnimationPropertyConfig* const ANIM) { - for (auto& [name, anim] : animationConfig) { - if (anim.pParentAnimation == ANIM && !anim.overridden) { - // if a child isnt overridden, set the values of the parent - anim.pValues = ANIM->pValues; - - setAnimForChildren(&anim); - } - } -}; - std::optional CConfigManager::handleAnimation(const std::string& command, const std::string& args) { const auto ARGS = CVarList(args); @@ -2077,14 +2039,9 @@ std::optional CConfigManager::handleAnimation(const std::string& co // anim name const auto ANIMNAME = ARGS[0]; - const auto PANIM = animationConfig.find(ANIMNAME); - - if (PANIM == animationConfig.end()) + if (!m_AnimationTree.nodeExists(ANIMNAME)) return "no such animation"; - PANIM->second.overridden = true; - PANIM->second.pValues = &PANIM->second; - // This helper casts strings like "1", "true", "off", "yes"... to int. int64_t enabledInt = configStringToInt(ARGS[1]).value_or(0) == 1; @@ -2092,33 +2049,31 @@ std::optional CConfigManager::handleAnimation(const std::string& co if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; - PANIM->second.internalEnabled = configStringToInt(ARGS[1]).value_or(0) == 1; + if (enabledInt) { + int64_t speed = -1; - if (PANIM->second.internalEnabled) { // speed if (isNumber(ARGS[2], true)) { - PANIM->second.internalSpeed = std::stof(ARGS[2]); + speed = std::stof(ARGS[2]); - if (PANIM->second.internalSpeed <= 0) { - PANIM->second.internalSpeed = 1.f; + if (speed <= 0) { + speed = 1.f; return "invalid speed"; } } else { - PANIM->second.internalSpeed = 10.f; + speed = 10.f; return "invalid speed"; } - // curve - PANIM->second.internalBezier = ARGS[3]; + std::string bezierName = ARGS[3]; + m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); - if (!g_pAnimationManager->bezierExists(ARGS[3])) { - PANIM->second.internalBezier = "default"; + if (!g_pAnimationManager->bezierExists(bezierName)) { + const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); + PANIMNODE->internalBezier = "default"; return "no such bezier"; } - // style - PANIM->second.internalStyle = ARGS[4]; - if (ARGS[4] != "") { auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); @@ -2127,9 +2082,6 @@ std::optional CConfigManager::handleAnimation(const std::string& co } } - // now, check for children, recursively - setAnimForChildren(&PANIM->second); - return {}; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 436362ae..53772401 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -1,5 +1,6 @@ #pragma once +#include #define CONFIG_MANAGER_H #include @@ -23,9 +24,6 @@ #include -#define INITANIMCFG(name) animationConfig[name] = {} -#define CREATEANIMCFG(name, parent) animationConfig[name] = {false, "", "", 0.f, -1, &animationConfig["global"], &animationConfig[parent]} - #define HANDLE void* struct SWorkspaceRule { @@ -54,18 +52,6 @@ struct SMonitorAdditionalReservedArea { int right = 0; }; -struct SAnimationPropertyConfig { - bool overridden = true; - - std::string internalBezier = ""; - std::string internalStyle = ""; - float internalSpeed = 0.f; - int internalEnabled = -1; - - SAnimationPropertyConfig* pValues = nullptr; - SAnimationPropertyConfig* pParentAnimation = nullptr; -}; - struct SPluginKeyword { HANDLE handle = nullptr; std::string name = ""; @@ -181,32 +167,32 @@ class CConfigManager { std::unordered_map m_mAdditionalReservedAreas; - std::unordered_map getAnimationConfig(); + const std::unordered_map>& getAnimationConfig(); - void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value); + void addPluginConfigVar(HANDLE handle, const std::string& name, const Hyprlang::CConfigValue& value); void addPluginKeyword(HANDLE handle, const std::string& name, Hyprlang::PCONFIGHANDLERFUNC fun, Hyprlang::SHandlerOptions opts = {}); void removePluginConfig(HANDLE handle); // no-op when done. - void dispatchExecOnce(); - void dispatchExecShutdown(); + void dispatchExecOnce(); + void dispatchExecShutdown(); - void performMonitorReload(); - void ensureMonitorStatus(); - void ensureVRR(PHLMONITOR pMonitor = nullptr); + void performMonitorReload(); + void ensureMonitorStatus(); + void ensureVRR(PHLMONITOR pMonitor = nullptr); - bool shouldUseSoftwareCursors(); + bool shouldUseSoftwareCursors(); - std::string parseKeyword(const std::string&, const std::string&); + std::string parseKeyword(const std::string&, const std::string&); - void addParseError(const std::string&); + void addParseError(const std::string&); - SAnimationPropertyConfig* getAnimationPropertyConfig(const std::string&); + SP getAnimationPropertyConfig(const std::string&); - void addExecRule(const SExecRequestedRule&); + void addExecRule(const SExecRequestedRule&); - void handlePluginLoads(); - std::string getErrors(); + void handlePluginLoads(); + std::string getErrors(); // keywords std::optional handleRawExec(const std::string&, const std::string&); @@ -269,39 +255,38 @@ class CConfigManager { bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking private: - std::unique_ptr m_pConfig; + std::unique_ptr m_pConfig; - std::vector configPaths; // stores all the config paths - std::unordered_map configModifyTimes; // stores modify times + std::vector configPaths; // stores all the config paths + std::unordered_map configModifyTimes; // stores modify times - std::unordered_map animationConfig; // stores all the animations with their set values + Hyprutils::Animation::CAnimationConfigTree m_AnimationTree; - std::string m_szCurrentSubmap = ""; // For storing the current keybind submap + std::string m_szCurrentSubmap = ""; // For storing the current keybind submap - std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty + std::vector execRequestedRules; // rules requested with exec, e.g. [workspace 2] kitty - std::vector m_vDeclaredPlugins; - std::vector pluginKeywords; - std::vector pluginVariables; + std::vector m_vDeclaredPlugins; + std::vector pluginKeywords; + std::vector pluginVariables; - bool isFirstLaunch = true; // For exec-once + bool isFirstLaunch = true; // For exec-once - std::vector m_vMonitorRules; - std::vector m_vWorkspaceRules; - std::vector> m_vWindowRules; - std::vector> m_vLayerRules; - std::vector m_dBlurLSNamespaces; + std::vector m_vMonitorRules; + std::vector m_vWorkspaceRules; + std::vector> m_vWindowRules; + std::vector> m_vLayerRules; + std::vector m_dBlurLSNamespaces; - bool firstExecDispatched = false; - bool m_bManualCrashInitiated = false; - std::vector firstExecRequests; - std::vector finalExecRequests; + bool firstExecDispatched = false; + bool m_bManualCrashInitiated = false; + std::vector firstExecRequests; + std::vector finalExecRequests; - std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins - std::string m_szConfigErrors = ""; + std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins + std::string m_szConfigErrors = ""; // internal methods - void setAnimForChildren(SAnimationPropertyConfig* const); void updateBlurredLS(const std::string&, const bool); void setDefaultAnimationVars(); std::optional resetHLConfig(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 8724d2c7..7edace21 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -248,8 +248,8 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "focusHistoryID": {}, "inhibitingIdle": {} }},)#", - (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, - (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, + (uintptr_t)w.get(), (w->m_bIsMapped ? "true" : "false"), (w->isHidden() ? "true" : "false"), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y, + (int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, escapeJSONStrings(!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), ((int)w->m_bIsFloating == 1 ? "true" : "false"), (w->m_bIsPseudotiled ? "true" : "false"), (int64_t)w->monitorID(), escapeJSONStrings(w->m_szClass), escapeJSONStrings(w->m_szTitle), escapeJSONStrings(w->m_szInitialClass), escapeJSONStrings(w->m_szInitialTitle), w->getPID(), ((int)w->m_bIsX11 == 1 ? "true" : "false"), (w->m_bPinned ? "true" : "false"), @@ -261,11 +261,12 @@ std::string CHyprCtl::getWindowData(PHLWINDOW w, eHyprCtlOutputFormat format) { "{}\n\tinitialClass: {}\n\tinitialTitle: {}\n\tpid: " "{}\n\txwayland: {}\n\tpinned: " "{}\n\tfullscreen: {}\n\tfullscreenClient: {}\n\tgrouped: {}\n\ttags: {}\n\tswallowing: {:x}\n\tfocusHistoryID: {}\n\tinhibitingIdle: {}\n\n", - (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition.goal().x, (int)w->m_vRealPosition.goal().y, - (int)w->m_vRealSize.goal().x, (int)w->m_vRealSize.goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), - (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), - (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), - (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), (int)g_pInputManager->isWindowInhibiting(w, false)); + (uintptr_t)w.get(), w->m_szTitle, (int)w->m_bIsMapped, (int)w->isHidden(), (int)w->m_vRealPosition->goal().x, (int)w->m_vRealPosition->goal().y, + (int)w->m_vRealSize->goal().x, (int)w->m_vRealSize->goal().y, w->m_pWorkspace ? w->workspaceID() : WORKSPACE_INVALID, + (!w->m_pWorkspace ? "" : w->m_pWorkspace->m_szName), (int)w->m_bIsFloating, (int)w->m_bIsPseudotiled, (int64_t)w->monitorID(), w->m_szClass, w->m_szTitle, + w->m_szInitialClass, w->m_szInitialTitle, w->getPID(), (int)w->m_bIsX11, (int)w->m_bPinned, (uint8_t)w->m_sFullscreenState.internal, + (uint8_t)w->m_sFullscreenState.client, getGroupedData(w, format), getTagsData(w, format), (uintptr_t)w->m_pSwallowed.lock().get(), getFocusHistoryID(w), + (int)g_pInputManager->isWindowInhibiting(w, false)); } } @@ -732,8 +733,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re ret += "animations:\n"; for (auto const& ac : g_pConfigManager->getAnimationConfig()) { - ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second.overridden, - ac.second.internalBezier, ac.second.internalEnabled, ac.second.internalSpeed, ac.second.internalStyle); + ret += std::format("\n\tname: {}\n\t\toverriden: {}\n\t\tbezier: {}\n\t\tenabled: {}\n\t\tspeed: {:.2f}\n\t\tstyle: {}\n", ac.first, (int)ac.second->overridden, + ac.second->internalBezier, ac.second->internalEnabled, ac.second->internalSpeed, ac.second->internalStyle); } ret += "beziers:\n"; @@ -755,8 +756,8 @@ static std::string animationsRequest(eHyprCtlOutputFormat format, std::string re "speed": {:.2f}, "style": "{}" }},)#", - ac.first, ac.second.overridden ? "true" : "false", escapeJSONStrings(ac.second.internalBezier), ac.second.internalEnabled ? "true" : "false", - ac.second.internalSpeed, escapeJSONStrings(ac.second.internalStyle)); + ac.first, ac.second->overridden ? "true" : "false", escapeJSONStrings(ac.second->internalBezier), ac.second->internalEnabled ? "true" : "false", + ac.second->internalSpeed, escapeJSONStrings(ac.second->internalStyle)); } ret[ret.length() - 1] = ']'; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 05ea4473..fe11f3f3 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -4,6 +4,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/AnimationManager.hpp" PHLLS CLayerSurface::create(SP resource) { PHLLS pLS = SP(new CLayerSurface(resource)); @@ -31,16 +32,13 @@ PHLLS CLayerSurface::create(SP resource) { pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); - pLS->alpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->realPosition.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->realSize.create(g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); - pLS->alpha.registerVar(); - pLS->realPosition.registerVar(); - pLS->realSize.registerVar(); + g_pAnimationManager->createAnimation(0.f, pLS->alpha, g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"), pLS, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realPosition, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pLS->realSize, g_pConfigManager->getAnimationPropertyConfig("layersIn"), pLS, AVARDAMAGE_ENTIRE); pLS->registerCallbacks(); - pLS->alpha.setValueAndWarp(0.f); + pLS->alpha->setValueAndWarp(0.f); Debug::log(LOG, "LayerSurface {:x} (namespace {} layer {}) created on monitor {}", (uintptr_t)resource.get(), resource->layerNamespace, (int)pLS->layer, pMonitor->szName); @@ -48,7 +46,7 @@ PHLLS CLayerSurface::create(SP resource) { } void CLayerSurface::registerCallbacks() { - alpha.setUpdateCallback([this](void*) { + alpha->setUpdateCallback([this](auto) { if (dimAround) g_pHyprRenderer->damageMonitor(monitor.lock()); }); @@ -93,7 +91,7 @@ void CLayerSurface::onDestroy() { onUnmap(); } else { Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); - alpha.setValueAndWarp(0.f); + alpha->setValueAndWarp(0.f); fadingOut = true; g_pCompositor->addToFadingOutSafe(self.lock()); } @@ -307,17 +305,17 @@ void CLayerSurface::onCommit() { } } - if (realPosition.goal() != geometry.pos()) { - if (realPosition.isBeingAnimated()) - realPosition = geometry.pos(); + if (realPosition->goal() != geometry.pos()) { + if (realPosition->isBeingAnimated()) + *realPosition = geometry.pos(); else - realPosition.setValueAndWarp(geometry.pos()); + realPosition->setValueAndWarp(geometry.pos()); } - if (realSize.goal() != geometry.size()) { - if (realSize.isBeingAnimated()) - realSize = geometry.size(); + if (realSize->goal() != geometry.size()) { + if (realSize->isBeingAnimated()) + *realSize = geometry.size(); else - realSize.setValueAndWarp(geometry.size()); + realSize->setValueAndWarp(geometry.size()); } if (mapped && (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_INTERACTIVITY)) { @@ -434,17 +432,17 @@ void CLayerSurface::applyRules() { } void CLayerSurface::startAnimation(bool in, bool instant) { - const auto ANIMSTYLE = animationStyle.value_or(realPosition.m_pConfig->pValues->internalStyle); if (in) { - realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn"); - realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersIn"); - alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn"); + realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); } else { - realPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut"); - realSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("layersOut"); - alpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut"); + realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); } + const auto ANIMSTYLE = animationStyle.value_or(realPosition->getStyle()); if (ANIMSTYLE.starts_with("slide")) { // get closest edge const auto MIDDLE = geometry.middle(); @@ -485,9 +483,9 @@ void CLayerSurface::startAnimation(bool in, bool instant) { } } - realSize.setValueAndWarp(geometry.size()); - alpha.setValueAndWarp(in ? 0.f : 1.f); - alpha = in ? 1.f : 0.f; + realSize->setValueAndWarp(geometry.size()); + alpha->setValueAndWarp(in ? 0.f : 1.f); + *alpha = in ? 1.f : 0.f; Vector2D prePos; @@ -512,11 +510,11 @@ void CLayerSurface::startAnimation(bool in, bool instant) { } if (in) { - realPosition.setValueAndWarp(prePos); - realPosition = geometry.pos(); + realPosition->setValueAndWarp(prePos); + *realPosition = geometry.pos(); } else { - realPosition.setValueAndWarp(geometry.pos()); - realPosition = prePos; + realPosition->setValueAndWarp(geometry.pos()); + *realPosition = prePos; } } else if (ANIMSTYLE.starts_with("popin")) { @@ -535,25 +533,25 @@ void CLayerSurface::startAnimation(bool in, bool instant) { const auto GOALSIZE = (geometry.size() * minPerc).clamp({5, 5}); const auto GOALPOS = geometry.pos() + (geometry.size() - GOALSIZE) / 2.f; - alpha.setValueAndWarp(in ? 0.f : 1.f); - alpha = in ? 1.f : 0.f; + alpha->setValueAndWarp(in ? 0.f : 1.f); + *alpha = in ? 1.f : 0.f; if (in) { - realSize.setValueAndWarp(GOALSIZE); - realPosition.setValueAndWarp(GOALPOS); - realSize = geometry.size(); - realPosition = geometry.pos(); + realSize->setValueAndWarp(GOALSIZE); + realPosition->setValueAndWarp(GOALPOS); + *realSize = geometry.size(); + *realPosition = geometry.pos(); } else { - realSize.setValueAndWarp(geometry.size()); - realPosition.setValueAndWarp(geometry.pos()); - realSize = GOALSIZE; - realPosition = GOALPOS; + realSize->setValueAndWarp(geometry.size()); + realPosition->setValueAndWarp(geometry.pos()); + *realSize = GOALSIZE; + *realPosition = GOALPOS; } } else { // fade - realPosition.setValueAndWarp(geometry.pos()); - realSize.setValueAndWarp(geometry.size()); - alpha = in ? 1.f : 0.f; + realPosition->setValueAndWarp(geometry.pos()); + realSize->setValueAndWarp(geometry.size()); + *alpha = in ? 1.f : 0.f; } if (!in) @@ -564,7 +562,7 @@ bool CLayerSurface::isFadedOut() { if (!fadingOut) return false; - return !realPosition.isBeingAnimated() && !realSize.isBeingAnimated() && !alpha.isBeingAnimated(); + return !realPosition->isBeingAnimated() && !realSize->isBeingAnimated() && !alpha->isBeingAnimated(); } int CLayerSurface::popupsCount() { diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index e906fc6f..3a03e57e 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -18,17 +18,17 @@ class CLayerSurface { public: ~CLayerSurface(); - void applyRules(); - void startAnimation(bool in, bool instant = false); - bool isFadedOut(); - int popupsCount(); + void applyRules(); + void startAnimation(bool in, bool instant = false); + bool isFadedOut(); + int popupsCount(); - CAnimatedVariable realPosition; - CAnimatedVariable realSize; - CAnimatedVariable alpha; + PHLANIMVAR realPosition; + PHLANIMVAR realSize; + PHLANIMVAR alpha; - WP layerSurface; - wl_list link; + WP layerSurface; + wl_list link; // the header providing the enum type cannot be imported here int interactivity = 0; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 692a75e3..ce286b28 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -243,9 +243,9 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) { Vector2D CPopup::t1ParentCoords() { if (!m_pWindowOwner.expired()) - return m_pWindowOwner->m_vRealPosition.value(); + return m_pWindowOwner->m_vRealPosition->value(); if (!m_pLayerOwner.expired()) - return m_pLayerOwner->realPosition.value(); + return m_pLayerOwner->realPosition->value(); ASSERT(false); return {}; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 893411bd..62854f80 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -169,7 +169,7 @@ Vector2D CSubsurface::coordsGlobal() { Vector2D coords = coordsRelativeToParent(); if (!m_pWindowParent.expired()) - coords += m_pWindowParent->m_vRealPosition.value(); + coords += m_pWindowParent->m_vRealPosition->value(); else if (m_pPopupParent) coords += m_pPopupParent->coordsGlobal(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 5e88f507..9ed8ec49 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -72,7 +72,7 @@ Vector2D CWLSurface::correctSmallVec() const { const auto SIZE = getViewporterCorrectedSize(); const auto O = m_pWindowOwner.lock(); - return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize.value() / O->m_vReportedSize); + return Vector2D{(O->m_vReportedSize.x - SIZE.x) / 2, (O->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_vRealSize->value() / O->m_vReportedSize); } Vector2D CWLSurface::correctSmallVecBuf() const { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 60914198..8175fc57 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -11,12 +12,16 @@ #include "../render/decorations/CHyprBorderDecoration.hpp" #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" +#include "../managers/AnimationManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include "../helpers/Color.hpp" #include + using namespace Hyprutils::String; +using namespace Hyprutils::Animation; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -24,16 +29,16 @@ PHLWINDOW CWindow::create(SP surface) { pWindow->m_pSelf = pWindow; pWindow->m_bIsX11 = true; - pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); - pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingFromWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -47,16 +52,16 @@ PHLWINDOW CWindow::create(SP resource) { pWindow->m_pSelf = pWindow; resource->toplevel->window = pWindow; - pWindow->m_vRealPosition.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_vRealSize.create(g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fBorderFadeAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fBorderAngleAnimationProgress.create(g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); - pWindow->m_fAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fActiveInactiveAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_cRealShadowColor.create(g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); - pWindow->m_fDimPercent.create(g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingToWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->m_fMovingFromWorkspaceAlpha.create(g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealPosition, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(Vector2D(0, 0), pWindow->m_vRealSize, g_pConfigManager->getAnimationPropertyConfig("windowsIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderFadeAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("border"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fBorderAngleAnimationProgress, g_pConfigManager->getAnimationPropertyConfig("borderangle"), pWindow, AVARDAMAGE_BORDER); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, pWindow->m_fActiveInactiveAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeSwitch"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(CHyprColor(), pWindow->m_cRealShadowColor, g_pConfigManager->getAnimationPropertyConfig("fadeShadow"), pWindow, AVARDAMAGE_SHADOW); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(std::make_unique(pWindow)); pWindow->addWindowDeco(std::make_unique(pWindow)); @@ -118,8 +123,8 @@ SBoxExtents CWindow::getFullWindowExtents() { if (m_sWindowData.dimAround.valueOrDefault()) { if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) - return {{m_vRealPosition.value().x - PMONITOR->vecPosition.x, m_vRealPosition.value().y - PMONITOR->vecPosition.y}, - {PMONITOR->vecSize.x - (m_vRealPosition.value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition.value().y - PMONITOR->vecPosition.y)}}; + return {{m_vRealPosition->value().x - PMONITOR->vecPosition.x, m_vRealPosition->value().y - PMONITOR->vecPosition.y}, + {PMONITOR->vecSize.x - (m_vRealPosition->value().x - PMONITOR->vecPosition.x), PMONITOR->vecSize.y - (m_vRealPosition->value().y - PMONITOR->vecPosition.y)}}; } SBoxExtents maxExtents = {{BORDERSIZE + 2, BORDERSIZE + 2}, {BORDERSIZE + 2, BORDERSIZE + 2}}; @@ -183,8 +188,8 @@ CBox CWindow::getFullWindowBoundingBox() { auto maxExtents = getFullWindowExtents(); - CBox finalBox = {m_vRealPosition.value().x - maxExtents.topLeft.x, m_vRealPosition.value().y - maxExtents.topLeft.y, - m_vRealSize.value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize.value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y}; + CBox finalBox = {m_vRealPosition->value().x - maxExtents.topLeft.x, m_vRealPosition->value().y - maxExtents.topLeft.y, + m_vRealSize->value().x + maxExtents.topLeft.x + maxExtents.bottomRight.x, m_vRealSize->value().y + maxExtents.topLeft.y + maxExtents.bottomRight.y}; return finalBox; } @@ -238,7 +243,7 @@ CBox CWindow::getWindowBoxUnified(uint64_t properties) { if (properties & FULL_EXTENTS) EXTENTS.addExtents(g_pDecorationPositioner->getWindowDecorationExtents(m_pSelf.lock(), false)); - CBox box = {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + CBox box = {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; box.addExtents(EXTENTS); return box; @@ -409,9 +414,9 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; - m_fMovingToWorkspaceAlpha.setValueAndWarp(1.F); - m_fMovingToWorkspaceAlpha = 0.F; - m_fMovingToWorkspaceAlpha.setCallbackOnEnd([this](void* thisptr) { m_iMonitorMovedFrom = -1; }); + m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); + m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); + *m_fMovingToWorkspaceAlpha = 0.F; m_pWorkspace = pWorkspace; @@ -439,7 +444,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } // update xwayland coords - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.value()); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->value()); if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) @@ -475,10 +480,6 @@ PHLWINDOW CWindow::x11TransientFor() { return nullptr; } -static void unregisterVar(void* ptr) { - ((CBaseAnimatedVariable*)ptr)->unregister(); -} - void CWindow::onUnmap() { static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); @@ -497,19 +498,6 @@ void CWindow::onUnmap() { m_iLastWorkspace = m_pWorkspace->m_iID; - m_vRealPosition.setCallbackOnEnd(unregisterVar); - m_vRealSize.setCallbackOnEnd(unregisterVar); - m_fBorderFadeAnimationProgress.setCallbackOnEnd(unregisterVar); - m_fBorderAngleAnimationProgress.setCallbackOnEnd(unregisterVar); - m_fActiveInactiveAlpha.setCallbackOnEnd(unregisterVar); - m_fAlpha.setCallbackOnEnd(unregisterVar); - m_cRealShadowColor.setCallbackOnEnd(unregisterVar); - m_fDimPercent.setCallbackOnEnd(unregisterVar); - m_fMovingToWorkspaceAlpha.setCallbackOnEnd(unregisterVar); - m_fMovingFromWorkspaceAlpha.setCallbackOnEnd(unregisterVar); - - m_vRealSize.setCallbackOnBegin(nullptr); - std::erase_if(g_pCompositor->m_vWindowFocusHistory, [&](const auto& other) { return other.expired() || other.lock().get() == this; }); if (*PCLOSEONLASTSPECIAL && m_pWorkspace && m_pWorkspace->getWindows() == 0 && onSpecialWorkspace()) { @@ -541,34 +529,24 @@ void CWindow::onUnmap() { void CWindow::onMap() { // JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped) - m_vRealPosition.resetAllCallbacks(); - m_vRealSize.resetAllCallbacks(); - m_fBorderFadeAnimationProgress.resetAllCallbacks(); - m_fBorderAngleAnimationProgress.resetAllCallbacks(); - m_fActiveInactiveAlpha.resetAllCallbacks(); - m_fAlpha.resetAllCallbacks(); - m_cRealShadowColor.resetAllCallbacks(); - m_fDimPercent.resetAllCallbacks(); - m_fMovingToWorkspaceAlpha.resetAllCallbacks(); - m_fMovingFromWorkspaceAlpha.resetAllCallbacks(); + m_vRealPosition->resetAllCallbacks(); + m_vRealSize->resetAllCallbacks(); + m_fBorderFadeAnimationProgress->resetAllCallbacks(); + m_fBorderAngleAnimationProgress->resetAllCallbacks(); + m_fActiveInactiveAlpha->resetAllCallbacks(); + m_fAlpha->resetAllCallbacks(); + m_cRealShadowColor->resetAllCallbacks(); + m_fDimPercent->resetAllCallbacks(); + m_fMovingToWorkspaceAlpha->resetAllCallbacks(); + m_fMovingFromWorkspaceAlpha->resetAllCallbacks(); - m_vRealPosition.registerVar(); - m_vRealSize.registerVar(); - m_fBorderFadeAnimationProgress.registerVar(); - m_fBorderAngleAnimationProgress.registerVar(); - m_fActiveInactiveAlpha.registerVar(); - m_fAlpha.registerVar(); - m_cRealShadowColor.registerVar(); - m_fDimPercent.registerVar(); - m_fMovingToWorkspaceAlpha.registerVar(); - m_fMovingFromWorkspaceAlpha.registerVar(); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); + m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); - m_fBorderAngleAnimationProgress.setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); + m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + *m_fBorderAngleAnimationProgress = 1.f; - m_fBorderAngleAnimationProgress.setValueAndWarp(0.f); - m_fBorderAngleAnimationProgress = 1.f; - - m_fMovingFromWorkspaceAlpha.setValueAndWarp(1.F); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); @@ -584,20 +562,22 @@ void CWindow::onMap() { m_pPopupHead = std::make_unique(m_pSelf.lock()); } -void CWindow::onBorderAngleAnimEnd(void* ptr) { - const auto PANIMVAR = (CAnimatedVariable*)ptr; - - const std::string STYLE = PANIMVAR->getConfig()->pValues->internalStyle; - - if (STYLE != "loop" || !PANIMVAR->getConfig()->pValues->internalEnabled) +void CWindow::onBorderAngleAnimEnd(WP pav) { + const auto PAV = pav.lock(); + if (!PAV) return; + if (PAV->getStyle() != "loop" || !PAV->enabled()) + return; + + const auto PANIMVAR = dynamic_cast*>(PAV.get()); + PANIMVAR->setCallbackOnEnd(nullptr); // we remove the callback here because otherwise setvalueandwarp will recurse this PANIMVAR->setValueAndWarp(0); *PANIMVAR = 1.f; - PANIMVAR->setCallbackOnEnd([&](void* ptr) { onBorderAngleAnimEnd(ptr); }, false); + PANIMVAR->setCallbackOnEnd([&](WP pav) { onBorderAngleAnimEnd(pav); }, false); } void CWindow::setHidden(bool hidden) { @@ -830,10 +810,10 @@ bool CWindow::isInCurvedCorner(double x, double y) { return false; // (x0, y0), (x0, y1), ... are the center point of rounding at each corner - double x0 = m_vRealPosition.value().x + ROUNDING; - double y0 = m_vRealPosition.value().y + ROUNDING; - double x1 = m_vRealPosition.value().x + m_vRealSize.value().x - ROUNDING; - double y1 = m_vRealPosition.value().y + m_vRealSize.value().y - ROUNDING; + double x0 = m_vRealPosition->value().x + ROUNDING; + double y0 = m_vRealPosition->value().y + ROUNDING; + double x1 = m_vRealPosition->value().x + m_vRealSize->value().x - ROUNDING; + double y1 = m_vRealPosition->value().y + m_vRealSize->value().y - ROUNDING; if (x < x0 && y < y0) { return std::pow(x0 - x, ROUNDINGPOWER) + std::pow(y0 - y, ROUNDINGPOWER) > std::pow((double)ROUNDING, ROUNDINGPOWER); @@ -1032,8 +1012,8 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { if (FULLSCREEN) g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE); - const auto PWINDOWSIZE = PCURRENT->m_vRealSize.goal(); - const auto PWINDOWPOS = PCURRENT->m_vRealPosition.goal(); + const auto PWINDOWSIZE = PCURRENT->m_vRealSize->goal(); + const auto PWINDOWPOS = PCURRENT->m_vRealPosition->goal(); PCURRENT->setHidden(true); pWindow->setHidden(false); // can remove m_pLastWindow @@ -1041,8 +1021,8 @@ void CWindow::setGroupCurrent(PHLWINDOW pWindow) { g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow); if (PCURRENT->m_bIsFloating) { - pWindow->m_vRealPosition.setValueAndWarp(PWINDOWPOS); - pWindow->m_vRealSize.setValueAndWarp(PWINDOWSIZE); + pWindow->m_vRealPosition->setValueAndWarp(PWINDOWPOS); + pWindow->m_vRealSize->setValueAndWarp(PWINDOWSIZE); } g_pCompositor->updateAllWindowsAnimatedDecorationValues(); @@ -1124,22 +1104,22 @@ void CWindow::updateGroupOutputs() { curr->m_pMonitor = m_pMonitor; curr->moveToWorkspace(WS); - curr->m_vRealPosition = m_vRealPosition.goal(); - curr->m_vRealSize = m_vRealSize.goal(); + *curr->m_vRealPosition = m_vRealPosition->goal(); + *curr->m_vRealSize = m_vRealSize->goal(); curr = curr->m_sGroupData.pNextWindow.lock(); } } Vector2D CWindow::middle() { - return m_vRealPosition.goal() + m_vRealSize.goal() / 2.f; + return m_vRealPosition->goal() + m_vRealSize->goal() / 2.f; } bool CWindow::opaque() { - if (m_fAlpha.value() != 1.f || m_fActiveInactiveAlpha.value() != 1.f) + if (m_fAlpha->value() != 1.f || m_fActiveInactiveAlpha->value() != 1.f) return false; - if (m_vRealSize.goal().floor() != m_vReportedSize) + if (m_vRealSize->goal().floor() != m_vReportedSize) return false; const auto PWORKSPACE = m_pWorkspace; @@ -1147,7 +1127,7 @@ bool CWindow::opaque() { if (m_pWLSurface->small() && !m_pWLSurface->m_bFillIgnoreSmall) return false; - if (PWORKSPACE->m_fAlpha.value() != 1.f) + if (PWORKSPACE->m_fAlpha->value() != 1.f) return false; if (m_bIsX11 && m_pXWaylandSurface && m_pXWaylandSurface->surface && m_pXWaylandSurface->surface->current.texture) @@ -1237,15 +1217,13 @@ void CWindow::setSuspended(bool suspend) { } bool CWindow::visibleOnMonitor(PHLMONITOR pMonitor) { - CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()}; + CBox wbox = {m_vRealPosition->value(), m_vRealSize->value()}; return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty(); } void CWindow::setAnimationsToMove() { - auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); - m_vRealPosition.setConfig(PANIMCFG); - m_vRealSize.setConfig(PANIMCFG); + m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); m_bAnimatingIn = false; } @@ -1266,16 +1244,16 @@ void CWindow::onWorkspaceAnimUpdate() { return; const auto WINBB = getFullWindowBoundingBox(); - if (PWORKSPACE->m_vRenderOffset.value().x != 0) { - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().x / PWSMON->vecSize.x; + if (PWORKSPACE->m_vRenderOffset->value().x != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().x / PWSMON->vecSize.x; if (WINBB.x < PWSMON->vecPosition.x) offset.x += (PWSMON->vecPosition.x - WINBB.x) * PROGRESS; if (WINBB.x + WINBB.width > PWSMON->vecPosition.x + PWSMON->vecSize.x) offset.x += (WINBB.x + WINBB.width - PWSMON->vecPosition.x - PWSMON->vecSize.x) * PROGRESS; - } else if (PWORKSPACE->m_vRenderOffset.value().y != 0) { - const auto PROGRESS = PWORKSPACE->m_vRenderOffset.value().y / PWSMON->vecSize.y; + } else if (PWORKSPACE->m_vRenderOffset->value().y != 0) { + const auto PROGRESS = PWORKSPACE->m_vRenderOffset->value().y / PWSMON->vecSize.y; if (WINBB.y < PWSMON->vecPosition.y) offset.y += (PWSMON->vecPosition.y - WINBB.y) * PROGRESS; @@ -1306,12 +1284,12 @@ int CWindow::surfacesCount() { } void CWindow::clampWindowSize(const std::optional minSize, const std::optional maxSize) { - const Vector2D REALSIZE = m_vRealSize.goal(); + const Vector2D REALSIZE = m_vRealSize->goal(); const Vector2D NEWSIZE = REALSIZE.clamp(minSize.value_or(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), maxSize.value_or(Vector2D{INFINITY, INFINITY})); const Vector2D DELTA = REALSIZE - NEWSIZE; - m_vRealPosition = m_vRealPosition.goal() + DELTA / 2.0; - m_vRealSize = NEWSIZE; + *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; + *m_vRealSize = NEWSIZE; g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE); } @@ -1525,7 +1503,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->goal(), true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); return; @@ -1538,19 +1516,19 @@ void CWindow::onX11Configure(CBox box) { const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos()); - m_vRealPosition.setValueAndWarp(LOGICALPOS); - m_vRealSize.setValueAndWarp(box.size()); + m_vRealPosition->setValueAndWarp(LOGICALPOS); + m_vRealSize->setValueAndWarp(box.size()); static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { - m_vRealSize.setValueAndWarp(m_vRealSize.goal() / PMONITOR->scale); + m_vRealSize->setValueAndWarp(m_vRealSize->goal() / PMONITOR->scale); m_fX11SurfaceScaledBy = PMONITOR->scale; } } - m_vPosition = m_vRealPosition.value(); - m_vSize = m_vRealSize.value(); + m_vPosition = m_vRealPosition->value(); + m_vSize = m_vRealSize->value(); m_pXWaylandSurface->configure(box); @@ -1562,7 +1540,7 @@ void CWindow::onX11Configure(CBox box) { if (!m_pWorkspace || !m_pWorkspace->isVisible()) return; // further things are only for visible windows - m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition.value() + m_vRealSize.value() / 2.f)->activeWorkspace; + m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->value() + m_vRealSize->value() / 2.f)->activeWorkspace; g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 3ceaf594..37189a00 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -233,8 +233,8 @@ class CWindow { Vector2D m_vSize = Vector2D(0, 0); // this is the real position and size used to draw the thing - CAnimatedVariable m_vRealPosition; - CAnimatedVariable m_vRealSize; + PHLANIMVAR m_vRealPosition; + PHLANIMVAR m_vRealSize; // for not spamming the protocols Vector2D m_vReportedPosition; @@ -298,19 +298,19 @@ class CWindow { std::unique_ptr m_pPopupHead; // Animated border - CGradientValueData m_cRealBorderColor = {0}; - CGradientValueData m_cRealBorderColorPrevious = {0}; - CAnimatedVariable m_fBorderFadeAnimationProgress; - CAnimatedVariable m_fBorderAngleAnimationProgress; + CGradientValueData m_cRealBorderColor = {0}; + CGradientValueData m_cRealBorderColorPrevious = {0}; + PHLANIMVAR m_fBorderFadeAnimationProgress; + PHLANIMVAR m_fBorderAngleAnimationProgress; // Fade in-out - CAnimatedVariable m_fAlpha; - bool m_bFadingOut = false; - bool m_bReadyToDelete = false; - Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in - Vector2D m_vOriginalClosedSize; // drawing the closing animations - SBoxExtents m_eOriginalClosedExtents; - bool m_bAnimatingIn = false; + PHLANIMVAR m_fAlpha; + bool m_bFadingOut = false; + bool m_bReadyToDelete = false; + Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in + Vector2D m_vOriginalClosedSize; // drawing the closing animations + SBoxExtents m_eOriginalClosedExtents; + bool m_bAnimatingIn = false; // For pinned (sticky) windows bool m_bPinned = false; @@ -336,18 +336,18 @@ class CWindow { std::vector> m_vTransformers; // for alpha - CAnimatedVariable m_fActiveInactiveAlpha; - CAnimatedVariable m_fMovingFromWorkspaceAlpha; + PHLANIMVAR m_fActiveInactiveAlpha; + PHLANIMVAR m_fMovingFromWorkspaceAlpha; // animated shadow color - CAnimatedVariable m_cRealShadowColor; + PHLANIMVAR m_cRealShadowColor; // animated tint - CAnimatedVariable m_fDimPercent; + PHLANIMVAR m_fDimPercent; // animate moving to an invisible workspace - int m_iMonitorMovedFrom = -1; // -1 means not moving - CAnimatedVariable m_fMovingToWorkspaceAlpha; + int m_iMonitorMovedFrom = -1; // -1 means not moving + PHLANIMVAR m_fMovingToWorkspaceAlpha; // swallowing PHLWINDOWREF m_pSwallowed; @@ -432,7 +432,7 @@ class CWindow { float getScrollTouchpad(); void updateWindowData(); void updateWindowData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(void* ptr); + void onBorderAngleAnimEnd(WP pav); bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); int popupsCount(); @@ -467,7 +467,7 @@ class CWindow { Vector2D requestedMaxSize(); CBox getWindowMainSurfaceBox() const { - return {m_vRealPosition.value().x, m_vRealPosition.value().y, m_vRealSize.value().x, m_vRealSize.value().y}; + return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; } // listeners diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 0930ef00..cab19254 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -1,7 +1,10 @@ #include "Workspace.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "config/ConfigManager.hpp" +#include "managers/AnimationManager.hpp" +#include #include using namespace Hyprutils::String; @@ -19,16 +22,10 @@ CWorkspace::CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, boo void CWorkspace::init(PHLWORKSPACE self) { m_pSelf = self; - m_vRenderOffset.create(m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : - g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), - self, AVARDAMAGE_ENTIRE); - m_fAlpha.create(AVARTYPE_FLOAT, - m_bIsSpecialWorkspace ? g_pConfigManager->getAnimationPropertyConfig("specialWorkspaceIn") : g_pConfigManager->getAnimationPropertyConfig("workspacesIn"), self, - AVARDAMAGE_ENTIRE); - m_fAlpha.setValueAndWarp(1.f); - - m_vRenderOffset.registerVar(); - m_fAlpha.registerVar(); + g_pAnimationManager->createAnimation(Vector2D(0, 0), m_vRenderOffset, + g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(1.f, m_fAlpha, g_pConfigManager->getAnimationPropertyConfig(m_bIsSpecialWorkspace ? "specialWorkspaceIn" : "workspacesIn"), self, + AVARDAMAGE_ENTIRE); const auto RULEFORTHIS = g_pConfigManager->getWorkspaceRuleFor(self); if (RULEFORTHIS.defaultName.has_value()) @@ -63,8 +60,6 @@ SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const { } CWorkspace::~CWorkspace() { - m_vRenderOffset.unregister(); - Debug::log(LOG, "Destroying workspace ID {}", m_iID); // check if g_pHookSystem and g_pEventManager exist, they might be destroyed as in when the compositor is closing. @@ -82,15 +77,15 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { if (!instant) { const std::string ANIMNAME = std::format("{}{}", m_bIsSpecialWorkspace ? "specialWorkspace" : "workspaces", in ? "In" : "Out"); - m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); - m_vRenderOffset.m_pConfig = g_pConfigManager->getAnimationPropertyConfig(ANIMNAME); + m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); + m_vRenderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); } - const auto ANIMSTYLE = m_fAlpha.m_pConfig->pValues->internalStyle; + const auto ANIMSTYLE = m_fAlpha->getStyle(); static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); // set floating windows offset callbacks - m_vRenderOffset.setUpdateCallback([&](void*) { + m_vRenderOffset->setUpdateCallback([&](auto) { for (auto const& w : g_pCompositor->m_vWindows) { if (!validMapped(w) || w->workspaceID() != m_iID) continue; @@ -110,84 +105,84 @@ void CWorkspace::startAnim(bool in, bool left, bool instant) { } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } } - m_fAlpha.setValueAndWarp(1.f); - m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + m_fAlpha->setValueAndWarp(1.f); + m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); if (ANIMSTYLE.starts_with("slidefadevert")) { if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); - m_fAlpha = 1.f; - m_vRenderOffset = Vector2D(0, 0); + m_fAlpha->setValueAndWarp(0.f); + m_vRenderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->vecSize.y : -PMONITOR->vecSize.y) * (movePerc / 100.f))); + *m_fAlpha = 1.f; + *m_vRenderOffset = Vector2D(0, 0); } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; - m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; + *m_vRenderOffset = Vector2D(0.0, (left ? -PMONITOR->vecSize.y : PMONITOR->vecSize.y) * (movePerc / 100.f)); } } else { if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_vRenderOffset.setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); - m_fAlpha = 1.f; - m_vRenderOffset = Vector2D(0, 0); + m_fAlpha->setValueAndWarp(0.f); + m_vRenderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->vecSize.x : -PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0)); + *m_fAlpha = 1.f; + *m_vRenderOffset = Vector2D(0, 0); } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; - m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; + *m_vRenderOffset = Vector2D((left ? -PMONITOR->vecSize.x : PMONITOR->vecSize.x) * (movePerc / 100.f), 0.0); } } } else if (ANIMSTYLE == "fade") { - m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. + m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_fAlpha = 1.f; + m_fAlpha->setValueAndWarp(0.f); + *m_fAlpha = 1.f; } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; } } else if (ANIMSTYLE == "slidevert") { // fallback is slide const auto PMONITOR = m_pMonitor.lock(); const auto YDISTANCE = PMONITOR->vecSize.y + *PWORKSPACEGAP; - m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); - m_vRenderOffset = Vector2D(0, 0); + m_vRenderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); + *m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); + *m_vRenderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); } } else { // fallback is slide const auto PMONITOR = m_pMonitor.lock(); const auto XDISTANCE = PMONITOR->vecSize.x + *PWORKSPACEGAP; - m_fAlpha.setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + m_fAlpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. if (in) { - m_vRenderOffset.setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); - m_vRenderOffset = Vector2D(0, 0); + m_vRenderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); + *m_vRenderOffset = Vector2D(0, 0); } else { - m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); + *m_vRenderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); } } if (m_bIsSpecialWorkspace) { // required for open/close animations if (in) { - m_fAlpha.setValueAndWarp(0.f); - m_fAlpha = 1.f; + m_fAlpha->setValueAndWarp(0.f); + *m_fAlpha = 1.f; } else { - m_fAlpha.setValueAndWarp(1.f); - m_fAlpha = 0.f; + m_fAlpha->setValueAndWarp(1.f); + *m_fAlpha = 0.f; } } if (instant) { - m_vRenderOffset.warp(); - m_fAlpha.warp(); + m_vRenderOffset->warp(); + m_fAlpha->warp(); } } @@ -633,7 +628,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize.value(), true); + g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->value(), true); } } diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index 606485a2..f86dd656 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -37,9 +37,9 @@ class CWorkspace { wl_array m_wlrCoordinateArr; // for animations - CAnimatedVariable m_vRenderOffset; - CAnimatedVariable m_fAlpha; - bool m_bForceRendering = false; + PHLANIMVAR m_vRenderOffset; + PHLANIMVAR m_fAlpha; + bool m_bForceRendering = false; // allows damage to propagate. bool m_bVisible = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a20cbcad..8082cdc9 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,10 +12,12 @@ #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" #include "../xwayland/XSurface.hpp" +#include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" #include using namespace Hyprutils::String; +using namespace Hyprutils::Animation; // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // @@ -27,15 +29,17 @@ using namespace Hyprutils::String; // // // ------------------------------------------------------------ // -static void setAnimToMove(void* data) { - auto* const PANIMCFG = g_pConfigManager->getAnimationPropertyConfig("windowsMove"); +static void setVector2DAnimToMove(WP pav) { + const auto PAV = pav.lock(); + if (!PAV) + return; - CBaseAnimatedVariable* animvar = (CBaseAnimatedVariable*)data; + CAnimatedVariable* animvar = dynamic_cast*>(PAV.get()); + animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); - animvar->setConfig(PANIMCFG); - - if (animvar->getWindow() && !animvar->getWindow()->m_vRealPosition.isBeingAnimated() && !animvar->getWindow()->m_vRealSize.isBeingAnimated()) - animvar->getWindow()->m_bAnimatingIn = false; + const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); + if (PHLWINDOW && PHLWINDOW->m_vRealPosition->isBeingAnimated() && PHLWINDOW->m_vRealSize->isBeingAnimated()) + PHLWINDOW->m_bAnimatingIn = false; } void Events::listener_mapWindow(void* owner, void* data) { @@ -378,10 +382,10 @@ void Events::listener_mapWindow(void* owner, void* data) { const auto MAXSIZE = PWINDOW->requestedMaxSize(); const float SIZEX = SIZEXSTR == "max" ? std::clamp(MAXSIZE.x, MIN_WINDOW_SIZE, PMONITOR->vecSize.x) : - stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize.goal().x, PMONITOR->vecSize.x); + stringToFloatClamp(SIZEXSTR, PWINDOW->m_vRealSize->goal().x, PMONITOR->vecSize.x); const float SIZEY = SIZEYSTR == "max" ? std::clamp(MAXSIZE.y, MIN_WINDOW_SIZE, PMONITOR->vecSize.y) : - stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize.goal().y, PMONITOR->vecSize.y); + stringToFloatClamp(SIZEYSTR, PWINDOW->m_vRealSize->goal().y, PMONITOR->vecSize.y); Debug::log(LOG, "Rule size, applying to {}", PWINDOW); @@ -418,7 +422,7 @@ void Events::listener_mapWindow(void* owner, void* data) { (!POSXRAW.contains('%') ? std::stoi(POSXRAW) : std::stof(POSXRAW.substr(0, POSXRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.x); if (subtractWindow) - posX -= PWINDOW->m_vRealSize.goal().x; + posX -= PWINDOW->m_vRealSize->goal().x; if (CURSOR) Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!"); @@ -430,7 +434,7 @@ void Events::listener_mapWindow(void* owner, void* data) { posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x; } else { posX = g_pInputManager->getMouseCoordsInternal().x - PMONITOR->vecPosition.x + - (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().x); + (!POSXSTR.contains('%') ? std::stoi(POSXSTR) : std::stof(POSXSTR.substr(0, POSXSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().x); } } @@ -441,7 +445,7 @@ void Events::listener_mapWindow(void* owner, void* data) { (!POSYRAW.contains('%') ? std::stoi(POSYRAW) : std::stof(POSYRAW.substr(0, POSYRAW.length() - 1)) * 0.01 * PMONITOR->vecSize.y); if (subtractWindow) - posY -= PWINDOW->m_vRealSize.goal().y; + posY -= PWINDOW->m_vRealSize->goal().y; if (CURSOR) Debug::log(ERR, "Cursor is not compatible with 100%-, ignoring cursor!"); @@ -453,7 +457,7 @@ void Events::listener_mapWindow(void* owner, void* data) { posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y; } else { posY = g_pInputManager->getMouseCoordsInternal().y - PMONITOR->vecPosition.y + - (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize.goal().y); + (!POSYSTR.contains('%') ? std::stoi(POSYSTR) : std::stof(POSYSTR.substr(0, POSYSTR.length() - 1)) * 0.01 * PWINDOW->m_vRealSize->goal().y); } } @@ -461,15 +465,15 @@ void Events::listener_mapWindow(void* owner, void* data) { int borderSize = PWINDOW->getRealBorderSize(); posX = std::clamp(posX, (int)(PMONITOR->vecReservedTopLeft.x + borderSize), - (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize.goal().x - borderSize)); + (int)(PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PWINDOW->m_vRealSize->goal().x - borderSize)); posY = std::clamp(posY, (int)(PMONITOR->vecReservedTopLeft.y + borderSize), - (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize.goal().y - borderSize)); + (int)(PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PWINDOW->m_vRealSize->goal().y - borderSize)); } Debug::log(LOG, "Rule move, applying to {}", PWINDOW); - PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition; + *PWINDOW->m_vRealPosition = Vector2D(posX, posY) + PMONITOR->vecPosition; PWINDOW->setHidden(false); } catch (...) { Debug::log(LOG, "Rule move failed, rule: {} -> {}", r->szRule, r->szValue); } @@ -481,7 +485,7 @@ void Events::listener_mapWindow(void* owner, void* data) { if (ARGS[1] == "1") RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f; - PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; + *PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize->goal() / 2.f + RESERVEDOFFSET; break; } @@ -491,7 +495,7 @@ void Events::listener_mapWindow(void* owner, void* data) { // set the pseudo size to the GOAL of our current size // because the windows are animated on RealSize - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal(); g_pCompositor->changeWindowZOrder(PWINDOW, true); } else { @@ -524,7 +528,7 @@ void Events::listener_mapWindow(void* owner, void* data) { } if (!setPseudo) - PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize.goal() - Vector2D(10, 10); + PWINDOW->m_vPseudoSize = PWINDOW->m_vRealSize->goal() - Vector2D(10, 10); } const auto PFOCUSEDWINDOWPREV = g_pCompositor->m_pLastWindow.lock(); @@ -554,11 +558,11 @@ void Events::listener_mapWindow(void* owner, void* data) { (!PWINDOW->isX11OverrideRedirect() || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->wantsFocus())) && !workspaceSilent && (!PFORCEFOCUS || PFORCEFOCUS == PWINDOW) && !g_pInputManager->isConstrained()) { g_pCompositor->focusWindow(PWINDOW); - PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PACTIVEALPHA); - PWINDOW->m_fDimPercent.setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); + PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PACTIVEALPHA); + PWINDOW->m_fDimPercent->setValueAndWarp(PWINDOW->m_sWindowData.noDim.valueOrDefault() ? 0.f : *PDIMSTRENGTH); } else { - PWINDOW->m_fActiveInactiveAlpha.setValueAndWarp(*PINACTIVEALPHA); - PWINDOW->m_fDimPercent.setValueAndWarp(0); + PWINDOW->m_fActiveInactiveAlpha->setValueAndWarp(*PINACTIVEALPHA); + PWINDOW->m_fDimPercent->setValueAndWarp(0); } if (requestedClientFSMode.has_value() && (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) @@ -571,8 +575,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWINDOW->m_pWorkspace->m_bHasFullscreenWindow) g_pCompositor->setWindowFullscreenInternal(PWINDOW->m_pWorkspace->getFullscreenWindow(), FSMODE_NONE); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); if (requestedFSState.has_value()) { PWINDOW->m_sWindowData.syncFullscreen = CWindowOverridableVar(false, PRIORITY_WINDOW_RULE); g_pCompositor->setWindowFullscreenState(PWINDOW, requestedFSState.value()); @@ -607,7 +611,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_bFirstMap = false; - Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition.goal(), PWINDOW->m_vRealSize.goal()); + Debug::log(LOG, "Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j}", PMONITOR->szName, PWINDOW->m_vRealPosition->goal(), PWINDOW->m_vRealSize->goal()); auto workspaceID = requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_szName; g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, workspaceID, PWINDOW->m_szClass, PWINDOW->m_szTitle)}); @@ -620,17 +624,17 @@ void Events::listener_mapWindow(void* owner, void* data) { // do animations g_pAnimationManager->onWindowPostCreateClose(PWINDOW, false); - PWINDOW->m_fAlpha.setValueAndWarp(0.f); - PWINDOW->m_fAlpha = 1.f; + PWINDOW->m_fAlpha->setValueAndWarp(0.f); + *PWINDOW->m_fAlpha = 1.f; - PWINDOW->m_vRealPosition.setCallbackOnEnd(setAnimToMove); - PWINDOW->m_vRealSize.setCallbackOnEnd(setAnimToMove); + PWINDOW->m_vRealPosition->setCallbackOnEnd(setVector2DAnimToMove); + PWINDOW->m_vRealSize->setCallbackOnEnd(setVector2DAnimToMove); // recalc the values for this window g_pCompositor->updateWindowAnimatedDecorationValues(PWINDOW); // avoid this window being visible if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen() && !PWINDOW->m_bIsFloating) - PWINDOW->m_fAlpha.setValueAndWarp(0.f); + PWINDOW->m_fAlpha->setValueAndWarp(0.f); g_pCompositor->setPreferredScaleForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->scale); g_pCompositor->setPreferredTransformForSurface(PWINDOW->m_pWLSurface->resource(), PMONITOR->transform); @@ -666,8 +670,8 @@ void Events::listener_unmapWindow(void* owner, void* data) { const auto PMONITOR = PWINDOW->m_pMonitor.lock(); if (PMONITOR) { - PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition.value() - PMONITOR->vecPosition; - PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize.value(); + PWINDOW->m_vOriginalClosedPos = PWINDOW->m_vRealPosition->value() - PMONITOR->vecPosition; + PWINDOW->m_vOriginalClosedSize = PWINDOW->m_vRealSize->value(); PWINDOW->m_eOriginalClosedExtents = PWINDOW->getFullWindowExtents(); } @@ -757,12 +761,12 @@ void Events::listener_unmapWindow(void* owner, void* data) { g_pCompositor->addToFadingOutSafe(PWINDOW); - if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it + if (!PWINDOW->m_bX11DoesntWantBorders) // don't animate out if they weren't animated in. + *PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition->value() + Vector2D(0.01f, 0.01f); // it has to be animated, otherwise onWindowPostCreateClose will ignore it // anims g_pAnimationManager->onWindowPostCreateClose(PWINDOW, true); - PWINDOW->m_fAlpha = 0.f; + *PWINDOW->m_fAlpha = 0.f; // recheck idle inhibitors g_pInputManager->recheckIdleInhibitorStatus(); @@ -812,7 +816,7 @@ void Events::listener_commitWindow(void* owner, void* data) { g_pSeatManager->isPointerFrameSkipped = false; g_pSeatManager->isPointerFrameCommit = false; } else - g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y, + g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition->goal().x, PWINDOW->m_vRealPosition->goal().y, PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0); if (g_pSeatManager->isPointerFrameSkipped) { @@ -903,8 +907,8 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { if (!PWINDOW->m_bIsMapped || !PWINDOW->m_pXWaylandSurface || !PWINDOW->m_pXWaylandSurface->overrideRedirect) return; - const auto POS = PWINDOW->m_vRealPosition.goal(); - const auto SIZ = PWINDOW->m_vRealSize.goal(); + const auto POS = PWINDOW->m_vRealPosition->goal(); + const auto SIZ = PWINDOW->m_vRealSize->goal(); if (PWINDOW->m_pXWaylandSurface->geometry.size() > Vector2D{1, 1}) PWINDOW->setHidden(false); @@ -912,7 +916,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal(), true); + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); g_pHyprRenderer->damageWindow(PWINDOW); return; } @@ -926,27 +930,27 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { Debug::log(LOG, "Unmanaged window {} requests geometry update to {:j} {:j}", PWINDOW, LOGICALPOS, PWINDOW->m_pXWaylandSurface->geometry.size()); g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); + PWINDOW->m_vRealPosition->setValueAndWarp(Vector2D(LOGICALPOS.x, LOGICALPOS.y)); if (abs(std::floor(SIZ.x) - PWINDOW->m_pXWaylandSurface->geometry.w) > 2 || abs(std::floor(SIZ.y) - PWINDOW->m_pXWaylandSurface->geometry.h) > 2) - PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); + PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_pXWaylandSurface->geometry.size()); if (*PXWLFORCESCALEZERO) { if (const auto PMONITOR = PWINDOW->m_pMonitor.lock(); PMONITOR) { - PWINDOW->m_vRealSize.setValueAndWarp(PWINDOW->m_vRealSize.goal() / PMONITOR->scale); + PWINDOW->m_vRealSize->setValueAndWarp(PWINDOW->m_vRealSize->goal() / PMONITOR->scale); } } - PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); - PWINDOW->m_vSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal(); + PWINDOW->m_vSize = PWINDOW->m_vRealSize->goal(); - PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition.value() + PWINDOW->m_vRealSize.value() / 2.f)->activeWorkspace; + PWINDOW->m_pWorkspace = g_pCompositor->getMonitorFromVector(PWINDOW->m_vRealPosition->value() + PWINDOW->m_vRealSize->value() / 2.f)->activeWorkspace; g_pCompositor->changeWindowZOrder(PWINDOW, true); PWINDOW->updateWindowDecos(); g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition.goal(); - PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize.goal(); + PWINDOW->m_vReportedPosition = PWINDOW->m_vRealPosition->goal(); + PWINDOW->m_vPendingReportedSize = PWINDOW->m_vRealSize->goal(); } } diff --git a/src/helpers/AnimatedVariable.cpp b/src/helpers/AnimatedVariable.cpp deleted file mode 100644 index ab5643a6..00000000 --- a/src/helpers/AnimatedVariable.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "AnimatedVariable.hpp" -#include "../managers/AnimationManager.hpp" -#include "../config/ConfigManager.hpp" - -CBaseAnimatedVariable::CBaseAnimatedVariable(eAnimatedVarType type) : m_Type(type) { - ; // dummy var -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pWindow = pWindow; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pLayer = pLayer; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - m_pWorkspace = pWorkspace; - - m_bDummy = false; -} - -void CBaseAnimatedVariable::create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { - m_eDamagePolicy = policy; - m_pConfig = pAnimConfig; - - m_bDummy = false; -} - -CBaseAnimatedVariable::~CBaseAnimatedVariable() { - unregister(); -} - -void CBaseAnimatedVariable::unregister() { - if (!g_pAnimationManager) - return; - std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; }); - m_bIsRegistered = false; - disconnectFromActive(); -} - -void CBaseAnimatedVariable::registerVar() { - if (!m_bIsRegistered) - g_pAnimationManager->m_vAnimatedVariables.push_back(this); - m_bIsRegistered = true; -} - -float CBaseAnimatedVariable::getPercent() { - const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::steady_clock::now() - animationBegin).count(); - return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f); -} - -float CBaseAnimatedVariable::getCurveValue() { - if (!m_bIsBeingAnimated) - return 1.f; - - const auto SPENT = getPercent(); - - if (SPENT >= 1.f) - return 1.f; - - return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT); -} - -void CBaseAnimatedVariable::connectToActive() { - g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up - - if (!m_bIsConnectedToActive) - g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this); - - m_bIsConnectedToActive = true; -} - -void CBaseAnimatedVariable::disconnectFromActive() { - std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; }); - m_bIsConnectedToActive = false; -} diff --git a/src/helpers/AnimatedVariable.hpp b/src/helpers/AnimatedVariable.hpp index a1da00da..e7d5fd8c 100644 --- a/src/helpers/AnimatedVariable.hpp +++ b/src/helpers/AnimatedVariable.hpp @@ -1,15 +1,18 @@ #pragma once -#include -#include -#include -#include -#include "math/Math.hpp" +#include + #include "Color.hpp" #include "../defines.hpp" -#include "../debug/Log.hpp" #include "../desktop/DesktopTypes.hpp" +enum eAVarDamagePolicy : int8_t { + AVARDAMAGE_NONE = -1, + AVARDAMAGE_ENTIRE = 0, + AVARDAMAGE_BORDER, + AVARDAMAGE_SHADOW +}; + enum eAnimatedVarType : int8_t { AVARTYPE_INVALID = -1, AVARTYPE_FLOAT, @@ -42,20 +45,6 @@ struct STypeToAnimatedVarType_t { template inline constexpr eAnimatedVarType typeToeAnimatedVarType = STypeToAnimatedVarType_t::value; -enum eAVarDamagePolicy : int8_t { - AVARDAMAGE_NONE = -1, - AVARDAMAGE_ENTIRE = 0, - AVARDAMAGE_BORDER, - AVARDAMAGE_SHADOW -}; - -class CAnimationManager; -struct SAnimationPropertyConfig; -class CHyprRenderer; -class CWindow; -class CWorkspace; -class CLayerSurface; - // Utility to define a concept as a list of possible type template concept OneOf = (... or std::same_as); @@ -66,245 +55,19 @@ concept OneOf = (... or std::same_as); template concept Animable = OneOf; -class CBaseAnimatedVariable { - public: - CBaseAnimatedVariable(eAnimatedVarType type); - void create(SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy); - void create(SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy); +struct SAnimationContext { + PHLWINDOWREF pWindow; + PHLWORKSPACEREF pWorkspace; + PHLLSREF pLayer; - CBaseAnimatedVariable(const CBaseAnimatedVariable&) = delete; - CBaseAnimatedVariable(CBaseAnimatedVariable&&) = delete; - CBaseAnimatedVariable& operator=(const CBaseAnimatedVariable&) = delete; - CBaseAnimatedVariable& operator=(CBaseAnimatedVariable&&) = delete; - - virtual ~CBaseAnimatedVariable(); - - void unregister(); - void registerVar(); - - virtual void warp(bool endCallback = true) = 0; - - // - void setConfig(SAnimationPropertyConfig* pConfig) { - m_pConfig = pConfig; - } - - SAnimationPropertyConfig* getConfig() { - return m_pConfig; - } - - /* returns the spent (completion) % */ - float getPercent(); - - /* returns the current curve value */ - float getCurveValue(); - - // checks if an animation is in progress - bool isBeingAnimated() const { - return m_bIsBeingAnimated; - } - - /* sets a function to be ran when the animation finishes. - if an animation is not running, runs instantly. - if "remove" is set to true, will remove the callback when ran. */ - void setCallbackOnEnd(std::function func, bool remove = true) { - m_fEndCallback = std::move(func); - m_bRemoveEndAfterRan = remove; - - if (!isBeingAnimated()) - onAnimationEnd(); - } - - /* sets a function to be ran when an animation is started. - if "remove" is set to true, will remove the callback when ran. */ - void setCallbackOnBegin(std::function func, bool remove = true) { - m_fBeginCallback = std::move(func); - m_bRemoveBeginAfterRan = remove; - } - - /* Sets the update callback, called every time the value is animated and a step is done - Warning: calling unregisterVar/registerVar in this handler will cause UB */ - void setUpdateCallback(std::function func) { - m_fUpdateCallback = std::move(func); - } - - /* resets all callbacks. Does not call any. */ - void resetAllCallbacks() { - m_fBeginCallback = nullptr; - m_fEndCallback = nullptr; - m_fUpdateCallback = nullptr; - m_bRemoveBeginAfterRan = false; - m_bRemoveEndAfterRan = false; - } - - PHLWINDOW getWindow() { - return m_pWindow.lock(); - } - - protected: - PHLWINDOWREF m_pWindow; - PHLWORKSPACEREF m_pWorkspace; - PHLLSREF m_pLayer; - - SAnimationPropertyConfig* m_pConfig = nullptr; - - bool m_bDummy = true; - bool m_bIsRegistered = false; - bool m_bIsBeingAnimated = false; - - std::chrono::steady_clock::time_point animationBegin; - - eAVarDamagePolicy m_eDamagePolicy = AVARDAMAGE_NONE; - eAnimatedVarType m_Type; - - bool m_bRemoveEndAfterRan = true; - bool m_bRemoveBeginAfterRan = true; - std::function m_fEndCallback; - std::function m_fBeginCallback; - std::function m_fUpdateCallback; - - bool m_bIsConnectedToActive = false; - - void connectToActive(); - - void disconnectFromActive(); - - // methods - void onAnimationEnd() { - m_bIsBeingAnimated = false; - disconnectFromActive(); - - if (m_fEndCallback) { - // loading m_bRemoveEndAfterRan before calling the callback allows the callback to delete this animation safely if it is false. - auto removeEndCallback = m_bRemoveEndAfterRan; - m_fEndCallback(this); - if (removeEndCallback) - m_fEndCallback = nullptr; // reset - } - } - - void onAnimationBegin() { - m_bIsBeingAnimated = true; - connectToActive(); - - if (m_fBeginCallback) { - m_fBeginCallback(this); - if (m_bRemoveBeginAfterRan) - m_fBeginCallback = nullptr; // reset - } - } - - friend class CAnimationManager; - friend class CWorkspace; - friend class CLayerSurface; - friend class CHyprRenderer; + eAVarDamagePolicy eDamagePolicy = AVARDAMAGE_NONE; }; template -class CAnimatedVariable : public CBaseAnimatedVariable { - public: - CAnimatedVariable() : CBaseAnimatedVariable(typeToeAnimatedVarType) { - ; - } // dummy var +using CAnimatedVariable = Hyprutils::Animation::CGenericAnimatedVariable; - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { - create(pAnimConfig, pWindow, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLLS pLayer, eAVarDamagePolicy policy) { - create(pAnimConfig, pLayer, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { - create(pAnimConfig, pWorkspace, policy); - m_Value = value; - m_Goal = value; - } - void create(const VarType& value, SAnimationPropertyConfig* pAnimConfig, eAVarDamagePolicy policy) { - create(pAnimConfig, policy); - m_Value = value; - m_Goal = value; - } +template +using PHLANIMVAR = SP>; - using CBaseAnimatedVariable::create; - - CAnimatedVariable(const CAnimatedVariable&) = delete; - CAnimatedVariable(CAnimatedVariable&&) = delete; - CAnimatedVariable& operator=(const CAnimatedVariable&) = delete; - CAnimatedVariable& operator=(CAnimatedVariable&&) = delete; - - ~CAnimatedVariable() = default; - - // gets the current vector value (real time) - const VarType& value() const { - return m_Value; - } - - // gets the goal vector value - const VarType& goal() const { - return m_Goal; - } - - CAnimatedVariable& operator=(const VarType& v) { - if (v == m_Goal) - return *this; - - m_Goal = v; - animationBegin = std::chrono::steady_clock::now(); - m_Begun = m_Value; - - onAnimationBegin(); - - return *this; - } - - // Sets the actual stored value, without affecting the goal, but resets the timer - void setValue(const VarType& v) { - if (v == m_Value) - return; - - m_Value = v; - animationBegin = std::chrono::steady_clock::now(); - m_Begun = m_Value; - - onAnimationBegin(); - } - - // Sets the actual value and goal - void setValueAndWarp(const VarType& v) { - m_Goal = v; - m_bIsBeingAnimated = true; - warp(); - } - - void warp(bool endCallback = true) override { - if (!m_bIsBeingAnimated) - return; - - m_Value = m_Goal; - - m_bIsBeingAnimated = false; - - if (m_fUpdateCallback) - m_fUpdateCallback(this); - - if (endCallback) - onAnimationEnd(); - } - - private: - VarType m_Value{}; - VarType m_Goal{}; - VarType m_Begun{}; - - // owners - - friend class CAnimationManager; - friend class CWorkspace; - friend class CLayerSurface; - friend class CHyprRenderer; -}; +template +using PHLANIMVARREF = WP>; diff --git a/src/helpers/BezierCurve.cpp b/src/helpers/BezierCurve.cpp deleted file mode 100644 index a0610fc9..00000000 --- a/src/helpers/BezierCurve.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "BezierCurve.hpp" -#include "../debug/Log.hpp" -#include "../macros.hpp" - -#include -#include - -void CBezierCurve::setup(std::vector* pVec) { - const auto BEGIN = std::chrono::high_resolution_clock::now(); - - // Avoid reallocations by reserving enough memory upfront - m_vPoints.resize(pVec->size() + 2); - m_vPoints[0] = Vector2D(0, 0); // Start point - size_t index = 1; // Start after the first element - for (const auto& vec : *pVec) { - if (index < m_vPoints.size() - 1) { // Bounds check to ensure safety - m_vPoints[index] = vec; - ++index; - } - } - m_vPoints.back() = Vector2D(1, 1); // End point - - RASSERT(m_vPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_vPoints.size()); - - // bake BAKEDPOINTS points for faster lookups - // T -> X ( / BAKEDPOINTS ) - for (int i = 0; i < BAKEDPOINTS; ++i) { - float const t = (i + 1) / (float)BAKEDPOINTS; - m_aPointsBaked[i] = Vector2D(getXForT(t), getYForT(t)); - } - - const auto ELAPSEDUS = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f; - const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f; - - const auto BEGINCALC = std::chrono::high_resolution_clock::now(); - for (int j = 1; j < 10; ++j) { - float i = j / 10.0f; - getYForPoint(i); - } - const auto ELAPSEDCALCAVG = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f; - - Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE, - ELAPSEDUS, ELAPSEDCALCAVG); -} - -float CBezierCurve::getXForT(float const& t) const { - float t2 = t * t; - float t3 = t2 * t; - - return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].x + 3 * t2 * (1 - t) * m_vPoints[2].x + t3 * m_vPoints[3].x; -} - -float CBezierCurve::getYForT(float const& t) const { - float t2 = t * t; - float t3 = t2 * t; - - return 3 * t * (1 - t) * (1 - t) * m_vPoints[1].y + 3 * t2 * (1 - t) * m_vPoints[2].y + t3 * m_vPoints[3].y; -} - -// Todo: this probably can be done better and faster -float CBezierCurve::getYForPoint(float const& x) const { - if (x >= 1.f) - return 1.f; - if (x <= 0.f) - return 0.f; - - int index = 0; - bool below = true; - for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) { - if (below) - index += step; - else - index -= step; - - below = m_aPointsBaked[index].x < x; - } - - int lowerIndex = index - (!below || index == BAKEDPOINTS - 1); - - // in the name of performance i shall make a hack - const auto LOWERPOINT = &m_aPointsBaked[lowerIndex]; - const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1]; - - const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x); - - if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x - return 0.f; - - return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA; -} diff --git a/src/helpers/BezierCurve.hpp b/src/helpers/BezierCurve.hpp deleted file mode 100644 index e643fb41..00000000 --- a/src/helpers/BezierCurve.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include -#include "math/Math.hpp" - -constexpr int BAKEDPOINTS = 255; -constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS; - -// an implementation of a cubic bezier curve -// might do better later -class CBezierCurve { - public: - // sets up the bezier curve. - // this EXCLUDES the 0,0 and 1,1 points, - void setup(std::vector* points); - - float getYForT(float const& t) const; - float getXForT(float const& t) const; - float getYForPoint(float const& x) const; - - private: - // this INCLUDES the 0,0 and 1,1 points. - std::vector m_vPoints; - - std::array m_aPointsBaked; -}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 76df00b3..e833e661 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1127,16 +1127,16 @@ void CMonitor::setSpecialWorkspace(const PHLWORKSPACE& pWorkspace) { if (w->m_bIsFloating && !VECINRECT(MIDDLE, vecPosition.x, vecPosition.y, vecPosition.x + vecSize.x, vecPosition.y + vecSize.y) && !w->isX11OverrideRedirect()) { // if it's floating and the middle isnt on the current mon, move it to the center const auto PMONFROMMIDDLE = g_pCompositor->getMonitorFromVector(MIDDLE); - Vector2D pos = w->m_vRealPosition.goal(); + Vector2D pos = w->m_vRealPosition->goal(); if (!VECINRECT(MIDDLE, PMONFROMMIDDLE->vecPosition.x, PMONFROMMIDDLE->vecPosition.y, PMONFROMMIDDLE->vecPosition.x + PMONFROMMIDDLE->vecSize.x, PMONFROMMIDDLE->vecPosition.y + PMONFROMMIDDLE->vecSize.y)) { // not on any monitor, center - pos = middle() / 2.f - w->m_vRealSize.goal() / 2.f; + pos = middle() / 2.f - w->m_vRealSize->goal() / 2.f; } else pos = pos - PMONFROMMIDDLE->vecPosition + vecPosition; - w->m_vRealPosition = pos; - w->m_vPosition = pos; + *w->m_vRealPosition = pos; + w->m_vPosition = pos; } } } diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index 0a6ef55d..b6e3ac12 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -5,7 +5,6 @@ #include "../desktop/Window.hpp" #include "../desktop/Subsurface.hpp" #include "../desktop/Popup.hpp" -#include "AnimatedVariable.hpp" #include "../desktop/WLSurface.hpp" #include "signal/Signal.hpp" #include "math/Math.hpp" diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index d3cd8273..5e0dcf5e 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -3,13 +3,13 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../render/pass/TexPassElement.hpp" +#include "../managers/AnimationManager.hpp" #include -using namespace Hyprutils::Utils; +using namespace Hyprutils::Animation; CHyprError::CHyprError() { - m_fFadeOpacity.create(AVARTYPE_FLOAT, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); - m_fFadeOpacity.registerVar(); + g_pAnimationManager->createAnimation(0.f, m_fFadeOpacity, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), AVARDAMAGE_NONE); static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { if (!m_bIsCreated) @@ -23,16 +23,14 @@ CHyprError::CHyprError() { if (!m_bIsCreated) return; - if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) + if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); }); m_pTexture = makeShared(); } -CHyprError::~CHyprError() { - m_fFadeOpacity.unregister(); -} +CHyprError::~CHyprError() = default; void CHyprError::queueCreate(std::string message, const CHyprColor& color) { m_szQueued = message; @@ -43,10 +41,10 @@ void CHyprError::createQueued() { if (m_bIsCreated) m_pTexture->destroyTexture(); - m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); + m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); - m_fFadeOpacity.setValueAndWarp(0.f); - m_fFadeOpacity = 1.f; + m_fFadeOpacity->setValueAndWarp(0.f); + *m_fFadeOpacity = 1.f; const auto PMONITOR = g_pCompositor->m_vMonitors.front(); @@ -176,8 +174,8 @@ void CHyprError::draw() { } if (m_bQueuedDestroy) { - if (!m_fFadeOpacity.isBeingAnimated()) { - if (m_fFadeOpacity.value() == 0.f) { + if (!m_fFadeOpacity->isBeingAnimated()) { + if (m_fFadeOpacity->value() == 0.f) { m_bQueuedDestroy = false; m_pTexture->destroyTexture(); m_bIsCreated = false; @@ -189,8 +187,8 @@ void CHyprError::draw() { return; } else { - m_fFadeOpacity.setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); - m_fFadeOpacity = 0.f; + m_fFadeOpacity->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); + *m_fFadeOpacity = 0.f; } } } @@ -202,7 +200,7 @@ void CHyprError::draw() { m_bDamageBox.x = (int)PMONITOR->vecPosition.x; m_bDamageBox.y = (int)PMONITOR->vecPosition.y; - if (m_fFadeOpacity.isBeingAnimated() || m_bMonitorChanged) + if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) g_pHyprRenderer->damageBox(&m_bDamageBox); m_bMonitorChanged = false; @@ -210,7 +208,7 @@ void CHyprError::draw() { CTexPassElement::SRenderData data; data.tex = m_pTexture; data.box = monbox; - data.a = m_fFadeOpacity.value(); + data.a = m_fFadeOpacity->value(); g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 042dccd0..9a662423 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -19,17 +19,17 @@ class CHyprError { float height(); // logical private: - void createQueued(); - std::string m_szQueued = ""; - CHyprColor m_cQueued; - bool m_bQueuedDestroy = false; - bool m_bIsCreated = false; - SP m_pTexture; - CAnimatedVariable m_fFadeOpacity; - CBox m_bDamageBox = {0, 0, 0, 0}; - float m_fLastHeight = 0.F; + void createQueued(); + std::string m_szQueued = ""; + CHyprColor m_cQueued; + bool m_bQueuedDestroy = false; + bool m_bIsCreated = false; + SP m_pTexture; + PHLANIMVAR m_fFadeOpacity; + CBox m_bDamageBox = {0, 0, 0, 0}; + float m_fLastHeight = 0.F; - bool m_bMonitorChanged = false; + bool m_bMonitorChanged = false; }; inline std::unique_ptr g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time. diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index dc6e37dd..2ee41eba 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -192,16 +192,16 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealSize = wb.size(); - PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } @@ -209,8 +209,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for if (force) { g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); g_pHyprRenderer->damageWindow(PWINDOW); } @@ -508,8 +508,8 @@ void CHyprDwindleLayout::calculateWorkspace(const PHLWORKSPACE& pWorkspace) { const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { - PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; - PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; + *PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; + *PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SDwindleNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; @@ -554,8 +554,8 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = - (PWINDOW->m_vRealSize.goal() + pixResize) + *PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize->goal() + pixResize) .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; @@ -575,7 +575,7 @@ void CHyprDwindleLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorn if (!m_PseudoDragFlags.started) { m_PseudoDragFlags.started = true; - const auto pseudoSize = PWINDOW->m_vRealSize.goal(); + const auto pseudoSize = PWINDOW->m_vRealSize->goal(); const auto mouseOffset = g_pInputManager->getMouseCoordsInternal() - (PNODE->box.pos() + ((PNODE->box.size() / 2) - (pseudoSize / 2))); if (mouseOffset.x > 0 && mouseOffset.x < pseudoSize.x && mouseOffset.y > 0 && mouseOffset.y < pseudoSize.y) { @@ -743,10 +743,10 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu // save position and size if floating if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { - pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); - pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vSize = pWindow->m_vRealSize.goal(); + pWindow->m_vLastFloatingSize = pWindow->m_vRealSize->goal(); + pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vSize = pWindow->m_vRealSize->goal(); } if (EFFECTIVE_MODE == FSMODE_NONE) { @@ -756,8 +756,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu applyNodeDataToWindow(PNODE); else { // get back its' dimensions from position and size - pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; - pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; + *pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; + *pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); @@ -765,8 +765,8 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFu } else { // apply new pos and size being monitors' box if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { - pWindow->m_vRealPosition = PMONITOR->vecPosition; - pWindow->m_vRealSize = PMONITOR->vecSize; + *pWindow->m_vRealPosition = PMONITOR->vecPosition; + *pWindow->m_vRealSize = PMONITOR->vecSize; } else { // This is a massive hack. // We make a fake "only" node and apply diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index f875b99c..eeebd815 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -106,7 +106,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { const auto PWINDOWSURFACE = pWindow->m_pWLSurface->resource(); - pWindow->m_vRealSize = PWINDOWSURFACE->current.size; + *pWindow->m_vRealSize = PWINDOWSURFACE->current.size; if ((desiredGeometry.width <= 1 || desiredGeometry.height <= 1) && pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { // XDG windows should be fine. TODO: check for weird atoms? @@ -115,23 +115,23 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } // reject any windows with size <= 5x5 - if (pWindow->m_vRealSize.goal().x <= 5 || pWindow->m_vRealSize.goal().y <= 5) - pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; + if (pWindow->m_vRealSize->goal().x <= 5 || pWindow->m_vRealSize->goal().y <= 5) + *pWindow->m_vRealSize = PMONITOR->vecSize / 2.f; if (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect()) { if (pWindow->m_pXWaylandSurface->geometry.x != 0 && pWindow->m_pXWaylandSurface->geometry.y != 0) - pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); + *pWindow->m_vRealPosition = g_pXWaylandManager->xwaylandToWaylandCoords(pWindow->m_pXWaylandSurface->geometry.pos()); else - pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f, - PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f); + *pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize->goal().x) / 2.f, + PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize->goal().y) / 2.f); } else { - pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize.goal().x) / 2.f, - PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize.goal().y) / 2.f); + *pWindow->m_vRealPosition = Vector2D(PMONITOR->vecPosition.x + (PMONITOR->vecSize.x - pWindow->m_vRealSize->goal().x) / 2.f, + PMONITOR->vecPosition.y + (PMONITOR->vecSize.y - pWindow->m_vRealSize->goal().y) / 2.f); } } else { // we respect the size. - pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + *pWindow->m_vRealSize = Vector2D(desiredGeometry.width, desiredGeometry.height); // check if it's on the correct monitor! Vector2D middlePoint = Vector2D(desiredGeometry.x, desiredGeometry.y) + Vector2D(desiredGeometry.width, desiredGeometry.height) / 2.f; @@ -150,35 +150,35 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_bIsX11) { // if the pos isn't set, fall back to the center placement if it's not a child, otherwise middle of parent if available if (!pWindow->m_bIsX11 && pWindow->m_pXDGSurface->toplevel->parent && validMapped(pWindow->m_pXDGSurface->toplevel->parent->window)) - pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition.goal() + - pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize.goal() / 2.F - desiredGeometry.size() / 2.F; + *pWindow->m_vRealPosition = pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealPosition->goal() + + pWindow->m_pXDGSurface->toplevel->parent->window->m_vRealSize->goal() / 2.F - desiredGeometry.size() / 2.F; else - pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F; + *pWindow->m_vRealPosition = PMONITOR->vecPosition + PMONITOR->vecSize / 2.F - desiredGeometry.size() / 2.F; } else { // if it is, we respect where it wants to put itself, but apply monitor offset if outside // most of these are popups if (const auto POPENMON = g_pCompositor->getMonitorFromVector(middlePoint); POPENMON->ID != PMONITOR->ID) - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; + *pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y) - POPENMON->vecPosition + PMONITOR->vecPosition; else - pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); + *pWindow->m_vRealPosition = Vector2D(desiredGeometry.x, desiredGeometry.y); } } if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11) - pWindow->m_vRealSize = pWindow->m_vRealSize.goal() / PMONITOR->scale; + *pWindow->m_vRealSize = pWindow->m_vRealSize->goal() / PMONITOR->scale; if (pWindow->m_bX11DoesntWantBorders || (pWindow->m_bIsX11 && pWindow->isX11OverrideRedirect())) { - pWindow->m_vRealPosition.warp(); - pWindow->m_vRealSize.warp(); + pWindow->m_vRealPosition->warp(); + pWindow->m_vRealSize->warp(); } if (!pWindow->isX11OverrideRedirect()) { - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize->goal()); g_pCompositor->changeWindowZOrder(pWindow, true); } else { - pWindow->m_vPendingReportedSize = pWindow->m_vRealSize.goal(); + pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal(); pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; } } @@ -250,18 +250,18 @@ void IHyprLayout::onBeginDragWindow() { if (!DRAGGINGWINDOW->m_bIsFloating) { if (g_pInputManager->dragMode == MBIND_MOVE) { - DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize.goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor(); + DRAGGINGWINDOW->m_vLastFloatingSize = (DRAGGINGWINDOW->m_vRealSize->goal() * 0.8489).clamp(Vector2D{5, 5}, Vector2D{}).floor(); changeWindowFloatingMode(DRAGGINGWINDOW); DRAGGINGWINDOW->m_bIsFloating = true; DRAGGINGWINDOW->m_bDraggingTiled = true; - DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize.goal() / 2.f; + *DRAGGINGWINDOW->m_vRealPosition = g_pInputManager->getMouseCoordsInternal() - DRAGGINGWINDOW->m_vRealSize->goal() / 2.f; } } m_vBeginDragXY = g_pInputManager->getMouseCoordsInternal(); - m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition.goal(); - m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize.goal(); + m_vBeginDragPositionXY = DRAGGINGWINDOW->m_vRealPosition->goal(); + m_vBeginDragSizeXY = DRAGGINGWINDOW->m_vRealSize->goal(); m_vLastDragXY = m_vBeginDragXY; // get the grab corner @@ -348,10 +348,10 @@ void IHyprLayout::onEndDragWindow() { if (DRAGGINGWINDOW->m_sGroupData.pNextWindow) { PHLWINDOW next = DRAGGINGWINDOW->m_sGroupData.pNextWindow.lock(); while (next != DRAGGINGWINDOW) { - next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members - next->m_vRealSize = pWindow->m_vRealSize.goal(); // match the size of group members - next->m_vRealPosition = pWindow->m_vRealPosition.goal(); // match the position of group members - next = next->m_sGroupData.pNextWindow.lock(); + next->m_bIsFloating = pWindow->m_bIsFloating; // match the floating state of group members + *next->m_vRealSize = pWindow->m_vRealSize->goal(); // match the size of group members + *next->m_vRealPosition = pWindow->m_vRealPosition->goal(); // match the position of group members + next = next->m_sGroupData.pNextWindow.lock(); } } @@ -360,7 +360,7 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_bDraggingTiled = false; if (pWindow->m_bIsFloating) - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize.goal()); // match the size of the window + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize->goal()); // match the size of the window static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); @@ -593,7 +593,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (g_pInputManager->dragMode == MBIND_MOVE) { Vector2D newPos = m_vBeginDragPositionXY + DELTA; - Vector2D newSize = DRAGGINGWINDOW->m_vRealSize.goal(); + Vector2D newSize = DRAGGINGWINDOW->m_vRealSize->goal(); if (*SNAPENABLED && !DRAGGINGWINDOW->m_bDraggingTiled) performSnap(newPos, newSize, DRAGGINGWINDOW, MBIND_MOVE, -1, m_vBeginDragSizeXY); @@ -602,11 +602,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { wb.round(); if (*PANIMATEMOUSE) - DRAGGINGWINDOW->m_vRealPosition = wb.pos(); + *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); else - DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { @@ -671,21 +671,21 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { wb.round(); if (*PANIMATE) { - DRAGGINGWINDOW->m_vRealSize = wb.size(); - DRAGGINGWINDOW->m_vRealPosition = wb.pos(); + *DRAGGINGWINDOW->m_vRealSize = wb.size(); + *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); } else { - DRAGGINGWINDOW->m_vRealSize.setValueAndWarp(wb.size()); - DRAGGINGWINDOW->m_vRealPosition.setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size()); + DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); } - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize.goal()); + g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); } } // get middle point - Vector2D middle = DRAGGINGWINDOW->m_vRealPosition.value() + DRAGGINGWINDOW->m_vRealSize.value() / 2.f; + Vector2D middle = DRAGGINGWINDOW->m_vRealPosition->value() + DRAGGINGWINDOW->m_vRealSize->value() / 2.f; // and check its monitor const auto PMONITOR = g_pCompositor->getMonitorFromVector(middle); @@ -719,7 +719,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { EMIT_HOOK_EVENT("changeFloatingMode", pWindow); if (!TILED) { - const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition.value() + pWindow->m_vRealSize.value() / 2.f); + const auto PNEWMON = g_pCompositor->getMonitorFromVector(pWindow->m_vRealPosition->value() + pWindow->m_vRealSize->value() / 2.f); pWindow->m_pMonitor = PNEWMON; pWindow->moveToWorkspace(PNEWMON->activeSpecialWorkspace ? PNEWMON->activeSpecialWorkspace : PNEWMON->activeWorkspace); pWindow->updateGroupOutputs(); @@ -730,12 +730,12 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); // save real pos cuz the func applies the default 5,5 mid - const auto PSAVEDPOS = pWindow->m_vRealPosition.goal(); - const auto PSAVEDSIZE = pWindow->m_vRealSize.goal(); + const auto PSAVEDPOS = pWindow->m_vRealPosition->goal(); + const auto PSAVEDSIZE = pWindow->m_vRealSize->goal(); // if the window is pseudo, update its size if (!pWindow->m_bDraggingTiled) - pWindow->m_vPseudoSize = pWindow->m_vRealSize.goal(); + pWindow->m_vPseudoSize = pWindow->m_vRealSize->goal(); pWindow->m_vLastFloatingSize = PSAVEDSIZE; @@ -744,8 +744,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { onWindowCreatedTiling(pWindow); - pWindow->m_vRealPosition.setValue(PSAVEDPOS); - pWindow->m_vRealSize.setValue(PSAVEDSIZE); + pWindow->m_vRealPosition->setValue(PSAVEDPOS); + pWindow->m_vRealSize->setValue(PSAVEDSIZE); // fix pseudo leaving artifacts g_pHyprRenderer->damageMonitor(pWindow->m_pMonitor.lock()); @@ -757,16 +757,16 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->changeWindowZOrder(pWindow, true); - CBox wb = {pWindow->m_vRealPosition.goal() + (pWindow->m_vRealSize.goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; + CBox wb = {pWindow->m_vRealPosition->goal() + (pWindow->m_vRealSize->goal() - pWindow->m_vLastFloatingSize) / 2.f, pWindow->m_vLastFloatingSize}; wb.round(); - if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize.value().x, pWindow->m_vLastFloatingSize.x, 10) && - DELTALESSTHAN(pWindow->m_vRealSize.value().y, pWindow->m_vLastFloatingSize.y, 10)) { + if (!(pWindow->m_bIsFloating && pWindow->m_bIsPseudotiled) && DELTALESSTHAN(pWindow->m_vRealSize->value().x, pWindow->m_vLastFloatingSize.x, 10) && + DELTALESSTHAN(pWindow->m_vRealSize->value().y, pWindow->m_vLastFloatingSize.y, 10)) { wb = {wb.pos() + Vector2D{10, 10}, wb.size() - Vector2D{20, 20}}; } - pWindow->m_vRealPosition = wb.pos(); - pWindow->m_vRealSize = wb.size(); + *pWindow->m_vRealPosition = wb.pos(); + *pWindow->m_vRealSize = wb.size(); pWindow->m_vSize = wb.pos(); pWindow->m_vPosition = wb.size(); @@ -798,7 +798,7 @@ void IHyprLayout::moveActiveWindow(const Vector2D& delta, PHLWINDOW pWindow) { PWINDOW->setAnimationsToMove(); - PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition.goal() + delta; + *PWINDOW->m_vRealPosition = PWINDOW->m_vRealPosition->goal() + delta; g_pHyprRenderer->damageWindow(PWINDOW); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 225246f0..e6e22326 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -301,8 +301,8 @@ void CHyprMasterLayout::calculateWorkspace(PHLWORKSPACE pWorkspace) { const auto PFULLWINDOW = pWorkspace->getFullscreenWindow(); if (pWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { - PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; - PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; + *PFULLWINDOW->m_vRealPosition = PMONITOR->vecPosition; + *PFULLWINDOW->m_vRealSize = PMONITOR->vecSize; } else if (pWorkspace->m_efFullscreenMode == FSMODE_MAXIMIZED) { SMasterNodeData fakeNode; fakeNode.pWindow = PFULLWINDOW; @@ -672,16 +672,16 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess - PWINDOW->m_vRealPosition = wb.pos(); - PWINDOW->m_vRealSize = wb.size(); + *PWINDOW->m_vRealPosition = wb.pos(); + *PWINDOW->m_vRealSize = wb.size(); g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); } @@ -689,8 +689,8 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { if (m_bForceWarps && !*PANIMATE) { g_pHyprRenderer->damageWindow(PWINDOW); - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); g_pHyprRenderer->damageWindow(PWINDOW); } @@ -711,8 +711,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne const auto PNODE = getNodeFromWindow(PWINDOW); if (!PNODE) { - PWINDOW->m_vRealSize = - (PWINDOW->m_vRealSize.goal() + pixResize) + *PWINDOW->m_vRealSize = + (PWINDOW->m_vRealSize->goal() + pixResize) .clamp(PWINDOW->m_sWindowData.minSize.valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}), PWINDOW->m_sWindowData.maxSize.valueOr(Vector2D{INFINITY, INFINITY})); PWINDOW->updateWindowDecos(); return; @@ -852,10 +852,10 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul // save position and size if floating if (pWindow->m_bIsFloating && CURRENT_EFFECTIVE_MODE == FSMODE_NONE) { - pWindow->m_vLastFloatingSize = pWindow->m_vRealSize.goal(); - pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vPosition = pWindow->m_vRealPosition.goal(); - pWindow->m_vSize = pWindow->m_vRealSize.goal(); + pWindow->m_vLastFloatingSize = pWindow->m_vRealSize->goal(); + pWindow->m_vLastFloatingPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vPosition = pWindow->m_vRealPosition->goal(); + pWindow->m_vSize = pWindow->m_vRealSize->goal(); } if (EFFECTIVE_MODE == FSMODE_NONE) { @@ -865,8 +865,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul applyNodeDataToWindow(PNODE); else { // get back its' dimensions from position and size - pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; - pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; + *pWindow->m_vRealPosition = pWindow->m_vLastFloatingPosition; + *pWindow->m_vRealSize = pWindow->m_vLastFloatingSize; pWindow->unsetWindowData(PRIORITY_LAYOUT); pWindow->updateWindowData(); @@ -874,8 +874,8 @@ void CHyprMasterLayout::fullscreenRequestForWindow(PHLWINDOW pWindow, const eFul } else { // apply new pos and size being monitors' box if (EFFECTIVE_MODE == FSMODE_FULLSCREEN) { - pWindow->m_vRealPosition = PMONITOR->vecPosition; - pWindow->m_vRealSize = PMONITOR->vecSize; + *pWindow->m_vRealPosition = PMONITOR->vecPosition; + *pWindow->m_vRealSize = PMONITOR->vecSize; } else { // This is a massive hack. // We make a fake "only" node and apply diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index cff438b1..6bfeed83 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -1,6 +1,9 @@ #include "AnimationManager.hpp" #include "../Compositor.hpp" #include "HookSystemManager.hpp" +#include "config/ConfigManager.hpp" +#include "desktop/DesktopTypes.hpp" +#include "helpers/AnimatedVariable.hpp" #include "macros.hpp" #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" @@ -9,6 +12,8 @@ #include "../helpers/varlist/VarList.hpp" #include +#include +#include static int wlTick(SP self, void* data) { if (g_pAnimationManager) @@ -26,324 +31,245 @@ static int wlTick(SP self, void* data) { return 0; } -CAnimationManager::CAnimationManager() { - std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; - m_mBezierCurves["default"].setup(&points); - - points = {Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)}; - m_mBezierCurves["linear"].setup(&points); - +CHyprAnimationManager::CHyprAnimationManager() { m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); g_pEventLoopManager->addTimer(m_pAnimationTimer); + + addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); } -void CAnimationManager::removeAllBeziers() { - m_mBezierCurves.clear(); +template +void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { + if (POINTY >= 1.f || warp || av.value() == av.goal()) { + av.warp(); + return; + } - // add the default one - std::vector points = {Vector2D(0.0, 0.75), Vector2D(0.15, 1.0)}; - m_mBezierCurves["default"].setup(&points); - - points = {Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)}; - m_mBezierCurves["linear"].setup(&points); + const auto DELTA = av.goal() - av.begun(); + av.value() = av.begun() + DELTA * POINTY; } -void CAnimationManager::addBezierWithName(std::string name, const Vector2D& p1, const Vector2D& p2) { - std::vector points = {p1, p2}; - m_mBezierCurves[name].setup(&points); +void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { + if (POINTY >= 1.f || warp || av.value() == av.goal()) { + av.warp(); + return; + } + + // convert both to OkLab, then lerp that, and convert back. + // This is not as fast as just lerping rgb, but it's WAY more precise... + // Use the CHyprColor cache for OkLab + + const auto& L1 = av.begun().asOkLab(); + const auto& L2 = av.goal().asOkLab(); + + static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; + + const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{ + .l = lerp(L1.l, L2.l, POINTY), + .a = lerp(L1.a, L2.a, POINTY), + .b = lerp(L1.b, L2.b, POINTY), + }; + + av.value() = {lerped, lerp(av.begun().a, av.goal().a, POINTY)}; } -void CAnimationManager::onTicked() { - m_bTickScheduled = false; +template +static void handleUpdate(CAnimatedVariable& av, bool warp) { + PHLWINDOW PWINDOW = av.m_Context.pWindow.lock(); + PHLWORKSPACE PWORKSPACE = av.m_Context.pWorkspace.lock(); + PHLLS PLAYER = av.m_Context.pLayer.lock(); + PHLMONITOR PMONITOR = nullptr; + bool animationsDisabled = warp; + + if (PWINDOW) { + if (av.m_Context.eDamagePolicy == AVARDAMAGE_ENTIRE) + g_pHyprRenderer->damageWindow(PWINDOW); + else if (av.m_Context.eDamagePolicy == AVARDAMAGE_BORDER) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); + } else if (av.m_Context.eDamagePolicy == AVARDAMAGE_SHADOW) { + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); + PDECO->damageEntire(); + } + + PMONITOR = PWINDOW->m_pMonitor.lock(); + if (!PMONITOR) + return; + + animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); + } else if (PWORKSPACE) { + PMONITOR = PWORKSPACE->m_pMonitor.lock(); + if (!PMONITOR) + return; + + // dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageMonitor(PMONITOR); + + // TODO: just make this into a damn callback already vax... + for (auto const& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) + continue; + + if (w->m_bIsFloating && !w->m_bPinned) { + // still doing the full damage hack for floating because sometimes when the window + // goes through multiple monitors the last rendered frame is missing damage somehow?? + const CBox windowBoxNoOffset = w->getFullWindowBoundingBox(); + const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize}; + if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors + g_pHyprRenderer->damageWindow(w, true); + } + + if (PWORKSPACE->m_bIsSpecialWorkspace) + g_pHyprRenderer->damageWindow(w, true); // hack for special too because it can cross multiple monitors + } + + // damage any workspace window that is on any monitor + for (auto const& w : g_pCompositor->m_vWindows) { + if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) + continue; + + g_pHyprRenderer->damageWindow(w); + } + } else if (PLAYER) { + // "some fucking layers miss 1 pixel???" -- vaxry + CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; + expandBox.expand(5); + g_pHyprRenderer->damageBox(&expandBox); + + PMONITOR = g_pCompositor->getMonitorFromVector(PLAYER->realPosition->goal() + PLAYER->realSize->goal() / 2.F); + if (!PMONITOR) + return; + animationsDisabled = animationsDisabled || PLAYER->noAnimations; + } + + const auto SPENT = av.getPercent(); + const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); + const auto POINTY = PBEZIER->getYForPoint(SPENT); + + if constexpr (std::same_as) { + updateColorVariable(av, POINTY, animationsDisabled); + } else { + updateVariable(av, POINTY, animationsDisabled); + } + + av.onUpdate(); + + switch (av.m_Context.eDamagePolicy) { + case AVARDAMAGE_ENTIRE: { + if (PWINDOW) { + PWINDOW->updateWindowDecos(); + g_pHyprRenderer->damageWindow(PWINDOW); + } else if (PWORKSPACE) { + for (auto const& w : g_pCompositor->m_vWindows) { + if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) + continue; + + w->updateWindowDecos(); + + // damage any workspace window that is on any monitor + if (!w->m_bPinned) + g_pHyprRenderer->damageWindow(w); + } + } else if (PLAYER) { + if (PLAYER->layer <= 1) + g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); + + // some fucking layers miss 1 pixel??? + CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; + expandBox.expand(5); + g_pHyprRenderer->damageBox(&expandBox); + } + break; + } + case AVARDAMAGE_BORDER: { + RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); + + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); + PDECO->damageEntire(); + + break; + } + case AVARDAMAGE_SHADOW: { + RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); + + const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); + + PDECO->damageEntire(); + + break; + } + default: { + break; + } + } + + // manually schedule a frame + if (PMONITOR) + g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } -void CAnimationManager::tick() { +void CHyprAnimationManager::tick() { static std::chrono::time_point lastTick = std::chrono::high_resolution_clock::now(); m_fLastTickTime = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - lastTick).count() / 1000.0; lastTick = std::chrono::high_resolution_clock::now(); - if (m_vActiveAnimatedVariables.empty()) - return; - - bool animGlobalDisabled = false; - static auto PANIMENABLED = CConfigValue("animations:enabled"); - - if (!*PANIMENABLED) - animGlobalDisabled = true; - - static auto* const PSHADOWSENABLED = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("decoration:shadow:enabled"); - - const auto DEFAULTBEZIER = m_mBezierCurves.find("default"); - - std::vector animationEndedVars; - - for (auto const& av : m_vActiveAnimatedVariables) { - - if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW && !*PSHADOWSENABLED) { - av->warp(false); - animationEndedVars.push_back(av); + for (auto const& pav : m_vActiveAnimatedVariables) { + const auto PAV = pav.lock(); + if (!PAV) continue; - } - // get the spent % (0 - 1) - const float SPENT = av->getPercent(); + // for disabled anims just warp + bool warp = !*PANIMENABLED || !PAV->enabled(); - // window stuff - PHLWINDOW PWINDOW = av->m_pWindow.lock(); - PHLWORKSPACE PWORKSPACE = av->m_pWorkspace.lock(); - PHLLS PLAYER = av->m_pLayer.lock(); - PHLMONITOR PMONITOR = nullptr; - bool animationsDisabled = animGlobalDisabled; - - if (PWINDOW) { - if (av->m_eDamagePolicy == AVARDAMAGE_ENTIRE) { - g_pHyprRenderer->damageWindow(PWINDOW); - } else if (av->m_eDamagePolicy == AVARDAMAGE_BORDER) { - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); - PDECO->damageEntire(); - } else if (av->m_eDamagePolicy == AVARDAMAGE_SHADOW) { - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - PDECO->damageEntire(); - } - - PMONITOR = PWINDOW->m_pMonitor.lock(); - if (!PMONITOR) - continue; - animationsDisabled = PWINDOW->m_sWindowData.noAnim.valueOr(animationsDisabled); - } else if (PWORKSPACE) { - PMONITOR = PWORKSPACE->m_pMonitor.lock(); - if (!PMONITOR) - continue; - - // dont damage the whole monitor on workspace change, unless it's a special workspace, because dim/blur etc - if (PWORKSPACE->m_bIsSpecialWorkspace) - g_pHyprRenderer->damageMonitor(PMONITOR); - - // TODO: just make this into a damn callback already vax... - for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden() || w->m_pWorkspace != PWORKSPACE) - continue; - - if (w->m_bIsFloating && !w->m_bPinned) { - // still doing the full damage hack for floating because sometimes when the window - // goes through multiple monitors the last rendered frame is missing damage somehow?? - const CBox windowBoxNoOffset = w->getFullWindowBoundingBox(); - const CBox monitorBox = {PMONITOR->vecPosition, PMONITOR->vecSize}; - if (windowBoxNoOffset.intersection(monitorBox) != windowBoxNoOffset) // on edges between multiple monitors - g_pHyprRenderer->damageWindow(w, true); - } - - if (PWORKSPACE->m_bIsSpecialWorkspace) - g_pHyprRenderer->damageWindow(w, true); // hack for special too because it can cross multiple monitors - } - - // damage any workspace window that is on any monitor - for (auto const& w : g_pCompositor->m_vWindows) { - if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE || w->m_bPinned) - continue; - - g_pHyprRenderer->damageWindow(w); - } - } else if (PLAYER) { - // "some fucking layers miss 1 pixel???" -- vaxry - CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; - expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); - - PMONITOR = g_pCompositor->getMonitorFromVector(PLAYER->realPosition.goal() + PLAYER->realSize.goal() / 2.F); - if (!PMONITOR) - continue; - animationsDisabled = animationsDisabled || PLAYER->noAnimations; - } - - const bool VISIBLE = PWINDOW && PWINDOW->m_pWorkspace ? PWINDOW->m_pWorkspace->isVisible() : true; - - // beziers are with a switch unforto - // TODO: maybe do something cleaner - - static const auto updateVariable = [this](CAnimatedVariable& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) { - // for disabled anims just warp - if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) { - av.warp(false); - return; - } - - if (SPENT >= 1.f || av.m_Begun == av.m_Goal) { - av.warp(false); - return; - } - - const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); - const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT); - - const auto DELTA = av.m_Goal - av.m_Begun; - - if (BEZIER != m_mBezierCurves.end()) - av.m_Value = av.m_Begun + DELTA * POINTY; - else - av.m_Value = av.m_Begun + DELTA * POINTY; - }; - - static const auto updateColorVariable = [this](CAnimatedVariable& av, const float SPENT, const CBezierCurve& DEFAULTBEZIER, const bool DISABLED) { - // for disabled anims just warp - if (av.m_pConfig->pValues->internalEnabled == 0 || DISABLED) { - av.warp(false); - return; - } - - if (SPENT >= 1.f || av.m_Begun == av.m_Goal) { - av.warp(false); - return; - } - - const auto BEZIER = m_mBezierCurves.find(av.m_pConfig->pValues->internalBezier); - const auto POINTY = BEZIER != m_mBezierCurves.end() ? BEZIER->second.getYForPoint(SPENT) : DEFAULTBEZIER.getYForPoint(SPENT); - - // convert both to OkLab, then lerp that, and convert back. - // This is not as fast as just lerping rgb, but it's WAY more precise... - // Use the CHyprColor cache for OkLab - - const auto& L1 = av.m_Begun.asOkLab(); - const auto& L2 = av.m_Goal.asOkLab(); - - static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; - - const Hyprgraphics::CColor lerped = Hyprgraphics::CColor::SOkLab{ - .l = lerp(L1.l, L2.l, POINTY), - .a = lerp(L1.a, L2.a, POINTY), - .b = lerp(L1.b, L2.b, POINTY), - }; - - av.m_Value = {lerped, lerp(av.m_Begun.a, av.m_Goal.a, POINTY)}; - - return; - }; - - switch (av->m_Type) { + switch (PAV->m_Type) { case AVARTYPE_FLOAT: { - auto typedAv = dynamic_cast*>(av); - updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated float"); + handleUpdate(*pTypedAV, warp); + } break; case AVARTYPE_VECTOR: { - auto typedAv = dynamic_cast*>(av); - updateVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated Vector2D"); + handleUpdate(*pTypedAV, warp); + } break; case AVARTYPE_COLOR: { - auto typedAv = dynamic_cast*>(av); - updateColorVariable(*typedAv, SPENT, DEFAULTBEZIER->second, animationsDisabled); - break; - } + auto pTypedAV = dynamic_cast*>(PAV.get()); + RASSERT(pTypedAV, "Failed to upcast animated CHyprColor"); + handleUpdate(*pTypedAV, warp); + } break; default: UNREACHABLE(); } - // set size and pos if valid, but only if damage policy entire (dont if border for example) - if (validMapped(PWINDOW) && av->m_eDamagePolicy == AVARDAMAGE_ENTIRE && !PWINDOW->isX11OverrideRedirect()) - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize.goal()); - - // check if we did not finish animating. If so, trigger onAnimationEnd. - if (!av->isBeingAnimated()) - animationEndedVars.push_back(av); - - // lastly, handle damage, but only if whatever we are animating is visible. - if (!VISIBLE) - continue; - - if (av->m_fUpdateCallback) - av->m_fUpdateCallback(av); - - switch (av->m_eDamagePolicy) { - case AVARDAMAGE_ENTIRE: { - if (PWINDOW) { - PWINDOW->updateWindowDecos(); - g_pHyprRenderer->damageWindow(PWINDOW); - } else if (PWORKSPACE) { - for (auto const& w : g_pCompositor->m_vWindows) { - if (!validMapped(w) || w->m_pWorkspace != PWORKSPACE) - continue; - - w->updateWindowDecos(); - - // damage any workspace window that is on any monitor - if (!w->m_bPinned) - g_pHyprRenderer->damageWindow(w); - } - } else if (PLAYER) { - if (PLAYER->layer <= 1) - g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); - - // some fucking layers miss 1 pixel??? - CBox expandBox = CBox{PLAYER->realPosition.value(), PLAYER->realSize.value()}; - expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); - } - break; - } - case AVARDAMAGE_BORDER: { - RASSERT(PWINDOW, "Tried to AVARDAMAGE_BORDER a non-window AVAR!"); - - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_BORDER); - PDECO->damageEntire(); - - break; - } - case AVARDAMAGE_SHADOW: { - RASSERT(PWINDOW, "Tried to AVARDAMAGE_SHADOW a non-window AVAR!"); - - const auto PDECO = PWINDOW->getDecorationByType(DECORATION_SHADOW); - - PDECO->damageEntire(); - - break; - } - default: { - break; - } - } - - // manually schedule a frame - if (PMONITOR) - g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION); } - // do it here, because if this alters the animation vars vec we would be in trouble above. - for (auto const& ave : animationEndedVars) { - ave->onAnimationEnd(); - } + tickDone(); } -bool CAnimationManager::deltaSmallToFlip(const Vector2D& a, const Vector2D& b) { - return std::abs(a.x - b.x) < 0.5f && std::abs(a.y - b.y) < 0.5f; -} +void CHyprAnimationManager::scheduleTick() { + if (m_bTickScheduled) + return; -bool CAnimationManager::deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b) { - return std::abs(a.r - b.r) < 0.5f && std::abs(a.g - b.g) < 0.5f && std::abs(a.b - b.b) < 0.5f && std::abs(a.a - b.a) < 0.5f; -} + m_bTickScheduled = true; -bool CAnimationManager::deltaSmallToFlip(const float& a, const float& b) { - return std::abs(a - b) < 0.5f; -} + const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor; -bool CAnimationManager::deltazero(const Vector2D& a, const Vector2D& b) { - return a.x == b.x && a.y == b.y; -} - -bool CAnimationManager::deltazero(const float& a, const float& b) { - return a == b; -} - -bool CAnimationManager::deltazero(const CHyprColor& a, const CHyprColor& b) { - return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; -} - -bool CAnimationManager::bezierExists(const std::string& bezier) { - for (auto const& [bc, bz] : m_mBezierCurves) { - if (bc == bezier) - return true; + if (!PMOSTHZ) { + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16)); + return; } - return false; + float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate); + + const float SINCEPRES = std::chrono::duration_cast(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; + + const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it + + m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES))); +} + +void CHyprAnimationManager::onTicked() { + m_bTickScheduled = false; } // @@ -351,24 +277,24 @@ bool CAnimationManager::bezierExists(const std::string& bezier) { // // -void CAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { - const auto GOALPOS = pWindow->m_vRealPosition.goal(); - const auto GOALSIZE = pWindow->m_vRealSize.goal(); +void CHyprAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); if (!close) { - pWindow->m_vRealSize.setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); - pWindow->m_vRealPosition.setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Value / 2.f); + pWindow->m_vRealSize->setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); + pWindow->m_vRealPosition->setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize->value() / 2.f); } else { - pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); - pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize.m_Goal / 2.f; + *pWindow->m_vRealSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); + *pWindow->m_vRealPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_vRealSize->goal() / 2.f; } } -void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { - pWindow->m_vRealSize.warp(false); // size we preserve in slide +void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { + pWindow->m_vRealSize->warp(false); // size we preserve in slide - const auto GOALPOS = pWindow->m_vRealPosition.goal(); - const auto GOALSIZE = pWindow->m_vRealSize.goal(); + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); const auto PMONITOR = pWindow->m_pMonitor.lock(); @@ -388,9 +314,9 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo posOffset = Vector2D(GOALPOS.x, PMONITOR->vecPosition.y - GOALSIZE.y); if (!close) - pWindow->m_vRealPosition.setValue(posOffset); + pWindow->m_vRealPosition->setValue(posOffset); else - pWindow->m_vRealPosition = posOffset; + *pWindow->m_vRealPosition = posOffset; return; } @@ -423,33 +349,33 @@ void CAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, boo } if (!close) - pWindow->m_vRealPosition.setValue(posOffset); + pWindow->m_vRealPosition->setValue(posOffset); else - pWindow->m_vRealPosition = posOffset; + *pWindow->m_vRealPosition = posOffset; } -void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { +void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (!close) { - pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn"); - pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsIn"); - pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeIn"); + pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_vRealSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); } else { - pWindow->m_vRealPosition.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut"); - pWindow->m_vRealSize.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("windowsOut"); - pWindow->m_fAlpha.m_pConfig = g_pConfigManager->getAnimationPropertyConfig("fadeOut"); + pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_vRealSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_fAlpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); } - auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle; + std::string ANIMSTYLE = pWindow->m_vRealPosition->getStyle(); transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower); CVarList animList(ANIMSTYLE, 0, 's'); // if the window is not being animated, that means the layout set a fixed size for it, don't animate. - if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated()) + if (!pWindow->m_vRealPosition->isBeingAnimated() && !pWindow->m_vRealSize->isBeingAnimated()) return; // if the animation is disabled and we are leaving, ignore the anim to prevent the snapshot being fucked - if (!pWindow->m_vRealPosition.m_pConfig->pValues->internalEnabled) + if (!pWindow->m_vRealPosition->enabled()) return; if (pWindow->m_sWindowData.animationStyle.hasValue()) { @@ -494,7 +420,7 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { } } -std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { +std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { if (style.starts_with("slide")) return ""; @@ -568,39 +494,3 @@ std::string CAnimationManager::styleValidInConfigVar(const std::string& config, return ""; } - -CBezierCurve* CAnimationManager::getBezier(const std::string& name) { - const auto BEZIER = std::find_if(m_mBezierCurves.begin(), m_mBezierCurves.end(), [&](const auto& other) { return other.first == name; }); - - return BEZIER == m_mBezierCurves.end() ? &m_mBezierCurves["default"] : &BEZIER->second; -} - -std::unordered_map CAnimationManager::getAllBeziers() { - return m_mBezierCurves; -} - -bool CAnimationManager::shouldTickForNext() { - return !m_vActiveAnimatedVariables.empty(); -} - -void CAnimationManager::scheduleTick() { - if (m_bTickScheduled) - return; - - m_bTickScheduled = true; - - const auto PMOSTHZ = g_pHyprRenderer->m_pMostHzMonitor; - - if (!PMOSTHZ) { - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds(16)); - return; - } - - float refreshDelayMs = std::floor(1000.f / PMOSTHZ->refreshRate); - - const float SINCEPRES = std::chrono::duration_cast(std::chrono::steady_clock::now() - PMOSTHZ->lastPresentationTimer.chrono()).count() / 1000.f; - - const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it - - m_pAnimationTimer->updateTimeout(std::chrono::milliseconds((int)std::floor(TOPRES))); -} diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 3960f261..7bf73f97 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -1,57 +1,64 @@ #pragma once +#include +#include + #include "../defines.hpp" -#include -#include #include "../helpers/AnimatedVariable.hpp" -#include "../helpers/BezierCurve.hpp" -#include "../helpers/Timer.hpp" +#include "desktop/DesktopTypes.hpp" #include "eventLoop/EventLoopTimer.hpp" -class CWindow; - -class CAnimationManager { +class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { public: - CAnimationManager(); + CHyprAnimationManager(); - void tick(); - bool shouldTickForNext(); - void onTicked(); - void scheduleTick(); - void addBezierWithName(std::string, const Vector2D&, const Vector2D&); - void removeAllBeziers(); + void tick(); + virtual void scheduleTick(); + virtual void onTicked(); - void onWindowPostCreateClose(PHLWINDOW, bool close = false); + using SAnimationPropertyConfig = Hyprutils::Animation::SAnimationPropertyConfig; + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, eAVarDamagePolicy policy) { + constexpr const eAnimatedVarType EAVTYPE = typeToeAnimatedVarType; + const auto PAV = makeShared>(); - bool bezierExists(const std::string&); - CBezierCurve* getBezier(const std::string&); + PAV->create(EAVTYPE, static_cast(this), PAV, v); + PAV->setConfig(pConfig); + PAV->m_Context.eDamagePolicy = policy; - std::string styleValidInConfigVar(const std::string&, const std::string&); + pav = std::move(PAV); + } - std::unordered_map getAllBeziers(); + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLWINDOW pWindow, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pWindow = pWindow; + } + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLWORKSPACE pWorkspace, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pWorkspace = pWorkspace; + } + template + void createAnimation(const VarType& v, PHLANIMVAR& pav, SP pConfig, PHLLS pLayer, eAVarDamagePolicy policy) { + createAnimation(v, pav, pConfig, policy); + pav->m_Context.pLayer = pLayer; + } - std::vector m_vAnimatedVariables; - std::vector m_vActiveAnimatedVariables; + void onWindowPostCreateClose(PHLWINDOW, bool close = false); - SP m_pAnimationTimer; + std::string styleValidInConfigVar(const std::string&, const std::string&); - float m_fLastTickTime; // in ms + SP m_pAnimationTimer; + + float m_fLastTickTime; // in ms private: - bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b); - bool deltaSmallToFlip(const CHyprColor& a, const CHyprColor& b); - bool deltaSmallToFlip(const float& a, const float& b); - bool deltazero(const Vector2D& a, const Vector2D& b); - bool deltazero(const CHyprColor& a, const CHyprColor& b); - bool deltazero(const float& a, const float& b); - - std::unordered_map m_mBezierCurves; - - bool m_bTickScheduled = false; + bool m_bTickScheduled = false; // Anim stuff void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); void animationSlide(PHLWINDOW, std::string force = "", bool close = false); }; -inline std::unique_ptr g_pAnimationManager; +inline std::unique_ptr g_pAnimationManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d368d14c..fd4992eb 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -377,8 +377,8 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); // warp the position + size animation, otherwise it looks weird. - PWINDOWTOCHANGETO->m_vRealPosition.warp(); - PWINDOWTOCHANGETO->m_vRealSize.warp(); + PWINDOWTOCHANGETO->m_vRealPosition->warp(); + PWINDOWTOCHANGETO->m_vRealSize->warp(); } else { updateRelativeCursorCoords(); g_pCompositor->focusWindow(PWINDOWTOCHANGETO); @@ -1070,8 +1070,8 @@ SDispatchResult CKeybindManager::centerWindow(std::string args) { if (args == "1") RESERVEDOFFSET = (PMONITOR->vecReservedTopLeft - PMONITOR->vecReservedBottomRight) / 2.f; - PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize.goal() / 2.f + RESERVEDOFFSET; - PWINDOW->m_vPosition = PWINDOW->m_vRealPosition.goal(); + *PWINDOW->m_vRealPosition = PMONITOR->middle() - PWINDOW->m_vRealSize->goal() / 2.f + RESERVEDOFFSET; + PWINDOW->m_vPosition = PWINDOW->m_vRealPosition->goal(); return {}; } @@ -1557,14 +1557,14 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) { switch (arg) { case 'l': vPosx = PMONITOR->vecReservedTopLeft.x + BORDERSIZE + PMONITOR->vecPosition.x; break; - case 'r': vPosx = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize.goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; + case 'r': vPosx = PMONITOR->vecSize.x - PMONITOR->vecReservedBottomRight.x - PLASTWINDOW->m_vRealSize->goal().x - BORDERSIZE + PMONITOR->vecPosition.x; break; case 't': case 'u': vPosy = PMONITOR->vecReservedTopLeft.y + BORDERSIZE + PMONITOR->vecPosition.y; break; case 'b': - case 'd': vPosy = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize.goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; + case 'd': vPosy = PMONITOR->vecSize.y - PMONITOR->vecReservedBottomRight.y - PLASTWINDOW->m_vRealSize->goal().y - BORDERSIZE + PMONITOR->vecPosition.y; break; } - PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition.goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition.goal().y)); + *PLASTWINDOW->m_vRealPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_vRealPosition->goal().x), vPosy.value_or(PLASTWINDOW->m_vRealPosition->goal().y)); return {}; } @@ -1735,20 +1735,20 @@ SDispatchResult CKeybindManager::moveCursorToCorner(std::string arg) { switch (CORNER) { case 0: // bottom left - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y + PWINDOW->m_vRealSize->value().y}, true); break; case 1: // bottom right - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, - true); + g_pCompositor->warpCursorTo( + {PWINDOW->m_vRealPosition->value().x + PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealPosition->value().y + PWINDOW->m_vRealSize->value().y}, true); break; case 2: // top right - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x + PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealPosition->value().y}, true); break; case 3: // top left - g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true); + g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y}, true); break; } @@ -1817,18 +1817,18 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { continue; if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) { - const auto SAVEDPOS = w->m_vRealPosition.value(); - const auto SAVEDSIZE = w->m_vRealSize.value(); + const auto SAVEDPOS = w->m_vRealPosition->value(); + const auto SAVEDSIZE = w->m_vRealSize->value(); w->m_bIsFloating = PWORKSPACE->m_bDefaultFloating; g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(w); if (PWORKSPACE->m_bDefaultFloating) { - w->m_vRealPosition.setValueAndWarp(SAVEDPOS); - w->m_vRealSize.setValueAndWarp(SAVEDSIZE); + w->m_vRealPosition->setValueAndWarp(SAVEDPOS); + w->m_vRealSize->setValueAndWarp(SAVEDSIZE); g_pXWaylandManager->setWindowSize(w, SAVEDSIZE); - w->m_vRealSize = w->m_vRealSize.value() + Vector2D(4, 4); - w->m_vRealPosition = w->m_vRealPosition.value() - Vector2D(2, 2); + *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); + *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); } } } @@ -2043,14 +2043,14 @@ SDispatchResult CKeybindManager::resizeActive(std::string args) { if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return {}; - const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize.goal()); + const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) return {}; - g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize.goal()); + g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal()); - if (PLASTWINDOW->m_vRealSize.goal().x > 1 && PLASTWINDOW->m_vRealSize.goal().y > 1) + if (PLASTWINDOW->m_vRealSize->goal().x > 1 && PLASTWINDOW->m_vRealSize->goal().y > 1) PLASTWINDOW->setHidden(false); return {}; @@ -2062,9 +2062,9 @@ SDispatchResult CKeybindManager::moveActive(std::string args) { if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) return {}; - const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition.goal()); + const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal()); - g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition.goal()); + g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PLASTWINDOW->m_vRealPosition->goal()); return {}; } @@ -2084,9 +2084,9 @@ SDispatchResult CKeybindManager::moveWindow(std::string args) { if (PWINDOW->isFullscreen()) return {}; - const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition.goal()); + const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal()); - g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition.goal(), PWINDOW); + g_pLayoutManager->getCurrentLayout()->moveActiveWindow(POS - PWINDOW->m_vRealPosition->goal(), PWINDOW); return {}; } @@ -2106,14 +2106,14 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) { if (PWINDOW->isFullscreen()) return {}; - const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize.goal()); + const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) return {}; - g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize.goal(), CORNER_NONE, PWINDOW); + g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW); - if (PWINDOW->m_vRealSize.goal().x > 1 && PWINDOW->m_vRealSize.goal().y > 1) + if (PWINDOW->m_vRealSize->goal().x > 1 && PWINDOW->m_vRealSize->goal().y > 1) PWINDOW->setHidden(false); return {}; @@ -2192,8 +2192,8 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { g_pCompositor->setWindowFullscreenClient(PWINDOW, FSMODE); // warp the position + size animation, otherwise it looks weird. - PWINDOW->m_vRealPosition.warp(); - PWINDOW->m_vRealSize.warp(); + PWINDOW->m_vRealPosition->warp(); + PWINDOW->m_vRealSize->warp(); } } else g_pCompositor->focusWindow(PWINDOW); @@ -2311,7 +2311,7 @@ SDispatchResult CKeybindManager::pass(std::string regexp) { } } - const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + const auto SL = PWINDOW->m_vRealPosition->goal() - g_pInputManager->getMouseCoordsInternal(); if (g_pKeybindManager->m_uLastCode != 0) g_pSeatManager->setKeyboardFocus(LASTKBSURF); @@ -2466,7 +2466,7 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) { } } - const auto SL = PWINDOW->m_vRealPosition.goal() - g_pInputManager->getMouseCoordsInternal(); + const auto SL = PWINDOW->m_vRealPosition->goal() - g_pInputManager->getMouseCoordsInternal(); if (!isMouse) g_pSeatManager->setKeyboardFocus(LASTSURFACE); diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index ca31752d..bc988f39 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - setWindowSize(pWindow, pWindow->m_vRealSize.value()); // update xwayland output pos + setWindowSize(pWindow, pWindow->m_vRealSize->value()); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) @@ -123,7 +123,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool // calculate pos // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = pWindow->m_vRealPosition.value(); + Vector2D windowPos = pWindow->m_vRealPosition->value(); if (pWindow->m_bIsX11 && PMONITOR) { windowPos -= PMONITOR->vecPosition; // normalize to monitor @@ -273,4 +273,4 @@ Vector2D CHyprXWaylandManager::xwaylandToWaylandCoords(const Vector2D& coord) { result += pMonitor->vecPosition; return result; -} \ No newline at end of file +} diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index cccaa43e..8a50a7bf 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -137,7 +137,7 @@ void CInputManager::sendMotionEventsToFocused() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - const auto LOCAL = getMouseCoordsInternal() - (PWINDOW ? PWINDOW->m_vRealPosition.goal() : (PLS ? Vector2D{PLS->geometry.x, PLS->geometry.y} : Vector2D{})); + const auto LOCAL = getMouseCoordsInternal() - (PWINDOW ? PWINDOW->m_vRealPosition->goal() : (PLS ? Vector2D{PLS->geometry.x, PLS->geometry.y} : Vector2D{})); m_bEmptyFocusCursorSet = false; @@ -243,7 +243,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (forcedFocus) { pFoundWindow = forcedFocus; - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); foundSurface = pFoundWindow->m_pWLSurface->resource(); } @@ -320,7 +320,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { surfacePos = Vector2D(-1337, -1337); } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } @@ -362,11 +362,11 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); if (!foundSurface) { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); - surfacePos = pFoundWindow->m_vRealPosition.value(); + surfacePos = pFoundWindow->m_vRealPosition->value(); } } } @@ -689,7 +689,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) { // TODO detect click on LS properly if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED && (!w || !w->isX11OverrideRedirect())) { if (w && !w->isFullscreen()) { - const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y}; + const CBox real = {w->m_vRealPosition->value().x, w->m_vRealPosition->value().y, w->m_vRealSize->value().x, w->m_vRealSize->value().y}; const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA}; if ((grab.containsPoint(mouseCoords) && (!real.containsPoint(mouseCoords) || w->isInCurvedCorner(mouseCoords.x, mouseCoords.y))) && !w->hasPopupAt(mouseCoords)) { diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 6cfe5a24..3e03c4c7 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -38,7 +38,7 @@ void CInputManager::beginWorkspaceSwipe() { if (PWORKSPACE->m_bHasFullscreenWindow) { for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { - ls->alpha = 1.f; + *ls->alpha = 1.f; } } } @@ -58,8 +58,8 @@ void CInputManager::endWorkspaceSwipe() { static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); // commit auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; @@ -86,7 +86,7 @@ void CInputManager::endWorkspaceSwipe() { auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER - const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.value(); + const auto RENDEROFFSETMIDDLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->value(); const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; @@ -97,35 +97,35 @@ void CInputManager::endWorkspaceSwipe() { // revert if (abs(m_sActiveSwipe.delta) < 2) { if (PWORKSPACEL) - PWORKSPACEL->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + PWORKSPACEL->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); if (PWORKSPACER) - PWORKSPACER->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); + PWORKSPACER->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0, 0)); } else { if (m_sActiveSwipe.delta < 0) { // to left if (PWORKSPACEL) { if (VERTANIMS) - PWORKSPACEL->m_vRenderOffset = Vector2D{0.0, -YDISTANCE}; + *PWORKSPACEL->m_vRenderOffset = Vector2D{0.0, -YDISTANCE}; else - PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0.0}; + *PWORKSPACEL->m_vRenderOffset = Vector2D{-XDISTANCE, 0.0}; } } else if (PWORKSPACER) { // to right if (VERTANIMS) - PWORKSPACER->m_vRenderOffset = Vector2D{0.0, YDISTANCE}; + *PWORKSPACER->m_vRenderOffset = Vector2D{0.0, YDISTANCE}; else - PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0.0}; + *PWORKSPACER->m_vRenderOffset = Vector2D{XDISTANCE, 0.0}; } - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(); } pSwitchedTo = m_sActiveSwipe.pWorkspaceBegin; } else if (m_sActiveSwipe.delta < 0) { // switch to left - const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_vRenderOffset.value() : Vector2D(); + const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_vRenderOffset->value() : Vector2D(); if (PWORKSPACEL) m_sActiveSwipe.pMonitor->changeWorkspace(workspaceIDLeft); @@ -134,15 +134,15 @@ void CInputManager::endWorkspaceSwipe() { PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); } - PWORKSPACEL->m_vRenderOffset.setValue(RENDEROFFSET); - PWORKSPACEL->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACEL->m_vRenderOffset->setValue(RENDEROFFSET); + PWORKSPACEL->m_fAlpha->setValueAndWarp(1.f); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, YDISTANCE); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0.0); - m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(XDISTANCE, 0.0); + m_sActiveSwipe.pWorkspaceBegin->m_fAlpha->setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -151,7 +151,7 @@ void CInputManager::endWorkspaceSwipe() { pSwitchedTo = PWORKSPACEL; } else { // switch to right - const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_vRenderOffset.value() : Vector2D(); + const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_vRenderOffset->value() : Vector2D(); if (PWORKSPACER) m_sActiveSwipe.pMonitor->changeWorkspace(workspaceIDRight); @@ -160,15 +160,15 @@ void CInputManager::endWorkspaceSwipe() { PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); } - PWORKSPACER->m_vRenderOffset.setValue(RENDEROFFSET); - PWORKSPACER->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACER->m_vRenderOffset->setValue(RENDEROFFSET); + PWORKSPACER->m_fAlpha->setValueAndWarp(1.f); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValue(RENDEROFFSETMIDDLE); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValue(RENDEROFFSETMIDDLE); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, -YDISTANCE); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(0.0, -YDISTANCE); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0.0); - m_sActiveSwipe.pWorkspaceBegin->m_fAlpha.setValueAndWarp(1.f); + *m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset = Vector2D(-XDISTANCE, 0.0); + m_sActiveSwipe.pWorkspaceBegin->m_fAlpha->setValueAndWarp(1.f); g_pInputManager->unconstrainMouse(); @@ -193,7 +193,7 @@ void CInputManager::endWorkspaceSwipe() { // apply alpha for (auto const& ls : g_pCompositor->m_pLastMonitor->m_aLayerSurfaceLayers[2]) { - ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + *ls->alpha = pSwitchedTo->m_bHasFullscreenWindow && pSwitchedTo->m_efFullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; } } @@ -202,30 +202,30 @@ void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { if (!m_sActiveSwipe.pWorkspaceBegin) return; - static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_invert"); + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x)); updateWorkspaceSwipe(delta); } void CInputManager::updateWorkspaceSwipe(double delta) { - static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); - static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); - static auto PSWIPEDIRLOCK = CConfigValue("gestures:workspace_swipe_direction_lock"); - static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue("gestures:workspace_swipe_direction_lock_threshold"); - static auto PSWIPEFOREVER = CConfigValue("gestures:workspace_swipe_forever"); - static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); - static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); + static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); + static auto PSWIPENEW = CConfigValue("gestures:workspace_swipe_create_new"); + static auto PSWIPEDIRLOCK = CConfigValue("gestures:workspace_swipe_direction_lock"); + static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue("gestures:workspace_swipe_direction_lock_threshold"); + static auto PSWIPEFOREVER = CConfigValue("gestures:workspace_swipe_forever"); + static auto PSWIPEUSER = CConfigValue("gestures:workspace_swipe_use_r"); + static auto PWORKSPACEGAP = CConfigValue("general:gaps_workspaces"); - const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); - const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; - const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); - const double d = m_sActiveSwipe.delta - delta; - m_sActiveSwipe.delta = delta; + const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); + const auto XDISTANCE = m_sActiveSwipe.pMonitor->vecSize.x + *PWORKSPACEGAP; + const auto YDISTANCE = m_sActiveSwipe.pMonitor->vecSize.y + *PWORKSPACEGAP; + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); + const double d = m_sActiveSwipe.delta - delta; + m_sActiveSwipe.delta = delta; m_sActiveSwipe.avgSpeed = (m_sActiveSwipe.avgSpeed * m_sActiveSwipe.speedPoints + abs(d)) / (m_sActiveSwipe.speedPoints + 1); m_sActiveSwipe.speedPoints++; @@ -265,9 +265,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; @@ -277,23 +277,23 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } PWORKSPACE->m_bForceRendering = true; - PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACE->m_fAlpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_sActiveSwipe.pWorkspaceBegin->m_iID) { const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); if (PWORKSPACER) { PWORKSPACER->m_bForceRendering = false; - PWORKSPACER->m_fAlpha.setValueAndWarp(0.f); + PWORKSPACER->m_fAlpha->setValueAndWarp(0.f); } } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } PWORKSPACE->updateWindowDecos(); @@ -305,9 +305,9 @@ void CInputManager::updateWorkspaceSwipe(double delta) { g_pHyprRenderer->damageMonitor(m_sActiveSwipe.pMonitor.lock()); if (VERTANIMS) - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); else - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); m_sActiveSwipe.pWorkspaceBegin->updateWindowDecos(); return; @@ -317,23 +317,23 @@ void CInputManager::updateWorkspaceSwipe(double delta) { } PWORKSPACE->m_bForceRendering = true; - PWORKSPACE->m_fAlpha.setValueAndWarp(1.f); + PWORKSPACE->m_fAlpha->setValueAndWarp(1.f); if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_sActiveSwipe.pWorkspaceBegin->m_iID) { const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); if (PWORKSPACEL) { PWORKSPACEL->m_bForceRendering = false; - PWORKSPACEL->m_fAlpha.setValueAndWarp(0.f); + PWORKSPACEL->m_fAlpha->setValueAndWarp(0.f); } } if (VERTANIMS) { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(0.0, ((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); } else { - PWORKSPACE->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + PWORKSPACE->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); + m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->setValueAndWarp(Vector2D(((-m_sActiveSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); } PWORKSPACE->updateWindowDecos(); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index aba54387..d7ebfe87 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -69,7 +69,7 @@ static void refocusTablet(SP tab, SP tool, bool motion = f // yes, this technically ignores any regions set by the app. Too bad! if (LASTHLSURFACE->getWindow()) - local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize.goal(); + local = tool->absolutePos * LASTHLSURFACE->getWindow()->m_vRealSize->goal(); else local = tool->absolutePos * BOX->size(); diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 4e3980aa..7212ba61 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -3,6 +3,7 @@ #include "../../config/ConfigValue.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" +#include "managers/AnimationManager.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { m_bLastInputTouch = true; @@ -36,9 +37,9 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { return; // TODO: Don't swipe if you touched a floating window. } else if (*PSWIPETOUCH && (m_pFoundLSToFocus.expired() || m_pFoundLSToFocus->layer <= 1)) { - const auto PWORKSPACE = PMONITOR->activeWorkspace; - const bool VERTANIMS = PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - PWORKSPACE->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + const auto PWORKSPACE = PMONITOR->activeWorkspace; + const auto STYLE = PWORKSPACE->m_vRenderOffset->getStyle(); + const bool VERTANIMS = STYLE == "slidevert" || STYLE.starts_with("slidefadevert"); const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x); const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x)); const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); @@ -62,8 +63,8 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { if (!m_sTouchData.touchFocusWindow.expired()) { if (m_sTouchData.touchFocusWindow->m_bIsX11) { - local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition.goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; - m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition.goal(); + local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition->goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; + m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition->goal(); } else { g_pCompositor->vectorWindowToSurface(g_pInputManager->getMouseCoordsInternal(), m_sTouchData.touchFocusWindow.lock(), local); m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; @@ -101,8 +102,9 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { // Do nothing if this is using a different finger. if (e.touchID != m_sActiveSwipe.touch_id) return; - const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" || - m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert"); + + const auto ANIMSTYLE = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); static auto PSWIPEINVR = CConfigValue("gestures:workspace_swipe_touch_invert"); static auto PSWIPEDIST = CConfigValue("gestures:workspace_swipe_distance"); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, (int64_t)1LL, (int64_t)UINT32_MAX); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 250c6326..fd7cdcd6 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -3,6 +3,7 @@ #include "../render/Renderer.hpp" #include "core/Output.hpp" #include "../config/ConfigValue.hpp" +#include "managers/AnimationManager.hpp" CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { if (!good()) @@ -92,8 +93,7 @@ bool CHyprlandCTMControlProtocol::isCTMAnimationEnabled() { } CHyprlandCTMControlProtocol::SCTMData::SCTMData() { - progress.create(g_pConfigManager->getAnimationPropertyConfig("__internal_fadeCTM"), AVARDAMAGE_NONE); - progress.setValueAndWarp(0.F); + g_pAnimationManager->createAnimation(0.f, progress, g_pConfigManager->getAnimationPropertyConfig("__internal_fadeCTM"), AVARDAMAGE_NONE); } void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) { @@ -112,18 +112,18 @@ void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) data->ctmFrom = data->ctmTo; data->ctmTo = ctm; - data->progress.setValueAndWarp(0.F); - data->progress = 1.F; + data->progress->setValueAndWarp(0.F); + *data->progress = 1.F; monitor->setCTM(data->ctmFrom); - data->progress.setUpdateCallback([monitor = PHLMONITORREF{monitor}, this](void* self) { + data->progress->setUpdateCallback([monitor = PHLMONITORREF{monitor}, this](auto) { if (!monitor || !m_mCTMDatas.contains(monitor)) return; auto& data = m_mCTMDatas.at(monitor); const auto from = data->ctmFrom.getMatrix(); const auto to = data->ctmTo.getMatrix(); - const auto PROGRESS = data->progress.getPercent(); + const auto PROGRESS = data->progress->getPercent(); static const auto lerp = [](const float one, const float two, const float progress) -> float { return one + (two - one) * progress; }; @@ -135,7 +135,7 @@ void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) monitor->setCTM(mtx); }); - data->progress.setCallbackOnEnd([monitor = PHLMONITORREF{monitor}, this](void* self) { + data->progress->setCallbackOnEnd([monitor = PHLMONITORREF{monitor}, this](auto) { if (!monitor || !m_mCTMDatas.contains(monitor)) { monitor->setCTM(Mat3x3::identity()); return; diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index dea2c258..2639d176 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -42,8 +42,8 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { // struct SCTMData { SCTMData(); - Mat3x3 ctmFrom = Mat3x3::identity(), ctmTo = Mat3x3::identity(); - CAnimatedVariable progress; + Mat3x3 ctmFrom = Mat3x3::identity(), ctmTo = Mat3x3::identity(); + PHLANIMVAR progress; }; std::map> m_mCTMDatas; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index f5fbaa0c..2c934b40 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -119,7 +119,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re dmabufFormat = PMONITOR->output->state->state().drmFormat; - box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; + box = {0, 0, (int)(pWindow->m_vRealSize->value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize->value().y * PMONITOR->scale)}; box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); @@ -263,7 +263,7 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition->value()); const auto PFORMAT = NFormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { @@ -315,7 +315,7 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) { g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (overlayCursor) - g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition.value()); + g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - pWindow->m_vRealPosition->value()); g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); @@ -386,7 +386,7 @@ void CToplevelExportProtocol::onOutputCommit(PHLMONITOR pMonitor) { if (pMonitor != PWINDOW->m_pMonitor.lock()) continue; - CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; + CBox geometry = {PWINDOW->m_vRealPosition->value().x, PWINDOW->m_vRealPosition->value().y, PWINDOW->m_vRealSize->value().x, PWINDOW->m_vRealSize->value().y}; if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty()) continue; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 94b70acf..93ab5fdf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -713,7 +713,7 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { if (!ws->m_bIsSpecialWorkspace || ws->m_pMonitor != pMonitor) continue; - if (ws->m_fAlpha.value() == 0) + if (ws->m_fAlpha->value() == 0) continue; return true; @@ -1517,7 +1517,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB if (allowDim && m_RenderData.currentWindow) { glUniform1i(shader->applyTint, 1); - const auto DIM = m_RenderData.currentWindow->m_fDimPercent.value(); + const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); } else { glUniform1i(shader->applyTint, 0); @@ -1931,7 +1931,7 @@ void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) { const auto PSURFACE = pWindow->m_pWLSurface->resource(); const auto PWORKSPACE = pWindow->m_pWorkspace; - const float A = pWindow->m_fAlpha.value() * pWindow->m_fActiveInactiveAlpha.value() * PWORKSPACE->m_fAlpha.value(); + const float A = pWindow->m_fAlpha->value() * pWindow->m_fActiveInactiveAlpha->value() * PWORKSPACE->m_fAlpha->value(); if (A >= 1.f) { // if (PSURFACE->opaque) @@ -1969,7 +1969,7 @@ void CHyprOpenGLImpl::preRender(PHLMONITOR pMonitor) { if (!ls->layerSurface || ls->xray != 1) continue; - // if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f) + // if (ls->layerSurface->surface->opaque && ls->alpha->value() >= 1.f) // continue; hasWindows = true; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d154e64a..4d93d92f 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -172,21 +172,21 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it. - if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha.isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha.value() > 0.F && pWindow->m_pWorkspace && + if (pWindow->m_iMonitorMovedFrom != -1 && pWindow->m_fMovingToWorkspaceAlpha->isBeingAnimated() && pWindow->m_fMovingToWorkspaceAlpha->value() > 0.F && pWindow->m_pWorkspace && !pWindow->m_pWorkspace->isVisible()) return true; const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_pMonitor == pMonitor) { - if (PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) + if (PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWINDOWWORKSPACE->m_fAlpha->isBeingAnimated() || PWINDOWWORKSPACE->m_bForceRendering) return true; // if hidden behind fullscreen if (PWINDOWWORKSPACE->m_bHasFullscreenWindow && !pWindow->isFullscreen() && (!pWindow->m_bIsFloating || !pWindow->m_bCreatedOverFullscreen) && - pWindow->m_fAlpha.value() == 0) + pWindow->m_fAlpha->value() == 0) return false; - if (!PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha.isBeingAnimated() && !PWINDOWWORKSPACE->isVisible()) + if (!PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOWWORKSPACE->m_fAlpha->isBeingAnimated() && !PWINDOWWORKSPACE->isVisible()) return false; } @@ -204,17 +204,17 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { return true; // if window is tiled and it's flying in, don't render on other mons (for slide) - if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition.isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_pMonitor != pMonitor) + if (!pWindow->m_bIsFloating && pWindow->m_vRealPosition->isBeingAnimated() && pWindow->m_bAnimatingIn && pWindow->m_pMonitor != pMonitor) return false; - if (pWindow->m_vRealPosition.isBeingAnimated()) { - if (PWINDOWWORKSPACE && !PWINDOWWORKSPACE->m_bIsSpecialWorkspace && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) + if (pWindow->m_vRealPosition->isBeingAnimated()) { + if (PWINDOWWORKSPACE && !PWINDOWWORKSPACE->m_bIsSpecialWorkspace && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated()) return false; // render window if window and monitor intersect // (when moving out of or through a monitor) CBox windowBox = pWindow->getFullWindowBoundingBox(); - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated()) - windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated()) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); windowBox.translate(pWindow->m_vFloatingOffset); const CBox monitorBox = {pMonitor->vecPosition, pMonitor->vecSize}; @@ -242,7 +242,7 @@ bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow) { return true; for (auto const& m : g_pCompositor->m_vMonitors) { - if (PWORKSPACE && PWORKSPACE->m_pMonitor == m && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) + if (PWORKSPACE && PWORKSPACE->m_pMonitor == m && (PWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWORKSPACE->m_fAlpha->isBeingAnimated())) return true; if (m->activeSpecialWorkspace && pWindow->onSpecialWorkspace()) @@ -262,7 +262,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (!shouldRenderWindow(w, pMonitor)) continue; - if (w->m_fAlpha.value() == 0.f) + if (w->m_fAlpha->value() == 0.f) continue; if (w->isFullscreen() || w->m_bIsFloating) @@ -279,7 +279,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR if (!shouldRenderWindow(w, pMonitor)) continue; - if (w->m_fAlpha.value() == 0.f) + if (w->m_fAlpha->value() == 0.f) continue; if (w->isFullscreen() || !w->m_bIsFloating) @@ -299,7 +299,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR const auto PWORKSPACE = w->m_pWorkspace; if (w->m_pWorkspace != pWorkspace || !w->isFullscreen()) { - if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated() || PWORKSPACE->m_bForceRendering))) + if (!(PWORKSPACE && (PWORKSPACE->m_vRenderOffset->isBeingAnimated() || PWORKSPACE->m_fAlpha->isBeingAnimated() || PWORKSPACE->m_bForceRendering))) continue; if (w->m_pMonitor != pMonitor) @@ -432,12 +432,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe TRACY_GPU_ZONE("RenderWindow"); const auto PWORKSPACE = pWindow->m_pWorkspace; - const auto REALPOS = pWindow->m_vRealPosition.value() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset.value()); + const auto REALPOS = pWindow->m_vRealPosition->value() + (pWindow->m_bPinned ? Vector2D{} : PWORKSPACE->m_vRenderOffset->value()); static auto PDIMAROUND = CConfigValue("decoration:dim_around"); static auto PBLUR = CConfigValue("decoration:blur:enabled"); CSurfacePassElement::SRenderData renderdata = {pMonitor, time}; - CBox textureBox = {REALPOS.x, REALPOS.y, std::max(pWindow->m_vRealSize.value().x, 5.0), std::max(pWindow->m_vRealSize.value().y, 5.0)}; + CBox textureBox = {REALPOS.x, REALPOS.y, std::max(pWindow->m_vRealSize->value().x, 5.0), std::max(pWindow->m_vRealSize->value().y, 5.0)}; renderdata.pos.x = textureBox.x; renderdata.pos.y = textureBox.y; @@ -458,9 +458,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.surface = pWindow->m_pWLSurface->resource(); renderdata.dontRound = pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || pWindow->m_sWindowData.noRounding.valueOrDefault(); - renderdata.fadeAlpha = pWindow->m_fAlpha.value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha.value()) * - (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha.value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha.value(); - renderdata.alpha = pWindow->m_fActiveInactiveAlpha.value(); + renderdata.fadeAlpha = pWindow->m_fAlpha->value() * (pWindow->m_bPinned || USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE->m_fAlpha->value()) * + (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha->value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha->value(); + renderdata.alpha = pWindow->m_fActiveInactiveAlpha->value(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; renderdata.roundingPower = ignoreAllGeometry || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); @@ -492,9 +492,9 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.pos.y += pWindow->m_vFloatingOffset.y; // if window is floating and we have a slide animation, clip it to its full bb - if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->isFullscreen() && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) { + if (!ignorePosition && pWindow->m_bIsFloating && !pWindow->isFullscreen() && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !pWindow->m_bPinned) { CRegion rg = - pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset.value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); + pWindow->getFullWindowBoundingBox().translate(-pMonitor->vecPosition + PWORKSPACE->m_vRenderOffset->value() + pWindow->m_vFloatingOffset).scale(pMonitor->scale); renderdata.clipBox = rg.getExtents(); } @@ -657,7 +657,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim if (*PDIMAROUND && pLayer->dimAround && !m_bRenderingSnapshot && !popups) { CRectPassElement::SRectData data; data.box = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize.y}; - data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha.value()); + data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pLayer->alpha->value()); m_sRenderPass.add(makeShared(data)); } @@ -671,11 +671,11 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim TRACY_GPU_ZONE("RenderLayer"); - const auto REALPOS = pLayer->realPosition.value(); - const auto REALSIZ = pLayer->realSize.value(); + const auto REALPOS = pLayer->realPosition->value(); + const auto REALSIZ = pLayer->realSize->value(); CSurfacePassElement::SRenderData renderdata = {pMonitor, time, REALPOS}; - renderdata.fadeAlpha = pLayer->alpha.value(); + renderdata.fadeAlpha = pLayer->alpha->value(); renderdata.blur = pLayer->forceBlur && *PBLUR; renderdata.surface = pLayer->surface->resource(); renderdata.decorate = false; @@ -866,8 +866,8 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // and then special for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_pMonitor == pMonitor && ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { - const auto SPECIALANIMPROGRS = ws->m_vRenderOffset.isBeingAnimated() ? ws->m_vRenderOffset.getCurveValue() : ws->m_fAlpha.getCurveValue(); + if (ws->m_pMonitor == pMonitor && ws->m_fAlpha->value() > 0.f && ws->m_bIsSpecialWorkspace) { + const auto SPECIALANIMPROGRS = ws->m_vRenderOffset->isBeingAnimated() ? ws->m_vRenderOffset->getCurveValue() : ws->m_fAlpha->getCurveValue(); const bool ANIMOUT = !pMonitor->activeSpecialWorkspace; if (*PDIMSPECIAL != 0.f) { @@ -894,7 +894,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPA // special for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (ws->m_fAlpha.value() > 0.f && ws->m_bIsSpecialWorkspace) { + if (ws->m_fAlpha->value() > 0.f && ws->m_bIsSpecialWorkspace) { if (ws->m_bHasFullscreenWindow) renderWorkspaceWindowsFullscreen(pMonitor, ws, time); else @@ -1617,8 +1617,8 @@ void CHyprRenderer::arrangeLayerArray(PHLMONITOR pMonitor, const std::vectorlayerSurface->configure(box.size()); - ls->realPosition = box.pos(); - ls->realSize = box.size(); + *ls->realPosition = box.pos(); + *ls->realSize = box.size(); } } @@ -1727,8 +1727,8 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { CBox windowBox = pWindow->getFullWindowBoundingBox(); const auto PWINDOWWORKSPACE = pWindow->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !pWindow->m_bPinned) - windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !pWindow->m_bPinned) + windowBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); windowBox.translate(pWindow->m_vFloatingOffset); for (auto const& m : g_pCompositor->m_vMonitors) { @@ -1977,8 +1977,8 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { const auto PWORKSPACE = pMonitor->activeWorkspace; - if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || PROTO::data->dndActive() || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha.value() != 1.f || - PWORKSPACE->m_vRenderOffset.value() != Vector2D{}) + if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || PROTO::data->dndActive() || pMonitor->activeSpecialWorkspace || PWORKSPACE->m_fAlpha->value() != 1.f || + PWORKSPACE->m_vRenderOffset->value() != Vector2D{}) return; const auto PCANDIDATE = PWORKSPACE->getFullscreenWindow(); @@ -1989,15 +1989,15 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { if (!PCANDIDATE->opaque()) return; - if (PCANDIDATE->m_vRealSize.value() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.value() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() || - PCANDIDATE->m_vRealSize.isBeingAnimated()) + if (PCANDIDATE->m_vRealSize->value() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition->value() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition->isBeingAnimated() || + PCANDIDATE->m_vRealSize->isBeingAnimated()) return; if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty()) return; for (auto const& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - if (topls->alpha.value() != 0.f) + if (topls->alpha->value() != 0.f) return; } @@ -2410,13 +2410,13 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { CBox windowBox; // some mafs to figure out the correct box // the originalClosedPos is relative to the monitor's pos - Vector2D scaleXY = Vector2D((PMONITOR->scale * pWindow->m_vRealSize.value().x / (pWindow->m_vOriginalClosedSize.x * PMONITOR->scale)), - (PMONITOR->scale * pWindow->m_vRealSize.value().y / (pWindow->m_vOriginalClosedSize.y * PMONITOR->scale))); + Vector2D scaleXY = Vector2D((PMONITOR->scale * pWindow->m_vRealSize->value().x / (pWindow->m_vOriginalClosedSize.x * PMONITOR->scale)), + (PMONITOR->scale * pWindow->m_vRealSize->value().y / (pWindow->m_vOriginalClosedSize.y * PMONITOR->scale))); windowBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x; windowBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y; - windowBox.x = ((pWindow->m_vRealPosition.value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); - windowBox.y = ((pWindow->m_vRealPosition.value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); + windowBox.x = ((pWindow->m_vRealPosition->value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); + windowBox.y = ((pWindow->m_vRealPosition->value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((pWindow->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; @@ -2425,7 +2425,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { CRectPassElement::SRectData data; data.box = {0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y}; - data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha.value()); + data.color = CHyprColor(0, 0, 0, *PDIMAROUND * pWindow->m_fAlpha->value()); m_sRenderPass.add(makeShared(data)); damageMonitor(PMONITOR); @@ -2435,7 +2435,7 @@ void CHyprRenderer::renderSnapshot(PHLWINDOW pWindow) { data.flipEndFrame = true; data.tex = FBDATA->getTexture(); data.box = windowBox; - data.a = pWindow->m_fAlpha.value(); + data.a = pWindow->m_fAlpha->value(); data.damage = fakeDamage; m_sRenderPass.add(makeShared(data)); @@ -2455,13 +2455,13 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { CBox layerBox; // some mafs to figure out the correct box // the originalClosedPos is relative to the monitor's pos - Vector2D scaleXY = Vector2D((PMONITOR->scale * pLayer->realSize.value().x / (pLayer->geometry.w * PMONITOR->scale)), - (PMONITOR->scale * pLayer->realSize.value().y / (pLayer->geometry.h * PMONITOR->scale))); + Vector2D scaleXY = Vector2D((PMONITOR->scale * pLayer->realSize->value().x / (pLayer->geometry.w * PMONITOR->scale)), + (PMONITOR->scale * pLayer->realSize->value().y / (pLayer->geometry.h * PMONITOR->scale))); layerBox.width = PMONITOR->vecTransformedSize.x * scaleXY.x; layerBox.height = PMONITOR->vecTransformedSize.y * scaleXY.y; - layerBox.x = ((pLayer->realPosition.value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - (((pLayer->geometry.x - PMONITOR->vecPosition.x) * PMONITOR->scale) * scaleXY.x); - layerBox.y = ((pLayer->realPosition.value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - (((pLayer->geometry.y - PMONITOR->vecPosition.y) * PMONITOR->scale) * scaleXY.y); + layerBox.x = ((pLayer->realPosition->value().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - (((pLayer->geometry.x - PMONITOR->vecPosition.x) * PMONITOR->scale) * scaleXY.x); + layerBox.y = ((pLayer->realPosition->value().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - (((pLayer->geometry.y - PMONITOR->vecPosition.y) * PMONITOR->scale) * scaleXY.y); CRegion fakeDamage{0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y}; @@ -2469,7 +2469,7 @@ void CHyprRenderer::renderSnapshot(PHLLS pLayer) { data.flipEndFrame = true; data.tex = FBDATA->getTexture(); data.box = layerBox; - data.a = pLayer->alpha.value(); + data.a = pLayer->alpha->value(); data.damage = fakeDamage; m_sRenderPass.add(makeShared(data)); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 2bc894ef..7261431f 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -43,7 +43,7 @@ CBox CHyprBorderDecoration::assignedBoxGlobal() { if (!PWORKSPACE) return box; - const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); + const auto WORKSPACEOFFSET = PWORKSPACE && !m_pWindow->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); return box.translate(WORKSPACEOFFSET); } @@ -60,10 +60,10 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { return; auto grad = m_pWindow->m_cRealBorderColor; - const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress.isBeingAnimated(); + const bool ANIMATED = m_pWindow->m_fBorderFadeAnimationProgress->isBeingAnimated(); - if (m_pWindow->m_fBorderAngleAnimationProgress.getConfig()->pValues->internalEnabled) { - grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress.value() * M_PI * 2; + if (m_pWindow->m_fBorderAngleAnimationProgress->enabled()) { + grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress->value() * M_PI * 2; grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); } @@ -83,7 +83,7 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { data.hasGrad2 = true; data.grad1 = m_pWindow->m_cRealBorderColorPrevious; data.grad2 = grad; - data.lerp = m_pWindow->m_fBorderFadeAnimationProgress.value(); + data.lerp = m_pWindow->m_fBorderFadeAnimationProgress->value(); } g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); @@ -117,8 +117,8 @@ void CHyprBorderDecoration::damageEntire() { const auto BORDERSIZE = m_pWindow->getRealBorderSize() + 1; const auto PWINDOWWORKSPACE = m_pWindow->m_pWorkspace; - if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset.isBeingAnimated() && !m_pWindow->m_bPinned) - surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset.value()); + if (PWINDOWWORKSPACE && PWINDOWWORKSPACE->m_vRenderOffset->isBeingAnimated() && !m_pWindow->m_bPinned) + surfaceBox.translate(PWINDOWWORKSPACE->m_vRenderOffset->value()); surfaceBox.translate(m_pWindow->m_vFloatingOffset); CBox surfaceBoxExpandedBorder = surfaceBox; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 07dbb436..ddd5198d 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -44,13 +44,13 @@ void CHyprDropShadowDecoration::damageEntire() { const auto PWINDOW = m_pWindow.lock(); - CBox shadowBox = {PWINDOW->m_vRealPosition.value().x - m_seExtents.topLeft.x, PWINDOW->m_vRealPosition.value().y - m_seExtents.topLeft.y, - PWINDOW->m_vRealSize.value().x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, - PWINDOW->m_vRealSize.value().y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; + CBox shadowBox = {PWINDOW->m_vRealPosition->value().x - m_seExtents.topLeft.x, PWINDOW->m_vRealPosition->value().y - m_seExtents.topLeft.y, + PWINDOW->m_vRealSize->value().x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x, + PWINDOW->m_vRealSize->value().y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y}; const auto PWORKSPACE = PWINDOW->m_pWorkspace; - if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOW->m_bPinned) - shadowBox.translate(PWORKSPACE->m_vRenderOffset.value()); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOW->m_bPinned) + shadowBox.translate(PWORKSPACE->m_vRenderOffset->value()); shadowBox.translate(PWINDOW->m_vFloatingOffset); static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); @@ -61,8 +61,8 @@ void CHyprDropShadowDecoration::damageEntire() { CRegion shadowRegion(shadowBox); if (*PSHADOWIGNOREWINDOW) { CBox surfaceBox = PWINDOW->getWindowMainSurfaceBox(); - if (PWORKSPACE && PWORKSPACE->m_vRenderOffset.isBeingAnimated() && !PWINDOW->m_bPinned) - surfaceBox.translate(PWORKSPACE->m_vRenderOffset.value()); + if (PWORKSPACE && PWORKSPACE->m_vRenderOffset->isBeingAnimated() && !PWINDOW->m_bPinned) + surfaceBox.translate(PWORKSPACE->m_vRenderOffset->value()); surfaceBox.translate(PWINDOW->m_vFloatingOffset); surfaceBox.expand(-ROUNDINGSIZE); shadowRegion.subtract(CRegion(surfaceBox)); @@ -81,8 +81,8 @@ void CHyprDropShadowDecoration::damageEntire() { void CHyprDropShadowDecoration::updateWindow(PHLWINDOW pWindow) { const auto PWINDOW = m_pWindow.lock(); - m_vLastWindowPos = PWINDOW->m_vRealPosition.value(); - m_vLastWindowSize = PWINDOW->m_vRealSize.value(); + m_vLastWindowPos = PWINDOW->m_vRealPosition->value(); + m_vLastWindowSize = PWINDOW->m_vRealSize->value(); m_bLastWindowBox = {m_vLastWindowPos.x, m_vLastWindowPos.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; m_bLastWindowBoxWithDecos = g_pDecorationPositioner->getBoxWithIncludedDecos(pWindow); @@ -101,7 +101,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { if (!validMapped(PWINDOW)) return; - if (PWINDOW->m_cRealShadowColor.value() == CHyprColor(0, 0, 0, 0)) + if (PWINDOW->m_cRealShadowColor->value() == CHyprColor(0, 0, 0, 0)) return; // don't draw invisible shadows if (!PWINDOW->m_sWindowData.decorate.valueOrDefault()) @@ -123,7 +123,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDING = ROUNDINGBASE > 0 ? ROUNDINGBASE + PWINDOW->getRealBorderSize() : 0; const auto PWORKSPACE = PWINDOW->m_pWorkspace; - const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset.value() : Vector2D(); + const auto WORKSPACEOFFSET = PWORKSPACE && !PWINDOW->m_bPinned ? PWORKSPACE->m_vRenderOffset->value() : Vector2D(); // draw the shadow CBox fullBox = m_bLastWindowBoxWithDecos; @@ -194,7 +194,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor.value().a), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor->value().a), a); // render black window box ("clip") g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); @@ -202,7 +202,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { alphaSwapFB.bind(); // alpha swap just has the shadow color. It will be the "texture" to render. - g_pHyprOpenGL->renderRect(&fullBox, PWINDOW->m_cRealShadowColor.value().stripA(), 0); + g_pHyprOpenGL->renderRect(&fullBox, PWINDOW->m_cRealShadowColor->value().stripA(), 0); LASTFB->bind(); @@ -216,7 +216,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor.value(), a); + drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor->value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index c6dc5779..970273d7 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -390,9 +390,9 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND // restores the group for (auto it = members.begin(); it != members.end(); ++it) { - (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members - (*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize.goal(); // match the size of group members - (*it)->m_vRealPosition = pWindowInsertAfter->m_vRealPosition.goal(); // match the position of group members + (*it)->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of group members + *(*it)->m_vRealSize = pWindowInsertAfter->m_vRealSize->goal(); // match the size of group members + *(*it)->m_vRealPosition = pWindowInsertAfter->m_vRealPosition->goal(); // match the position of group members if (std::next(it) != members.end()) (*it)->m_sGroupData.pNextWindow = *std::next(it); else @@ -406,7 +406,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window if (pWindowInsertAfter->m_bIsFloating) - g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize.goal()); // match the size of the window + g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); @@ -515,7 +515,7 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() { const auto PWORKSPACE = m_pWindow->m_pWorkspace; if (PWORKSPACE && !m_pWindow->m_bPinned) - box.translate(PWORKSPACE->m_vRenderOffset.value()); + box.translate(PWORKSPACE->m_vRenderOffset->value()); return box; } diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 6a41cbdc..abfa19ec 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -124,7 +124,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { datas.push_back(getDataFor(wd.get(), pWindow)); } - if (WINDOWDATA->lastWindowSize == pWindow->m_vRealSize.value() /* position not changed */ + if (WINDOWDATA->lastWindowSize == pWindow->m_vRealSize->value() /* position not changed */ && std::all_of(m_vWindowPositioningDatas.begin(), m_vWindowPositioningDatas.end(), [pWindow](const auto& data) { return pWindow != data->pWindow.lock() || !data->needsReposition; }) /* all window datas are either not for this window or don't need a reposition */ @@ -132,9 +132,9 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { ) return; - WINDOWDATA->lastWindowSize = pWindow->m_vRealSize.value(); + WINDOWDATA->lastWindowSize = pWindow->m_vRealSize->value(); WINDOWDATA->needsRecalc = false; - const bool EPHEMERAL = pWindow->m_vRealSize.isBeingAnimated(); + const bool EPHEMERAL = pWindow->m_vRealSize->isBeingAnimated(); std::sort(datas.begin(), datas.end(), [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; }); diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 13e9e741..f2f2627a 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -77,7 +77,7 @@ void CSurfacePassElement::draw(const CRegion& damage) { const bool MISALIGNEDFSV1 = std::floor(data.pMonitor->scale) != data.pMonitor->scale /* Fractional */ && data.surface->current.scale == 1 /* fs protocol */ && windowBox.size() != data.surface->current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, data.surface->current.bufferSize.x, 3) && DELTALESSTHAN(windowBox.height, data.surface->current.bufferSize.y, 3) /* off by one-or-two */ && - (!data.pWindow || (!data.pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + (!data.pWindow || (!data.pWindow->m_vRealSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); @@ -148,8 +148,8 @@ CBox CSurfacePassElement::getTexBox() { if (!INTERACTIVERESIZEINPROGRESS) { windowBox.translate(CORRECT); - windowBox.width = SIZE.x * (PWINDOW->m_vRealSize.value().x / PWINDOW->m_vReportedSize.x); - windowBox.height = SIZE.y * (PWINDOW->m_vRealSize.value().y / PWINDOW->m_vReportedSize.y); + windowBox.width = SIZE.x * (PWINDOW->m_vRealSize->value().x / PWINDOW->m_vReportedSize.x); + windowBox.height = SIZE.y * (PWINDOW->m_vRealSize->value().y / PWINDOW->m_vReportedSize.y); } else { windowBox.width = SIZE.x; windowBox.height = SIZE.y; @@ -159,10 +159,10 @@ CBox CSurfacePassElement::getTexBox() { } else { // here we clamp to 2, these might be some tiny specks windowBox = {(int)outputX + data.pos.x + data.localPos.x, (int)outputY + data.pos.y + data.localPos.y, std::max((float)data.surface->current.size.x, 2.F), std::max((float)data.surface->current.size.y, 2.F)}; - if (data.pWindow && data.pWindow->m_vRealSize.isBeingAnimated() && data.surface && !data.mainSurface && data.squishOversized /* subsurface */) { + if (data.pWindow && data.pWindow->m_vRealSize->isBeingAnimated() && data.surface && !data.mainSurface && data.squishOversized /* subsurface */) { // adjust subsurfaces to the window - windowBox.width = (windowBox.width / data.pWindow->m_vReportedSize.x) * data.pWindow->m_vRealSize.value().x; - windowBox.height = (windowBox.height / data.pWindow->m_vReportedSize.y) * data.pWindow->m_vRealSize.value().y; + windowBox.width = (windowBox.width / data.pWindow->m_vReportedSize.x) * data.pWindow->m_vRealSize->value().x; + windowBox.height = (windowBox.height / data.pWindow->m_vReportedSize.y) * data.pWindow->m_vRealSize->value().y; } } From 95542e44884d2131a742f92013826a0b5f341b33 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 19:13:35 +0100 Subject: [PATCH 1035/2393] animationmgr: fix invalid include --- src/managers/AnimationManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 7bf73f97..10eeef05 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -5,7 +5,7 @@ #include "../defines.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "desktop/DesktopTypes.hpp" +#include "../desktop/DesktopTypes.hpp" #include "eventLoop/EventLoopTimer.hpp" class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { From 830350a1f7a5ad653f33f2c62dd1694249a2f1e2 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Tue, 7 Jan 2025 21:32:50 +0300 Subject: [PATCH 1036/2393] core: Add support for HDR and color management protocols (#8715) --- CMakeLists.txt | 2 + protocols/frog-color-management-v1.xml | 366 ++++++ protocols/meson.build | 2 + protocols/xx-color-management-v4.xml | 1457 +++++++++++++++++++++++ src/Compositor.cpp | 19 + src/Compositor.hpp | 4 + src/config/ConfigDescriptions.hpp | 18 + src/config/ConfigManager.cpp | 4 + src/desktop/WLSurface.hpp | 1 + src/managers/ProtocolManager.cpp | 11 + src/protocols/ColorManagement.cpp | 571 +++++++++ src/protocols/ColorManagement.hpp | 182 +++ src/protocols/FrogColorManagement.cpp | 159 +++ src/protocols/FrogColorManagement.hpp | 55 + src/protocols/core/Compositor.hpp | 3 + src/protocols/types/ColorManagement.hpp | 47 + src/render/Renderer.cpp | 97 ++ src/render/pass/SurfacePassElement.cpp | 2 + 18 files changed, 3000 insertions(+) create mode 100644 protocols/frog-color-management-v1.xml create mode 100644 protocols/xx-color-management-v4.xml create mode 100644 src/protocols/ColorManagement.cpp create mode 100644 src/protocols/ColorManagement.hpp create mode 100644 src/protocols/FrogColorManagement.cpp create mode 100644 src/protocols/FrogColorManagement.hpp create mode 100644 src/protocols/types/ColorManagement.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa746d2e..c1ecb14c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -316,6 +316,8 @@ protocolnew("protocols" "kde-server-decoration" true) protocolnew("protocols" "wlr-data-control-unstable-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true) protocolnew("protocols" "wlr-layer-shell-unstable-v1" true) +protocolnew("protocols" "xx-color-management-v4" true) +protocolnew("protocols" "frog-color-management-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) diff --git a/protocols/frog-color-management-v1.xml b/protocols/frog-color-management-v1.xml new file mode 100644 index 00000000..aab235a7 --- /dev/null +++ b/protocols/frog-color-management-v1.xml @@ -0,0 +1,366 @@ + + + + + Copyright © 2023 Joshua Ashton for Valve Software + Copyright © 2023 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of this color management extension is to get HDR games working quickly, + and have an easy way to test implementations in the wild before the upstream + protocol is ready to be merged. + For that purpose it's intentionally limited and cut down and does not serve + all uses cases. + + + + + The color management factory singleton creates color managed surface objects. + + + + + + + + + + + + + + + + Interface for changing surface color management and HDR state. + + An implementation must: support every part of the version + of the frog_color_managed_surface interface it exposes. + Including all known enums associated with a given version. + + + + + Destroying the color managed surface resets all known color + state for the surface back to 'undefined' implementation-specific + values. + + + + + + Extended information on the transfer functions described + here can be found in the Khronos Data Format specification: + https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html + + + + + + + + + + + + + + + + + + + + + + + + + + + + Extended information on render intents described + here can be found in ICC.1:2022: + + https://www.color.org/specification/ICC.1-2022-05.pdf + + + + + + + NOTE: On a surface with "perceptual" (default) render intent, handling of the container's + color volume + is implementation-specific, and may differ between different transfer functions it is paired + with: + ie. sRGB + 709 rendering may have it's primaries widened to more of the available display's + gamut + to be be more pleasing for the viewer. + Compared to scRGB Linear + 709 being treated faithfully as 709 + (including utilizing negatives out of the 709 gamut triangle) + + + + + + + Forwards HDR metadata from the client to the compositor. + + HDR Metadata Infoframe as per CTA 861.G spec. + + Usage of this HDR metadata is implementation specific and + outside of the scope of this protocol. + + + + Mastering Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Mastering White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Mastering Display Luminance. + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Content Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Max Frame Average Light Level. + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + + + Current preferred metadata for a surface. + The application should use this information to tone-map its buffers + to this target before committing. + + This metadata does not necessarily correspond to any physical output, but + rather what the compositor thinks would be best for a given surface. + + + + Specifies a known transfer function that corresponds to the + output the surface is targeting. + + + + + Output Red Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Red Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Green Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary X Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output Blue Color Primary Y Coordinate of the Data. + + Coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point X Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Output White Point Y Coordinate of the Data. + + These are coded as unsigned 16-bit values in units of + 0.00002, where 0x0000 represents zero and 0xC350 + represents 1.0000. + + + + + Max Output Luminance + The max luminance in nits that the output is capable of rendering in small areas. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + Min Output Luminance + The min luminance that the output is capable of rendering. + Content should: not exceed this value to avoid clipping. + + This value is coded as an unsigned 16-bit value in units of + 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + represents 6.5535 cd/m2. + + + + + Max Full Frame Luminance + The max luminance in nits that the output is capable of rendering for the + full frame sustained. + + This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + + + + + \ No newline at end of file diff --git a/protocols/meson.build b/protocols/meson.build index a39602b7..fdbbf181 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -33,6 +33,8 @@ protocols = [ 'wayland-drm.xml', 'wlr-data-control-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml', + 'xx-color-management-v4.xml', + 'frog-color-management-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', diff --git a/protocols/xx-color-management-v4.xml b/protocols/xx-color-management-v4.xml new file mode 100644 index 00000000..23ff716e --- /dev/null +++ b/protocols/xx-color-management-v4.xml @@ -0,0 +1,1457 @@ + + + + Copyright 2019 Sebastian Wick + Copyright 2019 Erwin Burema + Copyright 2020 AMD + Copyright 2020-2024 Collabora, Ltd. + Copyright 2024 Xaver Hugl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + The aim of the color management extension is to allow clients to know + the color properties of outputs, and to tell the compositor about the color + properties of their content on surfaces. Doing this enables a compositor + to perform automatic color management of content for different outputs + according to how content is intended to look like. + + The color properties are represented as an image description object which + is immutable after it has been created. A wl_output always has an + associated image description that clients can observe. A wl_surface + always has an associated preferred image description as a hint chosen by + the compositor that clients can also observe. Clients can set an image + description on a wl_surface to denote the color characteristics of the + surface contents. + + An image description includes SDR and HDR colorimetry and encoding, HDR + metadata, and viewing environment parameters. An image description does + not include the properties set through color-representation extension. + It is expected that the color-representation extension is used in + conjunction with the color management extension when necessary, + particularly with the YUV family of pixel formats. + + Recommendation ITU-T H.273 + "Coding-independent code points for video signal type identification" + shall be referred to as simply H.273 here. + + The color-and-hdr repository + (https://gitlab.freedesktop.org/pq/color-and-hdr) contains + background information on the protocol design and legacy color management. + It also contains a glossary, learning resources for digital color, tools, + samples and more. + + The terminology used in this protocol is based on common color science and + color encoding terminology where possible. The glossary in the color-and-hdr + repository shall be the authority on the definition of terms in this + protocol. + + + + + A global interface used for getting color management extensions for + wl_surface and wl_output objects, and for creating client defined image + description objects. The extension interfaces allow + getting the image description of outputs and setting the image + description of surfaces. + + + + + Destroy the xx_color_manager_v4 object. This does not affect any other + objects in any way. + + + + + + + + + + + See the ICC.1:2022 specification from the International Color Consortium + for more details about rendering intents. + + The principles of ICC defined rendering intents apply with all types of + image descriptions, not only those with ICC file profiles. + + Compositors must support the perceptual rendering intent. Other + rendering intents are optional. + + + + + + + + + + + + + + + + + + + + The compositor supports set_mastering_display_primaries request with a + target color volume fully contained inside the primary color volume. + + + + + The compositor additionally supports target color volumes that + extend outside of the primary color volume. + + This can only be advertised if feature set_mastering_display_primaries + is supported as well. + + + + + + + Named color primaries used to encode well-known sets of primaries. H.273 + is the authority, when it comes to the exact values of primaries and + authoritative specifications, where an equivalent code point exists. + + Descriptions do list the specifications for convenience. + + + + + Color primaries as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system and extended + colour gamut system (historical) + - IEC 61966-2-1 sRGB or sYCC + - IEC 61966-2-4 + - Society of Motion Picture and Television Engineers (SMPTE) RP 177 + (1993) Annex B + Equivalent to H.273 ColourPrimaries code point 1. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a)(20) + Equivalent to H.273 ColourPrimaries code point 4. + + + + + Color primaries as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + - Rec. ITU-R BT.601-7 625 + - Rec. ITU-R BT.1358-0 625 (historical) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 ColourPrimaries code point 5. + + + + + Color primaries as defined by + - Rec. ITU-R BT.601-7 525 + - Rec. ITU-R BT.1358-1 525 or 625 (historical) + - Rec. ITU-R BT.1700-0 NTSC + - SMPTE 170M (2004) + - SMPTE 240M (1999) (historical) + Equivalent to H.273 ColourPrimaries code point 6 and 7. + + + + + Color primaries as defined by H.273 for generic film. + Equivalent to H.273 ColourPrimaries code point 8. + + + + + Color primaries as defined by + - Rec. ITU-R BT.2020-2 + - Rec. ITU-R BT.2100-0 + Equivalent to H.273 ColourPrimaries code point 9. + + + + + Color primaries as defined as the maximum of the CIE 1931 XYZ color + space by + - SMPTE ST 428-1 + - (CIE 1931 XYZ as in ISO 11664-1) + Equivalent to H.273 ColourPrimaries code point 10. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point + 11. + + + + + Color primaries as defined by Digital Cinema System and published in + SMPTE EG 432-1 (2010). + Equivalent to H.273 ColourPrimaries code point 12. + + + + + Color primaries as defined by Adobe as "Adobe RGB" and later published + by ISO 12640-4 (2011). + + + + + + + Named transfer functions used to encode well-known transfer + characteristics. H.273 is the authority, when it comes to the exact + formulas and authoritative specifications, where an equivalent code + point exists. + + Descriptions do list the specifications for convenience. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.709-6 + - Rec. ITU-R BT.1361-0 conventional colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 1, 6, 14, 15. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System M (historical) + - United States National Television System Committee 1953 + Recommendation for transmission standards for color television + - United States Federal Communications Commission (2003) Title 47 Code + of Federal Regulations 73.682 (a) (20) + - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + Equivalent to H.273 TransferCharacteristics code point 4. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.470-6 System B, G (historical) + Equivalent to H.273 TransferCharacteristics code point 5. + + + + + Transfer characteristics as defined by + - SMPTE ST 240 (1999) + Equivalent to H.273 TransferCharacteristics code point 7. + + + + + Linear transfer characteristics. + Equivalent to H.273 TransferCharacteristics code point 8. + + + + + Logarithmic transfer characteristic (100:1 range). + Equivalent to H.273 TransferCharacteristics code point 9. + + + + + Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + Equivalent to H.273 TransferCharacteristics code point 10. + + + + + Transfer characteristics as defined by + - IEC 61966-2-4 + Equivalent to H.273 TransferCharacteristics code point 11. + + + + + Transfer characteristics as defined by + - Rec. ITU-R BT.1361-0 extended colour gamut system (historical) + Equivalent to H.273 TransferCharacteristics code point 12. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sRGB + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to 0. + + + + + Transfer characteristics as defined by + - IEC 61966-2-1 sYCC + Equivalent to H.273 TransferCharacteristics code point 13 with + MatrixCoefficients set to anything but 0. + + + + + Transfer characteristics as defined by + - SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems + - Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system + Equivalent to H.273 TransferCharacteristics code point 16. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 10000 cd/m² + - reference white: 203 cd/m² + + + + + Transfer characteristics as defined by + - SMPTE ST 428-1 (2019) + Equivalent to H.273 TransferCharacteristics code point 17. + + + + + Transfer characteristics as defined by + - ARIB STD-B67 (2015) + - Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + Equivalent to H.273 TransferCharacteristics code point 18. + + This TF implies these default luminances + - primary color volume minimum: 0.005 cd/m² + - primary color volume maximum: 1000 cd/m² + - reference white: 203 cd/m² + Note: HLG is a scene referred signal. All absolute luminance values + used here for HLG assume a 1000 cd/m² display. + + + + + + + This creates a new xx_color_management_output_v4 object for the + given wl_output. + + See the xx_color_management_output_v4 interface for more details. + + + + + + + + + If a xx_color_management_surface_v4 object already exists for the given + wl_surface, the protocol error surface_exists is raised. + + This creates a new color xx_color_management_surface_v4 object for the + given wl_surface. + + See the xx_color_management_surface_v4 interface for more details. + + + + + + + + + This creates a new color xx_color_management_feedback_surface_v4 object + for the given wl_surface. + + See the xx_color_management_feedback_surface_v4 interface for more + details. + + + + + + + + + Makes a new ICC-based image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.icc_v2_v4. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + Makes a new parametric image description creator object with all + properties initially unset. The client can then use the object's + interface to define all the required properties for an image description + and finally create a xx_image_description_v4 object. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.parametric. + Otherwise this request raises the protocol error unsupported_feature. + + + + + + + + When this object is created, it shall immediately send this event once + for each rendering intent the compositor supports. + + + + + + + + When this object is created, it shall immediately send this event once + for each compositor supported feature listed in the enumeration. + + + + + + + + When this object is created, it shall immediately send this event once + for each named transfer function the compositor supports with the + parametric image description creator. + + + + + + + + When this object is created, it shall immediately send this event once + for each named set of primaries the compositor supports with the + parametric image description creator. + + + + + + + + + A xx_color_management_output_v4 describes the color properties of an + output. + + The xx_color_management_output_v4 is associated with the wl_output global + underlying the wl_output object. Therefore the client destroying the + wl_output object has no impact, but the compositor removing the output + global makes the xx_color_management_output_v4 object inert. + + + + + Destroy the color xx_color_management_output_v4 object. This does not + affect any remaining protocol objects. + + + + + + This event is sent whenever the image description of the output changed, + followed by one wl_output.done event common to output events across all + extensions. + + If the client wants to use the updated image description, it needs to do + get_image_description again, because image description objects are + immutable. + + + + + + This creates a new xx_image_description_v4 object for the current image + description of the output. There always is exactly one image description + active for an output so the client should destroy the image description + created by earlier invocations of this request. This request is usually + sent as a reaction to the image_description_changed event or when + creating a xx_color_management_output_v4 object. + + The image description of an output represents the color encoding the + output expects. There might be performance and power advantages, as well + as improved color reproduction, if a content update matches the image + description of the output it is being shown on. If a content update is + shown on any other output than the one it matches the image description + of, then the color reproduction on those outputs might be considerably + worse. + + The created xx_image_description_v4 object preserves the image + description of the output from the time the object was created. + + The resulting image description object allows get_information request. + + If this protocol object is inert, the resulting image description object + shall immediately deliver the xx_image_description_v4.failed event with + the no_output cause. + + If the interface version is inadequate for the output's image + description, meaning that the client does not support all the events + needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + xx_image_description_v4.failed event with the low_version cause. + + Otherwise the object shall immediately deliver the ready event. + + + + + + + + + A xx_color_management_surface_v4 allows the client to set the color + space and HDR properties of a surface. + + If the wl_surface associated with the xx_color_management_surface_v4 is + destroyed, the xx_color_management_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_surface_v4 object and do the same as + unset_image_description. + + + + + + + + + + + + Set the image description of the underlying surface. The image + description and rendering intent are double-buffered state, see + wl_surface.commit. + + It is the client's responsibility to understand the image description + it sets on a surface, and to provide content that matches that image + description. Compositors might convert images to match their own or any + other image descriptions. + + Image description whose creation gracefully failed (received + xx_image_description_v4.failed) are forbidden in this request, and in + such case the protocol error image_description is raised. + + All image descriptions whose creation succeeded (received + xx_image_description_v4.ready) are allowed and must always be accepted + by the compositor. + + A rendering intent provides the client's preference on how content + colors should be mapped to each output. The render_intent value must + be one advertised by the compositor with + xx_color_manager_v4.render_intent event, otherwise the protocol error + render_intent is raised. + + By default, a surface does not have an associated image description + nor a rendering intent. The handling of color on such surfaces is + compositor implementation defined. Compositors should handle such + surfaces as sRGB but may handle them differently if they have specific + requirements. + + + + + + + + + This request removes any image description from the surface. See + set_image_description for how a compositor handles a surface without + an image description. This is double-buffered state, see + wl_surface.commit. + + + + + + + A xx_color_management_feedback_surface_v4 allows the client to get the + preferred color description of a surface. + + If the wl_surface associated with this object is destroyed, the + xx_color_management_feedback_surface_v4 object becomes inert. + + + + + Destroy the xx_color_management_feedback_surface_v4 object. + + + + + + + + + + + The preferred image description is the one which likely has the most + performance and/or quality benefits for the compositor if used by the + client for its wl_surface contents. This event is sent whenever the + compositor changes the wl_surface's preferred image description. + + This event is merely a notification. When the client wants to know + what the preferred image description is, it shall use the get_preferred + request. + + The preferred image description is not automatically used for anything. + It is only a hint, and clients may set any valid image description with + set_image_description but there might be performance and color accuracy + improvements by providing the wl_surface contents in the preferred + image description. Therefore clients that can, should render according + to the preferred image description + + + + + + If this protocol object is inert, the protocol error inert is raised. + + The preferred image description represents the compositor's preferred + color encoding for this wl_surface at the current time. There might be + performance and power advantages, as well as improved color + reproduction, if the image description of a content update matches the + preferred image description. + + This creates a new xx_image_description_v4 object for the currently + preferred image description for the wl_surface. The client should + stop using and destroy the image descriptions created by earlier + invocations of this request for the associated wl_surface. + This request is usually sent as a reaction to the preferred_changed + event or when creating a xx_color_management_feedback_surface_v4 object + if the client is capable of adapting to image descriptions. + + The created xx_image_description_v4 object preserves the preferred image + description of the wl_surface from the time the object was created. + + The resulting image description object allows get_information request. + + If the interface version is inadequate for the preferred image + description, meaning that the client does not support all the + events needed to deliver the crucial information, the resulting image + description object shall immediately deliver the + xx_image_description_v4.failed event with the low_version cause, + otherwise the object shall immediately deliver the ready event. + + + + + + + + + This type of object is used for collecting all the information required + to create a xx_image_description_v4 object from an ICC file. A complete + set of required parameters consists of these properties: + - ICC file + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + Create an image description object based on the ICC information + previously set on this object. A compositor must parse the ICC data in + some undefined but finite amount of time. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + If the particular combination of the information is not supported + by the compositor, the resulting image description object shall + immediately deliver the xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + information, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_icc_v4 object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the ICC profile file to be used as the basis of the image + description. + + The data shall be found through the given fd at the given offset, having + the given length. The fd must seekable and readable. Violating these + requirements raises the bad_fd protocol error. + + If reading the data fails due to an error independent of the client, the + compositor shall send the xx_image_description_v4.failed event on the + created xx_image_description_v4 with the 'operating_system' cause. + + The maximum size of the ICC profile is 4 MB. If length is greater than + that or zero, the protocol error bad_size is raised. If offset + length + exceeds the file size, the protocol error out_of_file is raised. + + A compositor may read the file at any time starting from this request + and only until whichever happens first: + - If create request was issued, the xx_image_description_v4 object + delivers either failed or ready event; or + - if create request was not issued, this + xx_image_description_creator_icc_v4 object is destroyed. + + A compositor shall not modify the contents of the file, and the fd may + be sealed for writes and size changes. The client must ensure to its + best ability that the data does not change while the compositor is + reading it. + + The data must represent a valid ICC profile. The ICC profile version + must be 2 or 4, it must be a 3 channel profile and the class must be + Display or ColorSpace. Violating these requirements will not result in a + protocol error but will eventually send the + xx_image_description_v4.failed event on the created + xx_image_description_v4 with the 'unsupported' cause. + + See the International Color Consortium specification ICC.1:2022 for more + details about ICC profiles. + + If ICC file has already been set on this object, the protocol error + already_set is raised. + + + + + + + + + + + This type of object is used for collecting all the parameters required + to create a xx_image_description_v4 object. A complete set of required + parameters consists of these properties: + - transfer characteristic function (tf) + - chromaticities of primaries and white point (primary color volume) + + The following properties are optional and have a well-defined default + if not explicitly set: + - primary color volume luminance range + - reference white luminance level + - mastering display primaries and white point (target color volume) + - mastering luminance range + - maximum content light level + - maximum frame-average light level + + Each required property must be set exactly once if the client is to create + an image description. The set requests verify that a property was not + already set. The create request verifies that all required properties are + set. There may be several alternative requests for setting each property, + and in that case the client must choose one of them. + + Once all properties have been set, the create request must be used to + create the image description object, destroying the creator in the + process. + + + + + + + + + + + + + + + + + + Create an image description object based on the parameters previously + set on this object. + + The completeness of the parameter set is verified. If the set is not + complete, the protocol error incomplete_set is raised. For the + definition of a complete set, see the description of this interface. + + Also, the combination of the parameter set is verified. If the set is + not consistent, the protocol error inconsistent_set is raised. + + If the particular combination of the parameter set is not supported + by the compositor, the resulting image description object shall + immediately deliver the xx_image_description_v4.failed event with the + 'unsupported' cause. If a valid image description was created from the + parameter set, the xx_image_description_v4.ready event will eventually + be sent instead. + + This request destroys the xx_image_description_creator_params_v4 + object. + + The resulting image description object does not allow get_information + request. + + + + + + + + Sets the transfer characteristic using explicitly enumerated named + functions. + + When the resulting image description is attached to an image, the + content should be encoded and decoded according to the industry standard + practices for the transfer characteristic. + + Only names advertised with xx_color_manager_v4 event supported_tf_named + are allowed. Other values shall raise the protocol error invalid_tf. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + + + + + + + Sets the color component transfer characteristic to a power curve with + the given exponent. This curve represents the conversion from electrical + to optical pixel or color values. + + When the resulting image description is attached to an image, the + content should be encoded with the inverse of the power curve. + + The curve exponent shall be multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + The curve exponent must be at least 1.0 and at most 10.0. Otherwise the + protocol error invalid_tf is raised. + + If transfer characteristic has already been set on this object, the + protocol error already_set is raised. + + This request can be used when the compositor advertises + xx_color_manager_v4.feature.set_tf_power. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + Sets the color primaries and white point using explicitly named sets. + This describes the primary color volume which is the basis for color + value encoding. + + Only names advertised with xx_color_manager_v4 event + supported_primaries_named are allowed. Other values shall raise the + protocol error invalid_primaries. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + + + + + + + Sets the color primaries and white point using CIE 1931 xy chromaticity + coordinates. This describes the primary color volume which is the basis + for color value encoding. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + If primaries have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_primaries. Otherwise this request raises + the protocol error unsupported_feature. + + + + + + + + + + + + + + + Sets the primary color volume luminance range and the reference white + luminance level. + + The default luminances are + - primary color volume minimum: 0.2 cd/m² + - primary color volume maximum: 80 cd/m² + - reference white: 80 cd/m² + + Setting a named transfer characteristic can imply other default + luminances. + + The default luminances get overwritten when this request is used. + + 'min_lum' and 'max_lum' specify the minimum and maximum luminances of + the primary color volume as reproduced by the targeted display. + + 'reference_lum' specifies the luminance of the reference white as + reproduced by the targeted display, and reflects the targeted viewing + environment. + + Compositors should make sure that all content is anchored, meaning that + an input signal level of 'reference_lum' on one image description and + another input signal level of 'reference_lum' on another image + description should produce the same output level, even though the + 'reference_lum' on both image representations can be different. + + If 'max_lum' is less than the 'reference_lum', or 'reference_lum' is + less than or equal to 'min_lum', the protocol error invalid_luminance is + raised. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + If the primary color volume luminance range and the reference white + luminance level have already been set on this object, the protocol error + already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_luminances. Otherwise this request + raises the protocol error unsupported_feature. + + + + + + + + + + Provides the color primaries and white point of the mastering display + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata. + + The mastering display primaries define the target color volume. + + If mastering display primaries are not explicitly set, the target color + volume is assumed to be equal to the primary color volume. + + The target color volume is defined by all tristimulus values between 0.0 + and 1.0 (inclusive) of the color space defined by the given mastering + display primaries and white point. The colorimetry is identical between + the container color space and the mastering display color space, + including that no chromatic adaptation is applied even if the white + points differ. + + The target color volume can exceed the primary color volume to allow for + a greater color volume with an existing color space definition (for + example scRGB). It can be smaller than the primary color volume to + minimize gamut and tone mapping distances for big color spaces (HDR + metadata). + + To make use of the entire target color volume a suitable pixel format + has to be chosen (e.g. floating point to exceed the primary color + volume, or abusing limited quantization range as with xvYCC). + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + If mastering display primaries have already been set on this object, the + protocol error already_set is raised. + + This request can be used if the compositor advertises + xx_color_manager_v4.feature.set_mastering_display_primaries. Otherwise + this request raises the protocol error unsupported_feature. The + advertisement implies support only for target color volumes fully + contained within the primary color volume. + + If a compositor additionally supports target color volume exceeding the + primary color volume, it must advertise + xx_color_manager_v4.feature.extended_target_volume. If a client uses + target color volume exceeding the primary color volume and the + compositor does not support it, the result is implementation defined. + Compositors are recommended to detect this case and fail the image + description gracefully, but it may as well result in color artifacts. + + + + + + + + + + + + + + + Sets the luminance range that was used during the content mastering + process as the minimum and maximum absolute luminance L. This is + compatible with the SMPTE ST 2086 definition of HDR static metadata. + + The mastering luminance range is undefined by default. + + If max L is less than or equal to min L, the protocol error + invalid_luminance is raised. + + Min L value is multiplied by 10000 to get the argument min_lum value + and carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Sets the maximum content light level (max_cll) as defined by CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol + error. + + max_cll is undefined by default. + + + + + + + + Sets the maximum frame-average light level (max_fall) as defined by + CTA-861-H. + + This can only be set when set_tf_cicp is used to set the transfer + characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system. + Otherwise, 'create' request shall raise inconsistent_set protocol error. + + max_fall is undefined by default. + + + + + + + + + An image description carries information about the color encoding used on + a surface when attached to a wl_surface via + xx_color_management_surface_v4.set_image_description. A compositor can use + this information to decode pixel values into colorimetrically meaningful + quantities. + + Note, that the xx_image_description_v4 object is not ready to be used + immediately after creation. The object eventually delivers either the + 'ready' or the 'failed' event, specified in all requests creating it. The + object is deemed "ready" after receiving the 'ready' event. + + An object which is not ready is illegal to use, it can only be destroyed. + Any other request in this interface shall result in the 'not_ready' + protocol error. Attempts to use an object which is not ready through other + interfaces shall raise protocol errors defined there. + + Once created and regardless of how it was created, a + xx_image_description_v4 object always refers to one fixed image + description. It cannot change after creation. + + + + + Destroy this object. It is safe to destroy an object which is not ready. + + Destroying a xx_image_description_v4 object has no side-effects, not + even if a xx_color_management_surface_v4.set_image_description has not + yet been followed by a wl_surface.commit. + + + + + + + + + + + + + + + + + + + + + + If creating a xx_image_description_v4 object fails for a reason that is + not defined as a protocol error, this event is sent. + + The requests that create image description objects define whether and + when this can occur. Only such creation requests can trigger this event. + This event cannot be triggered after the image description was + successfully formed. + + Once this event has been sent, the xx_image_description_v4 object will + never become ready and it can only be destroyed. + + + + + + + + + Once this event has been sent, the xx_image_description_v4 object is + deemed "ready". Ready objects can be used to send requests and can be + used through other interfaces. + + Every ready xx_image_description_v4 protocol object refers to an + underlying image description record in the compositor. Multiple protocol + objects may end up referring to the same record. Clients may identify + these "copies" by comparing their id numbers: if the numbers from two + protocol objects are identical, the protocol objects refer to the same + image description record. Two different image description records + cannot have the same id number simultaneously. The id number does not + change during the lifetime of the image description record. + + The id number is valid only as long as the protocol object is alive. If + all protocol objects referring to the same image description record are + destroyed, the id number may be recycled for a different image + description record. + + Image description id number is not a protocol object id. Zero is + reserved as an invalid id number. It shall not be possible for a client + to refer to an image description by its id number in protocol. The id + numbers might not be portable between Wayland connections. + + This identity allows clients to de-duplicate image description records + and avoid get_information request if they already have the image + description information. + + + + + + + + Creates a xx_image_description_info_v4 object which delivers the + information that makes up the image description. + + Not all image description protocol objects allow get_information + request. Whether it is allowed or not is defined by the request that + created the object. If get_information is not allowed, the protocol + error no_information is raised. + + + + + + + + + Sends all matching events describing an image description object exactly + once and finally sends the 'done' event. + + Once a xx_image_description_info_v4 object has delivered a 'done' event it + is automatically destroyed. + + Every xx_image_description_info_v4 created from the same + xx_image_description_v4 shall always return the exact same data. + + + + + Signals the end of information events and destroys the object. + + + + + + The icc argument provides a file descriptor to the client which may be + memory-mapped to provide the ICC profile matching the image description. + The fd is read-only, and if mapped then it must be mapped with + MAP_PRIVATE by the client. + + The ICC profile version and other details are determined by the + compositor. There is no provision for a client to ask for a specific + kind of a profile. + + + + + + + + + + Delivers the primary color volume primaries and white point using CIE + 1931 xy chromaticity coordinates. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + + + + + + + + + + + + + + Delivers the primary color volume primaries and white point using an + explicitly enumerated named set. + + + + + + + + The color component transfer characteristic of this image description is + a pure power curve. This event provides the exponent of the power + function. This curve represents the conversion from electrical to + optical pixel or color values. + + The curve exponent has been multiplied by 10000 to get the argument eexp + value to carry the precision of 4 decimals. + + + + + + + + Delivers the transfer characteristic using an explicitly enumerated + named function. + + + + + + + + Delivers the primary color volume luminance range and the reference + white luminance level. + + The minimum luminance is multiplied by 10000 to get the argument + 'min_lum' value and carries precision of 4 decimals. The maximum + luminance and reference white luminance values are unscaled. + + + + + + + + + + Provides the color primaries and white point of the target color volume + using CIE 1931 xy chromaticity coordinates. This is compatible with the + SMPTE ST 2086 definition of HDR static metadata for mastering displays. + + While primary color volume is about how color is encoded, the target + color volume is the actually displayable color volume. If target color + volume is equal to the primary color volume, then this event is not + sent. + + Each coordinate value is multiplied by 10000 to get the argument value + to carry precision of 4 decimals. + + + + + + + + + + + + + + + Provides the luminance range that the image description is targeting as + the minimum and maximum absolute luminance L. This is compatible with + the SMPTE ST 2086 definition of HDR static metadata. + + This luminance range is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + Min L value is multiplied by 10000 to get the argument min_lum value and + carry precision of 4 decimals. Max L value is unscaled for max_lum. + + + + + + + + + Provides the targeted max_cll of the image description. max_cll is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + + + Provides the targeted max_fall of the image description. max_fall is + defined by CTA-861-H. + + This luminance is only theoretical and may not correspond to the + luminance of light emitted on an actual display. + + + + + + \ No newline at end of file diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5805eff9..3d159042 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -31,6 +31,7 @@ #include "protocols/XDGShell.hpp" #include "protocols/XDGOutput.hpp" #include "protocols/SecurityContext.hpp" +#include "protocols/ColorManagement.hpp" #include "protocols/core/Compositor.hpp" #include "protocols/core/Subcompositor.hpp" #include "desktop/LayerSurface.hpp" @@ -2985,4 +2986,22 @@ void CCompositor::onNewMonitor(SP output) { g_pHyprRenderer->damageMonitor(PNEWMONITOR); PNEWMONITOR->onMonitorFrame(); + + if (PROTO::colorManagement && shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); +} + +SImageDescription CCompositor::getPreferredImageDescription() { + if (!PROTO::colorManagement) { + Debug::log(ERR, "FIXME: color management protocol is not enabled, returning empty image description"); + return SImageDescription{}; + } + Debug::log(WARN, "FIXME: color management protocol is enabled, determine correct preferred image description"); + // should determine some common settings to avoid unnecessary transformations while keeping maximum displayable precision + return SImageDescription{.primaries = NColorPrimaries::BT709}; +} + +bool CCompositor::shouldChangePreferredImageDescription() { + Debug::log(WARN, "FIXME: color management protocol is enabled and outputs changed, check preferred image description changes"); + return false; } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 4c428fca..629b71bc 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -23,6 +23,7 @@ #include "helpers/Monitor.hpp" #include "desktop/Workspace.hpp" #include "desktop/Window.hpp" +#include "protocols/types/ColorManagement.hpp" #include "render/Renderer.hpp" #include "render/OpenGL.hpp" #include "hyprerror/HyprError.hpp" @@ -169,6 +170,9 @@ class CCompositor { void updateSuspendedStates(); void onNewMonitor(SP output); + SImageDescription getPreferredImageDescription(); + bool shouldChangePreferredImageDescription(); + std::string explicitConfigPath; private: diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 8c35a3b1..686b996a 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1658,4 +1658,22 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "experimental:wide_color_gamut", + .description = "force wide color gamut for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:hdr", + .description = "force static hdr for all supported outputs", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, + SConfigOptionDescription{ + .value = "experimental:xx_color_management_v4", + .description = "enable color management protocol", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, }; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1ab29b1f..bbb3e68f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -622,6 +622,10 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:wide_color_gamut", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:hdr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("experimental:xx_color_management_v4", Hyprlang::INT{0}); + // devices m_pConfig->addSpecialCategory("device", {"name"}); m_pConfig->addSpecialConfigValue("device", "sensitivity", {0.F}); diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 07af13df..057a6f90 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -119,4 +119,5 @@ class CWLSurface { } listeners; friend class CPointerConstraint; + friend class CXxColorManagerV4; }; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 0e1c21f5..b7d61f67 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -55,6 +55,8 @@ #include "../protocols/core/Subcompositor.hpp" #include "../protocols/core/Output.hpp" #include "../protocols/core/Shm.hpp" +#include "../protocols/ColorManagement.hpp" +#include "../protocols/FrogColorManagement.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" @@ -77,11 +79,15 @@ void CProtocolManager::onMonitorModeChange(PHLMONITOR pMonitor) { PROTO::outputs.erase(pMonitor->szName); PROTO::outputs.emplace(pMonitor->szName, makeShared(&wl_output_interface, 4, std::format("WLOutput ({})", pMonitor->szName), pMonitor->self.lock())); } + + if (PROTO::colorManagement && g_pCompositor->shouldChangePreferredImageDescription()) + PROTO::colorManagement->onImagePreferredChanged(); } CProtocolManager::CProtocolManager() { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static const auto PENABLEXXCM = CConfigValue("experimental:xx_color_management_v4"); // Outputs are a bit dumb, we have to agree. static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { @@ -162,6 +168,11 @@ CProtocolManager::CProtocolManager() { PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); PROTO::hyprlandSurface = std::make_unique(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface"); + if (*PENABLEXXCM) { + PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + PROTO::frogColorManagement = std::make_unique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); + } + for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp new file mode 100644 index 00000000..7ff4db4f --- /dev/null +++ b/src/protocols/ColorManagement.cpp @@ -0,0 +1,571 @@ +#include "ColorManagement.hpp" +#include "Compositor.hpp" + +CColorManager::CColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_EXTENDED_TARGET_VOLUME); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES); + resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_SET_LUMINANCES); + + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_SRGB); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_PAL); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_NTSC); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM); + resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_BT2020); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3); + // resource->sendSupportedPrimariesNamed(XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB); + + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB); + resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ); + // resource->sendSupportedTfNamed(XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR); + + resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_ABSOLUTE); + // resource->sendSupportedIntent(XX_COLOR_MANAGER_V4_RENDER_INTENT_RELATIVE_BPC); + + resource->setDestroy([](CXxColorManagerV4* r) { LOGM(TRACE, "Destroy xx_color_manager at {:x} (generated default)", (uintptr_t)r); }); + resource->setGetOutput([](CXxColorManagerV4* r, uint32_t id, wl_resource* output) { + LOGM(TRACE, "Get output for id={}, output={}", id, (uintptr_t)output); + const auto RESOURCE = + PROTO::colorManagement->m_vOutputs.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vOutputs.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + resource->setGetSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->colorManagement) { + r->error(XX_COLOR_MANAGER_V4_ERROR_SURFACE_EXISTS, "CM Surface already exists"); + return; + } + + const auto RESOURCE = + PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->colorManagement = RESOURCE; + }); + resource->setGetFeedbackSurface([](CXxColorManagerV4* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get feedback surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vFeedbackSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + resource->setNewIccCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(WARN, "New ICC creator for id={} (unsupported)", id); + r->error(XX_COLOR_MANAGER_V4_ERROR_UNSUPPORTED_FEATURE, "ICC profiles are not supported"); + }); + resource->setNewParametricCreator([](CXxColorManagerV4* r, uint32_t id) { + LOGM(TRACE, "New parametric creator for id={}", id); + + const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vParametricCreators.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); + + resource->setOnDestroy([this](CXxColorManagerV4* r) { PROTO::colorManagement->destroyResource(this); }); +} + +bool CColorManager::good() { + return resource->resource(); +} + +CColorManagementOutput::CColorManagementOutput(SP resource_) : resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + resource->setOnDestroy([this](CXxColorManagementOutputV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setGetImageDescription([this](CXxColorManagementOutputV4* r, uint32_t id) { + LOGM(TRACE, "Get image description for output={}, id={}", (uintptr_t)r, id); + if (imageDescription.valid()) + PROTO::colorManagement->destroyResource(imageDescription.get()); + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); +} + +bool CColorManagementOutput::good() { + return resource->resource(); +} + +wl_client* CColorManagementOutput::client() { + return pClient; +} + +CColorManagementSurface::CColorManagementSurface(SP surface_) : surface(surface_) { + // only for frog cm untill wayland cm is adopted +} + +CColorManagementSurface::CColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm surface {}", (uintptr_t)surface); + PROTO::colorManagement->destroyResource(this); + }); + + resource->setSetImageDescription([this](CXxColorManagementSurfaceV4* r, wl_resource* image_description, uint32_t render_intent) { + LOGM(TRACE, "Set image description for surface={}, desc={}, intent={}", (uintptr_t)r, (uintptr_t)image_description, render_intent); + + const auto PO = (CXxImageDescriptionV4*)wl_resource_get_user_data(image_description); + if (!PO) { // FIXME check validity + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description creation failed"); + return; + } + if (render_intent != XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_RENDER_INTENT, "Unsupported render intent"); + return; + } + + const auto imageDescription = std::find_if(PROTO::colorManagement->m_vImageDescriptions.begin(), PROTO::colorManagement->m_vImageDescriptions.end(), + [&](const auto& other) { return other->resource()->resource() == image_description; }); + if (imageDescription == PROTO::colorManagement->m_vImageDescriptions.end()) { + r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description not found"); + return; + } + + m_hasImageDescription = true; + m_imageDescription = imageDescription->get()->settings; + }); + resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) { + LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); + m_imageDescription = SImageDescription{}; + m_hasImageDescription = false; + }); +} + +bool CColorManagementSurface::good() { + return resource && resource->resource(); +} + +wl_client* CColorManagementSurface::client() { + return pClient; +} + +const SImageDescription& CColorManagementSurface::imageDescription() { + if (!hasImageDescription()) + LOGM(WARN, "Reading imageDescription while none set. Returns default or empty values"); + return m_imageDescription; +} + +bool CColorManagementSurface::hasImageDescription() { + return m_hasImageDescription; +} + +CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : + surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + resource->setDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + PROTO::colorManagement->destroyResource(this); + }); + resource->setOnDestroy([this](CXxColorManagementFeedbackSurfaceV4* r) { + LOGM(TRACE, "Destroy xx cm feedback surface {}", (uintptr_t)surface); + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + PROTO::colorManagement->destroyResource(this); + }); + + resource->setGetPreferred([this](CXxColorManagementFeedbackSurfaceV4* r, uint32_t id) { + LOGM(TRACE, "Get preferred for id {}", id); + + if (m_currentPreferred.valid()) + PROTO::colorManagement->destroyResource(m_currentPreferred.get()); + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), true)); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + m_currentPreferred = RESOURCE; + + m_currentPreferred->settings = g_pCompositor->getPreferredImageDescription(); + + RESOURCE->resource()->sendReady(id); + }); +} + +bool CColorManagementFeedbackSurface::good() { + return resource->resource(); +} + +wl_client* CColorManagementFeedbackSurface::client() { + return pClient; +} + +CColorManagementParametricCreator::CColorManagementParametricCreator(SP resource_) : resource(resource_) { + if (!good()) + return; + // + pClient = resource->client(); + + resource->setOnDestroy([this](CXxImageDescriptionCreatorParamsV4* r) { PROTO::colorManagement->destroyResource(this); }); + + resource->setCreate([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t id) { + LOGM(TRACE, "Create image description from params for id {}", id); + + // FIXME actually check completeness + if (!valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCOMPLETE_SET, "Missing required settings"); + return; + } + + // FIXME actually check consistency + if (!valuesSet) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INCONSISTENT_SET, "Set is not consistent"); + return; + } + + const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( + makeShared(makeShared(r->client(), r->version(), id))); + + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::colorManagement->m_vImageDescriptions.pop_back(); + return; + } + + // FIXME actually check support + if (!valuesSet) { + RESOURCE->resource()->sendFailed(XX_IMAGE_DESCRIPTION_V4_CAUSE_UNSUPPORTED, "unsupported"); + return; + } + + RESOURCE->self = RESOURCE; + RESOURCE->settings = settings; + RESOURCE->resource()->sendReady(id); + + PROTO::colorManagement->destroyResource(this); + }); + resource->setSetTfNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t tf) { + LOGM(TRACE, "Set image description transfer function to {}", tf); + if (valuesSet & PC_TF) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function already set"); + return; + } + + switch (tf) { + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB: break; + case XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ: break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_TF, "Unsupported transfer function"); return; + } + + settings.transferFunction = (xxColorManagerV4TransferFunction)tf; + valuesSet |= PC_TF; + }); + resource->setSetTfPower([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t eexp) { + LOGM(TRACE, "Set image description tf power to {}", eexp); + if (valuesSet & PC_TF_POWER) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Transfer function power already set"); + return; + } + settings.transferFunctionPower = eexp / 10000.0f; + valuesSet |= PC_TF_POWER; + }); + resource->setSetPrimariesNamed([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t primaries) { + LOGM(TRACE, "Set image description primaries by name {}", primaries); + if (valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + + switch (primaries) { + case XX_COLOR_MANAGER_V4_PRIMARIES_SRGB: + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + settings.primaries = NColorPrimaries::BT709; + valuesSet |= PC_PRIMARIES; + break; + case XX_COLOR_MANAGER_V4_PRIMARIES_BT2020: + settings.primariesNameSet = true; + settings.primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_BT2020; + settings.primaries = NColorPrimaries::BT2020; + valuesSet |= PC_PRIMARIES; + break; + default: r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_PRIMARIES, "Unsupported primaries"); + } + }); + resource->setSetPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { + LOGM(TRACE, "Set image description primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + if (valuesSet & PC_PRIMARIES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Primaries already set"); + return; + } + settings.primariesNameSet = false; + settings.primaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + valuesSet |= PC_PRIMARIES; + }); + resource->setSetLuminances([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description luminances to {} - {} ({})", min, max_lum, reference_lum); + if (valuesSet & PC_LUMINANCES) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Luminances already set"); + return; + } + if (max_lum < reference_lum || reference_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + settings.luminances = SImageDescription::SPCLuminances{.min = min, .max = max_lum, .reference = reference_lum}; + valuesSet |= PC_LUMINANCES; + }); + resource->setSetMasteringDisplayPrimaries( + [this](CXxImageDescriptionCreatorParamsV4* r, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) { + LOGM(TRACE, "Set image description mastering primaries by values r:{},{} g:{},{} b:{},{} w:{},{}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); + // if (valuesSet & PC_MASTERING_PRIMARIES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering primaries already set"); + // return; + // } + settings.masteringPrimaries = + SImageDescription::SPCPRimaries{.red = {.x = r_x, .y = r_y}, .green = {.x = g_x, .y = g_y}, .blue = {.x = b_x, .y = b_y}, .white = {.x = w_x, .y = w_y}}; + valuesSet |= PC_MASTERING_PRIMARIES; + }); + resource->setSetMasteringLuminance([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t min_lum, uint32_t max_lum) { + auto min = min_lum / 10000.0f; + LOGM(TRACE, "Set image description mastering luminances to {} - {}", min, max_lum); + // if (valuesSet & PC_MASTERING_LUMINANCES) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Mastering luminances already set"); + // return; + // } + if (min > 0 && max_lum > 0 && max_lum <= min) { + r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_INVALID_LUMINANCE, "Invalid luminances"); + return; + } + settings.masteringLuminances = SImageDescription::SPCMasteringLuminances{.min = min, .max = max_lum}; + valuesSet |= PC_MASTERING_LUMINANCES; + }); + resource->setSetMaxCll([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_cll) { + LOGM(TRACE, "Set image description max content light level to {}", max_cll); + // if (valuesSet & PC_CLL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max CLL already set"); + // return; + // } + settings.maxCLL = max_cll; + valuesSet |= PC_CLL; + }); + resource->setSetMaxFall([this](CXxImageDescriptionCreatorParamsV4* r, uint32_t max_fall) { + LOGM(TRACE, "Set image description max frame-average light level to {}", max_fall); + // if (valuesSet & PC_FALL) { + // r->error(XX_IMAGE_DESCRIPTION_CREATOR_PARAMS_V4_ERROR_ALREADY_SET, "Max FALL already set"); + // return; + // } + settings.maxFALL = max_fall; + valuesSet |= PC_FALL; + }); +} + +bool CColorManagementParametricCreator::good() { + return resource->resource(); +} + +wl_client* CColorManagementParametricCreator::client() { + return pClient; +} + +CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, bool allowGetInformation) : + m_resource(resource_), m_allowGetInformation(allowGetInformation) { + if (!good()) + return; + + pClient = m_resource->client(); + + m_resource->setDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + m_resource->setOnDestroy([this](CXxImageDescriptionV4* r) { PROTO::colorManagement->destroyResource(this); }); + + m_resource->setGetInformation([this](CXxImageDescriptionV4* r, uint32_t id) { + LOGM(TRACE, "Get image information for image={}, id={}", (uintptr_t)r, id); + if (!m_allowGetInformation) { + r->error(XX_IMAGE_DESCRIPTION_V4_ERROR_NO_INFORMATION, "Image descriptions doesn't allow get_information request"); + return; + } + + auto RESOURCE = makeShared(makeShared(r->client(), r->version(), id), settings); + + if (!RESOURCE->good()) + r->noMemory(); + + // CColorManagementImageDescriptionInfo should send everything in the constructor and be ready for destroying at this point + RESOURCE.reset(); + }); +} + +bool CColorManagementImageDescription::good() { + return m_resource->resource(); +} + +wl_client* CColorManagementImageDescription::client() { + return pClient; +} + +SP CColorManagementImageDescription::resource() { + return m_resource; +} + +CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_) : + m_resource(resource_), settings(settings_) { + if (!good()) + return; + + pClient = m_resource->client(); + + const auto toProto = [](float value) { return int32_t(std::round(value * 10000)); }; + + if (settings.iccFd >= 0) + m_resource->sendIccFile(settings.iccFd, settings.iccSize); + + // send preferred client paramateres + m_resource->sendPrimaries(toProto(settings.primaries.red.x), toProto(settings.primaries.red.y), toProto(settings.primaries.green.x), toProto(settings.primaries.green.y), + toProto(settings.primaries.blue.x), toProto(settings.primaries.blue.y), toProto(settings.primaries.white.x), toProto(settings.primaries.white.y)); + if (settings.primariesNameSet) + m_resource->sendPrimariesNamed(settings.primariesNamed); + m_resource->sendTfPower(std::round(settings.transferFunctionPower * 10000)); + m_resource->sendTfNamed(settings.transferFunction); + m_resource->sendLuminances(std::round(settings.luminances.min * 10000), settings.luminances.max, settings.luminances.reference); + + // send expexted display paramateres + m_resource->sendTargetPrimaries(toProto(settings.masteringPrimaries.red.x), toProto(settings.masteringPrimaries.red.y), toProto(settings.masteringPrimaries.green.x), + toProto(settings.masteringPrimaries.green.y), toProto(settings.masteringPrimaries.blue.x), toProto(settings.masteringPrimaries.blue.y), + toProto(settings.masteringPrimaries.white.x), toProto(settings.masteringPrimaries.white.y)); + m_resource->sendTargetLuminance(std::round(settings.masteringLuminances.min * 10000), settings.masteringLuminances.max); + m_resource->sendTargetMaxCll(settings.maxCLL); + m_resource->sendTargetMaxFall(settings.maxFALL); + + m_resource->sendDone(); +} + +bool CColorManagementImageDescriptionInfo::good() { + return m_resource->resource(); +} + +wl_client* CColorManagementImageDescriptionInfo::client() { + return pClient; +} + +CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(TRACE, "New xx_color_manager at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CColorManagementProtocol::onImagePreferredChanged() { + for (auto const& feedback : m_vFeedbackSurfaces) { + feedback->resource->sendPreferredChanged(); + } +} + +void CColorManagementProtocol::destroyResource(CColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementOutput* resource) { + std::erase_if(m_vOutputs, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementFeedbackSurface* resource) { + std::erase_if(m_vFeedbackSurfaces, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementParametricCreator* resource) { + std::erase_if(m_vParametricCreators, [&](const auto& other) { return other.get() == resource; }); +} + +void CColorManagementProtocol::destroyResource(CColorManagementImageDescription* resource) { + std::erase_if(m_vImageDescriptions, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp new file mode 100644 index 00000000..573abf69 --- /dev/null +++ b/src/protocols/ColorManagement.hpp @@ -0,0 +1,182 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "protocols/core/Compositor.hpp" +#include "xx-color-management-v4.hpp" +#include "types/ColorManagement.hpp" + +class CColorManager; +class CColorManagementOutput; +class CColorManagementImageDescription; +class CColorManagementProtocol; + +class CColorManager { + public: + CColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CColorManagementOutput { + public: + CColorManagementOutput(SP resource_); + + bool good(); + wl_client* client(); + + WP self; + WP imageDescription; + + private: + SP resource; + wl_client* pClient = nullptr; + + friend class CColorManagementProtocol; + friend class CColorManagementImageDescription; +}; + +class CColorManagementSurface { + public: + CColorManagementSurface(SP surface_); // temporary interface for frog CM + CColorManagementSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + const SImageDescription& imageDescription(); + bool hasImageDescription(); + + private: + SP resource; + wl_client* pClient = nullptr; + SImageDescription m_imageDescription; + bool m_hasImageDescription = false; + + friend class CFrogColorManagementSurface; +}; + +class CColorManagementFeedbackSurface { + public: + CColorManagementFeedbackSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + private: + SP resource; + wl_client* pClient = nullptr; + + WP m_currentPreferred; + + friend class CColorManagementProtocol; +}; + +class CColorManagementParametricCreator { + public: + CColorManagementParametricCreator(SP resource_); + + bool good(); + wl_client* client(); + + WP self; + + SImageDescription settings; + + private: + enum eValuesSet : uint32_t { // NOLINT + PC_TF = (1 << 0), + PC_TF_POWER = (1 << 1), + PC_PRIMARIES = (1 << 2), + PC_LUMINANCES = (1 << 3), + PC_MASTERING_PRIMARIES = (1 << 4), + PC_MASTERING_LUMINANCES = (1 << 5), + PC_CLL = (1 << 6), + PC_FALL = (1 << 7), + }; + + SP resource; + wl_client* pClient = nullptr; + uint32_t valuesSet = 0; // enum eValuesSet +}; + +class CColorManagementImageDescription { + public: + CColorManagementImageDescription(SP resource_, bool allowGetInformation = false); + + bool good(); + wl_client* client(); + SP resource(); + + WP self; + + SImageDescription settings; + + private: + SP m_resource; + wl_client* pClient = nullptr; + bool m_allowGetInformation = false; + + friend class CColorManagementOutput; +}; + +class CColorManagementImageDescriptionInfo { + public: + CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_); + + bool good(); + wl_client* client(); + + private: + SP m_resource; + wl_client* pClient = nullptr; + SImageDescription settings; +}; + +class CColorManagementProtocol : public IWaylandProtocol { + public: + CColorManagementProtocol(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); + + void onImagePreferredChanged(); + + private: + void destroyResource(CColorManager* resource); + void destroyResource(CColorManagementOutput* resource); + void destroyResource(CColorManagementSurface* resource); + void destroyResource(CColorManagementFeedbackSurface* resource); + void destroyResource(CColorManagementParametricCreator* resource); + void destroyResource(CColorManagementImageDescription* resource); + + std::vector> m_vManagers; + std::vector> m_vOutputs; + std::vector> m_vSurfaces; + std::vector> m_vFeedbackSurfaces; + std::vector> m_vParametricCreators; + std::vector> m_vImageDescriptions; + + friend class CColorManager; + friend class CColorManagementOutput; + friend class CColorManagementSurface; + friend class CColorManagementFeedbackSurface; + friend class CColorManagementParametricCreator; + friend class CColorManagementImageDescription; + + friend class CFrogColorManagementSurface; +}; + +namespace PROTO { + inline UP colorManagement; +}; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp new file mode 100644 index 00000000..3ea20405 --- /dev/null +++ b/src/protocols/FrogColorManagement.cpp @@ -0,0 +1,159 @@ +#include "FrogColorManagement.hpp" +#include "protocols/ColorManagement.hpp" +#include "protocols/core/Subcompositor.hpp" + +CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setDestroy([](CFrogColorManagementFactoryV1* r) { LOGM(TRACE, "Destroy frog_color_management at {:x} (generated default)", (uintptr_t)r); }); + resource->setOnDestroy([this](CFrogColorManagementFactoryV1* r) { PROTO::frogColorManagement->destroyResource(this); }); + + resource->setGetColorManagedSurface([](CFrogColorManagementFactoryV1* r, wl_resource* surface, uint32_t id) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->role->role() == SURFACE_ROLE_SUBSURFACE) + SURF = ((CSubsurfaceRole*)SURF->role.get())->subsurface->t1Parent(); + + const auto RESOURCE = PROTO::frogColorManagement->m_vSurfaces.emplace_back( + makeShared(makeShared(r->client(), r->version(), id), SURF)); + if (!RESOURCE->good()) { + r->noMemory(); + PROTO::frogColorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + }); +} + +bool CFrogColorManager::good() { + return resource->resource(); +} + +CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + pClient = resource->client(); + + if (!surface->colorManagement.valid()) { + const auto RESOURCE = PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(surface_)); + if (!RESOURCE) { + resource->noMemory(); + PROTO::colorManagement->m_vSurfaces.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + surface->colorManagement = RESOURCE; + + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm and xx cm for surface {}", (uintptr_t)surface); + if (surface.valid()) + PROTO::colorManagement->destroyResource(surface->colorManagement.get()); + PROTO::frogColorManagement->destroyResource(this); + }); + } else + resource->setOnDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + + resource->setDestroy([this](CFrogColorManagedSurface* r) { + LOGM(TRACE, "Destroy frog cm surface {}", (uintptr_t)surface); + PROTO::frogColorManagement->destroyResource(this); + }); + + resource->setSetKnownTransferFunction([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceTransferFunction tf) { + LOGM(TRACE, "Set frog cm transfer function {} for {}", (uint32_t)tf, surface->id()); + switch (tf) { + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_ST2084_PQ: + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + ; + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22: + if (pqIntentSent) { + LOGM(TRACE, + "FIXME: assuming broken enum value 2 (FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_GAMMA_22) referring to eotf value 2 (TRANSFER_FUNCTION_ST2084_PQ)"); + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ; + break; + }; // intended fall through + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SCRGB_LINEAR: LOGM(TRACE, std::format("FIXME: add tf support for {}", (uint32_t)tf)); // intended fall through + case FROG_COLOR_MANAGED_SURFACE_TRANSFER_FUNCTION_SRGB: + surface->colorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + + surface->colorManagement->m_hasImageDescription = true; + } + }); + resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { + LOGM(TRACE, "Set frog cm primaries {}", (uint32_t)primariesName); + switch (primariesName) { + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_UNDEFINED: + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC709: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT709; break; + case FROG_COLOR_MANAGED_SURFACE_PRIMARIES_REC2020: surface->colorManagement->m_imageDescription.primaries = NColorPrimaries::BT2020; break; + } + + surface->colorManagement->m_hasImageDescription = true; + }); + resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { + LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); + pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + surface->colorManagement->m_hasImageDescription = true; + }); + resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, + uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { + LOGM(TRACE, "Set frog primaries r:{},{} g:{},{} b:{},{} w:{},{} luminances {} - {} cll {} fall {}", r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y, min_lum, max_lum, cll, fall); + surface->colorManagement->m_imageDescription.masteringPrimaries = SImageDescription::SPCPRimaries{.red = {.x = r_x / 50000.0f, .y = r_y / 50000.0f}, + .green = {.x = g_x / 50000.0f, .y = g_y / 50000.0f}, + .blue = {.x = b_x / 50000.0f, .y = b_y / 50000.0f}, + .white = {.x = w_x / 50000.0f, .y = w_y / 50000.0f}}; + surface->colorManagement->m_imageDescription.masteringLuminances.min = min_lum / 10000.0f; + surface->colorManagement->m_imageDescription.masteringLuminances.max = max_lum; + surface->colorManagement->m_imageDescription.maxCLL = cll; + surface->colorManagement->m_imageDescription.maxFALL = fall; + + surface->colorManagement->m_hasImageDescription = true; + }); +} + +bool CFrogColorManagementSurface::good() { + return resource->resource(); +} + +wl_client* CFrogColorManagementSurface::client() { + return pClient; +} + +CFrogColorManagementProtocol::CFrogColorManagementProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CFrogColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + LOGM(TRACE, "New frog_color_management at {:x}", (uintptr_t)RESOURCE.get()); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CFrogColorManagementProtocol::destroyResource(CFrogColorManagementSurface* resource) { + std::erase_if(m_vSurfaces, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp new file mode 100644 index 00000000..6c00e38d --- /dev/null +++ b/src/protocols/FrogColorManagement.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "protocols/core/Compositor.hpp" +#include "frog-color-management-v1.hpp" + +class CFrogColorManager { + public: + CFrogColorManager(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CFrogColorManagementSurface { + public: + CFrogColorManagementSurface(SP resource_, SP surface_); + + bool good(); + wl_client* client(); + + WP self; + WP surface; + + bool pqIntentSent = false; + + private: + SP resource; + wl_client* pClient = nullptr; +}; + +class CFrogColorManagementProtocol : public IWaylandProtocol { + public: + CFrogColorManagementProtocol(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); + + private: + void destroyResource(CFrogColorManager* resource); + void destroyResource(CFrogColorManagementSurface* resource); + + std::vector> m_vManagers; + std::vector> m_vSurfaces; + + friend class CFrogColorManager; + friend class CFrogColorManagementSurface; +}; + +namespace PROTO { + inline UP frogColorManagement; +}; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 2a6f96f6..b347eb64 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -25,6 +25,8 @@ class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; class CDRMSyncobjSurfaceResource; +class CColorManagementSurface; +class CFrogColorManagementSurface; class CWLCallbackResource { public: @@ -121,6 +123,7 @@ class CWLSurfaceResource { SP role; WP viewportResource; WP syncobj; // may not be present + WP colorManagement; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp new file mode 100644 index 00000000..e18f0b84 --- /dev/null +++ b/src/protocols/types/ColorManagement.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "xx-color-management-v4.hpp" + +struct SImageDescription { + int iccFd = -1; + uint32_t iccSize = 0; + + xxColorManagerV4TransferFunction transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; + float transferFunctionPower = 1.0f; + + bool primariesNameSet = false; + xxColorManagerV4Primaries primariesNamed = XX_COLOR_MANAGER_V4_PRIMARIES_SRGB; + // primaries are stored as FP values with the same scale as standard defines (0.0 - 1.0) + // wayland protocol expects int32_t values multiplied by 10000 + // drm expects uint16_t values multiplied by 50000 + // frog protocol expects drm values + struct SPCPRimaries { + struct { + float x = 0; + float y = 0; + } red, green, blue, white; + } primaries, masteringPrimaries; + + // luminances in cd/m² + // protos and drm expect min * 10000 + struct SPCLuminances { + float min = 0.2; // 0.2 cd/m² + uint32_t max = 80; // 80 cd/m² + uint32_t reference = 80; // 80 cd/m² + } luminances; + struct SPCMasteringLuminances { + float min = 0; + uint32_t max = 0; + } masteringLuminances; + + uint32_t maxCLL = 0; + uint32_t maxFALL = 0; +}; + +namespace NColorPrimaries { + static const auto BT709 = + SImageDescription::SPCPRimaries{.red = {.x = 0.64, .y = 0.33}, .green = {.x = 0.30, .y = 0.60}, .blue = {.x = 0.15, .y = 0.06}, .white = {.x = 0.3127, .y = 0.3290}}; + + static const auto BT2020 = + SImageDescription::SPCPRimaries{.red = {.x = 0.708, .y = 0.292}, .green = {.x = 0.170, .y = 0.797}, .blue = {.x = 0.131, .y = 0.046}, .white = {.x = 0.3127, .y = 0.3290}}; +} \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4d93d92f..978384d5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -25,6 +25,7 @@ #include "pass/RendererHintsPassElement.hpp" #include "pass/SurfacePassElement.hpp" #include "debug/Log.hpp" +#include "protocols/ColorManagement.hpp" #include using namespace Hyprutils::Utils; @@ -1374,6 +1375,82 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { } } +static const auto BT709 = Aquamarine::IOutput::SChromaticityCoords{ + .red = Aquamarine::IOutput::xy{.x = 0.64, .y = 0.33}, + .green = Aquamarine::IOutput::xy{.x = 0.30, .y = 0.60}, + .blue = Aquamarine::IOutput::xy{.x = 0.15, .y = 0.06}, + .white = Aquamarine::IOutput::xy{.x = 0.3127, .y = 0.3290}, +}; + +static hdr_output_metadata createHDRMetadata(uint8_t eotf, Aquamarine::IOutput::SParsedEDID edid) { + if (eotf == 0) + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + + const auto toNits = [](float value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](float value) { return uint16_t(std::round(value * 50000)); }; + const auto colorimetry = edid.chromaticityCoords.value_or(BT709); + + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement max avg {}, min {}, max {}", edid.hdrMetadata->desiredMaxFrameAverageLuminance, edid.hdrMetadata->desiredContentMinLuminance, + edid.hdrMetadata->desiredContentMaxLuminance); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = eotf, + .metadata_type = 0, + .display_primaries = + { + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, + }, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .min_display_mastering_luminance = toNits(edid.hdrMetadata->desiredContentMinLuminance * 10000), + .max_cll = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + .max_fall = toNits(edid.hdrMetadata->desiredMaxFrameAverageLuminance), + }, + }; +} + +static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamarine::IOutput::SParsedEDID edid) { + if (settings.transferFunction != XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ) + return hdr_output_metadata{.hdmi_metadata_type1 = hdr_metadata_infoframe{.eotf = 0}}; // empty metadata for SDR + + const auto toNits = [](uint32_t value) { return uint16_t(std::round(value)); }; + const auto to16Bit = [](uint32_t value) { return uint16_t(std::round(value * 50000)); }; + + auto colorimetry = settings.primaries; + auto luminances = settings.masteringLuminances.max > 0 ? + settings.masteringLuminances : + SImageDescription::SPCMasteringLuminances{.min = edid.hdrMetadata->desiredContentMinLuminance, .max = edid.hdrMetadata->desiredContentMaxLuminance}; + + Debug::log(TRACE, "ColorManagement primaries {},{} {},{} {},{} {},{}", colorimetry.red.x, colorimetry.red.y, colorimetry.green.x, colorimetry.green.y, colorimetry.blue.x, + colorimetry.blue.y, colorimetry.white.x, colorimetry.white.y); + Debug::log(TRACE, "ColorManagement min {}, max {}, cll {}, fall {}", luminances.min, luminances.max, settings.maxCLL, settings.maxFALL); + return hdr_output_metadata{ + .metadata_type = 0, + .hdmi_metadata_type1 = + hdr_metadata_infoframe{ + .eotf = 2, + .metadata_type = 0, + .display_primaries = + { + {.x = to16Bit(colorimetry.red.x), .y = to16Bit(colorimetry.red.y)}, + {.x = to16Bit(colorimetry.green.x), .y = to16Bit(colorimetry.green.y)}, + {.x = to16Bit(colorimetry.blue.x), .y = to16Bit(colorimetry.blue.y)}, + }, + .white_point = {.x = to16Bit(colorimetry.white.x), .y = to16Bit(colorimetry.white.y)}, + .max_display_mastering_luminance = toNits(luminances.max), + .min_display_mastering_luminance = toNits(luminances.min * 10000), + .max_cll = toNits(settings.maxCLL), + .max_fall = toNits(settings.maxFALL), + }, + }; +} + bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it @@ -1382,6 +1459,26 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); + static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); + if (pMonitor->output->state->state().wideColorGamut != *PWIDE) + Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); + pMonitor->output->state->setWideColorGamut(*PWIDE); + + static auto PHDR = CConfigValue("experimental:hdr"); + + Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); + if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { + if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { + const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); + const auto SURF = WINDOW->m_pWLSurface->resource(); + if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) + pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); + else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } else + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + } + if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; pMonitor->output->state->setCTM(pMonitor->ctm); diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index f2f2627a..71aa26be 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -79,6 +79,8 @@ void CSurfacePassElement::draw(const CRegion& damage) { DELTALESSTHAN(windowBox.height, data.surface->current.bufferSize.y, 3) /* off by one-or-two */ && (!data.pWindow || (!data.pWindow->m_vRealSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */; + if (data.surface->colorManagement.valid()) + Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations"); g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); // check for fractional scale surfaces misaligning the buffer size From c14390785745972903865c824fd324aa708f296a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:27:07 +0100 Subject: [PATCH 1037/2393] config: update animation even if disabled --- src/config/ConfigManager.cpp | 44 +++++++++++++++++------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index bbb3e68f..5839204f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2053,37 +2053,35 @@ std::optional CConfigManager::handleAnimation(const std::string& co if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; - if (enabledInt) { - int64_t speed = -1; + int64_t speed = -1; - // speed - if (isNumber(ARGS[2], true)) { - speed = std::stof(ARGS[2]); + // speed + if (isNumber(ARGS[2], true)) { + speed = std::stof(ARGS[2]); - if (speed <= 0) { - speed = 1.f; - return "invalid speed"; - } - } else { - speed = 10.f; + if (speed <= 0) { + speed = 1.f; return "invalid speed"; } + } else { + speed = 10.f; + return "invalid speed"; + } - std::string bezierName = ARGS[3]; - m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); + std::string bezierName = ARGS[3]; + m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, speed, ARGS[3], ARGS[4]); - if (!g_pAnimationManager->bezierExists(bezierName)) { - const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); - PANIMNODE->internalBezier = "default"; - return "no such bezier"; - } + if (!g_pAnimationManager->bezierExists(bezierName)) { + const auto PANIMNODE = m_AnimationTree.getConfig(ANIMNAME); + PANIMNODE->internalBezier = "default"; + return "no such bezier"; + } - if (ARGS[4] != "") { - auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); + if (ARGS[4] != "") { + auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); - if (ERR != "") - return ERR; - } + if (ERR != "") + return ERR; } return {}; From 308b1f3afbb150fa008e3147faeee5d3ba7e6876 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:30:44 +0100 Subject: [PATCH 1038/2393] core: minor fixes for animation rewrite --- src/desktop/Workspace.cpp | 2 +- src/managers/AnimationManager.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index cab19254..376288ed 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -628,7 +628,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->value(), true); + g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->goal(), true); } } diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 6bfeed83..c1ea1d27 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -147,11 +147,10 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); const auto POINTY = PBEZIER->getYForPoint(SPENT); - if constexpr (std::same_as) { + if constexpr (std::same_as) updateColorVariable(av, POINTY, animationsDisabled); - } else { + else updateVariable(av, POINTY, animationsDisabled); - } av.onUpdate(); From 67e1e46f9b6285ea260bc88844f85dec6b7d7d02 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 7 Jan 2025 20:58:49 +0100 Subject: [PATCH 1039/2393] window: fixup fade out animation on silent moves --- src/desktop/Window.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 8175fc57..2bd82ad3 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -413,10 +413,10 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; - m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; - m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); *m_fMovingToWorkspaceAlpha = 0.F; + m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; m_pWorkspace = pWorkspace; @@ -541,9 +541,9 @@ void CWindow::onMap() { m_fMovingFromWorkspaceAlpha->resetAllCallbacks(); m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); - m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); *m_fBorderAngleAnimationProgress = 1.f; m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); From 75727e7c17f31d97d518df8fdb11ec9d802ca5f3 Mon Sep 17 00:00:00 2001 From: staz Date: Wed, 8 Jan 2025 15:28:47 +0500 Subject: [PATCH 1040/2393] protocols: fix compilation error (#8988) --- src/protocols/FrogColorManagement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 3ea20405..6a921981 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -88,7 +88,7 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPcolorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; From 5fa2594659f9f4ad19a1afe456ee34bd1c1907b7 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:28:55 +0000 Subject: [PATCH 1041/2393] renderer: don't access hdrMetadata optional if it has no value (#8987) --- src/render/Renderer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 978384d5..cf25d477 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1466,8 +1466,9 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { static auto PHDR = CConfigValue("experimental:hdr"); - Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, pMonitor->output->parsedEDID.hdrMetadata->supportsPQ); - if (pMonitor->output->parsedEDID.supportsBT2020 && pMonitor->output->parsedEDID.hdrMetadata->supportsPQ) { + const bool SUPPORTSPQ = pMonitor->output->parsedEDID.hdrMetadata.has_value() ? pMonitor->output->parsedEDID.hdrMetadata->supportsPQ : false; + Debug::log(TRACE, "ColorManagement supportsBT2020 {}, supportsPQ {}", pMonitor->output->parsedEDID.supportsBT2020, SUPPORTSPQ); + if (pMonitor->output->parsedEDID.supportsBT2020 && SUPPORTSPQ) { if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); From ad64726f5df0fa3cabcd6af9f872d5e8e1f65dbc Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 11:33:41 +0100 Subject: [PATCH 1042/2393] opengl: only allocate offMainFB on demand These are not used by hyprland, only potentially plugins. No need to keep the VRAM allocated all the time --- src/render/OpenGL.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 93ab5fdf..819791e8 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -843,7 +843,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_RenderData.pCurrentMonData->offloadFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); - m_RenderData.pCurrentMonData->offMainFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->offloadFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); @@ -954,6 +953,12 @@ void CHyprOpenGLImpl::end() { m_RenderData.mainFB = nullptr; m_RenderData.outFB = nullptr; + // if we dropped to offMain, release it now. + // if there is a plugin constantly using it, this might be a bit slow, + // but I havent seen a single plugin yet use these, so it's better to drop a bit of vram. + if (m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + m_RenderData.pCurrentMonData->offMainFB.release(); + // check for gl errors const GLenum ERR = glGetError(); @@ -2881,6 +2886,9 @@ void CHyprOpenGLImpl::restoreMatrix() { } void CHyprOpenGLImpl::bindOffMain() { + if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + m_RenderData.pCurrentMonData->offMainFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, + m_RenderData.pMonitor->output->state->state().drmFormat); m_RenderData.pCurrentMonData->offMainFB.bind(); clear(CHyprColor(0, 0, 0, 0)); m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB; From b320bc2dc6e308360936ce4396010359b74558bf Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 12:29:24 +0100 Subject: [PATCH 1043/2393] core: use cpu-buffer hw cursors on nvidia by default --- src/config/ConfigManager.cpp | 6 +++--- src/managers/PointerManager.cpp | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 5839204f..def15f26 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -578,7 +578,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{1}); // TODO: remove this. I don't think it does us any good to disable intro. - m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); @@ -593,7 +593,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:sync_gsettings_theme", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:hide_on_key_press", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:hide_on_touch", Hyprlang::INT{1}); - m_pConfig->addConfigValue("cursor:use_cpu_buffer", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:use_cpu_buffer", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:warp_back_after_non_mouse_input", Hyprlang::INT{0}); m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0}); @@ -2741,7 +2741,7 @@ bool CConfigManager::shouldUseSoftwareCursors() { switch (*PNOHW) { case 0: return false; case 1: return true; - default: return g_pHyprRenderer->isNvidia(); + default: break; } return true; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index bc166825..85e1c601 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -376,7 +376,9 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->cursorPlaneSize(); auto const& cursorSize = currentCursorImage.size; - static auto PDUMB = CConfigValue("cursor:use_cpu_buffer"); + static auto PCPUBUFFER = CConfigValue("cursor:use_cpu_buffer"); + + const bool shouldUseCpuBuffer = *PCPUBUFFER == 1 || (*PCPUBUFFER != 0 && g_pHyprRenderer->isNvidia()); if (maxSize == Vector2D{}) return nullptr; @@ -390,12 +392,12 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size || - *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { + shouldUseCpuBuffer != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { - if (!state->monitor->cursorSwapchain || *PDUMB != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { + if (!state->monitor->cursorSwapchain || shouldUseCpuBuffer != (state->monitor->cursorSwapchain->getAllocator()->type() != Aquamarine::AQ_ALLOCATOR_TYPE_GBM)) { auto allocator = state->monitor->output->getBackend()->preferredAllocator(); - if (*PDUMB) { + if (shouldUseCpuBuffer) { for (const auto& a : state->monitor->output->getBackend()->getAllocators()) { if (a->type() == Aquamarine::AQ_ALLOCATOR_TYPE_DRM_DUMB) { allocator = a; @@ -415,7 +417,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->output->getBackend()->preferredAllocator()->drmFD() != g_pCompositor->m_iDRMFD; // We do not set the format (unless shm). If it's unset (DRM_FORMAT_INVALID) then the swapchain will pick for us, // but if it's set, we don't wanna change it. - if (*PDUMB) + if (shouldUseCpuBuffer) options.format = DRM_FORMAT_ARGB8888; if (!state->monitor->cursorSwapchain->reconfigure(options)) { @@ -438,7 +440,7 @@ SP CPointerManager::renderHWCursorBuffer(SPdataCopy(); if (texData.empty()) { From 983bc067dac2e737bc724721c79d87cd81f27501 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 8 Jan 2025 12:34:43 +0100 Subject: [PATCH 1044/2393] opengl: fix crash on null fb stencil op --- src/render/OpenGL.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 819791e8..3a4781e7 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -847,7 +847,6 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb m_RenderData.pCurrentMonData->offloadFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); m_RenderData.pCurrentMonData->mirrorSwapFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); - m_RenderData.pCurrentMonData->offMainFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); } if (m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated() && m_RenderData.pMonitor->mirrors.empty()) @@ -2886,9 +2885,13 @@ void CHyprOpenGLImpl::restoreMatrix() { } void CHyprOpenGLImpl::bindOffMain() { - if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) + if (!m_RenderData.pCurrentMonData->offMainFB.isAllocated()) { m_RenderData.pCurrentMonData->offMainFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, m_RenderData.pMonitor->output->state->state().drmFormat); + + m_RenderData.pCurrentMonData->offMainFB.addStencil(m_RenderData.pCurrentMonData->stencilTex); + } + m_RenderData.pCurrentMonData->offMainFB.bind(); clear(CHyprColor(0, 0, 0, 0)); m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offMainFB; From c9822b08f914da2997e8ef47c8bef8016e5ff313 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Thu, 9 Jan 2025 05:16:34 +0800 Subject: [PATCH 1045/2393] keybinds: add new window destruction dispatchers (#8962) --- src/managers/KeybindManager.cpp | 84 +++++++++++++++++++++++++++++++-- src/managers/KeybindManager.hpp | 6 ++- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index fd4992eb..09f6f928 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -12,6 +12,7 @@ #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" +#include "../helpers/signal/Signal.hpp" #include #include @@ -63,8 +64,12 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["exec"] = spawn; m_mDispatchers["execr"] = spawnRaw; - m_mDispatchers["killactive"] = killActive; - m_mDispatchers["closewindow"] = kill; + m_mDispatchers["killactive"] = closeActive; + m_mDispatchers["forcekillactive"] = killActive; + m_mDispatchers["closewindow"] = closeWindow; + m_mDispatchers["killwindow"] = killWindow; + m_mDispatchers["signal"] = signalActive; + m_mDispatchers["signalwindow"] = signalWindow; m_mDispatchers["togglefloating"] = toggleActiveFloating; m_mDispatchers["setfloating"] = setActiveFloating; m_mDispatchers["settiled"] = setActiveTiled; @@ -978,17 +983,23 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo } SDispatchResult CKeybindManager::killActive(std::string args) { + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), SIGKILL); + + return {}; +} + +SDispatchResult CKeybindManager::closeActive(std::string args) { g_pCompositor->closeWindow(g_pCompositor->m_pLastWindow.lock()); return {}; } -SDispatchResult CKeybindManager::kill(std::string args) { +SDispatchResult CKeybindManager::closeWindow(std::string args) { const auto PWINDOW = g_pCompositor->getWindowByRegex(args); if (!PWINDOW) { - Debug::log(ERR, "kill: no window found"); - return {.success = false, .error = "kill: no window found"}; + Debug::log(ERR, "closeWindow: no window found"); + return {.success = false, .error = "closeWindow: no window found"}; } g_pCompositor->closeWindow(PWINDOW); @@ -996,6 +1007,69 @@ SDispatchResult CKeybindManager::kill(std::string args) { return {}; } +SDispatchResult CKeybindManager::killWindow(std::string args) { + const auto PWINDOW = g_pCompositor->getWindowByRegex(args); + + if (!PWINDOW) { + Debug::log(ERR, "killWindow: no window found"); + return {.success = false, .error = "killWindow: no window found"}; + } + + kill(PWINDOW->getPID(), SIGKILL); + + return {}; +} + +SDispatchResult CKeybindManager::signalActive(std::string args) { + if (!std::all_of(args.begin(), args.end(), ::isdigit)) + return {.success = false, .error = "signalActive: signal has to be int"}; + + try { + const auto SIGNALNUM = std::stoi(args); + if (SIGNALNUM < 1 || SIGNALNUM > 31) { + Debug::log(ERR, "signalActive: invalid signal number {}", SIGNALNUM); + return {.success = false, .error = std::format("signalActive: invalid signal number {}", SIGNALNUM)}; + } + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), SIGNALNUM); + } catch (const std::exception& e) { + Debug::log(ERR, "signalActive: invalid signal format \"{}\"", args); + return {.success = false, .error = std::format("signalActive: invalid signal format \"{}\"", args)}; + } + + kill(g_pCompositor->m_pLastWindow.lock()->getPID(), std::stoi(args)); + + return {}; +} + +SDispatchResult CKeybindManager::signalWindow(std::string args) { + const auto WINDOWREGEX = args.substr(0, args.find_first_of(',')); + const auto SIGNAL = args.substr(args.find_first_of(',') + 1); + + const auto PWINDOW = g_pCompositor->getWindowByRegex(WINDOWREGEX); + + if (!PWINDOW) { + Debug::log(ERR, "signalWindow: no window"); + return {.success = false, .error = "signalWindow: no window"}; + } + + if (!std::all_of(SIGNAL.begin(), SIGNAL.end(), ::isdigit)) + return {.success = false, .error = "signalWindow: signal has to be int"}; + + try { + const auto SIGNALNUM = std::stoi(SIGNAL); + if (SIGNALNUM < 1 || SIGNALNUM > 31) { + Debug::log(ERR, "signalWindow: invalid signal number {}", SIGNALNUM); + return {.success = false, .error = std::format("signalWindow: invalid signal number {}", SIGNALNUM)}; + } + kill(PWINDOW->getPID(), SIGNALNUM); + } catch (const std::exception& e) { + Debug::log(ERR, "signalWindow: invalid signal format \"{}\"", SIGNAL); + return {.success = false, .error = std::format("signalWindow: invalid signal format \"{}\"", SIGNAL)}; + } + + return {}; +} + void CKeybindManager::clearKeybinds() { m_vKeybinds.clear(); } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 02a39df9..76c72187 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -152,8 +152,12 @@ class CKeybindManager { static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); // -------------- Dispatchers -------------- // + static SDispatchResult closeActive(std::string); static SDispatchResult killActive(std::string); - static SDispatchResult kill(std::string); + static SDispatchResult closeWindow(std::string); + static SDispatchResult killWindow(std::string); + static SDispatchResult signalActive(std::string); + static SDispatchResult signalWindow(std::string); static SDispatchResult spawn(std::string); static SDispatchResult spawnRaw(std::string); static SDispatchResult toggleActiveFloating(std::string); From e66eab7b6a90514251439f661454c536afa3e5c8 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:13:47 +0000 Subject: [PATCH 1046/2393] animationmgr: don't warp based on POINTY value (#9000) --- src/managers/AnimationManager.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index c1ea1d27..f0f6a980 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -40,7 +40,7 @@ CHyprAnimationManager::CHyprAnimationManager() { template void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { - if (POINTY >= 1.f || warp || av.value() == av.goal()) { + if (warp || av.value() == av.goal()) { av.warp(); return; } @@ -50,7 +50,7 @@ void updateVariable(CAnimatedVariable& av, const float POINTY, bool war } void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { - if (POINTY >= 1.f || warp || av.value() == av.goal()) { + if (warp || av.value() == av.goal()) { av.warp(); return; } @@ -146,11 +146,12 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { const auto SPENT = av.getPercent(); const auto PBEZIER = g_pAnimationManager->getBezier(av.getBezierName()); const auto POINTY = PBEZIER->getYForPoint(SPENT); + const bool WARP = animationsDisabled || SPENT >= 1.f; if constexpr (std::same_as) - updateColorVariable(av, POINTY, animationsDisabled); + updateColorVariable(av, POINTY, WARP); else - updateVariable(av, POINTY, animationsDisabled); + updateVariable(av, POINTY, WARP); av.onUpdate(); From 2d1ebadb9b65ef8d57f998031f022b29842b40e4 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Thu, 9 Jan 2025 14:52:26 -0600 Subject: [PATCH 1047/2393] selectors: add a tag: to for matching window tag(s) by regex (#8985) --- src/Compositor.cpp | 15 +++++++++++++++ src/managers/KeybindManager.hpp | 1 + 2 files changed, 16 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3d159042..79574084 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2401,6 +2401,9 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) { } else if (regexp.starts_with("initialtitle:")) { mode = MODE_INITIAL_TITLE_REGEX; regexCheck = regexp.substr(13); + } else if (regexp.starts_with("tag:")) { + mode = MODE_TAG_REGEX; + regexCheck = regexp.substr(4); } else if (regexp.starts_with("address:")) { mode = MODE_ADDRESS; matchCheck = regexp.substr(8); @@ -2438,6 +2441,18 @@ PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp_) { continue; break; } + case MODE_TAG_REGEX: { + bool tagMatched = false; + for (auto const& t : w->m_tags.getTags()) { + if (RE2::FullMatch(t, regexCheck)) { + tagMatched = true; + break; + } + } + if (!tagMatched) + continue; + break; + } case MODE_ADDRESS: { std::string addr = std::format("0x{:x}", (uintptr_t)w.get()); if (matchCheck != addr) diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 76c72187..d01ec75b 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -49,6 +49,7 @@ enum eFocusWindowMode : uint8_t { MODE_INITIAL_CLASS_REGEX, MODE_TITLE_REGEX, MODE_INITIAL_TITLE_REGEX, + MODE_TAG_REGEX, MODE_ADDRESS, MODE_PID, MODE_ACTIVE_WINDOW From 85aba23cbeea2e651fa1d3f88345f9ba4d4bd4a8 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Fri, 10 Jan 2025 04:54:25 +0800 Subject: [PATCH 1048/2393] ci(clang-format): directly do the clang-format instead of error (#8955) Will suggest a clang-format fix on every MR that violates it. --- .github/workflows/ci.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 22421d18..65bfa1ca 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -126,3 +126,27 @@ jobs: - name: clang-format check run: ninja -C build clang-format-check + + - name: clang-format apply + if: ${{ failure() && github.event_name == 'pull_request' }} + run: ninja -C build clang-format + + - name: Create patch + if: ${{ failure() && github.event_name == 'pull_request' }} + run: | + echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch + echo '
' >> clang-format.patch + echo 'clang-format.patch' >> clang-format.patch + echo >> clang-format.patch + echo '```diff' >> clang-format.patch + git diff >> clang-format.patch + echo '```' >> clang-format.patch + echo >> clang-format.patch + echo '
' >> clang-format.patch + + - name: Comment patch + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: mshick/add-pr-comment@v2 + with: + message-path: | + clang-format.patch From 9dc9366fc65ca8b4f18f6554d0b147baceda01f0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 9 Jan 2025 22:08:16 +0100 Subject: [PATCH 1049/2393] config: fix animations requiring all args fixes #9009 --- src/config/ConfigManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index def15f26..b575a167 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2053,6 +2053,11 @@ std::optional CConfigManager::handleAnimation(const std::string& co if (enabledInt != 0 && enabledInt != 1) return "invalid animation on/off state"; + if (!enabledInt) { + m_AnimationTree.setConfigForNode(ANIMNAME, enabledInt, 1, "default"); + return {}; + } + int64_t speed = -1; // speed From f9c37ca43b14a4564d92b5788c81bf16f7bb719c Mon Sep 17 00:00:00 2001 From: Dardo D Kleiner Date: Thu, 9 Jan 2025 17:38:38 -0500 Subject: [PATCH 1050/2393] windows: honor xdg_toplevel_set_fullscreen output hint (#8965) Co-authored-by: Dardo D Kleiner --- src/desktop/Window.cpp | 21 ++++++++++++++++----- src/desktop/Window.hpp | 4 +++- src/events/Windows.cpp | 25 +++++++++++++++++++++++++ src/protocols/XDGShell.cpp | 8 +++++++- src/protocols/XDGShell.hpp | 7 ++++--- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 2bd82ad3..65e1eb79 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1382,15 +1382,26 @@ void CWindow::activate(bool force) { } void CWindow::onUpdateState() { - std::optional requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen; - std::optional requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize; + std::optional requestsFS = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreen : m_pXWaylandSurface->state.requestsFullscreen; + std::optional requestsID = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsFullscreenMonitor : MONITOR_INVALID; + std::optional requestsMX = m_pXDGSurface ? m_pXDGSurface->toplevel->state.requestsMaximize : m_pXWaylandSurface->state.requestsMaximize; if (requestsFS.has_value() && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN)) { - bool fs = requestsFS.value(); - if (m_bIsMapped) { - g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value()); + if (requestsID.has_value() && (requestsID.value() != MONITOR_INVALID) && !(m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT)) { + if (m_bIsMapped) { + const auto monitor = g_pCompositor->getMonitorFromID(requestsID.value()); + g_pCompositor->moveWindowToWorkspaceSafe(m_pSelf.lock(), monitor->activeWorkspace); + g_pCompositor->setActiveMonitor(monitor); + } + + if (!m_bIsMapped) + m_iWantsInitialFullscreenMonitor = requestsID.value(); } + bool fs = requestsFS.value(); + if (m_bIsMapped) + g_pCompositor->changeWindowFullscreenModeClient(m_pSelf.lock(), FSMODE_FULLSCREEN, requestsFS.value()); + if (!m_bIsMapped) m_bWantsInitialFullscreen = fs; } diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 37189a00..d503ac3b 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -57,6 +57,7 @@ enum eSuppressEvents : uint8_t { SUPPRESS_MAXIMIZE = 1 << 1, SUPPRESS_ACTIVATE = 1 << 2, SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3, + SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4, }; class IWindowTransformer; @@ -288,7 +289,8 @@ class CWindow { bool m_bNoInitialFocus = false; // Fullscreen and Maximize - bool m_bWantsInitialFullscreen = false; + bool m_bWantsInitialFullscreen = false; + MONITORID m_iWantsInitialFullscreenMonitor = MONITOR_INVALID; // bitfield eSuppressEvents uint64_t m_eSuppressedEvents = SUPPRESS_NONE; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 8082cdc9..ff69e83f 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -131,6 +131,7 @@ void Events::listener_mapWindow(void* owner, void* data) { std::optional requestedFSState; if (PWINDOW->m_bWantsInitialFullscreen || (PWINDOW->m_bIsX11 && PWINDOW->m_pXWaylandSurface->fullscreen)) requestedClientFSMode = FSMODE_FULLSCREEN; + MONITORID requestedFSMonitor = PWINDOW->m_iWantsInitialFullscreenMonitor; for (auto const& r : PWINDOW->m_vMatchedRules) { switch (r->ruleType) { @@ -168,6 +169,7 @@ void Events::listener_mapWindow(void* owner, void* data) { PWORKSPACE = PWINDOW->m_pWorkspace; Debug::log(LOG, "Rule monitor, applying to {:mw}", PWINDOW); + requestedFSMonitor = MONITOR_INVALID; } catch (std::exception& e) { Debug::log(ERR, "Rule monitor failed, rule: {} -> {} | err: {}", r->szRule, r->szValue, e.what()); } break; } @@ -186,6 +188,7 @@ void Events::listener_mapWindow(void* owner, void* data) { requestedWorkspace = ""; Debug::log(LOG, "Rule workspace matched by {}, {} applied.", PWINDOW, r->szValue); + requestedFSMonitor = MONITOR_INVALID; break; } case CWindowRule::RULE_FLOAT: { @@ -227,6 +230,8 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE; else if (vars[i] == "activatefocus") PWINDOW->m_eSuppressedEvents |= SUPPRESS_ACTIVATE_FOCUSONLY; + else if (vars[i] == "fullscreenoutput") + PWINDOW->m_eSuppressedEvents |= SUPPRESS_FULLSCREEN_OUTPUT; else Debug::log(ERR, "Error while parsing suppressevent windowrule: unknown event type {}", vars[i]); } @@ -337,10 +342,30 @@ void Events::listener_mapWindow(void* owner, void* data) { PMONITOR = g_pCompositor->m_pLastMonitor.lock(); } + + requestedFSMonitor = MONITOR_INVALID; } else workspaceSilent = false; } + if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT) + requestedFSMonitor = MONITOR_INVALID; + else if (requestedFSMonitor != MONITOR_INVALID) { + if (const auto PM = g_pCompositor->getMonitorFromID(requestedFSMonitor); PM) + PWINDOW->m_pMonitor = PM; + + const auto PMONITORFROMID = PWINDOW->m_pMonitor.lock(); + + if (PWINDOW->m_pMonitor != PMONITOR) { + g_pKeybindManager->m_mDispatchers["focusmonitor"](std::to_string(PWINDOW->monitorID())); + PMONITOR = PMONITORFROMID; + } + PWINDOW->m_pWorkspace = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace; + PWORKSPACE = PWINDOW->m_pWorkspace; + + Debug::log(LOG, "Requested monitor, applying to {:mw}", PWINDOW); + } + if (PWORKSPACE->m_bDefaultFloating) PWINDOW->m_bIsFloating = true; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 282aec47..6b7cb3c1 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -5,6 +5,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" +#include "protocols/core/Output.hpp" #include #include @@ -191,9 +192,14 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPsetSetFullscreen([this](CXdgToplevel* r, wl_resource* output) { + if (output) + if (const auto PM = CWLOutputResource::fromResource(output)->monitor; PM) + state.requestsFullscreenMonitor = PM->ID; + state.requestsFullscreen = true; events.stateChanged.emit(); state.requestsFullscreen.reset(); + state.requestsFullscreenMonitor.reset(); }); resource->setUnsetFullscreen([this](CXdgToplevel* r) { @@ -205,7 +211,7 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPsetSetMinimized([this](CXdgToplevel* r) { state.requestsMinimize = true; events.stateChanged.emit(); - state.requestsFullscreen.reset(); + state.requestsMinimize.reset(); }); resource->setSetParent([this](CXdgToplevel* r, wl_resource* parentR) { diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index ef847f3b..6eef99bb 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -123,9 +123,10 @@ class CXDGToplevelResource { std::string appid; // volatile state: is reset after the stateChanged signal fires - std::optional requestsMaximize; - std::optional requestsFullscreen; - std::optional requestsMinimize; + std::optional requestsMaximize; + std::optional requestsFullscreen; + std::optional requestsFullscreenMonitor; + std::optional requestsMinimize; } state; struct { From 8475a8ef992fd45be41b3217ac0f0dd71235f257 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 10 Jan 2025 14:09:09 +0100 Subject: [PATCH 1051/2393] core: always use goal size to send to clients --- src/desktop/Window.cpp | 2 +- src/managers/KeybindManager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 65e1eb79..5608daef 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -444,7 +444,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } // update xwayland coords - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->value()); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->goal()); if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 09f6f928..b0bd0e9c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1891,8 +1891,8 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { continue; if (!w->m_bRequestsFloat && w->m_bIsFloating != PWORKSPACE->m_bDefaultFloating) { - const auto SAVEDPOS = w->m_vRealPosition->value(); - const auto SAVEDSIZE = w->m_vRealSize->value(); + const auto SAVEDPOS = w->m_vRealPosition->goal(); + const auto SAVEDSIZE = w->m_vRealSize->goal(); w->m_bIsFloating = PWORKSPACE->m_bDefaultFloating; g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(w); From da9252a23e69fc4d34beca73ebcc90b03af0ed2a Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Fri, 10 Jan 2025 23:16:52 +0800 Subject: [PATCH 1052/2393] keybinds: fix nullptr deref in forcekillactive (#9021) --- src/managers/KeybindManager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index b0bd0e9c..4cd97913 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -983,7 +983,14 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo } SDispatchResult CKeybindManager::killActive(std::string args) { - kill(g_pCompositor->m_pLastWindow.lock()->getPID(), SIGKILL); + const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); + + if (!PWINDOW) { + Debug::log(ERR, "killActive: no window found"); + return {.success = false, .error = "killActive: no window found"}; + } + + kill(PWINDOW->getPID(), SIGKILL); return {}; } From b5fb6110ab1f75440b4b90d09f95d304d8c2080b Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Fri, 10 Jan 2025 19:09:40 +0100 Subject: [PATCH 1053/2393] core: Add a periodic donation request (#8981) Will fire once in december and july. Disableable with `ecosystem:no_donation:nag` --- src/Compositor.cpp | 9 +- src/config/ConfigManager.cpp | 1 + src/helpers/MiscFunctions.cpp | 27 ------ src/helpers/MiscFunctions.hpp | 1 - src/helpers/fs/FsUtils.cpp | 107 ++++++++++++++++++++++++ src/helpers/fs/FsUtils.hpp | 15 ++++ src/managers/DonationNagManager.cpp | 114 ++++++++++++++++++++++++++ src/managers/DonationNagManager.hpp | 16 ++++ src/managers/VersionKeeperManager.cpp | 92 +++------------------ src/managers/VersionKeeperManager.hpp | 11 +-- 10 files changed, 278 insertions(+), 115 deletions(-) create mode 100644 src/helpers/fs/FsUtils.cpp create mode 100644 src/helpers/fs/FsUtils.hpp create mode 100644 src/managers/DonationNagManager.cpp create mode 100644 src/managers/DonationNagManager.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 79574084..fcd15312 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -9,6 +9,7 @@ #include "managers/PointerManager.hpp" #include "managers/SeatManager.hpp" #include "managers/VersionKeeperManager.hpp" +#include "managers/DonationNagManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -25,6 +26,7 @@ #endif #include #include "helpers/varlist/VarList.hpp" +#include "helpers/fs/FsUtils.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" @@ -544,6 +546,8 @@ void CCompositor::cleanup() { g_pSeatManager.reset(); g_pHyprCtl.reset(); g_pEventLoopManager.reset(); + g_pVersionKeeperMgr.reset(); + g_pDonationNagManager.reset(); if (m_pAqBackend) m_pAqBackend.reset(); @@ -645,6 +649,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the VersionKeeper!"); g_pVersionKeeperMgr = std::make_unique(); + Debug::log(LOG, "Creating the DonationNag!"); + g_pDonationNagManager = std::make_unique(); + Debug::log(LOG, "Starting XWayland"); g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); } break; @@ -2645,7 +2652,7 @@ void CCompositor::performUserChecks() { } if (!*PNOCHECKQTUTILS) { - if (!executableExistsInPath("hyprland-dialog")) { + if (!NFsUtils::executableExistsInPath("hyprland-dialog")) { g_pHyprNotificationOverlay->addNotification( "Your system does not have hyprland-qtutils installed. This is a runtime dependency for some dialogs. Consider installing it.", CHyprColor{}, 15000, ICON_WARNING); } diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b575a167..3f8862ee 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -621,6 +621,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("render:ctm_animation", Hyprlang::INT{2}); m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0}); + m_pConfig->addConfigValue("ecosystem:no_donation_nag", Hyprlang::INT{0}); m_pConfig->addConfigValue("experimental:wide_color_gamut", Hyprlang::INT{0}); m_pConfig->addConfigValue("experimental:hdr", Hyprlang::INT{0}); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index e970b781..08a1106a 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -911,30 +911,3 @@ float stringToPercentage(const std::string& VALUE, const float REL) { else return std::stof(VALUE); } - -bool executableExistsInPath(const std::string& exe) { - if (!getenv("PATH")) - return false; - - static CVarList paths(getenv("PATH"), 0, ':', true); - - for (auto& p : paths) { - std::string path = p + std::string{"/"} + exe; - std::error_code ec; - if (!std::filesystem::exists(path, ec) || ec) - continue; - - if (!std::filesystem::is_regular_file(path, ec) || ec) - continue; - - auto stat = std::filesystem::status(path, ec); - if (ec) - continue; - - auto perms = stat.permissions(); - - return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec); - } - - return false; -} diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index b179b3d6..64802279 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -40,7 +40,6 @@ bool envEnabled(const std::string& env); int allocateSHMFile(size_t len); bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); float stringToPercentage(const std::string& VALUE, const float REL); -bool executableExistsInPath(const std::string& exe); template [[deprecated("use std::format instead")]] std::string getFormat(std::format_string fmt, Args&&... args) { diff --git a/src/helpers/fs/FsUtils.cpp b/src/helpers/fs/FsUtils.cpp new file mode 100644 index 00000000..0bc2e685 --- /dev/null +++ b/src/helpers/fs/FsUtils.cpp @@ -0,0 +1,107 @@ +#include "FsUtils.hpp" +#include "../../debug/Log.hpp" + +#include +#include + +#include +#include +using namespace Hyprutils::String; + +std::optional NFsUtils::getDataHome() { + const auto DATA_HOME = getenv("XDG_DATA_HOME"); + + std::string dataRoot; + + if (!DATA_HOME) { + const auto HOME = getenv("HOME"); + + if (!HOME) { + Debug::log(ERR, "FsUtils::getDataHome: can't get data home: no $HOME or $XDG_DATA_HOME"); + return std::nullopt; + } + + dataRoot = HOME + std::string{"/.local/share/"}; + } else + dataRoot = DATA_HOME + std::string{"/"}; + + std::error_code ec; + if (!std::filesystem::exists(dataRoot, ec) || ec) { + Debug::log(ERR, "FsUtils::getDataHome: can't get data home: inaccessible / missing"); + return std::nullopt; + } + + dataRoot += "hyprland/"; + + if (!std::filesystem::exists(dataRoot, ec) || ec) { + Debug::log(LOG, "FsUtils::getDataHome: no hyprland data home, creating."); + std::filesystem::create_directory(dataRoot, ec); + if (ec) { + Debug::log(ERR, "FsUtils::getDataHome: can't create new data home for hyprland"); + return std::nullopt; + } + std::filesystem::permissions(dataRoot, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | std::filesystem::perms::owner_exec, ec); + if (ec) + Debug::log(WARN, "FsUtils::getDataHome: couldn't set perms on hyprland data store. Proceeding anyways."); + } + + if (!std::filesystem::exists(dataRoot, ec) || ec) { + Debug::log(ERR, "FsUtils::getDataHome: no hyprland data home, failed to create."); + return std::nullopt; + } + + return dataRoot; +} + +std::optional NFsUtils::readFileAsString(const std::string& path) { + std::error_code ec; + + if (!std::filesystem::exists(path, ec) || ec) + return std::nullopt; + + std::ifstream file(path); + if (!file.good()) + return std::nullopt; + + return trim(std::string((std::istreambuf_iterator(file)), (std::istreambuf_iterator()))); +} + +bool NFsUtils::writeToFile(const std::string& path, const std::string& content) { + std::ofstream of(path, std::ios::trunc); + if (!of.good()) { + Debug::log(ERR, "CVersionKeeperManager: couldn't open an ofstream for writing the version file."); + return false; + } + + of << content; + of.close(); + + return true; +} + +bool NFsUtils::executableExistsInPath(const std::string& exe) { + if (!getenv("PATH")) + return false; + + static CVarList paths(getenv("PATH"), 0, ':', true); + + for (auto& p : paths) { + std::string path = p + std::string{"/"} + exe; + std::error_code ec; + if (!std::filesystem::exists(path, ec) || ec) + continue; + + if (!std::filesystem::is_regular_file(path, ec) || ec) + continue; + + auto stat = std::filesystem::status(path, ec); + if (ec) + continue; + + auto perms = stat.permissions(); + + return std::filesystem::perms::none != (perms & std::filesystem::perms::others_exec); + } + + return false; +} diff --git a/src/helpers/fs/FsUtils.hpp b/src/helpers/fs/FsUtils.hpp new file mode 100644 index 00000000..bc3b3bf1 --- /dev/null +++ b/src/helpers/fs/FsUtils.hpp @@ -0,0 +1,15 @@ +#pragma once +#include +#include + +namespace NFsUtils { + // Returns the path to the hyprland directory in data home. + std::optional getDataHome(); + + std::optional readFileAsString(const std::string& path); + + // overwrites the file if exists + bool writeToFile(const std::string& path, const std::string& content); + + bool executableExistsInPath(const std::string& exe); +}; diff --git a/src/managers/DonationNagManager.cpp b/src/managers/DonationNagManager.cpp new file mode 100644 index 00000000..d7eab9ae --- /dev/null +++ b/src/managers/DonationNagManager.cpp @@ -0,0 +1,114 @@ +#include "DonationNagManager.hpp" +#include "../debug/Log.hpp" +#include "VersionKeeperManager.hpp" +#include "eventLoop/EventLoopManager.hpp" +#include "../config/ConfigValue.hpp" + +#include +#include + +#include "../helpers/fs/FsUtils.hpp" + +#include +using namespace Hyprutils::OS; + +constexpr const char* LAST_NAG_FILE_NAME = "lastNag"; +constexpr uint64_t DAY_IN_SECONDS = 3600ULL * 24; +constexpr uint64_t MONTH_IN_SECONDS = DAY_IN_SECONDS * 30; + +struct SNagDatePoint { + // Counted from 1, as in Jan 1st is 1, 1 + // No month-boundaries because I am lazy + uint8_t month = 0, dayStart = 0, dayEnd = 0; +}; + +// clang-format off +const std::vector NAG_DATE_POINTS = { + SNagDatePoint { + 7, 20, 31, + }, + SNagDatePoint { + 12, 1, 28 + }, +}; +// clang-format on + +CDonationNagManager::CDonationNagManager() { + static auto PNONAG = CConfigValue("ecosystem:no_donation_nag"); + + if (g_pVersionKeeperMgr->fired() || *PNONAG) + return; + + const auto DATAROOT = NFsUtils::getDataHome(); + + if (!DATAROOT) + return; + + const auto EPOCH = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + const auto LASTNAGSTR = NFsUtils::readFileAsString(*DATAROOT + "/" + LAST_NAG_FILE_NAME); + + if (!LASTNAGSTR) { + const auto EPOCHSTR = std::format("{}", EPOCH); + NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); + return; + } + + uint64_t LAST_EPOCH = 0; + + try { + LAST_EPOCH = std::stoull(*LASTNAGSTR); + } catch (std::exception& e) { + Debug::log(ERR, "DonationNag: Last epoch invalid? Failed to parse \"{}\". Setting to today.", *LASTNAGSTR); + const auto EPOCHSTR = std::format("{}", EPOCH); + NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); + return; + } + + // don't nag if the last nag was less than a month ago. This is + // mostly for first-time nags, as other nags happen in specific time frames shorter than a month + if (EPOCH - LAST_EPOCH < MONTH_IN_SECONDS) { + Debug::log(LOG, "DonationNag: last nag was {} days ago, too early for a nag.", (int)std::round((EPOCH - LAST_EPOCH) / (double)MONTH_IN_SECONDS)); + return; + } + + if (!NFsUtils::executableExistsInPath("hyprland-donate-screen")) { + Debug::log(ERR, "DonationNag: executable doesn't exist, skipping."); + return; + } + + auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + auto local = *localtime(&tt); + + const auto MONTH = local.tm_mon + 1; + const auto DAY = local.tm_mday; + + for (const auto& nagPoint : NAG_DATE_POINTS) { + if (MONTH != nagPoint.month) + continue; + + if (DAY < nagPoint.dayStart || DAY > nagPoint.dayEnd) + continue; + + Debug::log(LOG, "DonationNag: hit nag month {} days {}-{}, it's {} today, nagging", MONTH, nagPoint.dayStart, nagPoint.dayEnd, DAY); + + m_bFired = true; + + const auto EPOCHSTR = std::format("{}", EPOCH); + NFsUtils::writeToFile(*DATAROOT + "/" + LAST_NAG_FILE_NAME, EPOCHSTR); + + g_pEventLoopManager->doLater([] { + CProcess proc("hyprland-donate-screen", {}); + proc.runAsync(); + }); + + break; + } + + if (!m_bFired) + Debug::log(LOG, "DonationNag: didn't hit any nagging periods"); +} + +bool CDonationNagManager::fired() { + return m_bFired; +} \ No newline at end of file diff --git a/src/managers/DonationNagManager.hpp b/src/managers/DonationNagManager.hpp new file mode 100644 index 00000000..e296d815 --- /dev/null +++ b/src/managers/DonationNagManager.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +class CDonationNagManager { + public: + CDonationNagManager(); + + // whether the donation nag was shown this boot. + bool fired(); + + private: + bool m_bFired = false; +}; + +inline std::unique_ptr g_pDonationNagManager; \ No newline at end of file diff --git a/src/managers/VersionKeeperManager.cpp b/src/managers/VersionKeeperManager.cpp index 1ef1040e..cc03a7b9 100644 --- a/src/managers/VersionKeeperManager.cpp +++ b/src/managers/VersionKeeperManager.cpp @@ -6,6 +6,7 @@ #include "../helpers/varlist/VarList.hpp" #include "eventLoop/EventLoopManager.hpp" #include "../config/ConfigValue.hpp" +#include "../helpers/fs/FsUtils.hpp" #include #include @@ -20,12 +21,12 @@ constexpr const char* VERSION_FILE_NAME = "lastVersion"; CVersionKeeperManager::CVersionKeeperManager() { static auto PNONOTIFY = CConfigValue("ecosystem:no_update_news"); - const auto DATAROOT = getDataHome(); + const auto DATAROOT = NFsUtils::getDataHome(); if (!DATAROOT) return; - const auto LASTVER = getDataLastVersion(*DATAROOT); + const auto LASTVER = NFsUtils::readFileAsString(*DATAROOT + "/" + VERSION_FILE_NAME); if (!LASTVER) return; @@ -35,101 +36,26 @@ CVersionKeeperManager::CVersionKeeperManager() { return; } - writeVersionToVersionFile(*DATAROOT); + NFsUtils::writeToFile(*DATAROOT + "/" + VERSION_FILE_NAME, HYPRLAND_VERSION); if (*PNONOTIFY) { Debug::log(LOG, "CVersionKeeperManager: updated, but update news is disabled in the config :("); return; } - if (!executableExistsInPath("hyprland-update-screen")) { + if (!NFsUtils::executableExistsInPath("hyprland-update-screen")) { Debug::log(ERR, "CVersionKeeperManager: hyprland-update-screen doesn't seem to exist, skipping notif about update..."); return; } + m_bFired = true; + g_pEventLoopManager->doLater([]() { CProcess proc("hyprland-update-screen", {"--new-version", HYPRLAND_VERSION}); proc.runAsync(); }); } -std::optional CVersionKeeperManager::getDataHome() { - const auto DATA_HOME = getenv("XDG_DATA_HOME"); - - std::string dataRoot; - - if (!DATA_HOME) { - const auto HOME = getenv("HOME"); - - if (!HOME) { - Debug::log(ERR, "CVersionKeeperManager: can't get data home: no $HOME or $XDG_DATA_HOME"); - return std::nullopt; - } - - dataRoot = HOME + std::string{"/.local/share/"}; - } else - dataRoot = DATA_HOME + std::string{"/"}; - - std::error_code ec; - if (!std::filesystem::exists(dataRoot, ec) || ec) { - Debug::log(ERR, "CVersionKeeperManager: can't get data home: inaccessible / missing"); - return std::nullopt; - } - - dataRoot += "hyprland/"; - - if (!std::filesystem::exists(dataRoot, ec) || ec) { - Debug::log(LOG, "CVersionKeeperManager: no hyprland data home, creating."); - std::filesystem::create_directory(dataRoot, ec); - if (ec) { - Debug::log(ERR, "CVersionKeeperManager: can't create new data home for hyprland"); - return std::nullopt; - } - std::filesystem::permissions(dataRoot, std::filesystem::perms::owner_read | std::filesystem::perms::owner_write | std::filesystem::perms::owner_exec, ec); - if (ec) - Debug::log(WARN, "CVersionKeeperManager: couldn't set perms on hyprland data store. Proceeding anyways."); - } - - if (!std::filesystem::exists(dataRoot, ec) || ec) { - Debug::log(ERR, "CVersionKeeperManager: no hyprland data home, failed to create."); - return std::nullopt; - } - - return dataRoot; -} - -std::optional CVersionKeeperManager::getDataLastVersion(const std::string& dataRoot) { - std::error_code ec; - std::string lastVerFile = dataRoot + "/" + VERSION_FILE_NAME; - - if (!std::filesystem::exists(lastVerFile, ec) || ec) { - Debug::log(LOG, "CVersionKeeperManager: no hyprland last version file, creating."); - writeVersionToVersionFile(dataRoot); - - return "0.0.0"; - } - - std::ifstream file(lastVerFile); - if (!file.good()) { - Debug::log(ERR, "CVersionKeeperManager: couldn't open an ifstream for reading the version file."); - return std::nullopt; - } - - return trim(std::string((std::istreambuf_iterator(file)), (std::istreambuf_iterator()))); -} - -void CVersionKeeperManager::writeVersionToVersionFile(const std::string& dataRoot) { - std::string lastVerFile = dataRoot + "/" + VERSION_FILE_NAME; - std::ofstream of(lastVerFile, std::ios::trunc); - if (!of.good()) { - Debug::log(ERR, "CVersionKeeperManager: couldn't open an ofstream for writing the version file."); - return; - } - - of << HYPRLAND_VERSION; - of.close(); -} - bool CVersionKeeperManager::isVersionOlderThanRunning(const std::string& ver) { const CVarList verStrings(ver, 0, '.', true); @@ -151,3 +77,7 @@ bool CVersionKeeperManager::isVersionOlderThanRunning(const std::string& ver) { return true; return false; } + +bool CVersionKeeperManager::fired() { + return m_bFired; +} diff --git a/src/managers/VersionKeeperManager.hpp b/src/managers/VersionKeeperManager.hpp index f0dc05ce..eb404d88 100644 --- a/src/managers/VersionKeeperManager.hpp +++ b/src/managers/VersionKeeperManager.hpp @@ -1,17 +1,18 @@ #pragma once #include -#include class CVersionKeeperManager { public: CVersionKeeperManager(); + // whether the update screen was shown this boot. + bool fired(); + private: - std::optional getDataHome(); - std::optional getDataLastVersion(const std::string& dataRoot); - void writeVersionToVersionFile(const std::string& dataRoot); - bool isVersionOlderThanRunning(const std::string& ver); + bool isVersionOlderThanRunning(const std::string& ver); + + bool m_bFired = false; }; inline std::unique_ptr g_pVersionKeeperMgr; \ No newline at end of file From a8b568c6c451cdce3c8d40ae010247be3f25728b Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 10 Jan 2025 21:42:26 +0300 Subject: [PATCH 1054/2393] core: Add render:allow_early_buffer_release to make buffer release configurable (#9019) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/protocols/core/Compositor.cpp | 15 ++++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 686b996a..483f1f1f 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1313,6 +1313,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{2, 0, 2}, }, + SConfigOptionDescription{ + .value = "render:allow_early_buffer_release", + .description = "Allow early buffer release event. Fixes stuttering and missing frames for some apps. May cause graphical glitches and memory leaks in others", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * cursor: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3f8862ee..299dfbc3 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -619,6 +619,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("render:expand_undersized_textures", Hyprlang::INT{1}); m_pConfig->addConfigValue("render:xp_mode", Hyprlang::INT{0}); m_pConfig->addConfigValue("render:ctm_animation", Hyprlang::INT{2}); + m_pConfig->addConfigValue("render:allow_early_buffer_release", Hyprlang::INT{1}); m_pConfig->addConfigValue("ecosystem:no_update_news", Hyprlang::INT{0}); m_pConfig->addConfigValue("ecosystem:no_donation_nag", Hyprlang::INT{0}); diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 6213f987..e1d6ef7d 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -11,6 +11,7 @@ #include "../PresentationTime.hpp" #include "../DRMSyncobj.hpp" #include "../../render/Renderer.hpp" +#include "config/ConfigValue.hpp" #include class CDefaultSurfaceRole : public ISurfaceRole { @@ -423,12 +424,14 @@ void CWLSurfaceResource::unlockPendingState() { } void CWLSurfaceResource::commitPendingState() { - auto const previousBuffer = current.buffer; - current = pending; + static auto PDROP = CConfigValue("render:allow_early_buffer_release"); + auto const previousBuffer = current.buffer; + current = pending; pending.damage.clear(); pending.bufferDamage.clear(); pending.newBuffer = false; - dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore + if (!*PDROP) + dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore events.roleCommit.emit(); @@ -450,8 +453,10 @@ void CWLSurfaceResource::commitPendingState() { // release the buffer if it's synchronous as update() has done everything thats needed // so we can let the app know we're done. // Some clients aren't ready to receive a release this early. Should be fine to release it on the next commitPendingState. - // if (current.buffer->buffer->isSynchronous()) - // dropCurrentBuffer(); + if (current.buffer->buffer->isSynchronous() && *PDROP) { + dropCurrentBuffer(); + dropPendingBuffer(); // at this point current.buffer holds the same SP and we don't use pending anymore + } } // TODO: we should _accumulate_ and not replace above if sync From cef09fbfe6624d2133d81be863bd48bcfc5939d3 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 10 Jan 2025 21:55:19 +0100 Subject: [PATCH 1055/2393] animation: avoid crashes in ::tick() on mutations mutating the active variables is valid during a tick, we can't let it crash --- src/managers/AnimationManager.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f0f6a980..ea74ffd2 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -215,7 +215,11 @@ void CHyprAnimationManager::tick() { lastTick = std::chrono::high_resolution_clock::now(); static auto PANIMENABLED = CConfigValue("animations:enabled"); - for (auto const& pav : m_vActiveAnimatedVariables) { + + // We need to do this because it's perfectly valid to add/change a var during this (via callbacks) + // FIXME: instead of doing this, make a fn to defer adding until tick is done and not in progress anymore. + const auto PAVS = m_vActiveAnimatedVariables; + for (auto const& pav : PAVS) { const auto PAV = pav.lock(); if (!PAV) continue; From 3b85690aa6d9c14bb926692e25cc4480b85200ab Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 11 Jan 2025 23:58:05 +0800 Subject: [PATCH 1056/2393] config: add exec(-onec) with rules and execr(-once) (#8953) --- src/config/ConfigManager.cpp | 51 +++++++++++++++++++++++++++++++++--- src/config/ConfigManager.hpp | 10 ++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 299dfbc3..60723220 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -130,6 +130,18 @@ static void configHandleGapDestroy(void** data) { delete reinterpret_cast(*data); } +static Hyprlang::CParseResult handleExec(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleExec(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} + static Hyprlang::CParseResult handleRawExec(const char* c, const char* v) { const std::string VALUE = v; const std::string COMMAND = c; @@ -154,6 +166,18 @@ static Hyprlang::CParseResult handleExecOnce(const char* c, const char* v) { return result; } +static Hyprlang::CParseResult handleExecRawOnce(const char* c, const char* v) { + const std::string VALUE = v; + const std::string COMMAND = c; + + const auto RESULT = g_pConfigManager->handleExecRawOnce(COMMAND, VALUE); + + Hyprlang::CParseResult result; + if (RESULT.has_value()) + result.setError(RESULT.value().c_str()); + return result; +} + static Hyprlang::CParseResult handleExecShutdown(const char* c, const char* v) { const std::string VALUE = v; const std::string COMMAND = c; @@ -666,8 +690,10 @@ CConfigManager::CConfigManager() { m_pConfig->addSpecialConfigValue("device", "active_area_size", Hyprlang::VEC2{0, 0}); // only for tablets // keywords - m_pConfig->registerHandler(&::handleRawExec, "exec", {false}); + m_pConfig->registerHandler(&::handleExec, "exec", {false}); + m_pConfig->registerHandler(&::handleRawExec, "execr", {false}); m_pConfig->registerHandler(&::handleExecOnce, "exec-once", {false}); + m_pConfig->registerHandler(&::handleExecRawOnce, "execr-once", {false}); m_pConfig->registerHandler(&::handleExecShutdown, "exec-shutdown", {false}); m_pConfig->registerHandler(&::handleMonitor, "monitor", {false}); m_pConfig->registerHandler(&::handleBind, "bind", {true}); @@ -1441,7 +1467,7 @@ void CConfigManager::dispatchExecOnce() { isLaunchingExecOnce = true; for (auto const& c : firstExecRequests) { - handleRawExec("", c); + c.withRules ? handleExec("", c.exec) : handleRawExec("", c.exec); } firstExecRequests.clear(); // free some kb of memory :P @@ -1744,7 +1770,17 @@ std::string CConfigManager::getDefaultWorkspaceFor(const std::string& name) { std::optional CConfigManager::handleRawExec(const std::string& command, const std::string& args) { if (isFirstLaunch) { - firstExecRequests.push_back(args); + firstExecRequests.push_back({args, false}); + return {}; + } + + g_pKeybindManager->spawnRaw(args); + return {}; +} + +std::optional CConfigManager::handleExec(const std::string& command, const std::string& args) { + if (isFirstLaunch) { + firstExecRequests.push_back({args, true}); return {}; } @@ -1754,7 +1790,14 @@ std::optional CConfigManager::handleRawExec(const std::string& comm std::optional CConfigManager::handleExecOnce(const std::string& command, const std::string& args) { if (isFirstLaunch) - firstExecRequests.push_back(args); + firstExecRequests.push_back({args, true}); + + return {}; +} + +std::optional CConfigManager::handleExecRawOnce(const std::string& command, const std::string& args) { + if (isFirstLaunch) + firstExecRequests.push_back({args, false}); return {}; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 53772401..a27ee7ab 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -132,6 +132,11 @@ struct SConfigOptionDescription { std::variant data; }; +struct SFirstExecRequest { + std::string exec = ""; + bool withRules = false; +}; + class CConfigManager { public: CConfigManager(); @@ -196,7 +201,9 @@ class CConfigManager { // keywords std::optional handleRawExec(const std::string&, const std::string&); + std::optional handleExec(const std::string&, const std::string&); std::optional handleExecOnce(const std::string&, const std::string&); + std::optional handleExecRawOnce(const std::string&, const std::string&); std::optional handleExecShutdown(const std::string&, const std::string&); std::optional handleMonitor(const std::string&, const std::string&); std::optional handleBind(const std::string&, const std::string&); @@ -280,7 +287,8 @@ class CConfigManager { bool firstExecDispatched = false; bool m_bManualCrashInitiated = false; - std::vector firstExecRequests; + + std::vector firstExecRequests; // bool is for if with rules std::vector finalExecRequests; std::vector> m_vFailedPluginConfigValues; // for plugin values of unloaded plugins From 15dc024a398d35957ccfb50ddade5f456a1646b5 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Sat, 11 Jan 2025 19:05:53 +0300 Subject: [PATCH 1057/2393] keybinds: fix previous_per_monitor logic (#9010) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- src/desktop/Workspace.cpp | 10 ++-------- src/desktop/Workspace.hpp | 22 +++++++++++----------- src/helpers/MiscFunctions.cpp | 2 +- src/helpers/Monitor.cpp | 24 ++++++++++++++++++++++++ src/helpers/Monitor.hpp | 15 +++++++++++---- src/managers/KeybindManager.cpp | 33 ++++++++++++++------------------- 6 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 376288ed..07c1a435 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -52,10 +52,7 @@ void CWorkspace::init(PHLWORKSPACE self) { EMIT_HOOK_EVENT("createWorkspace", this); } -SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName(bool perMonitor) const { - if (perMonitor) - return m_sPrevWorkspacePerMonitor; - +SWorkspaceIDName CWorkspace::getPrevWorkspaceIDName() const { return m_sPrevWorkspace; } @@ -216,10 +213,7 @@ void CWorkspace::rememberPrevWorkspace(const PHLWORKSPACE& prev) { m_sPrevWorkspace.id = prev->m_iID; m_sPrevWorkspace.name = prev->m_szName; - if (prev->m_pMonitor == m_pMonitor) { - m_sPrevWorkspacePerMonitor.id = prev->m_iID; - m_sPrevWorkspacePerMonitor.name = prev->m_szName; - } + prev->m_pMonitor->addPrevWorkspaceID(prev->m_iID); } std::string CWorkspace::getConfigName() { diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index f86dd656..e9859d4f 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -24,17 +24,14 @@ class CWorkspace { // Workspaces ID-based have IDs > 0 // and workspaces name-based have IDs starting with -1337 - WORKSPACEID m_iID = WORKSPACE_INVALID; - std::string m_szName = ""; - PHLMONITORREF m_pMonitor; - // Previous workspace ID and name is stored during a workspace change, allowing travel - // to the previous workspace. - SWorkspaceIDName m_sPrevWorkspace, m_sPrevWorkspacePerMonitor; + WORKSPACEID m_iID = WORKSPACE_INVALID; + std::string m_szName = ""; + PHLMONITORREF m_pMonitor; - bool m_bHasFullscreenWindow = false; - eFullscreenMode m_efFullscreenMode = FSMODE_NONE; + bool m_bHasFullscreenWindow = false; + eFullscreenMode m_efFullscreenMode = FSMODE_NONE; - wl_array m_wlrCoordinateArr; + wl_array m_wlrCoordinateArr; // for animations PHLANIMVAR m_vRenderOffset; @@ -72,7 +69,7 @@ class CWorkspace { std::string getConfigName(); bool matchesStaticSelector(const std::string& selector); void markInert(); - SWorkspaceIDName getPrevWorkspaceIDName(bool perMonitor) const; + SWorkspaceIDName getPrevWorkspaceIDName() const; void updateWindowDecos(); void updateWindowData(); int getWindows(std::optional onlyTiled = {}, std::optional onlyVisible = {}); @@ -88,7 +85,10 @@ class CWorkspace { void updateWindows(); private: - void init(PHLWORKSPACE self); + void init(PHLWORKSPACE self); + // Previous workspace ID and name is stored during a workspace change, allowing travel + // to the previous workspace. + SWorkspaceIDName m_sPrevWorkspace; SP m_pFocusedWindowHook; bool m_bInert = true; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 08a1106a..0fa73e45 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -258,7 +258,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { if (!valid(PWORKSPACE)) return {WORKSPACE_INVALID}; - const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->m_sPrevWorkspace.id); + const auto PLASTWORKSPACE = g_pCompositor->getWorkspaceByID(PWORKSPACE->getPrevWorkspaceIDName().id); if (!PLASTWORKSPACE) return {WORKSPACE_INVALID}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e833e661..cf62bc54 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,5 +1,6 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" +#include "macros.hpp" #include "math/Math.hpp" #include "sync/SyncReleaser.hpp" #include "../Compositor.hpp" @@ -1169,6 +1170,29 @@ void CMonitor::moveTo(const Vector2D& pos) { vecPosition = pos; } +SWorkspaceIDName CMonitor::getPrevWorkspaceIDName(const WORKSPACEID id) { + while (!prevWorkSpaces.empty()) { + const int PREVID = prevWorkSpaces.top(); + prevWorkSpaces.pop(); + if (PREVID == id) // skip same workspace + continue; + + // recheck if previous workspace's was moved to another monitor + const auto ws = g_pCompositor->getWorkspaceByID(PREVID); + if (ws && ws->monitorID() == ID) + return {.id = PREVID, .name = ws->m_szName}; + } + + return {.id = WORKSPACE_INVALID}; +} + +void CMonitor::addPrevWorkspaceID(const WORKSPACEID id) { + if (!prevWorkSpaces.empty() && prevWorkSpaces.top() == id) + return; + + prevWorkSpaces.emplace(id); +} + Vector2D CMonitor::middle() { return vecPosition + vecSize / 2.f; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index b075df81..8085c460 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -1,7 +1,9 @@ #pragma once #include "../defines.hpp" +#include #include +#include "SharedDefs.hpp" #include "WLClasses.hpp" #include #include @@ -196,11 +198,16 @@ class CMonitor { return vecPosition == rhs.vecPosition && vecSize == rhs.vecSize && szName == rhs.szName; } - private: - void setupDefaultWS(const SMonitorRule&); - WORKSPACEID findAvailableDefaultWS(); + // workspace previous per monitor functionality + SWorkspaceIDName getPrevWorkspaceIDName(const WORKSPACEID id); + void addPrevWorkspaceID(const WORKSPACEID id); - bool doneScheduled = false; + private: + void setupDefaultWS(const SMonitorRule&); + WORKSPACEID findAvailableDefaultWS(); + + bool doneScheduled = false; + std::stack prevWorkSpaces; struct { CHyprSignalListener frame; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4cd97913..720d27f6 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1176,27 +1176,24 @@ SDispatchResult CKeybindManager::toggleActivePseudo(std::string args) { return {}; } -static SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCURRENTWORKSPACE) { +static SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCURRENTWORKSPACE, PHLMONITORREF PMONITOR) { if (!args.starts_with("previous")) { return getWorkspaceIDNameFromString(args); } const bool PER_MON = args.contains("_per_monitor"); - const SWorkspaceIDName PPREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(PER_MON); + const SWorkspaceIDName PPREVWS = PER_MON ? PMONITOR->getPrevWorkspaceIDName(PCURRENTWORKSPACE->m_iID) : PCURRENTWORKSPACE->getPrevWorkspaceIDName(); // Do nothing if there's no previous workspace, otherwise switch to it. - if (PPREVWS.id == -1) { + if (PPREVWS.id == -1 || PPREVWS.id == PCURRENTWORKSPACE->m_iID) { Debug::log(LOG, "No previous workspace to change to"); - return {WORKSPACE_NOT_CHANGED, ""}; + return {.id = WORKSPACE_NOT_CHANGED}; } - const auto ID = PCURRENTWORKSPACE->m_iID; if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) { - if (PER_MON && PCURRENTWORKSPACE->m_pMonitor != PWORKSPACETOCHANGETO->m_pMonitor) - return {WORKSPACE_NOT_CHANGED, ""}; - return {ID, PWORKSPACETOCHANGETO->m_szName}; + return {.id = PWORKSPACETOCHANGETO->m_iID, .name = PWORKSPACETOCHANGETO->m_szName}; } - return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; + return {.id = PPREVWS.id, .name = PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name}; } SDispatchResult CKeybindManager::changeworkspace(std::string args) { @@ -1214,7 +1211,7 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) { const auto PCURRENTWORKSPACE = PMONITOR->activeWorkspace; const bool EXPLICITPREVIOUS = args.contains("previous"); - const auto& [workspaceToChangeTo, workspaceName] = getWorkspaceToChangeFromArgs(args, PCURRENTWORKSPACE); + const auto& [workspaceToChangeTo, workspaceName] = getWorkspaceToChangeFromArgs(args, PCURRENTWORKSPACE, PMONITOR); if (workspaceToChangeTo == WORKSPACE_INVALID) { Debug::log(ERR, "Error in changeworkspace, invalid value"); return {.success = false, .error = "Error in changeworkspace, invalid value"}; @@ -1223,19 +1220,19 @@ SDispatchResult CKeybindManager::changeworkspace(std::string args) { if (workspaceToChangeTo == WORKSPACE_NOT_CHANGED) return {}; - const auto PREVWS = PCURRENTWORKSPACE->getPrevWorkspaceIDName(args.contains("_per_monitor")); + const SWorkspaceIDName PPREVWS = args.contains("_per_monitor") ? PMONITOR->getPrevWorkspaceIDName(PCURRENTWORKSPACE->m_iID) : PCURRENTWORKSPACE->getPrevWorkspaceIDName(); - const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; - if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PREVWS.id == -1)) + const bool BISWORKSPACECURRENT = workspaceToChangeTo == PCURRENTWORKSPACE->m_iID; + if (BISWORKSPACECURRENT && (!(*PBACKANDFORTH || EXPLICITPREVIOUS) || PPREVWS.id == -1)) return {.success = false, .error = "Previous workspace doesn't exist"}; g_pInputManager->unconstrainMouse(); g_pInputManager->m_bEmptyFocusCursorSet = false; - auto pWorkspaceToChangeTo = g_pCompositor->getWorkspaceByID(BISWORKSPACECURRENT ? PREVWS.id : workspaceToChangeTo); + auto pWorkspaceToChangeTo = g_pCompositor->getWorkspaceByID(BISWORKSPACECURRENT ? PPREVWS.id : workspaceToChangeTo); if (!pWorkspaceToChangeTo) pWorkspaceToChangeTo = - g_pCompositor->createNewWorkspace(BISWORKSPACECURRENT ? PREVWS.id : workspaceToChangeTo, PMONITOR->ID, BISWORKSPACECURRENT ? PREVWS.name : workspaceName); + g_pCompositor->createNewWorkspace(BISWORKSPACECURRENT ? PPREVWS.id : workspaceToChangeTo, PMONITOR->ID, BISWORKSPACECURRENT ? PPREVWS.name : workspaceName); if (!BISWORKSPACECURRENT && pWorkspaceToChangeTo->m_bIsSpecialWorkspace) { PMONITOR->setSpecialWorkspace(pWorkspaceToChangeTo); @@ -1407,9 +1404,7 @@ SDispatchResult CKeybindManager::moveActiveToWorkspace(std::string args) { } SDispatchResult CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { - PHLWINDOW PWINDOW = nullptr; - - const auto ORIGINALARGS = args; + PHLWINDOW PWINDOW = nullptr; if (args.contains(',')) { PWINDOW = g_pCompositor->getWindowByRegex(args.substr(args.find_last_of(',') + 1)); @@ -2033,7 +2028,7 @@ SDispatchResult CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args } static auto PBACKANDFORTH = CConfigValue("binds:workspace_back_and_forth"); - const auto PREVWS = pWorkspace->getPrevWorkspaceIDName(false); + const auto PREVWS = pWorkspace->getPrevWorkspaceIDName(); if (*PBACKANDFORTH && PCURRMONITOR->activeWorkspaceID() == workspaceID && PREVWS.id != -1) { // Workspace to focus is previous workspace From 9e4f90aedf2f51d3e7f3dbe5391cb193aa0bddf5 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:35:57 +0000 Subject: [PATCH 1058/2393] animation: fixup adding animvars during ::tick (#9030) --- src/managers/AnimationManager.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index ea74ffd2..28adc330 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -216,11 +216,8 @@ void CHyprAnimationManager::tick() { static auto PANIMENABLED = CConfigValue("animations:enabled"); - // We need to do this because it's perfectly valid to add/change a var during this (via callbacks) - // FIXME: instead of doing this, make a fn to defer adding until tick is done and not in progress anymore. - const auto PAVS = m_vActiveAnimatedVariables; - for (auto const& pav : PAVS) { - const auto PAV = pav.lock(); + for (size_t i = 0; i < m_vActiveAnimatedVariables.size(); i++) { + const auto PAV = m_vActiveAnimatedVariables[i].lock(); if (!PAV) continue; From 2778aff08fba59a34b404751039d7acb6bfb3bdf Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:38:04 +0000 Subject: [PATCH 1059/2393] animations: fix XWayland cursor glitch and refactor skill issues (#9033) --- src/events/Windows.cpp | 2 +- src/managers/XWaylandManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index ff69e83f..14e89b4b 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -38,7 +38,7 @@ static void setVector2DAnimToMove(WP pav) { animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); - if (PHLWINDOW && PHLWINDOW->m_vRealPosition->isBeingAnimated() && PHLWINDOW->m_vRealSize->isBeingAnimated()) + if (PHLWINDOW && !PHLWINDOW->m_vRealPosition->isBeingAnimated() && !PHLWINDOW->m_vRealSize->isBeingAnimated()) PHLWINDOW->m_bAnimatingIn = false; } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index bc988f39..ab0bfb88 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -123,7 +123,7 @@ void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool // calculate pos // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = pWindow->m_vRealPosition->value(); + Vector2D windowPos = pWindow->m_vRealPosition->goal(); if (pWindow->m_bIsX11 && PMONITOR) { windowPos -= PMONITOR->vecPosition; // normalize to monitor From 2671656a75708452e9408a111e69e4436b6ad301 Mon Sep 17 00:00:00 2001 From: Toria Date: Sun, 12 Jan 2025 16:35:10 +0000 Subject: [PATCH 1060/2393] helpers/Monitor.cpp: fix include path (#9039) --- src/helpers/Monitor.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 8085c460..8c7566e2 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -3,7 +3,7 @@ #include "../defines.hpp" #include #include -#include "SharedDefs.hpp" +#include "../SharedDefs.hpp" #include "WLClasses.hpp" #include #include From b117fae3b493b9d5ac7ada3140cac555c3979dfd Mon Sep 17 00:00:00 2001 From: staz Date: Sun, 12 Jan 2025 22:00:56 +0500 Subject: [PATCH 1061/2393] keybinds: fix movefocus fallback for special workspaces (#9040) --- src/managers/KeybindManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 720d27f6..9a719130 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1534,7 +1534,8 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) { break; } - const auto PWINDOWCANDIDATE = g_pCompositor->getWindowInDirection(box, PMONITOR->activeWorkspace, arg, PLASTWINDOW, PLASTWINDOW->m_bIsFloating); + const auto PWINDOWCANDIDATE = g_pCompositor->getWindowInDirection(box, PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace, arg, + PLASTWINDOW, PLASTWINDOW->m_bIsFloating); if (PWINDOWCANDIDATE) switchToWindow(PWINDOWCANDIDATE); From a3a74993173662c06025ca633faa68b5590e2c5b Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:02:41 +0300 Subject: [PATCH 1062/2393] renderer: Do not set hdr metadata unless needed (#9014) --- src/protocols/ColorManagement.cpp | 26 ++++++++++++++++++++++---- src/protocols/ColorManagement.hpp | 7 +++++++ src/protocols/FrogColorManagement.cpp | 10 +++++----- src/render/Renderer.cpp | 23 ++++++++++++++++------- src/render/Renderer.hpp | 1 + 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index 7ff4db4f..a76e13c0 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -194,13 +194,13 @@ CColorManagementSurface::CColorManagementSurface(SP return; } - m_hasImageDescription = true; - m_imageDescription = imageDescription->get()->settings; + setHasImageDescription(true); + m_imageDescription = imageDescription->get()->settings; }); resource->setUnsetImageDescription([this](CXxColorManagementSurfaceV4* r) { LOGM(TRACE, "Unset image description for surface={}", (uintptr_t)r); - m_imageDescription = SImageDescription{}; - m_hasImageDescription = false; + m_imageDescription = SImageDescription{}; + setHasImageDescription(false); }); } @@ -222,6 +222,24 @@ bool CColorManagementSurface::hasImageDescription() { return m_hasImageDescription; } +void CColorManagementSurface::setHasImageDescription(bool has) { + m_hasImageDescription = has; + m_needsNewMetadata = true; +} + +const hdr_output_metadata& CColorManagementSurface::hdrMetadata() { + return m_hdrMetadata; +} + +void CColorManagementSurface::setHDRMetadata(const hdr_output_metadata& metadata) { + m_hdrMetadata = metadata; + m_needsNewMetadata = false; +} + +bool CColorManagementSurface::needsHdrMetadataUpdate() { + return m_needsNewMetadata; +} + CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if (!good()) diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index 573abf69..e387b3b7 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -54,12 +55,18 @@ class CColorManagementSurface { const SImageDescription& imageDescription(); bool hasImageDescription(); + void setHasImageDescription(bool has); + const hdr_output_metadata& hdrMetadata(); + void setHDRMetadata(const hdr_output_metadata& metadata); + bool needsHdrMetadataUpdate(); private: SP resource; wl_client* pClient = nullptr; SImageDescription m_imageDescription; bool m_hasImageDescription = false; + bool m_needsNewMetadata = false; + hdr_output_metadata m_hdrMetadata; friend class CFrogColorManagementSurface; }; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index 6a921981..f27af5c8 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -92,7 +92,7 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPcolorManagement->m_imageDescription.transferFunction = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB; - surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->setHasImageDescription(true); } }); resource->setSetKnownContainerColorVolume([this](CFrogColorManagedSurface* r, frogColorManagedSurfacePrimaries primariesName) { @@ -103,12 +103,12 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPcolorManagement->m_imageDescription.primaries = NColorPrimaries::BT2020; break; } - surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->setHasImageDescription(true); }); resource->setSetRenderIntent([this](CFrogColorManagedSurface* r, frogColorManagedSurfaceRenderIntent intent) { LOGM(TRACE, "Set frog cm intent {}", (uint32_t)intent); - pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; - surface->colorManagement->m_hasImageDescription = true; + pqIntentSent = intent == FROG_COLOR_MANAGED_SURFACE_RENDER_INTENT_PERCEPTUAL; + surface->colorManagement->setHasImageDescription(true); }); resource->setSetHdrMetadata([this](CFrogColorManagedSurface* r, uint32_t r_x, uint32_t r_y, uint32_t g_x, uint32_t g_y, uint32_t b_x, uint32_t b_y, uint32_t w_x, uint32_t w_y, uint32_t max_lum, uint32_t min_lum, uint32_t cll, uint32_t fall) { @@ -122,7 +122,7 @@ CFrogColorManagementSurface::CFrogColorManagementSurface(SPcolorManagement->m_imageDescription.maxCLL = cll; surface->colorManagement->m_imageDescription.maxFALL = fall; - surface->colorManagement->m_hasImageDescription = true; + surface->colorManagement->setHasImageDescription(true); }); } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index cf25d477..b9c8dd98 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1460,9 +1460,10 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { pMonitor->output->state->setExplicitInFence(inFD); static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); - if (pMonitor->output->state->state().wideColorGamut != *PWIDE) + if (pMonitor->output->state->state().wideColorGamut != *PWIDE) { Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); - pMonitor->output->state->setWideColorGamut(*PWIDE); + pMonitor->output->state->setWideColorGamut(*PWIDE); + } static auto PHDR = CConfigValue("experimental:hdr"); @@ -1472,12 +1473,20 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); - if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) - pMonitor->output->state->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); - else + if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) { + bool needsHdrMetadataUpdate = SURF->colorManagement->needsHdrMetadataUpdate() || m_previousFSWindow != WINDOW; + if (SURF->colorManagement->needsHdrMetadataUpdate()) + SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); + if (needsHdrMetadataUpdate) + pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata()); + } else pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); - } else - pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + m_previousFSWindow = WINDOW; + } else { + if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR) + pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); + m_previousFSWindow.reset(); + } } if (pMonitor->ctmUpdated) { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 6900c775..f3e0c5a2 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -129,6 +129,7 @@ class CHyprRenderer { bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); + WP m_previousFSWindow; bool m_bCursorHidden = false; bool m_bCursorHasSurface = false; SP m_pCurrentRenderbuffer = nullptr; From 4f0f512cab5a8052c80b365449b69b953a97e169 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 12 Jan 2025 09:09:02 -0800 Subject: [PATCH 1063/2393] protocols: do not capture cursor in toplevel without pointer focus (#9042) --- src/protocols/ToplevelExport.cpp | 21 ++++++++++++++++++++- src/protocols/ToplevelExport.hpp | 7 ++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 2c934b40..68561533 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "ForeignToplevelWlr.hpp" #include "../managers/PointerManager.hpp" +#include "../managers/SeatManager.hpp" #include "types/WLBuffer.hpp" #include "types/Buffer.hpp" #include "../helpers/Format.hpp" @@ -77,7 +78,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re if (!good()) return; - overlayCursor = !!overlayCursor_; + cursorOverlayRequested = !!overlayCursor_; if (!pWindow) { LOGM(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow); @@ -247,6 +248,8 @@ bool CToplevelExportFrame::copyShm(timespec* now) { CFramebuffer outFB; outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, PMONITOR->output->state->state().drmFormat); + auto overlayCursor = shouldOverlayCursor(); + if (overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); g_pPointerManager->damageCursor(PMONITOR->self.lock()); @@ -300,6 +303,8 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) { CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; + auto overlayCursor = shouldOverlayCursor(); + if (overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); g_pPointerManager->damageCursor(PMONITOR->self.lock()); @@ -328,6 +333,20 @@ bool CToplevelExportFrame::copyDmabuf(timespec* now) { return true; } +bool CToplevelExportFrame::shouldOverlayCursor() const { + if (!cursorOverlayRequested) + return false; + + auto pointerSurfaceResource = g_pSeatManager->state.pointerFocus.lock(); + + if (!pointerSurfaceResource) + return false; + + auto pointerSurface = CWLSurface::fromResource(pointerSurfaceResource); + + return pointerSurface && pointerSurface->getWindow() == pWindow; +} + bool CToplevelExportFrame::good() { return resource->resource(); } diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 1ca3e5aa..956a085b 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -51,9 +51,9 @@ class CToplevelExportFrame { SP resource; PHLWINDOW pWindow; - bool overlayCursor = false; - bool ignoreDamage = false; - bool lockedSWCursors = false; + bool cursorOverlayRequested = false; + bool ignoreDamage = false; + bool lockedSWCursors = false; WP buffer; bool bufferDMA = false; @@ -66,6 +66,7 @@ class CToplevelExportFrame { bool copyDmabuf(timespec* now); bool copyShm(timespec* now); void share(); + bool shouldOverlayCursor() const; friend class CToplevelExportProtocol; }; From a6b263713a2b862ed41362082e2147e081934077 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 12 Jan 2025 09:10:36 -0800 Subject: [PATCH 1064/2393] protocols: allow hyprland-toplevel-export to capture hidden windows (#9041) --- src/protocols/ToplevelExport.cpp | 4 ++-- src/render/Renderer.cpp | 14 +++++++------- src/render/Renderer.hpp | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 68561533..0ddd84c8 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -87,7 +87,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re return; } - if (!pWindow->m_bIsMapped || pWindow->isHidden()) { + if (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); @@ -148,7 +148,7 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou return; } - if (!pWindow->m_bIsMapped || pWindow->isHidden()) { + if (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b9c8dd98..d4523a31 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -417,8 +417,8 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo } } -void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool ignoreAllGeometry) { - if (pWindow->isHidden()) +void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespec* time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool standalone) { + if (pWindow->isHidden() && !standalone) return; if (pWindow->m_bFadingOut) { @@ -450,7 +450,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.pos.y = pMonitor->vecPosition.y; } - if (ignoreAllGeometry) + if (standalone) decorate = false; // whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws @@ -463,12 +463,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe (USE_WORKSPACE_FADE_ALPHA ? pWindow->m_fMovingToWorkspaceAlpha->value() : 1.F) * pWindow->m_fMovingFromWorkspaceAlpha->value(); renderdata.alpha = pWindow->m_fActiveInactiveAlpha->value(); renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && !pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN); - renderdata.rounding = ignoreAllGeometry || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; - renderdata.roundingPower = ignoreAllGeometry || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); - renderdata.blur = !ignoreAllGeometry && *PBLUR && !DONT_BLUR; + renderdata.rounding = standalone || renderdata.dontRound ? 0 : pWindow->rounding() * pMonitor->scale; + renderdata.roundingPower = standalone || renderdata.dontRound ? 2.0f : pWindow->roundingPower(); + renderdata.blur = !standalone && *PBLUR && !DONT_BLUR; renderdata.pWindow = pWindow; - if (ignoreAllGeometry) { + if (standalone) { renderdata.alpha = 1.f; renderdata.fadeAlpha = 1.f; } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index f3e0c5a2..8b4988c3 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -117,7 +117,7 @@ class CHyprRenderer { void arrangeLayerArray(PHLMONITOR, const std::vector&, bool, CBox*); void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special) void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) - void renderWindow(PHLWINDOW, PHLMONITOR, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool ignoreAllGeometry = false); + void renderWindow(PHLWINDOW, PHLMONITOR, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false); void renderLayer(PHLLS, PHLMONITOR, timespec*, bool popups = false); void renderSessionLockSurface(SSessionLockSurface*, PHLMONITOR, timespec*); void renderDragIcon(PHLMONITOR, timespec*); From f16f170433540d85cf672217bca2d64c6db9eb01 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 14 Jan 2025 08:44:09 -0800 Subject: [PATCH 1065/2393] protocols: immediately copy toplevel content when ignoreDamage set (#9049) Also sets m_ignoreDamage, as it wasn't set before. --- src/protocols/ToplevelExport.cpp | 9 +++++++-- src/protocols/ToplevelExport.hpp | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 0ddd84c8..73e5cad9 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -202,7 +202,12 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou buffer = PBUFFER->buffer; - PROTO::toplevelExport->m_vFramesAwaitingWrite.emplace_back(self); + m_ignoreDamage = ignoreDamage; + + if (ignoreDamage && validMapped(pWindow)) + share(); + else + PROTO::toplevelExport->m_vFramesAwaitingWrite.emplace_back(self); } void CToplevelExportFrame::share() { @@ -226,7 +231,7 @@ void CToplevelExportFrame::share() { resource->sendFlags((hyprlandToplevelExportFrameV1Flags)0); - if (!ignoreDamage) { + if (!m_ignoreDamage) { resource->sendDamage(0, 0, box.width, box.height); } diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 956a085b..8d734dbd 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -52,7 +52,7 @@ class CToplevelExportFrame { PHLWINDOW pWindow; bool cursorOverlayRequested = false; - bool ignoreDamage = false; + bool m_ignoreDamage = false; bool lockedSWCursors = false; WP buffer; From 25add26881d7b98d2b80eb7a95d3aee0449b72b9 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 14 Jan 2025 17:52:19 +0100 Subject: [PATCH 1066/2393] renderer: unload background texture if it's disabled ref #9031 --- src/config/ConfigManager.cpp | 5 +++-- src/render/OpenGL.cpp | 21 ++++++++++++++------- src/render/OpenGL.hpp | 4 +++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 60723220..17957899 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -899,11 +899,12 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { g_pInputManager->setPointerConfigs(); g_pInputManager->setTouchDeviceConfigs(); g_pInputManager->setTabletConfigs(); - } - if (!isFirstLaunch) g_pHyprOpenGL->m_bReloadScreenShader = true; + g_pHyprOpenGL->ensureBackgroundTexturePresence(); + } + // parseError will be displayed next frame if (result.error) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 3a4781e7..b68448ae 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2699,10 +2699,6 @@ void CHyprOpenGLImpl::initMissingAssetTexture() { void CHyprOpenGLImpl::initAssets() { initMissingAssetTexture(); - static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); - - const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); - m_pLockDeadTexture = loadAsset("lockdead.png"); m_pLockDead2Texture = loadAsset("lockdead2.png"); @@ -2712,9 +2708,20 @@ void CHyprOpenGLImpl::initAssets() { "unknown"), CHyprColor{0.9F, 0.9F, 0.9F, 0.7F}, 20, true); - // create the default background texture - { - std::string texPath = std::format("{}", "wall"); + ensureBackgroundTexturePresence(); +} + +void CHyprOpenGLImpl::ensureBackgroundTexturePresence() { + static auto PNOWALLPAPER = CConfigValue("misc:disable_hyprland_logo"); + static auto PFORCEWALLPAPER = CConfigValue("misc:force_default_wallpaper"); + + const auto FORCEWALLPAPER = std::clamp(*PFORCEWALLPAPER, static_cast(-1L), static_cast(2L)); + + if (*PNOWALLPAPER) + m_pBackgroundTexture.reset(); + else if (!m_pBackgroundTexture) { + // create the default background texture + std::string texPath = "wall"; // get the adequate tex if (FORCEWALLPAPER == -1) { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 3f117a5a..2b600a03 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -223,6 +223,8 @@ class CHyprOpenGLImpl { void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void ensureBackgroundTexturePresence(); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); @@ -293,7 +295,7 @@ class CHyprOpenGLImpl { CShader m_sFinalScreenShader; CTimer m_tGlobalTimer; - SP m_pMissingAssetTexture, m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; + SP m_pMissingAssetTexture, m_pBackgroundTexture, m_pLockDeadTexture, m_pLockDead2Texture, m_pLockTtyTextTexture; // TODO: don't always load lock void logShaderError(const GLuint&, bool program = false); GLuint createProgram(const std::string&, const std::string&, bool dynamic = false); From 52b9ae592b90cc9f857743ae7f59e787cc58fc8a Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:13:47 +0300 Subject: [PATCH 1067/2393] renderer: fix fullscreen hdr check (#9076) --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d4523a31..6c77b27a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1479,7 +1479,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); if (needsHdrMetadataUpdate) pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata()); - } else + } else if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR) pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); m_previousFSWindow = WINDOW; } else { From 0dc7367a7006cc3cc877d52bf34c4998144bff84 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 16 Jan 2025 15:42:39 +0100 Subject: [PATCH 1068/2393] renderer: use cairo for cpu buffer rendering (#9071) Instead of a wonky memcpy which doesn't work when anything non-standard is used (size, pos, transform), just use cairo --- src/managers/PointerManager.cpp | 58 +++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 85e1c601..522187b4 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -12,6 +12,7 @@ #include "SeatManager.hpp" #include #include +#include CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { @@ -481,15 +482,58 @@ SP CPointerManager::renderHWCursorBuffer(SPdmabuf(); auto [data, fmt, size] = buf->beginDataPtr(0); - memset(data, 0, size); - if (buf->dmabuf().size.x > texture->m_vSize.x) { - size_t STRIDE = 4 * texture->m_vSize.x; - for (int i = 0; i < texture->m_vSize.y; i++) - memcpy(data + i * buf->dmabuf().strides[0], texData.data() + i * STRIDE, STRIDE); - } else - memcpy(data, texData.data(), std::min(size, texData.size())); + auto CAIROSURFACE = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, DMABUF.size.x, DMABUF.size.y); + auto CAIRODATASURFACE = + cairo_image_surface_create_for_data((unsigned char*)texData.data(), CAIRO_FORMAT_ARGB32, texture->m_vSize.x, texture->m_vSize.y, texture->m_vSize.x * 4); + + auto CAIRO = cairo_create(CAIROSURFACE); + + cairo_set_operator(CAIRO, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(CAIRO, 0, 0, 0, 0); + cairo_rectangle(CAIRO, 0, 0, texture->m_vSize.x, texture->m_vSize.y); + cairo_fill(CAIRO); + + const auto PATTERNPRE = cairo_pattern_create_for_surface(CAIRODATASURFACE); + cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); + cairo_matrix_t matrixPre; + cairo_matrix_init_identity(&matrixPre); + + const auto TR = state->monitor->transform; + + if (TR) { + cairo_matrix_rotate(&matrixPre, M_PI_2 * (double)TR); + + // FIXME: this is wrong, and doesnt work for 5, 6 and 7. (flipped + rot) + // cba to do it rn, does anyone fucking use that?? + if (TR >= WL_OUTPUT_TRANSFORM_FLIPPED) { + cairo_matrix_scale(&matrixPre, -1, 1); + cairo_matrix_translate(&matrixPre, -DMABUF.size.x, 0); + } + + if (TR == 3 || TR == 7) + cairo_matrix_translate(&matrixPre, -DMABUF.size.x, 0); + else if (TR == 2 || TR == 6) + cairo_matrix_translate(&matrixPre, -DMABUF.size.x, -DMABUF.size.y); + else if (TR == 1 || TR == 5) + cairo_matrix_translate(&matrixPre, 0, -DMABUF.size.y); + } + + cairo_pattern_set_matrix(PATTERNPRE, &matrixPre); + cairo_set_source(CAIRO, PATTERNPRE); + cairo_paint(CAIRO); + + cairo_surface_flush(CAIROSURFACE); + + cairo_pattern_destroy(PATTERNPRE); + + memcpy(data, cairo_image_surface_get_data(CAIROSURFACE), (size_t)cairo_image_surface_get_height(CAIROSURFACE) * cairo_image_surface_get_stride(CAIROSURFACE)); + + cairo_destroy(CAIRO); + cairo_surface_destroy(CAIROSURFACE); + cairo_surface_destroy(CAIRODATASURFACE); buf->endDataPtr(); From 2bad73354a5dbb9be8ba9a39b6238017a216a25b Mon Sep 17 00:00:00 2001 From: user111111111111111111111111111111111 <192911676+user111111111111111111111111111111111@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:21:35 +0000 Subject: [PATCH 1069/2393] core: cleanup header includes (#9088) Cleanup some unneeded includes to speed up compilation --- src/Compositor.cpp | 19 +++++++++++++++++++ src/Compositor.hpp | 18 ------------------ src/SharedDefs.hpp | 1 + src/config/ConfigManager.cpp | 13 ++++++++++++- src/config/ConfigManager.hpp | 13 +++++++------ src/config/ConfigValue.hpp | 3 +-- src/debug/CrashReporter.cpp | 1 + src/debug/HyprCtl.cpp | 10 ++++++++++ src/debug/HyprCtl.hpp | 2 +- src/debug/HyprDebugOverlay.cpp | 1 + src/debug/HyprDebugOverlay.hpp | 3 +-- src/debug/HyprNotificationOverlay.cpp | 4 ++++ src/debug/HyprNotificationOverlay.hpp | 1 - src/debug/Log.cpp | 1 - src/debug/Log.hpp | 2 -- src/defines.hpp | 2 ++ src/desktop/DesktopTypes.hpp | 2 +- src/desktop/LayerSurface.cpp | 6 ++++++ src/desktop/LayerSurface.hpp | 1 - src/desktop/Popup.cpp | 4 ++++ src/desktop/Subsurface.cpp | 2 ++ src/desktop/WLSurface.cpp | 4 +++- src/desktop/Window.cpp | 7 +++++++ src/desktop/Window.hpp | 2 +- src/desktop/Workspace.cpp | 2 ++ src/devices/Keyboard.cpp | 1 - src/events/Windows.cpp | 5 +++++ src/helpers/Color.hpp | 1 - src/helpers/MiscFunctions.cpp | 2 ++ src/helpers/MiscFunctions.hpp | 2 -- src/helpers/Monitor.cpp | 6 ++++++ src/helpers/Monitor.hpp | 1 + src/helpers/WLClasses.hpp | 6 +++--- src/hyprerror/HyprError.cpp | 2 ++ src/layout/DwindleLayout.cpp | 4 ++++ src/layout/IHyprLayout.cpp | 5 +++++ src/layout/MasterLayout.cpp | 4 ++++ src/layout/MasterLayout.hpp | 2 +- src/macros.hpp | 1 + src/managers/AnimationManager.cpp | 1 + src/managers/CursorManager.cpp | 1 + src/managers/HookSystemManager.hpp | 2 +- src/managers/KeybindManager.cpp | 6 ++++++ src/managers/PointerManager.cpp | 4 ++++ src/managers/ProtocolManager.hpp | 1 - src/managers/SeatManager.cpp | 3 +++ src/managers/SeatManager.hpp | 1 - src/managers/SessionLockManager.cpp | 4 +++- src/managers/input/InputManager.cpp | 5 +++++ src/managers/input/InputMethodPopup.cpp | 2 ++ src/managers/input/InputMethodRelay.cpp | 1 + src/managers/input/Swipe.cpp | 3 +++ src/managers/input/Tablets.cpp | 2 +- src/managers/input/TextInput.hpp | 2 +- src/managers/input/Touch.cpp | 2 ++ src/plugins/HookSystem.cpp | 4 ++-- src/plugins/PluginAPI.cpp | 5 +++++ src/plugins/PluginSystem.cpp | 4 +++- src/protocols/CTMControl.cpp | 1 + src/protocols/DRMLease.cpp | 1 + src/protocols/ForeignToplevel.cpp | 1 + src/protocols/ForeignToplevelWlr.cpp | 1 + src/protocols/GammaControl.cpp | 2 +- src/protocols/GlobalShortcuts.cpp | 1 - src/protocols/LayerShell.cpp | 2 ++ src/protocols/MesaDRM.cpp | 1 + src/protocols/OutputManagement.cpp | 3 +++ src/protocols/OutputPower.cpp | 2 +- src/protocols/PointerConstraints.cpp | 3 +++ src/protocols/PointerGestures.cpp | 1 - src/protocols/RelativePointer.cpp | 3 +-- src/protocols/Screencopy.cpp | 4 ++++ src/protocols/SessionLock.cpp | 3 ++- src/protocols/SinglePixel.cpp | 1 + src/protocols/Tablet.cpp | 1 + src/protocols/TearingControl.cpp | 1 + src/protocols/TextInputV1.cpp | 1 - src/protocols/ToplevelExport.cpp | 3 +++ src/protocols/XDGOutput.cpp | 4 ++-- src/protocols/XDGShell.cpp | 1 + src/protocols/core/DataDevice.cpp | 4 ++++ src/protocols/core/Shm.cpp | 2 +- src/protocols/types/DMABuffer.cpp | 1 + src/protocols/types/WLBuffer.cpp | 1 - src/render/OpenGL.cpp | 3 +++ src/render/OpenGL.hpp | 1 - src/render/Renderbuffer.cpp | 3 ++- src/render/Renderer.cpp | 7 +++++++ src/render/Renderer.hpp | 1 + .../decorations/CHyprBorderDecoration.cpp | 2 ++ .../decorations/CHyprDropShadowDecoration.cpp | 1 + .../decorations/CHyprGroupBarDecoration.cpp | 2 ++ .../decorations/DecorationPositioner.cpp | 4 +++- src/render/pass/Pass.cpp | 1 + src/render/pass/SurfacePassElement.cpp | 1 + src/xwayland/XSurface.cpp | 1 - src/xwayland/XWM.hpp | 1 - 97 files changed, 224 insertions(+), 72 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index fcd15312..496ca4fe 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -42,6 +42,25 @@ #include "helpers/ByteOperations.hpp" #include "render/decorations/CHyprGroupBarDecoration.hpp" +#include "managers/KeybindManager.hpp" +#include "managers/SessionLockManager.hpp" +#include "managers/ThreadManager.hpp" +#include "managers/XWaylandManager.hpp" + +#include "config/ConfigManager.hpp" +#include "render/OpenGL.hpp" +#include "managers/input/InputManager.hpp" +#include "managers/AnimationManager.hpp" +#include "managers/EventManager.hpp" +#include "managers/HookSystemManager.hpp" +#include "managers/ProtocolManager.hpp" +#include "managers/LayoutManager.hpp" +#include "plugins/PluginSystem.hpp" +#include "helpers/Watchdog.hpp" +#include "hyprerror/HyprError.hpp" +#include "debug/HyprNotificationOverlay.hpp" +#include "debug/HyprDebugOverlay.hpp" + #include #include diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 629b71bc..0a701a59 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -5,30 +5,12 @@ #include #include "defines.hpp" -#include "debug/Log.hpp" -#include "events/Events.hpp" -#include "config/ConfigManager.hpp" #include "managers/ThreadManager.hpp" #include "managers/XWaylandManager.hpp" -#include "managers/input/InputManager.hpp" -#include "managers/LayoutManager.hpp" #include "managers/KeybindManager.hpp" -#include "managers/AnimationManager.hpp" -#include "managers/EventManager.hpp" -#include "managers/ProtocolManager.hpp" #include "managers/SessionLockManager.hpp" -#include "managers/HookSystemManager.hpp" -#include "debug/HyprDebugOverlay.hpp" -#include "debug/HyprNotificationOverlay.hpp" -#include "helpers/Monitor.hpp" -#include "desktop/Workspace.hpp" #include "desktop/Window.hpp" #include "protocols/types/ColorManagement.hpp" -#include "render/Renderer.hpp" -#include "render/OpenGL.hpp" -#include "hyprerror/HyprError.hpp" -#include "plugins/PluginSystem.hpp" -#include "helpers/Watchdog.hpp" #include #include diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index a6271556..a46a2429 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include enum eIcons : uint8_t { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 17957899..52f2e316 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -11,8 +11,19 @@ #include "../protocols/LayerShell.hpp" #include "../xwayland/XWayland.hpp" #include "../protocols/OutputManagement.hpp" -#include "managers/AnimationManager.hpp" +#include "../managers/AnimationManager.hpp" +#include "../desktop/LayerSurface.hpp" +#include "defaultConfig.hpp" +#include "../render/Renderer.hpp" +#include "../hyprerror/HyprError.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" +#include "../debug/HyprNotificationOverlay.hpp" +#include "../plugins/PluginSystem.hpp" + +#include "managers/HookSystemManager.hpp" #include #include #include diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index a27ee7ab..1ba1df62 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -4,23 +4,24 @@ #define CONFIG_MANAGER_H #include -#include "../debug/Log.hpp" #include #include "../defines.hpp" #include #include -#include #include #include #include -#include "../helpers/WLClasses.hpp" #include "../helpers/Monitor.hpp" -#include "../helpers/varlist/VarList.hpp" #include "../desktop/Window.hpp" -#include "../desktop/LayerSurface.hpp" +#include "../desktop/LayerRule.hpp" -#include "defaultConfig.hpp" #include "ConfigDataValues.hpp" +#include "SharedDefs.hpp" +#include "helpers/Color.hpp" +#include "desktop/DesktopTypes.hpp" +#include "helpers/memory/Memory.hpp" +#include "desktop/WindowRule.hpp" +#include "managers/XWaylandManager.hpp" #include diff --git a/src/config/ConfigValue.hpp b/src/config/ConfigValue.hpp index 181fdd0f..089ae8bf 100644 --- a/src/config/ConfigValue.hpp +++ b/src/config/ConfigValue.hpp @@ -3,7 +3,6 @@ #include #include #include -#include "../debug/Log.hpp" #include "../macros.hpp" #include "ConfigManager.hpp" @@ -71,4 +70,4 @@ template <> inline Hyprlang::CUSTOMTYPE CConfigValue::operator*() const { RASSERT(false, "Impossible to implement operator* of CConfigValue, use ptr()"); return *ptr(); -} \ No newline at end of file +} diff --git a/src/debug/CrashReporter.cpp b/src/debug/CrashReporter.cpp index 7bff7295..f6e0b55f 100644 --- a/src/debug/CrashReporter.cpp +++ b/src/debug/CrashReporter.cpp @@ -6,6 +6,7 @@ #include #include #include +#include "../helpers/MiscFunctions.hpp" #include "../plugins/PluginSystem.hpp" #include "../signal-safe.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 7edace21..41b0abe1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -39,8 +39,18 @@ using namespace Hyprutils::String; #include "debug/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" +#include "../desktop/LayerSurface.hpp" #include "../version.h" +#include "../Compositor.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/XWaylandManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../plugins/PluginSystem.hpp" +#include "../managers/AnimationManager.hpp" +#include "../debug/HyprNotificationOverlay.hpp" +#include "../render/Renderer.hpp" + static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') str.pop_back(); diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index c1bf51ca..2603612c 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Compositor.hpp" #include #include "../helpers/MiscFunctions.hpp" +#include "../desktop/Window.hpp" #include // exposed for main.cpp diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index d72e2144..6e7a0407 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -4,6 +4,7 @@ #include "../Compositor.hpp" #include "../render/pass/TexPassElement.hpp" #include "../render/Renderer.hpp" +#include "../managers/AnimationManager.hpp" CHyprDebugOverlay::CHyprDebugOverlay() { m_pTexture = makeShared(); diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index 42cdac55..a58ecffc 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../helpers/Monitor.hpp" #include "../render/Texture.hpp" #include #include @@ -49,4 +48,4 @@ class CHyprDebugOverlay { friend class CHyprRenderer; }; -inline std::unique_ptr g_pDebugOverlay; \ No newline at end of file +inline std::unique_ptr g_pDebugOverlay; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 504ad6c9..09125243 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -5,6 +5,10 @@ #include "../config/ConfigValue.hpp" #include "../render/pass/TexPassElement.hpp" +#include "../managers/AnimationManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../render/Renderer.hpp" + static inline auto iconBackendFromLayout(PangoLayout* layout) { // preference: Nerd > FontAwesome > text auto eIconBackendChecks = std::array{ICONS_BACKEND_NF, ICONS_BACKEND_FA}; diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 3ff0b35c..2546d04f 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -2,7 +2,6 @@ #include "../defines.hpp" #include "../helpers/Timer.hpp" -#include "../helpers/Monitor.hpp" #include "../render/Texture.hpp" #include "../SharedDefs.hpp" diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 1563628c..9cf86345 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -1,6 +1,5 @@ #include "Log.hpp" #include "../defines.hpp" -#include "../Compositor.hpp" #include "RollingLogFollow.hpp" #include diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index 9696aa90..3791aeac 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -5,8 +5,6 @@ #include #include #include -#include "../includes.hpp" -#include "../helpers/MiscFunctions.hpp" #define LOGMESSAGESIZE 1024 #define ROLLING_LOG_SIZE 4096 diff --git a/src/defines.hpp b/src/defines.hpp index 41ee4502..5c70f21a 100644 --- a/src/defines.hpp +++ b/src/defines.hpp @@ -1,3 +1,5 @@ +#pragma once + #include "includes.hpp" #include "debug/Log.hpp" #include "helpers/Color.hpp" diff --git a/src/desktop/DesktopTypes.hpp b/src/desktop/DesktopTypes.hpp index 7f812cc1..ae2ac366 100644 --- a/src/desktop/DesktopTypes.hpp +++ b/src/desktop/DesktopTypes.hpp @@ -1,5 +1,5 @@ #pragma once -#include "../macros.hpp" +#include "helpers/memory/Memory.hpp" class CWorkspace; class CWindow; class CLayerSurface; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index fe11f3f3..c572f6b2 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -5,6 +5,12 @@ #include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" #include "../managers/AnimationManager.hpp" +#include "../render/Renderer.hpp" +#include "../config/ConfigManager.hpp" +#include "../helpers/Monitor.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/EventManager.hpp" PHLLS CLayerSurface::create(SP resource) { PHLLS pLS = SP(new CLayerSurface(resource)); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 3a03e57e..591dfd99 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -4,7 +4,6 @@ #include "../defines.hpp" #include "WLSurface.hpp" #include "../helpers/AnimatedVariable.hpp" -#include "LayerRule.hpp" class CLayerShellResource; diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index ce286b28..ce6ab9a0 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -6,6 +6,10 @@ #include "../protocols/core/Compositor.hpp" #include "../managers/SeatManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" +#include "../desktop/LayerSurface.hpp" +#include "../managers/input/InputManager.hpp" +#include "../render/Renderer.hpp" +#include "../render/OpenGL.hpp" #include CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 62854f80..26638f7a 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -4,6 +4,8 @@ #include "../config/ConfigValue.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/core/Subcompositor.hpp" +#include "../render/Renderer.hpp" +#include "../managers/input/InputManager.hpp" CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { initSignals(); diff --git a/src/desktop/WLSurface.cpp b/src/desktop/WLSurface.cpp index 9ed8ec49..e86ac036 100644 --- a/src/desktop/WLSurface.cpp +++ b/src/desktop/WLSurface.cpp @@ -1,7 +1,9 @@ #include "WLSurface.hpp" -#include "../Compositor.hpp" +#include "LayerSurface.hpp" +#include "../desktop/Window.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/LayerShell.hpp" +#include "../render/Renderer.hpp" void CWLSurface::assign(SP pSurface) { m_pResource = pSurface; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5608daef..241a17d7 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -17,6 +17,13 @@ #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" #include "../helpers/Color.hpp" +#include "../events/Events.hpp" +#include "../managers/XWaylandManager.hpp" +#include "../render/Renderer.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/input/InputManager.hpp" #include diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index d503ac3b..ebda235c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -4,7 +4,6 @@ #include #include "../config/ConfigDataValues.hpp" -#include "../defines.hpp" #include "../helpers/AnimatedVariable.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/signal/Signal.hpp" @@ -12,6 +11,7 @@ #include "../macros.hpp" #include "../managers/XWaylandManager.hpp" #include "../render/decorations/IHyprWindowDecoration.hpp" +#include "../render/Transformer.hpp" #include "DesktopTypes.hpp" #include "Popup.hpp" #include "Subsurface.hpp" diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 07c1a435..99ba441d 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -3,6 +3,8 @@ #include "../config/ConfigValue.hpp" #include "config/ConfigManager.hpp" #include "managers/AnimationManager.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/HookSystemManager.hpp" #include #include diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp index 0a8f6b57..191cc6b2 100644 --- a/src/devices/Keyboard.cpp +++ b/src/devices/Keyboard.cpp @@ -1,6 +1,5 @@ #include "Keyboard.hpp" #include "../defines.hpp" -#include "../Compositor.hpp" #include diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 14e89b4b..cadd4cbc 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -14,6 +14,11 @@ #include "../xwayland/XSurface.hpp" #include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" +#include "../desktop/LayerSurface.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/AnimationManager.hpp" #include using namespace Hyprutils::String; diff --git a/src/helpers/Color.hpp b/src/helpers/Color.hpp index 0ea816f3..8050bebd 100644 --- a/src/helpers/Color.hpp +++ b/src/helpers/Color.hpp @@ -2,7 +2,6 @@ #include #include -#include "../debug/Log.hpp" #include "../macros.hpp" class CHyprColor { diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 0fa73e45..fafe1811 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -3,6 +3,8 @@ #include #include "../Compositor.hpp" #include "../managers/TokenManager.hpp" +#include "Monitor.hpp" +#include "../config/ConfigManager.hpp" #include #include #include diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 64802279..d0824284 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -1,9 +1,7 @@ #pragma once #include -#include #include -#include "math/Math.hpp" #include #include #include diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index cf62bc54..718baf23 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -17,9 +17,15 @@ #include "../managers/PointerManager.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../protocols/core/Compositor.hpp" +#include "../render/Renderer.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/input/InputManager.hpp" #include "sync/SyncTimeline.hpp" +#include "../desktop/LayerSurface.hpp" #include #include "debug/Log.hpp" +#include "debug/HyprNotificationOverlay.hpp" #include #include #include diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 8c7566e2..3335a896 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -4,6 +4,7 @@ #include #include #include "../SharedDefs.hpp" +#include "MiscFunctions.hpp" #include "WLClasses.hpp" #include #include diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index b6e3ac12..c2e828e7 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -1,13 +1,13 @@ #pragma once -#include "../events/Events.hpp" #include "../defines.hpp" -#include "../desktop/Window.hpp" #include "../desktop/Subsurface.hpp" #include "../desktop/Popup.hpp" #include "../desktop/WLSurface.hpp" +#include "macros.hpp" +#include "desktop/DesktopTypes.hpp" +#include "helpers/memory/Memory.hpp" #include "signal/Signal.hpp" -#include "math/Math.hpp" class CMonitor; class IPointer; diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 5e0dcf5e..d14173bf 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -4,6 +4,8 @@ #include "../config/ConfigValue.hpp" #include "../render/pass/TexPassElement.hpp" #include "../managers/AnimationManager.hpp" +#include "../render/Renderer.hpp" +#include "../managers/HookSystemManager.hpp" #include using namespace Hyprutils::Animation; diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 2ee41eba..c6cf2b4c 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -2,6 +2,10 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" +#include "../render/Renderer.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" void SDwindleNodeData::recalcSizePosRecursive(bool force, bool horizontalOverride, bool verticalOverride) { if (children[0]) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index eeebd815..156141f6 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -7,6 +7,11 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" +#include "../render/Renderer.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/HookSystemManager.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { CBox desiredGeometry = {}; diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index e6e22326..3b8ff734 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -4,6 +4,10 @@ #include "config/ConfigDataValues.hpp" #include #include "../config/ConfigValue.hpp" +#include "../render/Renderer.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" SMasterNodeData* CHyprMasterLayout::getNodeFromWindow(PHLWINDOW pWindow) { for (auto& nd : m_lMasterNodesData) { diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 03ca3c3b..381ccc9d 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -2,7 +2,7 @@ #include "IHyprLayout.hpp" #include "../desktop/DesktopTypes.hpp" -#include "../config/ConfigManager.hpp" +#include "../helpers/varlist/VarList.hpp" #include #include #include diff --git a/src/macros.hpp b/src/macros.hpp index de2fd009..08c17952 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -6,6 +6,7 @@ #include #include "helpers/memory/Memory.hpp" +#include "debug/Log.hpp" #ifndef NDEBUG #ifdef HYPRLAND_DEBUG diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 28adc330..9cf35116 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -10,6 +10,7 @@ #include "../desktop/LayerSurface.hpp" #include "eventLoop/EventLoopManager.hpp" #include "../helpers/varlist/VarList.hpp" +#include "../render/Renderer.hpp" #include #include diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 2dd97feb..d6584f35 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -3,6 +3,7 @@ #include "../config/ConfigValue.hpp" #include "PointerManager.hpp" #include "../xwayland/XWayland.hpp" +#include "../managers/HookSystemManager.hpp" static int cursorAnimTimer(SP self, void* data) { const auto cursorMgr = reinterpret_cast(data); diff --git a/src/managers/HookSystemManager.hpp b/src/managers/HookSystemManager.hpp index 75377aaa..5a9d0c00 100644 --- a/src/managers/HookSystemManager.hpp +++ b/src/managers/HookSystemManager.hpp @@ -57,4 +57,4 @@ class CHookSystemManager { std::unordered_map> m_mRegisteredHooks; }; -inline std::unique_ptr g_pHookSystem; \ No newline at end of file +inline std::unique_ptr g_pHookSystem; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 9a719130..a1979206 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -13,6 +13,12 @@ #include "debug/Log.hpp" #include "helpers/varlist/VarList.hpp" #include "../helpers/signal/Signal.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/EventManager.hpp" +#include "../render/Renderer.hpp" +#include "../hyprerror/HyprError.hpp" #include #include diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 522187b4..df145f6d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -9,6 +9,10 @@ #include "../protocols/core/Seat.hpp" #include "eventLoop/EventLoopManager.hpp" #include "../render/pass/TexPassElement.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../render/Renderer.hpp" +#include "../render/OpenGL.hpp" #include "SeatManager.hpp" #include #include diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 69dadd0f..6ceff9ad 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../helpers/Monitor.hpp" #include "../helpers/memory/Memory.hpp" #include "../helpers/signal/Signal.hpp" #include diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 3b9a4925..8fee6b16 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -6,6 +6,9 @@ #include "../protocols/core/Compositor.hpp" #include "../Compositor.hpp" #include "../devices/IKeyboard.hpp" +#include "../desktop/LayerSurface.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/HookSystemManager.hpp" #include "wlr-layer-shell-unstable-v1.hpp" #include #include diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index ccfe5e76..32472aa3 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -2,7 +2,6 @@ #include #include -#include "../macros.hpp" #include "../helpers/signal/Signal.hpp" #include "../helpers/math/Math.hpp" #include "../protocols/types/DataDevice.hpp" diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index b7110990..3d77f05a 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -4,6 +4,8 @@ #include "../protocols/FractionalScale.hpp" #include "../protocols/SessionLock.hpp" #include "../managers/SeatManager.hpp" +#include "../render/Renderer.hpp" +#include "../managers/input/InputManager.hpp" #include #include @@ -185,4 +187,4 @@ bool CSessionLockManager::shallConsiderLockMissing() { static auto LOCKDEAD_SCREEN_DELAY = CConfigValue("misc:lockdead_screen_delay"); return m_pSessionLock->mLockTimer.getMillis() > *LOCKDEAD_SCREEN_DELAY; -} \ No newline at end of file +} diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 8a50a7bf..3d8c6de8 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -5,6 +5,7 @@ #include #include "../../config/ConfigValue.hpp" #include "../../desktop/Window.hpp" +#include "../../desktop/LayerSurface.hpp" #include "../../protocols/CursorShape.hpp" #include "../../protocols/IdleInhibit.hpp" #include "../../protocols/RelativePointer.hpp" @@ -29,6 +30,10 @@ #include "../../managers/PointerManager.hpp" #include "../../managers/SeatManager.hpp" #include "../../managers/KeybindManager.hpp" +#include "../../render/Renderer.hpp" +#include "../../managers/HookSystemManager.hpp" +#include "../../managers/EventManager.hpp" +#include "../../managers/LayoutManager.hpp" #include diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index ffb4edcc..8c55416b 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -4,6 +4,8 @@ #include "../../protocols/FractionalScale.hpp" #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/core/Compositor.hpp" +#include "../../helpers/Monitor.hpp" +#include "../../render/Renderer.hpp" CInputPopup::CInputPopup(SP popup_) : popup(popup_) { listeners.commit = popup_->events.commit.registerListener([this](std::any d) { onCommit(); }); diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 88439924..58cff043 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -5,6 +5,7 @@ #include "../../protocols/TextInputV1.hpp" #include "../../protocols/InputMethodV2.hpp" #include "../../protocols/core/Compositor.hpp" +#include "../../managers/HookSystemManager.hpp" CInputMethodRelay::CInputMethodRelay() { static auto P = diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp index 3e03c4c7..b5282e3c 100644 --- a/src/managers/input/Swipe.cpp +++ b/src/managers/input/Swipe.cpp @@ -1,6 +1,9 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" +#include "../../desktop/LayerSurface.hpp" #include "../../config/ConfigValue.hpp" +#include "../../managers/HookSystemManager.hpp" +#include "../../render/Renderer.hpp" void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { static auto PSWIPE = CConfigValue("gestures:workspace_swipe"); diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index d7ebfe87..f61d8184 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -1,5 +1,5 @@ #include "InputManager.hpp" -#include "../../Compositor.hpp" +#include "../../desktop/Window.hpp" #include "../../protocols/Tablet.hpp" #include "../../devices/Tablet.hpp" #include "../../managers/PointerManager.hpp" diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 3cf07006..c0b590ac 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../../macros.hpp" #include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" +#include "../../helpers/memory/Memory.hpp" #include struct wl_client; diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 7212ba61..990fbc41 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -1,9 +1,11 @@ #include "InputManager.hpp" #include "../../Compositor.hpp" +#include "../../desktop/LayerSurface.hpp" #include "../../config/ConfigValue.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" #include "managers/AnimationManager.hpp" +#include "../HookSystemManager.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { m_bLastInputTouch = true; diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 3baca5b1..c19f6f46 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -2,7 +2,7 @@ #include "../debug/Log.hpp" #include "../helpers/varlist/VarList.hpp" #include "../managers/TokenManager.hpp" -#include "../Compositor.hpp" +#include "../helpers/MiscFunctions.hpp" #define register #include @@ -383,4 +383,4 @@ uint64_t CHookSystem::getAddressForTrampo() { Debug::log(LOG, "getAddressForTrampo: Returning addr 0x{:x} for page at 0x{:x}", ADDRFORCONSUMER, page->addr); return ADDRFORCONSUMER; -} \ No newline at end of file +} diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index 5e1d9e58..b6bbc460 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -1,6 +1,11 @@ #include "PluginAPI.hpp" #include "../Compositor.hpp" #include "../debug/HyprCtl.hpp" +#include "../plugins/PluginSystem.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../config/ConfigManager.hpp" +#include "../debug/HyprNotificationOverlay.hpp" #include #include diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index 52a3bace..ce7dd7c7 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -2,7 +2,9 @@ #include #include -#include "../Compositor.hpp" +#include "../config/ConfigManager.hpp" +#include "../managers/LayoutManager.hpp" +#include "../managers/HookSystemManager.hpp" CPluginSystem::CPluginSystem() { g_pFunctionHookSystem = std::make_unique(); diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index fd7cdcd6..91e05ac4 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -4,6 +4,7 @@ #include "core/Output.hpp" #include "../config/ConfigValue.hpp" #include "managers/AnimationManager.hpp" +#include "../helpers/Monitor.hpp" CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { if (!good()) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index be5a6985..4ab46a46 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -1,5 +1,6 @@ #include "DRMLease.hpp" #include "../Compositor.hpp" +#include "../helpers/Monitor.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 38bb5e69..f6513a1d 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -1,5 +1,6 @@ #include "ForeignToplevel.hpp" #include "../Compositor.hpp" +#include "../managers/HookSystemManager.hpp" CForeignToplevelHandle::CForeignToplevelHandle(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 6bbd377c..45ef3f93 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -3,6 +3,7 @@ #include "../Compositor.hpp" #include "protocols/core/Output.hpp" #include "render/Renderer.hpp" +#include "../managers/HookSystemManager.hpp" CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { if (!resource_->resource()) diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 14c6596f..b0da29a2 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -2,8 +2,8 @@ #include #include #include "../helpers/Monitor.hpp" -#include "../Compositor.hpp" #include "../protocols/core/Output.hpp" +#include "../render/Renderer.hpp" CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if (!resource_->resource()) diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index b02126ef..ca67f063 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,5 +1,4 @@ #include "GlobalShortcuts.hpp" -#include "../Compositor.hpp" CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { if (!good()) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 5ceae5f2..0777149f 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -1,8 +1,10 @@ #include "LayerShell.hpp" #include "../Compositor.hpp" +#include "../desktop/LayerSurface.hpp" #include "XDGShell.hpp" #include "core/Compositor.hpp" #include "core/Output.hpp" +#include "../helpers/Monitor.hpp" void CLayerShellResource::SState::reset() { anchor = 0; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index b4efd2c8..41536988 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include "types/WLBuffer.hpp" +#include "../render/OpenGL.hpp" CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 4f7d48c4..4a976021 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -1,6 +1,9 @@ #include "OutputManagement.hpp" #include #include "../Compositor.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../config/ConfigManager.hpp" using namespace Aquamarine; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index 257155e4..dd3e8e1a 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -1,6 +1,6 @@ #include "OutputPower.hpp" -#include "../Compositor.hpp" #include "core/Output.hpp" +#include "../helpers/Monitor.hpp" COutputPower::COutputPower(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { if (!resource->resource()) diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 0a787414..e12fa75f 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -4,6 +4,9 @@ #include "../config/ConfigValue.hpp" #include "../managers/SeatManager.hpp" #include "core/Compositor.hpp" +#include "../managers/input/InputManager.hpp" +#include "../render/Renderer.hpp" +#include "../helpers/Monitor.hpp" CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : resourceL(resource_), locked(true), lifetime(lifetime_) { diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 4eb74102..5dfb9d51 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -1,5 +1,4 @@ #include "PointerGestures.hpp" -#include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index 16248c02..b7cf75c6 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -1,5 +1,4 @@ #include "RelativePointer.hpp" -#include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include @@ -71,4 +70,4 @@ void CRelativePointerProtocol::sendRelativeMotion(uint64_t time, const Vector2D& rp->sendRelativeMotion(time, delta, deltaUnaccel); } -} \ No newline at end of file +} diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 898a1d6b..da0a9412 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -2,6 +2,10 @@ #include "../Compositor.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/PointerManager.hpp" +#include "../managers/EventManager.hpp" +#include "../render/Renderer.hpp" +#include "../render/OpenGL.hpp" +#include "../helpers/Monitor.hpp" #include "core/Output.hpp" #include "types/WLBuffer.hpp" #include "types/Buffer.hpp" diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 642a5b89..c3f19e53 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -4,6 +4,7 @@ #include "FractionalScale.hpp" #include "core/Compositor.hpp" #include "core/Output.hpp" +#include "../helpers/Monitor.hpp" CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, PHLMONITOR pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { @@ -208,4 +209,4 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id bool CSessionLockProtocol::isLocked() { return locked; -} \ No newline at end of file +} diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 41771ce2..91154671 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -1,4 +1,5 @@ #include "SinglePixel.hpp" +#include "../desktop/LayerSurface.hpp" #include #include "render/Renderer.hpp" diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index b4ab6ea0..2fdd8731 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -2,6 +2,7 @@ #include "../devices/Tablet.hpp" #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/input/InputManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index 66a4efd2..eb1a53cb 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -3,6 +3,7 @@ #include "../desktop/Window.hpp" #include "../Compositor.hpp" #include "core/Compositor.hpp" +#include "../managers/HookSystemManager.hpp" CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index 6395e158..b8eb5835 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -1,6 +1,5 @@ #include "TextInputV1.hpp" -#include "../Compositor.hpp" #include "core/Compositor.hpp" CTextInputV1::~CTextInputV1() { diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 73e5cad9..8e34cf4b 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -6,6 +6,9 @@ #include "types/WLBuffer.hpp" #include "types/Buffer.hpp" #include "../helpers/Format.hpp" +#include "../managers/EventManager.hpp" +#include "../managers/input/InputManager.hpp" +#include "../render/Renderer.hpp" #include diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index deb87829..fadc48a1 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -1,7 +1,7 @@ #include "XDGOutput.hpp" -#include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../xwayland/XWayland.hpp" +#include "../managers/HookSystemManager.hpp" #include "core/Output.hpp" #define OUTPUT_MANAGER_VERSION 3 @@ -119,4 +119,4 @@ void CXDGOutput::sendDetails() { if (resource->version() < OUTPUT_DONE_DEPRECATED_SINCE_VERSION) resource->sendDone(); -} \ No newline at end of file +} diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 6b7cb3c1..aabb225a 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../helpers/Monitor.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" #include "protocols/core/Output.hpp" diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 722eb9fd..fd3cd1fa 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -9,6 +9,10 @@ #include "Compositor.hpp" #include "../../xwayland/XWayland.hpp" #include "../../xwayland/Server.hpp" +#include "../../managers/input/InputManager.hpp" +#include "../../managers/HookSystemManager.hpp" +#include "../../helpers/Monitor.hpp" +#include "../../render/Renderer.hpp" CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if (!good()) diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index fddd4e9a..6365c5d6 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -5,8 +5,8 @@ #include #include "../../render/Texture.hpp" #include "../types/WLBuffer.hpp" -#include "../../Compositor.hpp" #include "../../helpers/Format.hpp" +#include "../../render/Renderer.hpp" CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if (!pool_->pool->data) diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index ae684424..9f31f6a2 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -1,5 +1,6 @@ #include "DMABuffer.hpp" #include "WLBuffer.hpp" +#include "../../desktop/LayerSurface.hpp" #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index eb7d1fde..a9e6400a 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -3,7 +3,6 @@ #include "../core/Compositor.hpp" #include "../DRMSyncobj.hpp" #include "../../helpers/sync/SyncTimeline.hpp" -#include "../../Compositor.hpp" #include CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index b68448ae..c5bb3620 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2,12 +2,15 @@ #include #include "Shaders.hpp" #include "OpenGL.hpp" +#include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/MiscFunctions.hpp" #include "../config/ConfigValue.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/core/Compositor.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/input/InputManager.hpp" #include "pass/TexPassElement.hpp" #include "pass/RectPassElement.hpp" #include "pass/PreBlurElement.hpp" diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 2b600a03..8098485e 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -17,7 +17,6 @@ #include "Shader.hpp" #include "Texture.hpp" #include "Framebuffer.hpp" -#include "Transformer.hpp" #include "Renderbuffer.hpp" #include "pass/Pass.hpp" diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index c4425ce9..887f31a9 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -1,4 +1,5 @@ #include "Renderbuffer.hpp" +#include "Renderer.hpp" #include "OpenGL.hpp" #include "../Compositor.hpp" #include "../protocols/types/Buffer.hpp" @@ -76,4 +77,4 @@ void CRenderbuffer::unbind() { CFramebuffer* CRenderbuffer::getFB() { return &m_sFramebuffer; -} \ No newline at end of file +} diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6c77b27a..fddb9a9a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -8,6 +8,10 @@ #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" +#include "../managers/input/InputManager.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../managers/AnimationManager.hpp" +#include "../managers/LayoutManager.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "../protocols/SessionLock.hpp" @@ -19,6 +23,9 @@ #include "../protocols/DRMSyncobj.hpp" #include "../protocols/LinuxDMABUF.hpp" #include "../helpers/sync/SyncTimeline.hpp" +#include "../hyprerror/HyprError.hpp" +#include "../debug/HyprDebugOverlay.hpp" +#include "../debug/HyprNotificationOverlay.hpp" #include "pass/TexPassElement.hpp" #include "pass/ClearPassElement.hpp" #include "pass/RectPassElement.hpp" diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 8b4988c3..6ba7a654 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -3,6 +3,7 @@ #include "../defines.hpp" #include #include "../helpers/Monitor.hpp" +#include "../desktop/LayerSurface.hpp" #include "OpenGL.hpp" #include "Renderbuffer.hpp" #include "../helpers/Timer.hpp" diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 7261431f..6fb0ff88 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -3,6 +3,8 @@ #include "../../config/ConfigValue.hpp" #include "../../managers/eventLoop/EventLoopManager.hpp" #include "../pass/BorderPassElement.hpp" +#include "../Renderer.hpp" +#include "../../managers/HookSystemManager.hpp" CHyprBorderDecoration::CHyprBorderDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_pWindow(pWindow) { ; diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index ddd5198d..022e123e 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -3,6 +3,7 @@ #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" #include "../pass/ShadowPassElement.hpp" +#include "../Renderer.hpp" CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_pWindow(pWindow) { ; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 970273d7..4a411b6c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -6,6 +6,8 @@ #include #include "../pass/TexPassElement.hpp" #include "../pass/RectPassElement.hpp" +#include "../Renderer.hpp" +#include "../../managers/input/InputManager.hpp" // shared things to conserve VRAM static SP m_tGradientActive = makeShared(); diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index abfa19ec..c2d34fb6 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -1,5 +1,7 @@ #include "DecorationPositioner.hpp" -#include "../../Compositor.hpp" +#include "../../desktop/Window.hpp" +#include "../../managers/HookSystemManager.hpp" +#include "../../managers/LayoutManager.hpp" CDecorationPositioner::CDecorationPositioner() { static auto P = g_pHookSystem->hookDynamic("closeWindow", [this](void* call, SCallbackInfo& info, std::any data) { diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index b72248c2..5b133b7d 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -6,6 +6,7 @@ #include "../../desktop/WLSurface.hpp" #include "../../managers/SeatManager.hpp" #include "../../managers/eventLoop/EventLoopManager.hpp" +#include "../../render/Renderer.hpp" #include "../../Compositor.hpp" bool CRenderPass::empty() const { diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index 71aa26be..d720081f 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -1,6 +1,7 @@ #include "SurfacePassElement.hpp" #include "../OpenGL.hpp" #include "../../desktop/WLSurface.hpp" +#include "../../desktop/Window.hpp" #include "../../protocols/core/Compositor.hpp" #include "../../protocols/DRMSyncobj.hpp" #include "../../managers/input/InputManager.hpp" diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 6048269a..b5ee75f6 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -6,7 +6,6 @@ #ifndef NO_XWAYLAND #include -#include "../Compositor.hpp" CXWaylandSurface::CXWaylandSurface(uint32_t xID_, CBox geometry_, bool OR) : xID(xID_), geometry(geometry_), overrideRedirect(OR) { xcb_res_query_client_ids_cookie_t client_id_cookie = {0}; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 38fdab94..bc5aa47b 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,6 +1,5 @@ #pragma once -#include "../macros.hpp" #include "XDataSource.hpp" #include "Dnd.hpp" #include "../helpers/memory/Memory.hpp" From b7a3c4526990d6601ff2cac748ff860cda6bc16d Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 17 Jan 2025 18:21:34 +0100 Subject: [PATCH 1070/2393] core: add LIKELY and UNLIKELY macros helps the compiler optimize --- src/devices/VirtualPointer.cpp | 2 +- src/macros.hpp | 3 ++ src/protocols/AlphaModifier.cpp | 4 +- src/protocols/CTMControl.cpp | 8 +-- src/protocols/ColorManagement.cpp | 32 ++++++------ src/protocols/CursorShape.cpp | 2 +- src/protocols/DRMLease.cpp | 16 +++--- src/protocols/DRMSyncobj.cpp | 18 +++---- src/protocols/DataDeviceWlr.cpp | 16 +++--- src/protocols/FocusGrab.cpp | 14 +++--- src/protocols/ForeignToplevel.cpp | 20 ++++---- src/protocols/ForeignToplevelWlr.cpp | 70 +++++++++++++-------------- src/protocols/FractionalScale.cpp | 2 +- src/protocols/FrogColorManagement.cpp | 10 ++-- src/protocols/GammaControl.cpp | 20 ++++---- src/protocols/GlobalShortcuts.cpp | 8 +-- src/protocols/HyprlandSurface.cpp | 8 +-- src/protocols/IdleNotify.cpp | 4 +- src/protocols/InputMethodV2.cpp | 16 +++--- src/protocols/LayerShell.cpp | 8 +-- src/protocols/LinuxDMABUF.cpp | 26 +++++----- src/protocols/MesaDRM.cpp | 6 +-- src/protocols/OutputManagement.cpp | 22 ++++----- src/protocols/OutputPower.cpp | 6 +-- src/protocols/PointerConstraints.cpp | 12 ++--- src/protocols/PointerGestures.cpp | 12 ++--- src/protocols/PresentationTime.cpp | 8 +-- src/protocols/PrimarySelection.cpp | 16 +++--- src/protocols/RelativePointer.cpp | 4 +- src/protocols/Screencopy.cpp | 17 +++---- src/protocols/SecurityContext.cpp | 26 +++++----- src/protocols/ServerDecorationKDE.cpp | 4 +- src/protocols/SessionLock.cpp | 8 +-- src/protocols/ShortcutsInhibit.cpp | 6 +-- src/protocols/SinglePixel.cpp | 8 +-- src/protocols/Tablet.cpp | 28 +++++------ src/protocols/TearingControl.cpp | 4 +- src/protocols/TextInputV1.cpp | 6 +-- src/protocols/TextInputV3.cpp | 4 +- src/protocols/ToplevelExport.cpp | 29 ++++++----- src/protocols/Viewporter.cpp | 16 +++--- src/protocols/VirtualKeyboard.cpp | 14 +++--- src/protocols/VirtualPointer.cpp | 10 ++-- src/protocols/WaylandProtocol.cpp | 2 +- src/protocols/XDGActivation.cpp | 12 ++--- src/protocols/XDGDecoration.cpp | 6 +-- src/protocols/XDGDialog.cpp | 14 +++--- src/protocols/XDGOutput.cpp | 10 ++-- src/protocols/XDGShell.cpp | 34 ++++++------- src/protocols/XWaylandShell.cpp | 8 +-- src/protocols/core/Compositor.cpp | 34 ++++++------- src/protocols/core/DataDevice.cpp | 18 +++---- src/protocols/core/Output.cpp | 10 ++-- src/protocols/core/Seat.cpp | 16 +++--- src/protocols/core/Shm.cpp | 32 ++++++------ src/protocols/core/Subcompositor.cpp | 14 +++--- src/protocols/types/DMABuffer.cpp | 6 +-- src/protocols/types/WLBuffer.cpp | 2 +- 58 files changed, 395 insertions(+), 396 deletions(-) diff --git a/src/devices/VirtualPointer.cpp b/src/devices/VirtualPointer.cpp index 514c8c32..7cfb0631 100644 --- a/src/devices/VirtualPointer.cpp +++ b/src/devices/VirtualPointer.cpp @@ -11,7 +11,7 @@ SP CVirtualPointer::create(SP resour } CVirtualPointer::CVirtualPointer(SP resource) : pointer(resource) { - if (!resource->good()) + if UNLIKELY (!resource->good()) return; listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) { diff --git a/src/macros.hpp b/src/macros.hpp index 08c17952..0a3be8bc 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -114,3 +114,6 @@ namespace Aquamarine { \ class name; \ } + +#define UNLIKELY(expr) (expr) [[unlikely]] +#define LIKELY(expr) (expr) [[likely]] diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index d695b58f..dc32bb8c 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -15,7 +15,7 @@ bool CAlphaModifier::good() { void CAlphaModifier::setResource(SP resource) { m_pResource = std::move(resource); - if (!m_pResource->resource()) + if UNLIKELY (!m_pResource->resource()) return; m_pResource->setDestroy([this](CWpAlphaModifierSurfaceV1* resource) { destroy(); }); @@ -98,7 +98,7 @@ void CAlphaModifierProtocol::getSurface(CWpAlphaModifierV1* manager, uint32_t id .first->second.get(); } - if (!alphaModifier->good()) { + if UNLIKELY (!alphaModifier->good()) { manager->noMemory(); m_mAlphaModifiers.erase(surface); } diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 91e05ac4..91f4501f 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -7,7 +7,7 @@ #include "../helpers/Monitor.hpp" CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); }); @@ -17,12 +17,12 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPmonitor.lock(); - if (!PMONITOR) + if UNLIKELY (!PMONITOR) return; // ?!?! const std::array MAT = {wl_fixed_to_double(mat0), wl_fixed_to_double(mat1), wl_fixed_to_double(mat2), wl_fixed_to_double(mat3), wl_fixed_to_double(mat4), @@ -72,7 +72,7 @@ void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uin const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index a76e13c0..c2814361 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -2,7 +2,7 @@ #include "Compositor.hpp" CColorManager::CColorManager(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->sendSupportedFeature(XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC); @@ -38,7 +38,7 @@ CColorManager::CColorManager(SP resource_) : resource(resourc const auto RESOURCE = PROTO::colorManagement->m_vOutputs.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vOutputs.pop_back(); return; @@ -63,7 +63,7 @@ CColorManager::CColorManager(SP resource_) : resource(resourc const auto RESOURCE = PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vSurfaces.pop_back(); return; @@ -86,7 +86,7 @@ CColorManager::CColorManager(SP resource_) : resource(resourc const auto RESOURCE = PROTO::colorManagement->m_vFeedbackSurfaces.emplace_back( makeShared(makeShared(r->client(), r->version(), id), SURF)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vFeedbackSurfaces.pop_back(); return; @@ -104,7 +104,7 @@ CColorManager::CColorManager(SP resource_) : resource(resourc const auto RESOURCE = PROTO::colorManagement->m_vParametricCreators.emplace_back( makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vParametricCreators.pop_back(); return; @@ -121,7 +121,7 @@ bool CColorManager::good() { } CColorManagementOutput::CColorManagementOutput(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -137,7 +137,7 @@ CColorManagementOutput::CColorManagementOutput(SP re const auto RESOURCE = PROTO::colorManagement->m_vImageDescriptions.emplace_back( makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vImageDescriptions.pop_back(); return; @@ -160,7 +160,7 @@ CColorManagementSurface::CColorManagementSurface(SP surface_ } CColorManagementSurface::CColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -242,7 +242,7 @@ bool CColorManagementSurface::needsHdrMetadataUpdate() { CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -269,7 +269,7 @@ CColorManagementFeedbackSurface::CColorManagementFeedbackSurface(SPm_vImageDescriptions.emplace_back( makeShared(makeShared(r->client(), r->version(), id), true)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vImageDescriptions.pop_back(); return; @@ -293,7 +293,7 @@ wl_client* CColorManagementFeedbackSurface::client() { } CColorManagementParametricCreator::CColorManagementParametricCreator(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; // pClient = resource->client(); @@ -318,7 +318,7 @@ CColorManagementParametricCreator::CColorManagementParametricCreator(SPm_vImageDescriptions.emplace_back( makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::colorManagement->m_vImageDescriptions.pop_back(); return; @@ -465,7 +465,7 @@ wl_client* CColorManagementParametricCreator::client() { CColorManagementImageDescription::CColorManagementImageDescription(SP resource_, bool allowGetInformation) : m_resource(resource_), m_allowGetInformation(allowGetInformation) { - if (!good()) + if UNLIKELY (!good()) return; pClient = m_resource->client(); @@ -482,7 +482,7 @@ CColorManagementImageDescription::CColorManagementImageDescription(SP(makeShared(r->client(), r->version(), id), settings); - if (!RESOURCE->good()) + if UNLIKELY (!RESOURCE->good()) r->noMemory(); // CColorManagementImageDescriptionInfo should send everything in the constructor and be ready for destroying at this point @@ -504,7 +504,7 @@ SP CColorManagementImageDescription::resource() { CColorManagementImageDescriptionInfo::CColorManagementImageDescriptionInfo(SP resource_, const SImageDescription& settings_) : m_resource(resource_), settings(settings_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = m_resource->client(); @@ -549,7 +549,7 @@ CColorManagementProtocol::CColorManagementProtocol(const wl_interface* iface, co void CColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 233a5df9..429d604f 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -41,7 +41,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr } void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { - if ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) { + if UNLIKELY ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) { pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); return; } diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 4ab46a46..fce1e345 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -6,7 +6,7 @@ #include CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); @@ -79,7 +79,7 @@ CDRMLeaseResource::~CDRMLeaseResource() { } CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); }); @@ -109,7 +109,7 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP reso } auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), self.lock()); - if (!RESOURCE) { + if UNLIKELY (!RESOURCE) { resource->noMemory(); return; } @@ -131,7 +131,7 @@ SP CDRMLeaseConnectorResource::fromResource(wl_resou } CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, PHLMONITOR monitor_) : monitor(monitor_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); @@ -160,7 +160,7 @@ void CDRMLeaseConnectorResource::sendData() { } CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); @@ -168,7 +168,7 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) { auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id)); - if (!RESOURCE) { + if UNLIKELY (!RESOURCE) { resource->noMemory(); return; } @@ -209,7 +209,7 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { return; auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), 0), monitor); - if (!RESOURCE) { + if UNLIKELY (!RESOURCE) { resource->noMemory(); return; } @@ -262,7 +262,7 @@ CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 1da4baaf..ce598385 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -8,7 +8,7 @@ #include CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -104,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { } CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -135,31 +135,31 @@ bool CDRMSyncobjTimelineResource::good() { } CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); resource->setDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); resource->setGetSurface([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, wl_resource* surf) { - if (!surf) { + if UNLIKELY (!surf) { resource->error(-1, "Invalid surface"); return; } auto SURF = CWLSurfaceResource::fromResource(surf); - if (!SURF) { + if UNLIKELY (!SURF) { resource->error(-1, "Invalid surface (2)"); return; } - if (SURF->syncobj) { + if UNLIKELY (SURF->syncobj) { resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_SURFACE_EXISTS, "Surface already has a syncobj attached"); return; } auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), SURF); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; } @@ -172,7 +172,7 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SPsetImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; } @@ -195,7 +195,7 @@ CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& v void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index d8103d11..71ee1c4a 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -4,7 +4,7 @@ #include "core/Seat.hpp" CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); @@ -34,7 +34,7 @@ bool CWLRDataOffer::good() { } void CWLRDataOffer::sendData() { - if (!source) + if UNLIKELY (!source) return; for (auto const& m : source->mimes()) { @@ -43,7 +43,7 @@ void CWLRDataOffer::sendData() { } CWLRDataSource::CWLRDataSource(SP resource_, SP device_) : device(device_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -104,7 +104,7 @@ void CWLRDataSource::error(uint32_t code, const std::string& msg) { } CWLRDataDevice::CWLRDataDevice(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -173,7 +173,7 @@ void CWLRDataDevice::sendPrimarySelection(SP selection) { } CWLRDataControlManagerResource::CWLRDataControlManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwlrDataControlManagerV1* r) { PROTO::dataWlr->destroyResource(this); }); @@ -182,7 +182,7 @@ CWLRDataControlManagerResource::CWLRDataControlManagerResource(SPsetGetDataDevice([this](CZwlrDataControlManagerV1* r, uint32_t id, wl_resource* seat) { const auto RESOURCE = PROTO::dataWlr->m_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::dataWlr->m_vDevices.pop_back(); return; @@ -208,7 +208,7 @@ CWLRDataControlManagerResource::CWLRDataControlManagerResource(SPm_vSources.emplace_back(makeShared(makeShared(r->client(), r->version(), id), device.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::dataWlr->m_vSources.pop_back(); return; @@ -236,7 +236,7 @@ CDataDeviceWLRProtocol::CDataDeviceWLRProtocol(const wl_interface* iface, const void CDataDeviceWLRProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index aff232e4..ee30343f 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -17,7 +17,7 @@ CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { } CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; grab = makeShared(); @@ -63,9 +63,8 @@ void CFocusGrab::finish(bool sendCleared) { if (m_bGrabActive) { m_bGrabActive = false; - if (g_pSeatManager->seatGrab == grab) { + if (g_pSeatManager->seatGrab == grab) g_pSeatManager->setGrab(nullptr); - } grab->clear(); m_mSurfaces.clear(); @@ -77,17 +76,16 @@ void CFocusGrab::finish(bool sendCleared) { void CFocusGrab::addSurface(SP surface) { auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; }); - if (iter == m_mSurfaces.end()) { + if (iter == m_mSurfaces.end()) m_mSurfaces.emplace(surface, std::make_unique(this, surface)); - } } void CFocusGrab::removeSurface(SP surface) { auto iter = m_mSurfaces.find(surface); if (iter != m_mSurfaces.end()) { - if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) { + if (iter->second->state == CFocusGrabSurfaceState::PendingAddition) m_mSurfaces.erase(iter); - } else + else iter->second->state = CFocusGrabSurfaceState::PendingRemoval; } } @@ -172,7 +170,7 @@ void CFocusGrabProtocol::onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_ m_vGrabs.push_back(std::make_unique(makeShared(pMgr->client(), pMgr->version(), id))); const auto RESOURCE = m_vGrabs.back().get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vGrabs.pop_back(); } diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index f6513a1d..6880164f 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -3,7 +3,7 @@ #include "../managers/HookSystemManager.hpp" CForeignToplevelHandle::CForeignToplevelHandle(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setOnDestroy([this](CExtForeignToplevelHandleV1* h) { PROTO::foreignToplevel->destroyHandle(this); }); @@ -19,7 +19,7 @@ PHLWINDOW CForeignToplevelHandle::window() { } CForeignToplevelList::CForeignToplevelList(SP resource_) : resource(resource_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setOnDestroy([this](CExtForeignToplevelListV1* h) { PROTO::foreignToplevel->onManagerResourceDestroy(this); }); @@ -40,7 +40,7 @@ CForeignToplevelList::CForeignToplevelList(SP resourc } void CForeignToplevelList::onMap(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto NEWHANDLE = PROTO::foreignToplevel->m_vHandles.emplace_back( @@ -72,11 +72,11 @@ SP CForeignToplevelList::handleForWindow(PHLWINDOW pWind } void CForeignToplevelList::onTitle(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->resource->sendTitle(pWindow->m_szTitle.c_str()); @@ -84,11 +84,11 @@ void CForeignToplevelList::onTitle(PHLWINDOW pWindow) { } void CForeignToplevelList::onClass(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->resource->sendAppId(pWindow->m_szClass.c_str()); @@ -96,11 +96,11 @@ void CForeignToplevelList::onClass(PHLWINDOW pWindow) { } void CForeignToplevelList::onUnmap(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H) + if UNLIKELY (!H) return; H->resource->sendClosed(); @@ -149,7 +149,7 @@ CForeignToplevelProtocol::CForeignToplevelProtocol(const wl_interface* iface, co void CForeignToplevelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); wl_client_post_no_memory(client); m_vManagers.pop_back(); diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 45ef3f93..e18f6e23 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -6,7 +6,7 @@ #include "../managers/HookSystemManager.hpp" CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP resource_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setOnDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); @@ -15,7 +15,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetActivate([this](CZwlrForeignToplevelHandleV1* p, wl_resource* seat) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; // these requests bypass the config'd stuff cuz it's usually like @@ -26,13 +26,13 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetSetFullscreen([this](CZwlrForeignToplevelHandleV1* p, wl_resource* output) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; - if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + if UNLIKELY (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) return; - if (!PWINDOW->m_bIsMapped) { + if UNLIKELY (!PWINDOW->m_bIsMapped) { PWINDOW->m_bWantsInitialFullscreen = true; return; } @@ -57,10 +57,10 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetUnsetFullscreen([this](CZwlrForeignToplevelHandleV1* p) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; - if (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + if UNLIKELY (PWINDOW->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) return; g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_FULLSCREEN, false); @@ -69,13 +69,13 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetSetMaximized([this](CZwlrForeignToplevelHandleV1* p) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; - if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + if UNLIKELY (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) return; - if (!PWINDOW->m_bIsMapped) { + if UNLIKELY (!PWINDOW->m_bIsMapped) { PWINDOW->m_bWantsInitialFullscreen = true; return; } @@ -86,10 +86,10 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; - if (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + if UNLIKELY (PWINDOW->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) return; g_pCompositor->changeWindowFullscreenModeClient(PWINDOW, FSMODE_MAXIMIZED, false); @@ -98,7 +98,7 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SPsetClose([this](CZwlrForeignToplevelHandleV1* p) { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW) + if UNLIKELY (!PWINDOW) return; g_pCompositor->closeWindow(PWINDOW); @@ -126,14 +126,14 @@ void CForeignToplevelHandleWlr::sendMonitor(PHLMONITOR pMonitor) { if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR && PROTO::outputs.contains(PLASTMONITOR->szName)) { const auto OLDRESOURCE = PROTO::outputs.at(PLASTMONITOR->szName)->outputResourceFrom(CLIENT); - if (OLDRESOURCE) + if LIKELY (OLDRESOURCE) resource->sendOutputLeave(OLDRESOURCE->getResource()->resource()); } if (PROTO::outputs.contains(pMonitor->szName)) { const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT); - if (NEWRESOURCE) + if LIKELY (NEWRESOURCE) resource->sendOutputEnter(NEWRESOURCE->getResource()->resource()); } @@ -143,7 +143,7 @@ void CForeignToplevelHandleWlr::sendMonitor(PHLMONITOR pMonitor) { void CForeignToplevelHandleWlr::sendState() { const auto PWINDOW = pWindow.lock(); - if (!PWINDOW || !PWINDOW->m_pWorkspace || !PWINDOW->m_bIsMapped) + if UNLIKELY (!PWINDOW || !PWINDOW->m_pWorkspace || !PWINDOW->m_bIsMapped) return; wl_array state; @@ -168,7 +168,7 @@ void CForeignToplevelHandleWlr::sendState() { } CForeignToplevelWlrManager::CForeignToplevelWlrManager(SP resource_) : resource(resource_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setOnDestroy([this](CZwlrForeignToplevelManagerV1* h) { PROTO::foreignToplevelWlr->onManagerResourceDestroy(this); }); @@ -191,13 +191,13 @@ CForeignToplevelWlrManager::CForeignToplevelWlrManager(SPm_vHandles.emplace_back( makeShared(makeShared(resource->client(), resource->version(), 0), pWindow)); - if (!NEWHANDLE->good()) { + if UNLIKELY (!NEWHANDLE->good()) { LOGM(ERR, "Couldn't create a foreign handle"); resource->noMemory(); PROTO::foreignToplevelWlr->m_vHandles.pop_back(); @@ -208,7 +208,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { resource->sendToplevel(NEWHANDLE->resource.get()); NEWHANDLE->resource->sendAppId(pWindow->m_szClass.c_str()); NEWHANDLE->resource->sendTitle(pWindow->m_szTitle.c_str()); - if (const auto PMONITOR = pWindow->m_pMonitor.lock(); PMONITOR) + if LIKELY (const auto PMONITOR = pWindow->m_pMonitor.lock(); PMONITOR) NEWHANDLE->sendMonitor(PMONITOR); NEWHANDLE->sendState(); NEWHANDLE->resource->sendDone(); @@ -223,11 +223,11 @@ SP CForeignToplevelWlrManager::handleForWindow(PHLWIN } void CForeignToplevelWlrManager::onTitle(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->resource->sendTitle(pWindow->m_szTitle.c_str()); @@ -235,11 +235,11 @@ void CForeignToplevelWlrManager::onTitle(PHLWINDOW pWindow) { } void CForeignToplevelWlrManager::onClass(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->resource->sendAppId(pWindow->m_szClass.c_str()); @@ -247,11 +247,11 @@ void CForeignToplevelWlrManager::onClass(PHLWINDOW pWindow) { } void CForeignToplevelWlrManager::onUnmap(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H) + if UNLIKELY (!H) return; H->resource->sendClosed(); @@ -260,16 +260,16 @@ void CForeignToplevelWlrManager::onUnmap(PHLWINDOW pWindow) { } void CForeignToplevelWlrManager::onMoveMonitor(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; const auto PMONITOR = pWindow->m_pMonitor.lock(); - if (!PMONITOR) + if UNLIKELY (!PMONITOR) return; H->sendMonitor(PMONITOR); @@ -277,11 +277,11 @@ void CForeignToplevelWlrManager::onMoveMonitor(PHLWINDOW pWindow) { } void CForeignToplevelWlrManager::onFullscreen(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->sendState(); @@ -289,10 +289,10 @@ void CForeignToplevelWlrManager::onFullscreen(PHLWINDOW pWindow) { } void CForeignToplevelWlrManager::onNewFocus(PHLWINDOW pWindow) { - if (finished) + if UNLIKELY (finished) return; - if (const auto HOLD = handleForWindow(lastFocus.lock()); HOLD) { + if LIKELY (const auto HOLD = handleForWindow(lastFocus.lock()); HOLD) { HOLD->sendState(); HOLD->resource->sendDone(); } @@ -300,7 +300,7 @@ void CForeignToplevelWlrManager::onNewFocus(PHLWINDOW pWindow) { lastFocus = pWindow; const auto H = handleForWindow(pWindow); - if (!H || H->closed) + if UNLIKELY (!H || H->closed) return; H->sendState(); @@ -378,7 +378,7 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa void CForeignToplevelWlrProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); wl_client_post_no_memory(client); m_vManagers.pop_back(); diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index d8010eac..d1e0a604 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -35,7 +35,7 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* const auto PADDON = m_mAddons.emplace(surface, std::make_unique(makeShared(pMgr->client(), pMgr->version(), id), surface)).first->second.get(); - if (!PADDON->good()) { + if UNLIKELY (!PADDON->good()) { m_mAddons.erase(surface); pMgr->noMemory(); return; diff --git a/src/protocols/FrogColorManagement.cpp b/src/protocols/FrogColorManagement.cpp index f27af5c8..cb2eed12 100644 --- a/src/protocols/FrogColorManagement.cpp +++ b/src/protocols/FrogColorManagement.cpp @@ -3,7 +3,7 @@ #include "protocols/core/Subcompositor.hpp" CFrogColorManager::CFrogColorManager(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([](CFrogColorManagementFactoryV1* r) { LOGM(TRACE, "Destroy frog_color_management at {:x} (generated default)", (uintptr_t)r); }); @@ -24,7 +24,7 @@ CFrogColorManager::CFrogColorManager(SP resource_ const auto RESOURCE = PROTO::frogColorManagement->m_vSurfaces.emplace_back( makeShared(makeShared(r->client(), r->version(), id), SURF)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::frogColorManagement->m_vSurfaces.pop_back(); return; @@ -39,14 +39,14 @@ bool CFrogColorManager::good() { } CFrogColorManagementSurface::CFrogColorManagementSurface(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); if (!surface->colorManagement.valid()) { const auto RESOURCE = PROTO::colorManagement->m_vSurfaces.emplace_back(makeShared(surface_)); - if (!RESOURCE) { + if UNLIKELY (!RESOURCE) { resource->noMemory(); PROTO::colorManagement->m_vSurfaces.pop_back(); return; @@ -141,7 +141,7 @@ CFrogColorManagementProtocol::CFrogColorManagementProtocol(const wl_interface* i void CFrogColorManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index b0da29a2..299d7717 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -6,12 +6,12 @@ #include "../render/Renderer.hpp" CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; auto OUTPUTRES = CWLOutputResource::fromResource(output); - if (!OUTPUTRES) { + if UNLIKELY (!OUTPUTRES) { LOGM(ERR, "No output in CGammaControl"); resource->sendFailed(); return; @@ -19,14 +19,14 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out pMonitor = OUTPUTRES->monitor; - if (!pMonitor || !pMonitor->output) { + if UNLIKELY (!pMonitor || !pMonitor->output) { LOGM(ERR, "No CMonitor"); resource->sendFailed(); return; } for (auto const& g : PROTO::gamma->m_vGammaControllers) { - if (g->pMonitor == pMonitor) { + if UNLIKELY (g->pMonitor == pMonitor) { resource->sendFailed(); return; } @@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out gammaSize = pMonitor->output->getGammaSize(); - if (gammaSize <= 0) { + if UNLIKELY (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); resource->sendFailed(); return; @@ -46,7 +46,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { - if (!pMonitor) { + if UNLIKELY (!pMonitor) { LOGM(ERR, "setGamma for a dead monitor"); resource->sendFailed(); close(fd); @@ -56,14 +56,14 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out LOGM(LOG, "setGamma for {}", pMonitor->szName); int fdFlags = fcntl(fd, F_GETFL, 0); - if (fdFlags < 0) { + if UNLIKELY (fdFlags < 0) { LOGM(ERR, "Failed to get fd flags"); resource->sendFailed(); close(fd); return; } - if (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { + if UNLIKELY (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { LOGM(ERR, "Failed to set fd flags"); resource->sendFailed(); close(fd); @@ -126,7 +126,7 @@ bool CGammaControl::good() { } void CGammaControl::applyToMonitor() { - if (!pMonitor || !pMonitor->output) + if UNLIKELY (!pMonitor || !pMonitor->output) return; // ?? LOGM(LOG, "setting to monitor {}", pMonitor->szName); @@ -179,7 +179,7 @@ void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vGammaControllers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), output)).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vGammaControllers.pop_back(); return; diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index ca67f063..6fac2d7f 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -1,7 +1,7 @@ #include "GlobalShortcuts.hpp" CShortcutClient::CShortcutClient(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CHyprlandGlobalShortcutsManagerV1* pMgr) { PROTO::globalShortcuts->destroyResource(this); }); @@ -9,7 +9,7 @@ CShortcutClient::CShortcutClient(SP resource_ resource->setRegisterShortcut([this](CHyprlandGlobalShortcutsManagerV1* pMgr, uint32_t shortcut, const char* id, const char* app_id, const char* description, const char* trigger_description) { - if (PROTO::globalShortcuts->isTaken(id, app_id)) { + if UNLIKELY (PROTO::globalShortcuts->isTaken(id, app_id)) { resource->error(HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken"); return; } @@ -20,7 +20,7 @@ CShortcutClient::CShortcutClient(SP resource_ PSHORTCUT->appid = app_id; PSHORTCUT->shortcut = shortcut; - if (!PSHORTCUT->resource->resource()) { + if UNLIKELY (!PSHORTCUT->resource->resource()) { PSHORTCUT->resource->noMemory(); shortcuts.pop_back(); return; @@ -41,7 +41,7 @@ CGlobalShortcutsProtocol::CGlobalShortcutsProtocol(const wl_interface* iface, co void CGlobalShortcutsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESROUCE = m_vClients.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESROUCE->good()) { + if UNLIKELY (!RESROUCE->good()) { wl_client_post_no_memory(client); m_vClients.pop_back(); return; diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp index ce6fc77a..bcf4905c 100644 --- a/src/protocols/HyprlandSurface.cpp +++ b/src/protocols/HyprlandSurface.cpp @@ -15,20 +15,20 @@ bool CHyprlandSurface::good() const { void CHyprlandSurface::setResource(SP resource) { m_pResource = std::move(resource); - if (!m_pResource->resource()) + if UNLIKELY (!m_pResource->resource()) return; m_pResource->setDestroy([this](CHyprlandSurfaceV1* resource) { destroy(); }); m_pResource->setOnDestroy([this](CHyprlandSurfaceV1* resource) { destroy(); }); m_pResource->setSetOpacity([this](CHyprlandSurfaceV1* resource, uint32_t opacity) { - if (!m_pSurface) { + if UNLIKELY (!m_pSurface) { m_pResource->error(HYPRLAND_SURFACE_V1_ERROR_NO_SURFACE, "set_opacity called for destroyed wl_surface"); return; } auto fOpacity = wl_fixed_to_double(opacity); - if (fOpacity < 0.0 || fOpacity > 1.0) { + if UNLIKELY (fOpacity < 0.0 || fOpacity > 1.0) { m_pResource->error(HYPRLAND_SURFACE_V1_ERROR_OUT_OF_RANGE, "set_opacity called with an opacity value larger than 1.0 or smaller than 0.0."); return; } @@ -104,7 +104,7 @@ void CHyprlandSurfaceProtocol::getSurface(CHyprlandSurfaceManagerV1* manager, ui .first->second.get(); } - if (!hyprlandSurface->good()) { + if UNLIKELY (!hyprlandSurface->good()) { manager->noMemory(); m_mSurfaces.erase(surface); } diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 3517a62d..85a9f8e2 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -11,7 +11,7 @@ static int onTimer(SP self, void* data) { } CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_) : resource(resource_), timeoutMs(timeoutMs_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); }); @@ -78,7 +78,7 @@ void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t i const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout)).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vNotifications.pop_back(); return; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 5fd1e893..cf777f45 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -7,7 +7,7 @@ #include CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP resource_, SP owner_) : resource(resource_), owner(owner_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setRelease([this](CZwpInputMethodKeyboardGrabV2* r) { PROTO::ime->destroyResource(this); }); @@ -34,13 +34,13 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { pLastKeyboard = keyboard; int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); - if (keymapFD < 0) { + if UNLIKELY (keymapFD < 0) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); - if (data == MAP_FAILED) { + if UNLIKELY (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); close(keymapFD); return; @@ -83,7 +83,7 @@ wl_client* CInputMethodKeyboardGrabV2::client() { } CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, SP owner_, SP surface) : resource(resource_), owner(owner_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CZwpInputPopupSurfaceV2* r) { PROTO::ime->destroyResource(this); }); @@ -149,7 +149,7 @@ void CInputMethodV2::SState::reset() { } CInputMethodV2::CInputMethodV2(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CZwpInputMethodV2* r) { @@ -189,7 +189,7 @@ CInputMethodV2::CInputMethodV2(SP resource_) : resource(resou const auto RESOURCE = PROTO::ime->m_vPopups.emplace_back( makeShared(makeShared(r->client(), r->version(), id), self.lock(), CWLSurfaceResource::fromResource(surface))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::ime->m_vPopups.pop_back(); return; @@ -206,7 +206,7 @@ CInputMethodV2::CInputMethodV2(SP resource_) : resource(resou const auto RESOURCE = PROTO::ime->m_vGrabs.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::ime->m_vGrabs.pop_back(); return; @@ -360,7 +360,7 @@ void CInputMethodV2Protocol::destroyResource(CInputMethodV2* ime) { void CInputMethodV2Protocol::onGetIME(CZwpInputMethodManagerV2* mgr, wl_resource* seat, uint32_t id) { const auto RESOURCE = m_vIMEs.emplace_back(makeShared(makeShared(mgr->client(), mgr->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { mgr->noMemory(); m_vIMEs.pop_back(); return; diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 0777149f..82d00a30 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -18,7 +18,7 @@ void CLayerShellResource::SState::reset() { CLayerShellResource::CLayerShellResource(SP resource_, SP surf_, std::string namespace_, PHLMONITOR pMonitor, zwlrLayerShellV1Layer layer) : layerNamespace(namespace_), surface(surf_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; current.layer = layer; @@ -223,19 +223,19 @@ void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id const auto PMONITOR = output ? CWLOutputResource::fromResource(output)->monitor.lock() : nullptr; auto SURF = CWLSurfaceResource::fromResource(surface); - if (!SURF) { + if UNLIKELY (!SURF) { pMgr->error(-1, "Invalid surface"); return; } - if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + if UNLIKELY (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { pMgr->error(-1, "Surface already has a different role"); return; } const auto RESOURCE = m_vLayers.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), SURF, namespace_, PMONITOR, layer)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vLayers.pop_back(); return; diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 24b8f62c..85f7b1c6 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -126,7 +126,7 @@ bool CLinuxDMABuffer::good() { } CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); @@ -208,12 +208,12 @@ bool CLinuxDMABBUFParamsResource::good() { void CLinuxDMABBUFParamsResource::create(uint32_t id) { used = true; - if (!verify()) { + if UNLIKELY (!verify()) { LOGM(ERR, "Failed creating a dmabuf: verify() said no"); return; // if verify failed, we errored the resource. } - if (!commence()) { + if UNLIKELY (!commence()) { LOGM(ERR, "Failed creating a dmabuf: commence() said no"); resource->sendFailed(); return; @@ -226,7 +226,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { auto buf = PROTO::linuxDma->m_vBuffers.emplace_back(makeShared(id, resource->client(), *attrs)); - if (!buf->good() || !buf->buffer->success) { + if UNLIKELY (!buf->good() || !buf->buffer->success) { resource->sendFailed(); return; } @@ -259,12 +259,12 @@ bool CLinuxDMABBUFParamsResource::commence() { } bool CLinuxDMABBUFParamsResource::verify() { - if (attrs->planes <= 0) { + if UNLIKELY (attrs->planes <= 0) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added"); return false; } - if (attrs->fds.at(0) < 0) { + if UNLIKELY (attrs->fds.at(0) < 0) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No plane 0"); return false; } @@ -282,7 +282,7 @@ bool CLinuxDMABBUFParamsResource::verify() { } } - if (attrs->size.x < 1 || attrs->size.y < 1) { + if UNLIKELY (attrs->size.x < 1 || attrs->size.y < 1) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS, "x/y < 1"); return false; } @@ -300,7 +300,7 @@ bool CLinuxDMABBUFParamsResource::verify() { } CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); @@ -355,7 +355,7 @@ void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() { } CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwpLinuxDmabufV1* r) { PROTO::linuxDma->destroyResource(this); }); @@ -365,7 +365,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : re const auto RESOURCE = PROTO::linuxDma->m_vFeedbacks.emplace_back(makeShared(makeShared(r->client(), r->version(), id), nullptr)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::linuxDma->m_vFeedbacks.pop_back(); return; @@ -376,7 +376,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : re const auto RESOURCE = PROTO::linuxDma->m_vFeedbacks.emplace_back( makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::linuxDma->m_vFeedbacks.pop_back(); return; @@ -386,7 +386,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : re resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) { const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::linuxDma->m_vParams.pop_back(); return; @@ -535,7 +535,7 @@ CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 41536988..caa539a2 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -35,7 +35,7 @@ bool CMesaDRMBufferResource::good() { } CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); }); @@ -87,7 +87,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { const auto RESOURCE = PROTO::mesaDRM->m_vBuffers.emplace_back(makeShared(id, resource->client(), attrs)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::mesaDRM->m_vBuffers.pop_back(); return; @@ -140,7 +140,7 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 4a976021..ecca0c48 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -8,7 +8,7 @@ using namespace Aquamarine; COutputManager::COutputManager(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; LOGM(LOG, "New OutputManager registered"); @@ -23,7 +23,7 @@ COutputManager::COutputManager(SP resource_) : resource(re const auto RESOURCE = PROTO::outputManagement->m_vConfigurations.emplace_back( makeShared(makeShared(resource->client(), resource->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::outputManagement->m_vConfigurations.pop_back(); return; @@ -48,13 +48,13 @@ bool COutputManager::good() { } void COutputManager::makeAndSendNewHead(PHLMONITOR pMonitor) { - if (stopped) + if UNLIKELY (stopped) return; const auto RESOURCE = PROTO::outputManagement->m_vHeads.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), pMonitor)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::outputManagement->m_vHeads.pop_back(); return; @@ -90,7 +90,7 @@ void COutputManager::sendDone() { } COutputHead::COutputHead(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CZwlrOutputHeadV1* r) { PROTO::outputManagement->destroyResource(this); }); @@ -213,7 +213,7 @@ void COutputHead::updateMode() { void COutputHead::makeAndSendNewMode(SP mode) { const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), mode)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::outputManagement->m_vModes.pop_back(); return; @@ -229,7 +229,7 @@ PHLMONITOR COutputHead::monitor() { } COutputMode::COutputMode(SP resource_, SP mode_) : resource(resource_), mode(mode_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CZwlrOutputModeV1* r) { PROTO::outputManagement->destroyResource(this); }); @@ -258,7 +258,7 @@ SP COutputMode::getMode() { } COutputConfiguration::COutputConfiguration(SP resource_, SP owner_) : resource(resource_), owner(owner_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwlrOutputConfigurationV1* r) { PROTO::outputManagement->destroyResource(this); }); @@ -282,7 +282,7 @@ COutputConfiguration::COutputConfiguration(SP resour const auto RESOURCE = PROTO::outputManagement->m_vConfigurationHeads.emplace_back( makeShared(makeShared(resource->client(), resource->version(), id), PMONITOR)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::outputManagement->m_vConfigurationHeads.pop_back(); return; @@ -428,7 +428,7 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { } COutputConfigurationHead::COutputConfigurationHead(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwlrOutputConfigurationHeadV1* r) { PROTO::outputManagement->destroyResource(this); }); @@ -581,7 +581,7 @@ COutputManagementProtocol::COutputManagementProtocol(const wl_interface* iface, void COutputManagementProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index dd3e8e1a..f97babc2 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -3,7 +3,7 @@ #include "../helpers/Monitor.hpp" COutputPower::COutputPower(SP resource_, PHLMONITOR pMonitor_) : resource(resource_), pMonitor(pMonitor_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CZwlrOutputPowerV1* r) { PROTO::outputPower->destroyOutputPower(this); }); @@ -62,7 +62,7 @@ void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uin const auto OUTPUT = CWLOutputResource::fromResource(output); - if (!OUTPUT) { + if UNLIKELY (!OUTPUT) { pMgr->error(0, "Invalid output resource"); return; } @@ -70,7 +70,7 @@ void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uin const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.lock())).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vOutputPowers.pop_back(); return; diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index e12fa75f..c0531799 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -10,7 +10,7 @@ CPointerConstraint::CPointerConstraint(SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : resourceL(resource_), locked(true), lifetime(lifetime_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource_->setOnDestroy([this](CZwpLockedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); @@ -49,7 +49,7 @@ CPointerConstraint::CPointerConstraint(SP resource_, SP resource_, SP surf, wl_resource* region_, zwpPointerConstraintsV1Lifetime lifetime_) : resourceC(resource_), lifetime(lifetime_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource_->setOnDestroy([this](CZwpConfinedPointerV1* p) { PROTO::constraints->destroyPointerConstraint(this); }); @@ -185,7 +185,7 @@ bool CPointerConstraint::isLocked() { } Vector2D CPointerConstraint::logicPositionHint() { - if (!pHLSurface) + if UNLIKELY (!pHLSurface) return {}; const auto SURFBOX = pHLSurface->getSurfaceBoxGlobal(); @@ -218,14 +218,14 @@ void CPointerConstraintsProtocol::destroyPointerConstraint(CPointerConstraint* h } void CPointerConstraintsProtocol::onNewConstraint(SP constraint, CZwpPointerConstraintsV1* pMgr) { - if (!constraint->good()) { + if UNLIKELY (!constraint->good()) { LOGM(ERR, "Couldn't create constraint??"); pMgr->noMemory(); m_vConstraints.pop_back(); return; } - if (!constraint->owner()) { + if UNLIKELY (!constraint->owner()) { LOGM(ERR, "New constraint has no CWLSurface owner??"); return; } @@ -234,7 +234,7 @@ void CPointerConstraintsProtocol::onNewConstraint(SP constra const auto DUPES = std::count_if(m_vConstraints.begin(), m_vConstraints.end(), [OWNER](const auto& c) { return c->owner() == OWNER; }); - if (DUPES > 1) { + if UNLIKELY (DUPES > 1) { LOGM(ERR, "Constraint for surface duped"); pMgr->error(ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED, "Surface already confined"); m_vConstraints.pop_back(); diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 5dfb9d51..4df51b47 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -4,7 +4,7 @@ #include "core/Compositor.hpp" CPointerGestureSwipe::CPointerGestureSwipe(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setOnDestroy([this](CZwpPointerGestureSwipeV1* p) { PROTO::pointerGestures->onGestureDestroy(this); }); @@ -16,7 +16,7 @@ bool CPointerGestureSwipe::good() { } CPointerGestureHold::CPointerGestureHold(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setOnDestroy([this](CZwpPointerGestureHoldV1* p) { PROTO::pointerGestures->onGestureDestroy(this); }); @@ -28,7 +28,7 @@ bool CPointerGestureHold::good() { } CPointerGesturePinch::CPointerGesturePinch(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setOnDestroy([this](CZwpPointerGesturePinchV1* p) { PROTO::pointerGestures->onGestureDestroy(this); }); @@ -73,7 +73,7 @@ void CPointerGesturesProtocol::onGetPinchGesture(CZwpPointerGesturesV1* pMgr, ui const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vPinches.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); LOGM(ERR, "Couldn't create gesture"); return; @@ -84,7 +84,7 @@ void CPointerGesturesProtocol::onGetSwipeGesture(CZwpPointerGesturesV1* pMgr, ui const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vSwipes.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); LOGM(ERR, "Couldn't create gesture"); return; @@ -95,7 +95,7 @@ void CPointerGesturesProtocol::onGetHoldGesture(CZwpPointerGesturesV1* pMgr, uin const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vHolds.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); LOGM(ERR, "Couldn't create gesture"); return; diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 411036c3..1654041c 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -27,7 +27,7 @@ void CQueuedPresentationData::discarded() { } CPresentationFeedback::CPresentationFeedback(SP resource_, SP surf) : resource(resource_), surface(surf) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWpPresentationFeedback* pMgr) { @@ -43,8 +43,8 @@ bool CPresentationFeedback::good() { void CPresentationFeedback::sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { auto client = resource->client(); - if (PROTO::outputs.contains(data->pMonitor->szName)) { - if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource) + if LIKELY (PROTO::outputs.contains(data->pMonitor->szName)) { + if LIKELY (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource) resource->sendSyncOutput(outputResource->getResource()->resource()); } @@ -100,7 +100,7 @@ void CPresentationProtocol::onGetFeedback(CWpPresentation* pMgr, wl_resource* su m_vFeedbacks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) .get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vFeedbacks.pop_back(); return; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index ecc4ee71..567bfdd2 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -5,7 +5,7 @@ #include "../config/ConfigValue.hpp" CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); @@ -35,7 +35,7 @@ bool CPrimarySelectionOffer::good() { } void CPrimarySelectionOffer::sendData() { - if (!source) + if UNLIKELY (!source) return; for (auto const& m : source->mimes()) { @@ -44,7 +44,7 @@ void CPrimarySelectionOffer::sendData() { } CPrimarySelectionSource::CPrimarySelectionSource(SP resource_, SP device_) : device(device_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -105,7 +105,7 @@ void CPrimarySelectionSource::error(uint32_t code, const std::string& msg) { } CPrimarySelectionDevice::CPrimarySelectionDevice(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -159,7 +159,7 @@ void CPrimarySelectionDevice::sendSelection(SP selection } CPrimarySelectionManager::CPrimarySelectionManager(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwpPrimarySelectionDeviceManagerV1* r) { PROTO::primarySelection->destroyResource(this); }); @@ -168,7 +168,7 @@ CPrimarySelectionManager::CPrimarySelectionManager(SPm_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::primarySelection->m_vDevices.pop_back(); return; @@ -192,7 +192,7 @@ CPrimarySelectionManager::CPrimarySelectionManager(SPm_vSources.emplace_back( makeShared(makeShared(r->client(), r->version(), id), device.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::primarySelection->m_vSources.pop_back(); return; @@ -220,7 +220,7 @@ CPrimarySelectionProtocol::CPrimarySelectionProtocol(const wl_interface* iface, void CPrimarySelectionProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index b7cf75c6..842af894 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -4,7 +4,7 @@ #include CRelativePointer::CRelativePointer(SP resource_) : resource(resource_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; pClient = resource->client(); @@ -50,7 +50,7 @@ void CRelativePointerProtocol::onGetRelativePointer(CZwpRelativePointerManagerV1 const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vRelativePointers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vRelativePointers.pop_back(); return; diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index da0a9412..8bdaf8f9 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -19,7 +19,7 @@ CScreencopyFrame::~CScreencopyFrame() { } CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t overlay_cursor, wl_resource* output, CBox box_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; overlayCursor = !!overlay_cursor; @@ -77,21 +77,20 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t resource->sendBuffer(NFormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride); if (resource->version() >= 3) { - if (dmabufFormat != DRM_FORMAT_INVALID) { + if LIKELY (dmabufFormat != DRM_FORMAT_INVALID) resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height); - } resource->sendBufferDone(); } } void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_) { - if (!good()) { + if UNLIKELY (!good()) { LOGM(ERR, "No frame in copyFrame??"); return; } - if (!g_pCompositor->monitorExists(pMonitor.lock())) { + if UNLIKELY (!g_pCompositor->monitorExists(pMonitor.lock())) { LOGM(ERR, "Client requested sharing of a monitor that is gone"); resource->sendFailed(); PROTO::screencopy->destroyResource(this); @@ -99,7 +98,7 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ } const auto PBUFFER = CWLBufferResource::fromResource(buffer_); - if (!PBUFFER) { + if UNLIKELY (!PBUFFER) { LOGM(ERR, "Invalid buffer in {:x}", (uintptr_t)this); resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); PROTO::screencopy->destroyResource(this); @@ -108,14 +107,14 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ PBUFFER->buffer->lock(); - if (PBUFFER->buffer->size != box.size()) { + if UNLIKELY (PBUFFER->buffer->size != box.size()) { LOGM(ERR, "Invalid dimensions in {:x}", (uintptr_t)this); resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); PROTO::screencopy->destroyResource(this); return; } - if (buffer) { + if UNLIKELY (buffer) { LOGM(ERR, "Buffer used in {:x}", (uintptr_t)this); resource->error(ZWLR_SCREENCOPY_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); PROTO::screencopy->destroyResource(this); @@ -308,7 +307,7 @@ CScreencopyClient::~CScreencopyClient() { } CScreencopyClient::CScreencopyClient(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwlrScreencopyManagerV1* pMgr) { PROTO::screencopy->destroyResource(this); }); diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index 0818907f..e5b3cf2a 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -49,7 +49,7 @@ void CSecurityContextSandboxedClient::onDestroy() { } CSecurityContext::CSecurityContext(SP resource_, int listenFD_, int closeFD_) : listenFD(listenFD_), closeFD(closeFD_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWpSecurityContextV1* r) { @@ -64,12 +64,12 @@ CSecurityContext::CSecurityContext(SP resource_, int liste LOGM(LOG, "New security_context at 0x{:x}", (uintptr_t)this); resource->setSetSandboxEngine([this](CWpSecurityContextV1* r, const char* engine) { - if (!sandboxEngine.empty()) { + if UNLIKELY (!sandboxEngine.empty()) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox engine already set"); return; } - if (committed) { + if UNLIKELY (committed) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); return; } @@ -79,12 +79,12 @@ CSecurityContext::CSecurityContext(SP resource_, int liste }); resource->setSetAppId([this](CWpSecurityContextV1* r, const char* appid) { - if (!appID.empty()) { + if UNLIKELY (!appID.empty()) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox appid already set"); return; } - if (committed) { + if UNLIKELY (committed) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); return; } @@ -94,12 +94,12 @@ CSecurityContext::CSecurityContext(SP resource_, int liste }); resource->setSetInstanceId([this](CWpSecurityContextV1* r, const char* instance) { - if (!instanceID.empty()) { + if UNLIKELY (!instanceID.empty()) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_SET, "Sandbox instance already set"); return; } - if (committed) { + if UNLIKELY (committed) { r->error(WP_SECURITY_CONTEXT_V1_ERROR_ALREADY_USED, "Context already committed"); return; } @@ -135,7 +135,7 @@ bool CSecurityContext::good() { } void CSecurityContext::onListen(uint32_t mask) { - if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { + if UNLIKELY (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) { LOGM(ERR, "security_context at 0x{:x} got an error in listen", (uintptr_t)this); PROTO::securityContext->destroyContext(this); return; @@ -145,13 +145,13 @@ void CSecurityContext::onListen(uint32_t mask) { return; int clientFD = accept(listenFD, nullptr, nullptr); - if (clientFD < 0) { + if UNLIKELY (clientFD < 0) { LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); return; } auto newClient = CSecurityContextSandboxedClient::create(clientFD); - if (!newClient) { + if UNLIKELY (!newClient) { LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); close(clientFD); return; @@ -170,7 +170,7 @@ void CSecurityContext::onClose(uint32_t mask) { } CSecurityContextManagerResource::CSecurityContextManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWpSecurityContextManagerV1* r) { PROTO::securityContext->destroyResource(this); }); @@ -180,7 +180,7 @@ CSecurityContextManagerResource::CSecurityContextManagerResource(SPm_vContexts.emplace_back(makeShared(makeShared(r->client(), r->version(), id), lfd, cfd)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::securityContext->m_vContexts.pop_back(); return; @@ -199,7 +199,7 @@ CSecurityContextProtocol::CSecurityContextProtocol(const wl_interface* iface, co void CSecurityContextProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index c7b98a9c..3e33db52 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -2,7 +2,7 @@ #include "core/Compositor.hpp" CServerDecorationKDE::CServerDecorationKDE(SP resource_, SP surf) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](COrgKdeKwinServerDecoration* pMgr) { PROTO::serverDecorationKDE->destroyResource(this); }); @@ -44,7 +44,7 @@ void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationM m_vDecos.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) .get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vDecos.pop_back(); return; diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index c3f19e53..db65ee5f 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -8,7 +8,7 @@ CSessionLockSurface::CSessionLockSurface(SP resource_, SP surface_, PHLMONITOR pMonitor_, WP owner_) : resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CExtSessionLockSurfaceV1* r) { @@ -92,7 +92,7 @@ SP CSessionLockSurface::surface() { } CSessionLock::CSessionLock(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CExtSessionLockV1* r) { PROTO::sessionLock->destroyResource(this); }); @@ -170,7 +170,7 @@ void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vLocks.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vLocks.pop_back(); return; @@ -198,7 +198,7 @@ void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id const auto RESOURCE = m_vLockSurfaces.emplace_back(makeShared(makeShared(lock->client(), lock->version(), id), PSURFACE, PMONITOR, sessionLock)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { lock->noMemory(); m_vLockSurfaces.pop_back(); return; diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index 308b385d..a0d29f92 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -4,7 +4,7 @@ #include "core/Compositor.hpp" CKeyboardShortcutsInhibitor::CKeyboardShortcutsInhibitor(SP resource_, SP surf) : resource(resource_), pSurface(surf) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CZwpKeyboardShortcutsInhibitorV1* pMgr) { PROTO::shortcutsInhibit->destroyInhibitor(this); }); @@ -49,7 +49,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa const auto CLIENT = pMgr->client(); for (auto const& in : m_vInhibitors) { - if (in->surface() != surf) + if LIKELY (in->surface() != surf) continue; pMgr->error(ZWP_KEYBOARD_SHORTCUTS_INHIBIT_MANAGER_V1_ERROR_ALREADY_INHIBITED, "Already inhibited for surface resource"); @@ -59,7 +59,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa const auto RESOURCE = m_vInhibitors.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), surf)).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vInhibitors.pop_back(); LOGM(ERR, "Failed to create an inhibitor resource"); diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 91154671..2fbfc93d 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -63,7 +63,7 @@ bool CSinglePixelBuffer::good() { CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color) { buffer = makeShared(id, client, color); - if (!buffer->good()) + if UNLIKELY (!buffer->good()) return; buffer->resource->buffer = buffer; @@ -83,7 +83,7 @@ bool CSinglePixelBufferResource::good() { } CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWpSinglePixelBufferManagerV1* r) { PROTO::singlePixel->destroyResource(this); }); @@ -94,7 +94,7 @@ CSinglePixelBufferManagerResource::CSinglePixelBufferManagerResource(SP::max()}; const auto RESOURCE = PROTO::singlePixel->m_vBuffers.emplace_back(makeShared(id, resource->client(), color)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { res->noMemory(); PROTO::singlePixel->m_vBuffers.pop_back(); return; @@ -113,7 +113,7 @@ CSinglePixelProtocol::CSinglePixelProtocol(const wl_interface* iface, const int& void CSinglePixelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 2fdd8731..62e8b2d2 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -9,7 +9,7 @@ #include CTabletPadStripV2Resource::CTabletPadStripV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletPadStripV2* r) { PROTO::tablet->destroyResource(this); }); @@ -21,7 +21,7 @@ bool CTabletPadStripV2Resource::good() { } CTabletPadRingV2Resource::CTabletPadRingV2Resource(SP resource_, uint32_t id_) : id(id_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletPadRingV2* r) { PROTO::tablet->destroyResource(this); }); @@ -33,7 +33,7 @@ bool CTabletPadRingV2Resource::good() { } CTabletPadGroupV2Resource::CTabletPadGroupV2Resource(SP resource_, size_t idx_) : idx(idx_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletPadGroupV2* r) { PROTO::tablet->destroyResource(this); }); @@ -58,7 +58,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, SPm_vStrips.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vStrips.pop_back(); return; @@ -71,7 +71,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, SPm_vRings.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vRings.pop_back(); return; @@ -84,7 +84,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, SP resource_, SP pad_, SP seat_) : pad(pad_), seat(seat_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletPadV2* r) { PROTO::tablet->destroyResource(this); }); @@ -114,7 +114,7 @@ void CTabletPadV2Resource::createGroup(SPm_vGroups.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), idx)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vGroups.pop_back(); return; @@ -126,7 +126,7 @@ void CTabletPadV2Resource::createGroup(SP resource_, SP tablet_, SP seat_) : tablet(tablet_), seat(seat_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletV2* r) { PROTO::tablet->destroyResource(this); }); @@ -149,7 +149,7 @@ void CTabletV2Resource::sendData() { } CTabletToolV2Resource::CTabletToolV2Resource(SP resource_, SP tool_, SP seat_) : tool(tool_), seat(seat_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletToolV2* r) { PROTO::tablet->destroyResource(this); }); @@ -228,7 +228,7 @@ void CTabletToolV2Resource::sendFrame(bool removeSource) { } CTabletSeat::CTabletSeat(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpTabletSeatV2* r) { PROTO::tablet->destroyResource(this); }); @@ -243,7 +243,7 @@ void CTabletSeat::sendTool(SP tool) { const auto RESOURCE = PROTO::tablet->m_vTools.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), tool, self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vTools.pop_back(); return; @@ -259,7 +259,7 @@ void CTabletSeat::sendPad(SP pad) { const auto RESOURCE = PROTO::tablet->m_vPads.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), pad, self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vPads.pop_back(); return; @@ -275,7 +275,7 @@ void CTabletSeat::sendTablet(SP tablet) { const auto RESOURCE = PROTO::tablet->m_vTablets.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), tablet, self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); PROTO::tablet->m_vTablets.pop_back(); return; @@ -357,7 +357,7 @@ void CTabletV2Protocol::destroyResource(CTabletPadStripV2Resource* resource) { void CTabletV2Protocol::onGetSeat(CZwpTabletManagerV2* pMgr, uint32_t id, wl_resource* seat) { const auto RESOURCE = m_vSeats.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vSeats.pop_back(); return; diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index eb1a53cb..14c80052 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -27,7 +27,7 @@ void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP surf) { const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique(makeShared(client, pMgr->version(), id), surf)).get(); - if (!CONTROLLER->good()) { + if UNLIKELY (!CONTROLLER->good()) { pMgr->noMemory(); m_vTearingControllers.pop_back(); return; @@ -67,7 +67,7 @@ void CTearingControl::onHint(wpTearingControlV1PresentationHint hint_) { } void CTearingControl::updateWindow() { - if (pWindow.expired()) + if UNLIKELY (pWindow.expired()) return; pWindow->m_bTearingHint = hint == WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC; diff --git a/src/protocols/TextInputV1.cpp b/src/protocols/TextInputV1.cpp index b8eb5835..4bf5e9e1 100644 --- a/src/protocols/TextInputV1.cpp +++ b/src/protocols/TextInputV1.cpp @@ -7,13 +7,13 @@ CTextInputV1::~CTextInputV1() { } CTextInputV1::CTextInputV1(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CZwpTextInputV1* pMgr) { PROTO::textInputV1->destroyResource(this); }); resource->setActivate([this](CZwpTextInputV1* pMgr, wl_resource* seat, wl_resource* surface) { - if (!surface) { + if UNLIKELY (!surface) { LOGM(WARN, "Text-input-v1 PTI{:x}: No surface to activate text input on!", (uintptr_t)this); return; } @@ -105,7 +105,7 @@ void CTextInputV1Protocol::bindManager(wl_client* client, void* data, uint32_t v const auto PTI = m_vClients.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); LOGM(LOG, "New TI V1 at {:x}", (uintptr_t)PTI.get()); - if (!PTI->good()) { + if UNLIKELY (!PTI->good()) { LOGM(ERR, "Could not alloc wl_resource for TIV1"); pMgr->noMemory(); PROTO::textInputV1->destroyResource(PTI.get()); diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 30374104..71ef6dac 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -10,7 +10,7 @@ void CTextInputV3::SState::reset() { } CTextInputV3::CTextInputV3(SP resource_) : resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; LOGM(LOG, "New tiv3 at {:016x}", (uintptr_t)this); @@ -129,7 +129,7 @@ void CTextInputV3Protocol::onGetTextInput(CZwpTextInputManagerV3* pMgr, uint32_t const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vTextInputs.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vTextInputs.pop_back(); LOGM(ERR, "Failed to create a tiv3 resource"); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 8e34cf4b..2d40cb78 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -13,7 +13,7 @@ #include CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CHyprlandToplevelExportManagerV1* pMgr) { PROTO::toplevelExport->destroyResource(this); }); @@ -35,7 +35,7 @@ void CToplevelExportClient::captureToplevel(CHyprlandToplevelExportManagerV1* pM const auto FRAME = PROTO::toplevelExport->m_vFrames.emplace_back( makeShared(makeShared(resource->client(), resource->version(), frame), overlayCursor_, handle)); - if (!FRAME->good()) { + if UNLIKELY (!FRAME->good()) { LOGM(ERR, "Couldn't alloc frame for sharing! (no memory)"); resource->noMemory(); PROTO::toplevelExport->destroyResource(FRAME.get()); @@ -78,19 +78,19 @@ CToplevelExportFrame::~CToplevelExportFrame() { } CToplevelExportFrame::CToplevelExportFrame(SP resource_, int32_t overlayCursor_, PHLWINDOW pWindow_) : resource(resource_), pWindow(pWindow_) { - if (!good()) + if UNLIKELY (!good()) return; cursorOverlayRequested = !!overlayCursor_; - if (!pWindow) { + if UNLIKELY (!pWindow) { LOGM(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); return; } - if (!pWindow->m_bIsMapped) { + if UNLIKELY (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); @@ -106,7 +106,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re g_pHyprRenderer->makeEGLCurrent(); shmFormat = g_pHyprOpenGL->getPreferredReadFormat(PMONITOR); - if (shmFormat == DRM_FORMAT_INVALID) { + if UNLIKELY (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture toplevel"); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); @@ -114,7 +114,7 @@ CToplevelExportFrame::CToplevelExportFrame(SP re } const auto PSHMINFO = NFormatUtils::getPixelFormatFromDRM(shmFormat); - if (!PSHMINFO) { + if UNLIKELY (!PSHMINFO) { LOGM(ERR, "No pixel format supported by renderer in capture toplevel"); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); @@ -131,27 +131,26 @@ CToplevelExportFrame::CToplevelExportFrame(SP re resource->sendBuffer(NFormatUtils::drmToShm(shmFormat), box.width, box.height, shmStride); - if (dmabufFormat != DRM_FORMAT_INVALID) { + if LIKELY (dmabufFormat != DRM_FORMAT_INVALID) resource->sendLinuxDmabuf(dmabufFormat, box.width, box.height); - } resource->sendBufferDone(); } void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resource* buffer_, int32_t ignoreDamage) { - if (!good()) { + if UNLIKELY (!good()) { LOGM(ERR, "No frame in copyFrame??"); return; } - if (!validMapped(pWindow)) { + if UNLIKELY (!validMapped(pWindow)) { LOGM(ERR, "Client requested sharing of window handle {:x} which is gone!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); return; } - if (!pWindow->m_bIsMapped) { + if UNLIKELY (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", pWindow); resource->sendFailed(); PROTO::toplevelExport->destroyResource(this); @@ -159,7 +158,7 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou } const auto PBUFFER = CWLBufferResource::fromResource(buffer_); - if (!PBUFFER) { + if UNLIKELY (!PBUFFER) { resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer"); PROTO::toplevelExport->destroyResource(this); return; @@ -167,13 +166,13 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou PBUFFER->buffer->lock(); - if (PBUFFER->buffer->size != box.size()) { + if UNLIKELY (PBUFFER->buffer->size != box.size()) { resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER, "invalid buffer dimensions"); PROTO::toplevelExport->destroyResource(this); return; } - if (buffer) { + if UNLIKELY (buffer) { resource->error(HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED, "frame already used"); PROTO::toplevelExport->destroyResource(this); return; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 58cb851d..4964bead 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -3,14 +3,14 @@ #include CViewportResource::CViewportResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); resource->setOnDestroy([this](CWpViewport* r) { PROTO::viewport->destroyResource(this); }); resource->setSetDestination([this](CWpViewport* r, int32_t x, int32_t y) { - if (!surface) { + if UNLIKELY (!surface) { r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); return; } @@ -20,7 +20,7 @@ CViewportResource::CViewportResource(SP resource_, SPerror(WP_VIEWPORT_ERROR_BAD_SIZE, "Size was <= 0"); return; } @@ -30,7 +30,7 @@ CViewportResource::CViewportResource(SP resource_, SPsetSetSource([this](CWpViewport* r, wl_fixed_t fx, wl_fixed_t fy, wl_fixed_t fw, wl_fixed_t fh) { - if (!surface) { + if UNLIKELY (!surface) { r->error(WP_VIEWPORT_ERROR_NO_SURFACE, "Surface is gone"); return; } @@ -42,7 +42,7 @@ CViewportResource::CViewportResource(SP resource_, SPerror(WP_VIEWPORT_ERROR_BAD_SIZE, "Pos was < 0"); return; } @@ -80,7 +80,7 @@ bool CViewportResource::good() { } CViewporterResource::CViewporterResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWpViewporter* r) { PROTO::viewport->destroyResource(this); }); @@ -90,7 +90,7 @@ CViewporterResource::CViewporterResource(SP resource_) : resource const auto RESOURCE = PROTO::viewport->m_vViewports.emplace_back( makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surf))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::viewport->m_vViewports.pop_back(); return; @@ -109,7 +109,7 @@ CViewporterProtocol::CViewporterProtocol(const wl_interface* iface, const int& v void CViewporterProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index bb51315d..7da1fe01 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -3,7 +3,7 @@ #include "../devices/IKeyboard.hpp" CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwpVirtualKeyboardV1* r) { @@ -18,7 +18,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setKey([this](CZwpVirtualKeyboardV1* r, uint32_t timeMs, uint32_t key, uint32_t state) { - if (!hasKeymap) { + if UNLIKELY (!hasKeymap) { r->error(ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP, "Key event received before a keymap was set"); return; } @@ -37,7 +37,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { - if (!hasKeymap) { + if UNLIKELY (!hasKeymap) { r->error(ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP, "Mods event received before a keymap was set"); return; } @@ -52,7 +52,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!xkbContext) { + if UNLIKELY (!xkbContext) { LOGM(ERR, "xkbContext creation failed"); r->noMemory(); close(fd); @@ -60,7 +60,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP } auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); - if (keymapData == MAP_FAILED) { + if UNLIKELY (keymapData == MAP_FAILED) { LOGM(ERR, "keymapData alloc failed"); xkb_context_unref(xkbContext); r->noMemory(); @@ -71,7 +71,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP auto xkbKeymap = xkb_keymap_new_from_string(xkbContext, (const char*)keymapData, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(keymapData, len); - if (!xkbKeymap) { + if UNLIKELY (!xkbKeymap) { LOGM(ERR, "xkbKeymap creation failed"); xkb_context_unref(xkbContext); r->noMemory(); @@ -142,7 +142,7 @@ void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, const auto RESOURCE = m_vKeyboards.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vKeyboards.pop_back(); return; diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 4c5aa13a..3e0b00eb 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -2,7 +2,7 @@ #include "core/Output.hpp" CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_, PHLMONITORREF boundOutput_) : boundOutput(boundOutput_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CZwlrVirtualPointerV1* r) { @@ -41,7 +41,7 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r }); resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) { - if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + if UNLIKELY (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); return; } @@ -64,7 +64,7 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; }); resource->setAxisStop([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_) { - if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + if UNLIKELY (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); return; } @@ -77,7 +77,7 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r }); resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) { - if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + if UNLIKELY (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) { r->error(ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS, "Invalid axis"); return; } @@ -138,7 +138,7 @@ void CVirtualPointerProtocol::onCreatePointer(CZwlrVirtualPointerManagerV1* pMgr const auto RESOURCE = m_vPointers.emplace_back(makeShared(makeShared(pMgr->client(), pMgr->version(), id), output)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vPointers.pop_back(); return; diff --git a/src/protocols/WaylandProtocol.cpp b/src/protocols/WaylandProtocol.cpp index 5c6a4a56..7fef5179 100644 --- a/src/protocols/WaylandProtocol.cpp +++ b/src/protocols/WaylandProtocol.cpp @@ -20,7 +20,7 @@ void IWaylandProtocol::onDisplayDestroy() { IWaylandProtocol::IWaylandProtocol(const wl_interface* iface, const int& ver, const std::string& name) : m_szName(name), m_pGlobal(wl_global_create(g_pCompositor->m_sWLDisplay, iface, ver, this, &bindManagerInternal)) { - if (!m_pGlobal) { + if UNLIKELY (!m_pGlobal) { LOGM(ERR, "could not create a global [{}]", m_szName); return; } diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index 4a6c7bfe..c49dc3dc 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -5,7 +5,7 @@ #include CXDGActivationToken::CXDGActivationToken(SP resource_) : resource(resource_) { - if (!resource_->resource()) + if UNLIKELY (!resource_->resource()) return; resource->setDestroy([this](CXdgActivationTokenV1* r) { PROTO::activation->destroyToken(this); }); @@ -18,7 +18,7 @@ CXDGActivationToken::CXDGActivationToken(SP resource_) : resource->setCommit([this](CXdgActivationTokenV1* r) { // TODO: should we send a protocol error of already_used here // if it was used? the protocol spec doesn't say _when_ it should be sent... - if (committed) { + if UNLIKELY (committed) { LOGM(WARN, "possible protocol error, two commits from one token. Ignoring."); return; } @@ -36,7 +36,7 @@ CXDGActivationToken::CXDGActivationToken(SP resource_) : auto count = std::count_if(PROTO::activation->m_vSentTokens.begin(), PROTO::activation->m_vSentTokens.end(), [this](const auto& other) { return other.client == resource->client(); }); - if (count > 10) { + if UNLIKELY (count > 10) { // remove first token. Too many, dear app. for (auto i = PROTO::activation->m_vSentTokens.begin(); i != PROTO::activation->m_vSentTokens.end(); ++i) { if (i->client == resource->client()) { @@ -70,7 +70,7 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t RESOURCE->setActivate([this](CXdgActivationV1* pMgr, const char* token, wl_resource* surface) { auto TOKEN = std::find_if(m_vSentTokens.begin(), m_vSentTokens.end(), [token](const auto& t) { return t.token == token; }); - if (TOKEN == m_vSentTokens.end()) { + if UNLIKELY (TOKEN == m_vSentTokens.end()) { LOGM(WARN, "activate event for non-existent token {}??", token); return; } @@ -81,7 +81,7 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t SP surf = CWLSurfaceResource::fromResource(surface); const auto PWINDOW = g_pCompositor->getWindowFromSurface(surf); - if (!PWINDOW) { + if UNLIKELY (!PWINDOW) { LOGM(WARN, "activate event for non-window or gone surface with token {}, ignoring", token); return; } @@ -102,7 +102,7 @@ void CXDGActivationProtocol::onGetToken(CXdgActivationV1* pMgr, uint32_t id) { const auto CLIENT = pMgr->client(); const auto RESOURCE = m_vTokens.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_vTokens.pop_back(); return; diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index 07b1694c..8ec0d5b0 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -2,7 +2,7 @@ #include CXDGDecoration::CXDGDecoration(SP resource_, wl_resource* toplevel) : resource(resource_), pToplevelResource(toplevel) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([this](CZxdgToplevelDecorationV1* pMgr) { PROTO::xdgDecoration->destroyDecoration(this); }); @@ -57,7 +57,7 @@ void CXDGDecorationProtocol::destroyDecoration(CXDGDecoration* decoration) { } void CXDGDecorationProtocol::onGetDecoration(CZxdgDecorationManagerV1* pMgr, uint32_t id, wl_resource* xdgToplevel) { - if (m_mDecorations.contains(xdgToplevel)) { + if UNLIKELY (m_mDecorations.contains(xdgToplevel)) { pMgr->error(ZXDG_TOPLEVEL_DECORATION_V1_ERROR_ALREADY_CONSTRUCTED, "Decoration object already exists"); return; } @@ -66,7 +66,7 @@ void CXDGDecorationProtocol::onGetDecoration(CZxdgDecorationManagerV1* pMgr, uin const auto RESOURCE = m_mDecorations.emplace(xdgToplevel, std::make_unique(makeShared(CLIENT, pMgr->version(), id), xdgToplevel)).first->second.get(); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); m_mDecorations.erase(xdgToplevel); return; diff --git a/src/protocols/XDGDialog.cpp b/src/protocols/XDGDialog.cpp index 3f58f326..675d4e78 100644 --- a/src/protocols/XDGDialog.cpp +++ b/src/protocols/XDGDialog.cpp @@ -5,7 +5,7 @@ #include CXDGDialogV1Resource::CXDGDialogV1Resource(SP resource_, SP toplevel_) : resource(resource_), toplevel(toplevel_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CXdgDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); @@ -23,11 +23,11 @@ CXDGDialogV1Resource::CXDGDialogV1Resource(SP resource_, SPparent || !toplevel->parent->owner) + if UNLIKELY (!toplevel || !toplevel->parent || !toplevel->parent->owner) return; auto HLSurface = CWLSurface::fromResource(toplevel->parent->owner->surface.lock()); - if (!HLSurface || !HLSurface->getWindow()) + if UNLIKELY (!HLSurface || !HLSurface->getWindow()) return; g_pCompositor->updateWindowAnimatedDecorationValues(HLSurface->getWindow()); @@ -38,7 +38,7 @@ bool CXDGDialogV1Resource::good() { } CXDGWmDialogManagerResource::CXDGWmDialogManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CXdgWmDialogV1* r) { PROTO::xdgDialog->destroyResource(this); }); @@ -46,14 +46,14 @@ CXDGWmDialogManagerResource::CXDGWmDialogManagerResource(SP reso resource->setGetXdgDialog([](CXdgWmDialogV1* r, uint32_t id, wl_resource* toplevel) { auto tl = CXDGToplevelResource::fromResource(toplevel); - if (!tl) { + if UNLIKELY (!tl) { r->error(-1, "Toplevel inert"); return; } const auto RESOURCE = PROTO::xdgDialog->m_vDialogs.emplace_back(makeShared(makeShared(r->client(), r->version(), id), tl)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); return; } @@ -73,7 +73,7 @@ CXDGDialogProtocol::CXDGDialogProtocol(const wl_interface* iface, const int& ver void CXDGDialogProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); return; } diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index fadc48a1..5be16d07 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -23,7 +23,7 @@ void CXDGOutputProtocol::onOutputResourceDestroy(wl_resource* res) { void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagerResources.emplace_back(std::make_unique(client, ver, id)).get(); - if (!RESOURCE->resource()) { + if UNLIKELY (!RESOURCE->resource()) { LOGM(LOG, "Couldn't bind XDGOutputMgr"); wl_client_post_no_memory(client); return; @@ -53,13 +53,13 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 pXDGOutput->outputProto = OUTPUT->owner; - if (!pXDGOutput->resource->resource()) { + if UNLIKELY (!pXDGOutput->resource->resource()) { m_vXDGOutputs.pop_back(); mgr->noMemory(); return; } - if (!PMONITOR) { + if UNLIKELY (!PMONITOR) { LOGM(ERR, "New xdg_output from client {:x} ({}) has no CMonitor?!", (uintptr_t)CLIENT, pXDGOutput->isXWayland ? "xwayland" : "not xwayland"); return; } @@ -96,7 +96,7 @@ void CXDGOutputProtocol::updateAllOutputs() { // CXDGOutput::CXDGOutput(SP resource_, PHLMONITOR monitor_) : monitor(monitor_), resource(resource_) { - if (!resource->resource()) + if UNLIKELY (!resource->resource()) return; resource->setDestroy([](CZxdgOutputV1* pMgr) { PROTO::xdgOutput->onOutputResourceDestroy(pMgr->resource()); }); @@ -106,7 +106,7 @@ CXDGOutput::CXDGOutput(SP resource_, PHLMONITOR monitor_) : monit void CXDGOutput::sendDetails() { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (!monitor || !outputProto || outputProto->isDefunct()) + if UNLIKELY (!monitor || !outputProto || outputProto->isDefunct()) return; const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition; diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index aabb225a..f5d1a8fa 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -26,7 +26,7 @@ void SXDGPositionerState::setGravity(xdgPositionerGravity edges) { CXDGPopupResource::CXDGPopupResource(SP resource_, SP owner_, SP surface_, SP positioner) : surface(surface_), parent(owner_), resource(resource_), positionerRules(positioner) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -79,7 +79,7 @@ void CXDGPopupResource::applyPositioning(const CBox& box, const Vector2D& t1coor configure(geometry); - if (lastRepositionToken) + if UNLIKELY (lastRepositionToken) repositioned(); } @@ -118,7 +118,7 @@ void CXDGPopupResource::done() { } void CXDGPopupResource::repositioned() { - if (!lastRepositionToken) + if LIKELY (!lastRepositionToken) return; LOGM(LOG, "repositioned: sending reposition token {}", lastRepositionToken); @@ -128,7 +128,7 @@ void CXDGPopupResource::repositioned() { } CXDGToplevelResource::CXDGToplevelResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -350,7 +350,7 @@ Vector2D CXDGToplevelResource::layoutMaxSize() { CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SP owner_, SP surface_) : owner(owner_), surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -386,7 +386,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPcurrent = toplevel->pending; - if (initialCommit && surface->pending.texture) { + if UNLIKELY (initialCommit && surface->pending.texture) { resource->error(-1, "Buffer attached before initial commit"); return; } @@ -416,7 +416,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPsetGetToplevel([this](CXdgSurface* r, uint32_t id) { const auto RESOURCE = PROTO::xdgShell->m_vToplevels.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::xdgShell->m_vToplevels.pop_back(); return; @@ -442,7 +442,7 @@ CXDGSurfaceResource::CXDGSurfaceResource(SP resource_, SPm_vPopups.emplace_back(makeShared(makeShared(r->client(), r->version(), id), parent, self.lock(), positioner)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::xdgShell->m_vPopups.pop_back(); return; @@ -511,7 +511,7 @@ void CXDGSurfaceResource::configure() { } CXDGPositionerResource::CXDGPositionerResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -520,7 +520,7 @@ CXDGPositionerResource::CXDGPositionerResource(SP resource_, SP< resource->setOnDestroy([this](CXdgPositioner* r) { PROTO::xdgShell->destroyResource(this); }); resource->setSetSize([this](CXdgPositioner* r, int32_t x, int32_t y) { - if (x <= 0 || y <= 0) { + if UNLIKELY (x <= 0 || y <= 0) { r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid size"); return; } @@ -529,7 +529,7 @@ CXDGPositionerResource::CXDGPositionerResource(SP resource_, SP< }); resource->setSetAnchorRect([this](CXdgPositioner* r, int32_t x, int32_t y, int32_t w, int32_t h) { - if (w <= 0 || h <= 0) { + if UNLIKELY (w <= 0 || h <= 0) { r->error(XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid box"); return; } @@ -686,7 +686,7 @@ CBox CXDGPositionerRules::getPosition(CBox constraint, const Vector2D& parentCoo } CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CXdgWmBase* r) { PROTO::xdgShell->destroyResource(this); }); @@ -698,7 +698,7 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { const auto RESOURCE = PROTO::xdgShell->m_vPositioners.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::xdgShell->m_vPositioners.pop_back(); return; @@ -714,19 +714,19 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { resource->setGetXdgSurface([this](CXdgWmBase* r, uint32_t id, wl_resource* surf) { auto SURF = CWLSurfaceResource::fromResource(surf); - if (!SURF) { + if UNLIKELY (!SURF) { r->error(-1, "Invalid surface passed"); return; } - if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + if UNLIKELY (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { r->error(-1, "Surface already has a different role"); return; } const auto RESOURCE = PROTO::xdgShell->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock(), SURF)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::xdgShell->m_vSurfaces.pop_back(); return; @@ -765,7 +765,7 @@ CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, void CXDGShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vWMBases.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vWMBases.pop_back(); return; diff --git a/src/protocols/XWaylandShell.cpp b/src/protocols/XWaylandShell.cpp index 81194163..b4615e19 100644 --- a/src/protocols/XWaylandShell.cpp +++ b/src/protocols/XWaylandShell.cpp @@ -3,7 +3,7 @@ #include CXWaylandSurfaceResource::CXWaylandSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CXwaylandSurfaceV1* r) { @@ -36,7 +36,7 @@ wl_client* CXWaylandSurfaceResource::client() { } CXWaylandShellResource::CXWaylandShellResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CXwaylandShellV1* r) { PROTO::xwaylandShell->destroyResource(this); }); @@ -46,7 +46,7 @@ CXWaylandShellResource::CXWaylandShellResource(SP resource_) : const auto RESOURCE = PROTO::xwaylandShell->m_vSurfaces.emplace_back( makeShared(makeShared(r->client(), r->version(), id), CWLSurfaceResource::fromResource(surface))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::xwaylandShell->m_vSurfaces.pop_back(); return; @@ -67,7 +67,7 @@ CXWaylandShellProtocol::CXWaylandShellProtocol(const wl_interface* iface, const void CXWaylandShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index e1d6ef7d..93683993 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -34,7 +34,7 @@ void CWLCallbackResource::send(timespec* now) { } CWLRegionResource::CWLRegionResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -56,7 +56,7 @@ SP CWLRegionResource::fromResource(wl_resource* res) { } CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; pClient = resource->client(); @@ -187,20 +187,20 @@ void CWLSurfaceResource::enter(PHLMONITOR monitor) { if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) != enteredOutputs.end()) return; - if (!PROTO::outputs.contains(monitor->szName)) { + if UNLIKELY (!PROTO::outputs.contains(monitor->szName)) { // can happen on unplug/replug LOGM(ERR, "enter() called on a non-existent output global"); return; } - if (PROTO::outputs.at(monitor->szName)->isDefunct()) { + if UNLIKELY (PROTO::outputs.at(monitor->szName)->isDefunct()) { LOGM(ERR, "enter() called on a defunct output global"); return; } auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); - if (!output || !output->getResource() || !output->getResource()->resource()) { + if UNLIKELY (!output || !output->getResource() || !output->getResource()->resource()) { LOGM(ERR, "Cannot enter surface {:x} to {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); return; } @@ -211,12 +211,12 @@ void CWLSurfaceResource::enter(PHLMONITOR monitor) { } void CWLSurfaceResource::leave(PHLMONITOR monitor) { - if (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end()) + if UNLIKELY (std::find(enteredOutputs.begin(), enteredOutputs.end(), monitor) == enteredOutputs.end()) return; auto output = PROTO::outputs.at(monitor->szName)->outputResourceFrom(pClient); - if (!output) { + if UNLIKELY (!output) { LOGM(ERR, "Cannot leave surface {:x} from {}, client hasn't bound the output", (uintptr_t)this, monitor->szName); return; } @@ -332,7 +332,7 @@ uint32_t CWLSurfaceResource::id() { } void CWLSurfaceResource::map() { - if (mapped) + if UNLIKELY (mapped) return; mapped = true; @@ -346,7 +346,7 @@ void CWLSurfaceResource::map() { } void CWLSurfaceResource::unmap() { - if (!mapped) + if UNLIKELY (!mapped) return; mapped = false; @@ -385,10 +385,10 @@ CBox CWLSurfaceResource::extends() { } Vector2D CWLSurfaceResource::sourceSize() { - if (!current.texture) + if UNLIKELY (!current.texture) return {}; - if (current.viewport.hasSource) + if UNLIKELY (current.viewport.hasSource) return current.viewport.source.size(); Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.bufferSize.y, current.bufferSize.x} : current.bufferSize; @@ -396,7 +396,7 @@ Vector2D CWLSurfaceResource::sourceSize() { } CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { - if (!current.texture) + if UNLIKELY (!current.texture) return {}; CRegion surfaceDamage = current.damage; @@ -495,7 +495,7 @@ void CWLSurfaceResource::commitPendingState() { void CWLSurfaceResource::updateCursorShm(CRegion damage) { auto buf = current.buffer ? current.buffer->buffer : lastBuffer; - if (!buf) + if UNLIKELY (!buf) return; auto& shmData = CCursorSurfaceRole::cursorPixelData(self.lock()); @@ -545,7 +545,7 @@ void CWLSurfaceResource::presentFeedback(timespec* when, PHLMONITOR pMonitor, bo } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlCompositor* r) { PROTO::compositor->destroyResource(this); }); @@ -553,7 +553,7 @@ CWLCompositorResource::CWLCompositorResource(SP resource_) : reso resource->setCreateSurface([](CWlCompositor* r, uint32_t id) { const auto RESOURCE = PROTO::compositor->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::compositor->m_vSurfaces.pop_back(); return; @@ -569,7 +569,7 @@ CWLCompositorResource::CWLCompositorResource(SP resource_) : reso resource->setCreateRegion([](CWlCompositor* r, uint32_t id) { const auto RESOURCE = PROTO::compositor->m_vRegions.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::compositor->m_vRegions.pop_back(); return; @@ -592,7 +592,7 @@ CWLCompositorProtocol::CWLCompositorProtocol(const wl_interface* iface, const in void CWLCompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index fd3cd1fa..ade16498 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -15,7 +15,7 @@ #include "../../render/Renderer.hpp" CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setDestroy([this](CWlDataOffer* r) { PROTO::data->destroyResource(this); }); @@ -127,7 +127,7 @@ SP CWLDataOfferResource::getSource() { } CWLDataSourceResource::CWLDataSourceResource(SP resource_, SP device_) : device(device_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -237,7 +237,7 @@ eDataSourceType CWLDataSourceResource::type() { } CWLDataDeviceResource::CWLDataDeviceResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CWlDataDevice* r) { PROTO::data->destroyResource(this); }); @@ -333,7 +333,7 @@ SP CWLDataDeviceResource::getX11() { } CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlDataDeviceManager* r) { PROTO::data->destroyResource(this); }); @@ -343,7 +343,7 @@ CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SPm_vSources.emplace_back(makeShared(makeShared(r->client(), r->version(), id), device.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::data->m_vSources.pop_back(); return; @@ -362,7 +362,7 @@ CWLDataDeviceManagerResource::CWLDataDeviceManagerResource(SPsetGetDataDevice([this](CWlDataDeviceManager* r, uint32_t id, wl_resource* seat) { const auto RESOURCE = PROTO::data->m_vDevices.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::data->m_vDevices.pop_back(); return; @@ -394,7 +394,7 @@ CWLDataDeviceProtocol::CWLDataDeviceProtocol(const wl_interface* iface, const in void CWLDataDeviceProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; @@ -441,7 +441,7 @@ void CWLDataDeviceProtocol::sendSelectionToDevice(SP dev, SPgetWayland(); WL) { const auto OFFER = m_vOffers.emplace_back(makeShared(makeShared(WL->resource->client(), WL->resource->version(), 0), sel)); - if (!OFFER->good()) { + if UNLIKELY (!OFFER->good()) { WL->resource->noMemory(); m_vOffers.pop_back(); return; @@ -455,7 +455,7 @@ void CWLDataDeviceProtocol::sendSelectionToDevice(SP dev, SPpWM->createX11DataOffer(g_pSeatManager->state.keyboardFocus.lock(), sel); #endif - if (!offer) { + if UNLIKELY (!offer) { LOGM(ERR, "No offer could be created in sendSelectionToDevice"); return; } diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index db580457..77f0661e 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -4,7 +4,7 @@ #include "../../helpers/Monitor.hpp" CWLOutputResource::CWLOutputResource(SP resource_, PHLMONITOR pMonitor) : monitor(pMonitor), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setData(this); @@ -94,12 +94,12 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, } void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - if (defunct) + if UNLIKELY (defunct) Debug::log(WARN, "[wl_output] Binding a wl_output that's inert?? Possible client bug."); const auto RESOURCE = m_vOutputs.emplace_back(makeShared(makeShared(client, ver, id), monitor.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vOutputs.pop_back(); return; @@ -128,7 +128,7 @@ SP CWLOutputProtocol::outputResourceFrom(wl_client* client) { } void CWLOutputProtocol::remove() { - if (defunct) + if UNLIKELY (defunct) return; defunct = true; @@ -140,7 +140,7 @@ bool CWLOutputProtocol::isDefunct() { } void CWLOutputProtocol::sendDone() { - if (defunct) + if UNLIKELY (defunct) return; for (auto const& r : m_vOutputs) { diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index f7969a4d..c6b2de05 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -10,7 +10,7 @@ #include CWLTouchResource::CWLTouchResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CWlTouch* r) { PROTO::seat->destroyResource(this); }); @@ -105,7 +105,7 @@ void CWLTouchResource::sendOrientation(int32_t id, double angle) { } CWLPointerResource::CWLPointerResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CWlPointer* r) { PROTO::seat->destroyResource(this); }); @@ -292,7 +292,7 @@ void CWLPointerResource::sendAxisRelativeDirection(wl_pointer_axis axis, wl_poin } CWLKeyboardResource::CWLKeyboardResource(SP resource_, SP owner_) : owner(owner_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); @@ -419,7 +419,7 @@ void CWLKeyboardResource::repeatInfo(uint32_t rate, uint32_t delayMs) { } CWLSeatResource::CWLSeatResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlSeat* r) { @@ -436,7 +436,7 @@ CWLSeatResource::CWLSeatResource(SP resource_) : resource(resource_) { resource->setGetKeyboard([this](CWlSeat* r, uint32_t id) { const auto RESOURCE = PROTO::seat->m_vKeyboards.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::seat->m_vKeyboards.pop_back(); return; @@ -448,7 +448,7 @@ CWLSeatResource::CWLSeatResource(SP resource_) : resource(resource_) { resource->setGetPointer([this](CWlSeat* r, uint32_t id) { const auto RESOURCE = PROTO::seat->m_vPointers.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::seat->m_vPointers.pop_back(); return; @@ -460,7 +460,7 @@ CWLSeatResource::CWLSeatResource(SP resource_) : resource(resource_) { resource->setGetTouch([this](CWlSeat* r, uint32_t id) { const auto RESOURCE = PROTO::seat->m_vTouches.emplace_back(makeShared(makeShared(r->client(), r->version(), id), self.lock())); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::seat->m_vTouches.pop_back(); return; @@ -506,7 +506,7 @@ CWLSeatProtocol::CWLSeatProtocol(const wl_interface* iface, const int& ver, cons void CWLSeatProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vSeatResources.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vSeatResources.pop_back(); return; diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 6365c5d6..28585aeb 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -9,7 +9,7 @@ #include "../../render/Renderer.hpp" CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { - if (!pool_->pool->data) + if UNLIKELY (!pool_->pool->data) return; g_pHyprRenderer->makeEGLCurrent(); @@ -32,7 +32,7 @@ CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t of success = texture->m_iTexID; - if (!success) + if UNLIKELY (!success) Debug::log(ERR, "Failed creating a shm texture: null texture id"); } @@ -96,13 +96,13 @@ void CSHMPool::resize(size_t size_) { size = size_; data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) + if UNLIKELY (data == MAP_FAILED) LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); } static int shmIsSizeValid(int fd, size_t size) { struct stat st; - if (fstat(fd, &st) == -1) { + if UNLIKELY (fstat(fd, &st) == -1) { LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); return 0; } @@ -111,10 +111,10 @@ static int shmIsSizeValid(int fd, size_t size) { } CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; - if (!shmIsSizeValid(fd_, size_)) { + if UNLIKELY (!shmIsSizeValid(fd_, size_)) { resource_->error(-1, "The size of the file is not big enough for the shm pool"); return; } @@ -125,11 +125,11 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); resource->setResize([this](CWlShmPool* r, int32_t size_) { - if (size_ < (int32_t)pool->size) { + if UNLIKELY (size_ < (int32_t)pool->size) { r->error(-1, "Shrinking a shm pool is illegal"); return; } - if (!shmIsSizeValid(pool->fd, size_)) { + if UNLIKELY (!shmIsSizeValid(pool->fd, size_)) { r->error(-1, "The size of the file is not big enough for the shm pool"); return; } @@ -138,24 +138,24 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t }); resource->setCreateBuffer([this](CWlShmPool* r, uint32_t id, int32_t offset, int32_t w, int32_t h, int32_t stride, uint32_t fmt) { - if (!pool || !pool->data) { + if UNLIKELY (!pool || !pool->data) { r->error(-1, "The provided shm pool failed to allocate properly"); return; } - if (std::find(PROTO::shm->shmFormats.begin(), PROTO::shm->shmFormats.end(), fmt) == PROTO::shm->shmFormats.end()) { + if UNLIKELY (std::find(PROTO::shm->shmFormats.begin(), PROTO::shm->shmFormats.end(), fmt) == PROTO::shm->shmFormats.end()) { r->error(WL_SHM_ERROR_INVALID_FORMAT, "Format invalid"); return; } - if (offset < 0 || w <= 0 || h <= 0 || stride <= 0) { + if UNLIKELY (offset < 0 || w <= 0 || h <= 0 || stride <= 0) { r->error(WL_SHM_ERROR_INVALID_STRIDE, "Invalid stride, w, h, or offset"); return; } const auto RESOURCE = PROTO::shm->m_vBuffers.emplace_back(makeShared(self.lock(), id, offset, Vector2D{w, h}, stride, fmt)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::shm->m_vBuffers.pop_back(); return; @@ -165,7 +165,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t RESOURCE->resource->buffer = RESOURCE; }); - if (pool->data == MAP_FAILED) + if UNLIKELY (pool->data == MAP_FAILED) resource->error(WL_SHM_ERROR_INVALID_FD, "Couldn't mmap from fd"); } @@ -174,7 +174,7 @@ bool CWLSHMPoolResource::good() { } CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); @@ -182,7 +182,7 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::shm->m_vPools.pop_back(); return; @@ -221,7 +221,7 @@ void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, ui const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 46e20305..4edb07ff 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -4,7 +4,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SP surface_, SP parent_) : surface(surface_), parent(parent_), resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlSubsurface* r) { destroy(); }); @@ -142,7 +142,7 @@ SP CWLSubsurfaceResource::t1Parent() { } CWLSubcompositorResource::CWLSubcompositorResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlSubcompositor* r) { PROTO::subcompositor->destroyResource(this); }); @@ -152,12 +152,12 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource auto SURF = CWLSurfaceResource::fromResource(surface); auto PARENT = CWLSurfaceResource::fromResource(parent); - if (!SURF || !PARENT || SURF == PARENT) { + if UNLIKELY (!SURF || !PARENT || SURF == PARENT) { r->error(WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Invalid surface/parent"); return; } - if (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { + if UNLIKELY (SURF->role->role() != SURFACE_ROLE_UNASSIGNED) { r->error(-1, "Surface already has a different role"); return; } @@ -170,7 +170,7 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource } else t1Parent = PARENT; - if (t1Parent == SURF) { + if UNLIKELY (t1Parent == SURF) { r->error(WL_SUBCOMPOSITOR_ERROR_BAD_PARENT, "Bad parent, t1 parent == surf"); return; } @@ -178,7 +178,7 @@ CWLSubcompositorResource::CWLSubcompositorResource(SP resource const auto RESOURCE = PROTO::subcompositor->m_vSurfaces.emplace_back(makeShared(makeShared(r->client(), r->version(), id), SURF, PARENT)); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::subcompositor->m_vSurfaces.pop_back(); return; @@ -205,7 +205,7 @@ CWLSubcompositorProtocol::CWLSubcompositorProtocol(const wl_interface* iface, co void CWLSubcompositorProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); - if (!RESOURCE->good()) { + if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_vManagers.pop_back(); return; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 9f31f6a2..3f53225c 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -17,11 +17,11 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs auto eglImage = g_pHyprOpenGL->createEGLImage(attrs); - if (!eglImage) { + if UNLIKELY (!eglImage) { Debug::log(ERR, "CDMABuffer: failed to import EGLImage, retrying as implicit"); attrs.modifier = DRM_FORMAT_MOD_INVALID; eglImage = g_pHyprOpenGL->createEGLImage(attrs); - if (!eglImage) { + if UNLIKELY (!eglImage) { Debug::log(ERR, "CDMABuffer: failed to import EGLImage"); return; } @@ -31,7 +31,7 @@ CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs opaque = NFormatUtils::isFormatOpaque(attrs.format); success = texture->m_iTexID; - if (!success) + if UNLIKELY (!success) Debug::log(ERR, "Failed to create a dmabuf: texture is null"); } diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index a9e6400a..4bd115a2 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -6,7 +6,7 @@ #include CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { - if (!good()) + if UNLIKELY (!good()) return; resource->setOnDestroy([this](CWlBuffer* r) { From 76a899627ecff1f4fa3644ee06d8e1d279634850 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 17 Jan 2025 18:24:10 +0100 Subject: [PATCH 1071/2393] regex: log an error if regex parsing fails --- src/desktop/Rule.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/desktop/Rule.cpp b/src/desktop/Rule.cpp index dd1848d4..ae280642 100644 --- a/src/desktop/Rule.cpp +++ b/src/desktop/Rule.cpp @@ -1,11 +1,16 @@ #include "Rule.hpp" #include +#include "../debug/Log.hpp" CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) { const bool NEGATIVE = regex_.starts_with("negative:"); negative = NEGATIVE; regex = std::make_unique(NEGATIVE ? regex_.substr(9) : regex_); + + // TODO: maybe pop an error? + if (!regex->ok()) + Debug::log(ERR, "RuleRegexContainer: regex {} failed to parse!", regex_); } bool CRuleRegexContainer::passes(const std::string& str) const { From 401a3bae614ae4863da3e5cd5bf4d9997a893045 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 17 Jan 2025 18:28:53 +0100 Subject: [PATCH 1072/2393] core: fix warning in shadow --- src/render/decorations/CHyprDropShadowDecoration.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 022e123e..c576b966 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -56,7 +56,6 @@ void CHyprDropShadowDecoration::damageEntire() { static auto PSHADOWIGNOREWINDOW = CConfigValue("decoration:shadow:ignore_window"); const auto ROUNDING = PWINDOW->rounding(); - const auto ROUNDINGPOWER = PWINDOW->roundingPower(); const auto ROUNDINGSIZE = ROUNDING - M_SQRT1_2 * ROUNDING + 1; CRegion shadowRegion(shadowBox); From b65f8a87232c13697f0469fb7dfa31ff4f14af22 Mon Sep 17 00:00:00 2001 From: Beau Date: Fri, 17 Jan 2025 18:35:39 +0100 Subject: [PATCH 1073/2393] desktop/DesktopTypes.hpp: fix include (#9104) --- src/desktop/DesktopTypes.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/DesktopTypes.hpp b/src/desktop/DesktopTypes.hpp index ae2ac366..080f13d3 100644 --- a/src/desktop/DesktopTypes.hpp +++ b/src/desktop/DesktopTypes.hpp @@ -1,5 +1,5 @@ #pragma once -#include "helpers/memory/Memory.hpp" +#include "../helpers/memory/Memory.hpp" class CWorkspace; class CWindow; class CLayerSurface; From 47d645d84a7a290dc974cad552ee4912ca606069 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 17 Jan 2025 19:14:55 +0100 Subject: [PATCH 1074/2393] core: fixup includes --- src/config/ConfigManager.hpp | 12 ++++++------ src/helpers/Monitor.cpp | 2 +- src/helpers/WLClasses.hpp | 6 +++--- src/managers/AnimationManager.cpp | 8 ++++---- src/protocols/FocusGrab.hpp | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 1ba1df62..bef52584 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -16,12 +16,12 @@ #include "../desktop/LayerRule.hpp" #include "ConfigDataValues.hpp" -#include "SharedDefs.hpp" -#include "helpers/Color.hpp" -#include "desktop/DesktopTypes.hpp" -#include "helpers/memory/Memory.hpp" -#include "desktop/WindowRule.hpp" -#include "managers/XWaylandManager.hpp" +#include "../SharedDefs.hpp" +#include "../helpers/Color.hpp" +#include "../desktop/DesktopTypes.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../desktop/WindowRule.hpp" +#include "../managers/XWaylandManager.hpp" #include diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 718baf23..1f00e4ad 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1,6 +1,6 @@ #include "Monitor.hpp" #include "MiscFunctions.hpp" -#include "macros.hpp" +#include "../macros.hpp" #include "math/Math.hpp" #include "sync/SyncReleaser.hpp" #include "../Compositor.hpp" diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index c2e828e7..bedea065 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -4,9 +4,9 @@ #include "../desktop/Subsurface.hpp" #include "../desktop/Popup.hpp" #include "../desktop/WLSurface.hpp" -#include "macros.hpp" -#include "desktop/DesktopTypes.hpp" -#include "helpers/memory/Memory.hpp" +#include "../macros.hpp" +#include "../desktop/DesktopTypes.hpp" +#include "memory/Memory.hpp" #include "signal/Signal.hpp" class CMonitor; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 9cf35116..f884acdd 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -1,10 +1,10 @@ #include "AnimationManager.hpp" #include "../Compositor.hpp" #include "HookSystemManager.hpp" -#include "config/ConfigManager.hpp" -#include "desktop/DesktopTypes.hpp" -#include "helpers/AnimatedVariable.hpp" -#include "macros.hpp" +#include "../config/ConfigManager.hpp" +#include "../desktop/DesktopTypes.hpp" +#include "../helpers/AnimatedVariable.hpp" +#include "../macros.hpp" #include "../config/ConfigValue.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 6fe8780f..3c907ed0 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -2,7 +2,7 @@ #include "WaylandProtocol.hpp" #include "hyprland-focus-grab-v1.hpp" -#include "macros.hpp" +#include "../macros.hpp" #include #include #include From 078e13f463d56a4e773aa104bca5567b9e9c8658 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 17 Jan 2025 23:23:57 +0300 Subject: [PATCH 1075/2393] renderer: Auto enable wide color gamut in HDR mode (#9090) --- src/helpers/Monitor.hpp | 1 + src/render/Renderer.cpp | 29 ++++++++++++++++++++--------- src/render/Renderer.hpp | 1 - 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 3335a896..b33725d5 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -192,6 +192,7 @@ class CMonitor { bool m_bEnabled = false; bool m_bRenderingInitPassed = false; + WP m_previousFSWindow; // For the list lookup diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index fddb9a9a..384db1e6 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1466,12 +1466,6 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (inFD >= 0) pMonitor->output->state->setExplicitInFence(inFD); - static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); - if (pMonitor->output->state->state().wideColorGamut != *PWIDE) { - Debug::log(TRACE, "Setting wide color gamut {}", *PWIDE ? "on" : "off"); - pMonitor->output->state->setWideColorGamut(*PWIDE); - } - static auto PHDR = CConfigValue("experimental:hdr"); const bool SUPPORTSPQ = pMonitor->output->parsedEDID.hdrMetadata.has_value() ? pMonitor->output->parsedEDID.hdrMetadata->supportsPQ : false; @@ -1481,18 +1475,35 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); const auto SURF = WINDOW->m_pWLSurface->resource(); if (SURF->colorManagement.valid() && SURF->colorManagement->hasImageDescription()) { - bool needsHdrMetadataUpdate = SURF->colorManagement->needsHdrMetadataUpdate() || m_previousFSWindow != WINDOW; + bool needsHdrMetadataUpdate = SURF->colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != WINDOW; if (SURF->colorManagement->needsHdrMetadataUpdate()) SURF->colorManagement->setHDRMetadata(createHDRMetadata(SURF->colorManagement.get()->imageDescription(), pMonitor->output->parsedEDID)); if (needsHdrMetadataUpdate) pMonitor->output->state->setHDRMetadata(SURF->colorManagement->hdrMetadata()); } else if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR) pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); - m_previousFSWindow = WINDOW; + pMonitor->m_previousFSWindow = WINDOW; } else { if ((pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != *PHDR) pMonitor->output->state->setHDRMetadata(*PHDR ? createHDRMetadata(2, pMonitor->output->parsedEDID) : createHDRMetadata(0, pMonitor->output->parsedEDID)); - m_previousFSWindow.reset(); + pMonitor->m_previousFSWindow.reset(); + } + } + + static auto PWIDE = CConfigValue("experimental:wide_color_gamut"); + const bool needsWCG = *PWIDE || pMonitor->output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2; + if (pMonitor->output->state->state().wideColorGamut != needsWCG) { + Debug::log(TRACE, "Setting wide color gamut {}", needsWCG ? "on" : "off"); + pMonitor->output->state->setWideColorGamut(needsWCG); + + // FIXME do not trust enabled10bit, auto switch to 10bit and back if needed + if (needsWCG && !pMonitor->enabled10bit) { + Debug::log(WARN, "Wide color gamut is enabled but the display is not in 10bit mode"); + static bool shown = false; + if (!shown) { + g_pHyprNotificationOverlay->addNotification("Wide color gamut is enabled but the display is not in 10bit mode", CHyprColor{}, 15000, ICON_WARNING); + shown = true; + } } } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 6ba7a654..7aef96e6 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -130,7 +130,6 @@ class CHyprRenderer { bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); - WP m_previousFSWindow; bool m_bCursorHidden = false; bool m_bCursorHasSurface = false; SP m_pCurrentRenderbuffer = nullptr; From d01756c1f41977e852eba1cbf45c0149ae0f08e8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 18 Jan 2025 10:59:25 +0200 Subject: [PATCH 1076/2393] Meson: properly install 'hyprland' symlink (#9091) --- CMakeLists.txt | 11 +++++++++-- src/meson.build | 6 ++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1ecb14c..532f1d95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,15 @@ target_precompile_headers(Hyprland PRIVATE message(STATUS "Setting link libraries") -target_link_libraries(Hyprland rt PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep PkgConfig::deps) +target_link_libraries( + Hyprland + rt + PkgConfig::aquamarine_dep + PkgConfig::hyprlang_dep + PkgConfig::hyprutils_dep + PkgConfig::hyprcursor_dep + PkgConfig::hyprgraphics_dep + PkgConfig::deps) if(udis_dep_FOUND) target_link_libraries(Hyprland PkgConfig::udis_dep) else() @@ -369,7 +377,6 @@ install( ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \ \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \ )") - # session file install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions) diff --git a/src/meson.build b/src/meson.build index 2efc2213..7054d8e4 100644 --- a/src/meson.build +++ b/src/meson.build @@ -49,3 +49,9 @@ executable( ], install: true, ) + +install_symlink( + 'hyprland', + install_dir: get_option('bindir'), + pointing_to: 'Hyprland', +) From fdfcfc824e715d372b5cc6791d5e1b7c2bc4769b Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 18 Jan 2025 11:04:40 +0200 Subject: [PATCH 1077/2393] CMake, Meson: add option controlling hyprpm building --- CMakeLists.txt | 8 +++++++- meson.build | 5 ++++- meson_options.txt | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 532f1d95..a36d70fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -366,7 +366,13 @@ protocolwayland() # tools add_subdirectory(hyprctl) -add_subdirectory(hyprpm) + +if(NO_HYPRPM) + message(STATUS "hyprpm is disabled") +else() + add_subdirectory(hyprpm) + message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)") +endif() # binary and symlink install(TARGETS Hyprland) diff --git a/meson.build b/meson.build index d79a2845..6b50ff2d 100644 --- a/meson.build +++ b/meson.build @@ -101,11 +101,14 @@ endif subdir('protocols') subdir('src') subdir('hyprctl') -subdir('hyprpm/src') subdir('assets') subdir('example') subdir('docs') +if get_option('hyprpm').enabled() + subdir('hyprpm/src') +endif + # Generate hyprland.pc pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig') diff --git a/meson_options.txt b/meson_options.txt index 9b64fb32..3eb01696 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -2,4 +2,5 @@ option('xwayland', type: 'feature', value: 'auto', description: 'Enable support option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration') option('uwsm', type: 'feature', value: 'enabled', description: 'Enable uwsm integration (only if systemd is enabled)') option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer') +option('hyprpm', type: 'feature', value: 'enabled', description: 'Enable hyprpm') option('tracy_enable', type: 'boolean', value: false , description: 'Enable profiling') From a36fa5c229c175f47602f1b92d97e6a4dd3417a8 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 18 Jan 2025 11:05:05 +0200 Subject: [PATCH 1078/2393] Nix: disable hyprpm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It does not work properly on Nix anyway. If you were using hyprpm in some way before, please switch to using the `plugins` option in the HM module (and the upcoming option in the NixOS module, soon™). --- nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/default.nix b/nix/default.nix index 8e3af31d..a4ddc63b 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -163,6 +163,7 @@ in "xwayland" = enableXWayland; "legacy_renderer" = legacyRenderer; "uwsm" = false; + "hyprpm" = false; }) (mapAttrsToList mesonBool { "b_pch" = false; From f56153a9c1b0a00fac0932a95e0cfa5a4f6c681f Mon Sep 17 00:00:00 2001 From: Charlie Root Date: Sat, 18 Jan 2025 10:48:38 +0000 Subject: [PATCH 1079/2393] nix/module.nix: expand nixos module for configuring hyprland Expand the nixos module to be able to configure hyprland, just like the current home-manager module does. --- nix/module.nix | 205 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 198 insertions(+), 7 deletions(-) diff --git a/nix/module.nix b/nix/module.nix index 6f553893..46191dfa 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -7,15 +7,206 @@ inputs: { inherit (pkgs.stdenv.hostPlatform) system; cfg = config.programs.hyprland; - package = inputs.self.packages.${system}.hyprland; - portalPackage = inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override { - hyprland = cfg.finalPackage; - }; + # basically 1:1 taken from https://github.com/nix-community/home-manager/blob/master/modules/services/window-managers/hyprland.nix + toHyprconf = { + attrs, + indentLevel ? 0, + importantPrefixes ? ["$"], + }: let + inherit + (lib) + all + concatMapStringsSep + concatStrings + concatStringsSep + filterAttrs + foldl + generators + hasPrefix + isAttrs + isList + mapAttrsToList + replicate + ; + + initialIndent = concatStrings (replicate indentLevel " "); + + toHyprconf' = indent: attrs: let + sections = + filterAttrs (n: v: isAttrs v || (isList v && all isAttrs v)) attrs; + + mkSection = n: attrs: + if lib.isList attrs + then (concatMapStringsSep "\n" (a: mkSection n a) attrs) + else '' + ${indent}${n} { + ${toHyprconf' " ${indent}" attrs}${indent}} + ''; + + mkFields = generators.toKeyValue { + listsAsDuplicateKeys = true; + inherit indent; + }; + + allFields = + filterAttrs (n: v: !(isAttrs v || (isList v && all isAttrs v))) + attrs; + + isImportantField = n: _: + foldl (acc: prev: + if hasPrefix prev n + then true + else acc) + false + importantPrefixes; + + importantFields = filterAttrs isImportantField allFields; + + fields = + builtins.removeAttrs allFields + (mapAttrsToList (n: _: n) importantFields); + in + mkFields importantFields + + concatStringsSep "\n" (mapAttrsToList mkSection sections) + + mkFields fields; + in + toHyprconf' initialIndent attrs; in { - config = { + options = { programs.hyprland = { - package = lib.mkDefault package; - portalPackage = lib.mkDefault portalPackage; + plugins = lib.mkOption { + type = with lib.types; listOf (either package path); + default = []; + description = '' + List of Hyprland plugins to use. Can either be packages or + absolute plugin paths. + ''; + }; + + settings = lib.mkOption { + type = with lib.types; let + valueType = + nullOr (oneOf [ + bool + int + float + str + path + (attrsOf valueType) + (listOf valueType) + ]) + // { + description = "Hyprland configuration value"; + }; + in + valueType; + default = {}; + description = '' + Hyprland configuration written in Nix. Entries with the same key + should be written as lists. Variables' and colors' names should be + quoted. See for more examples. + + ::: {.note} + Use the [](#programs.hyprland.plugins) option to + declare plugins. + ::: + + ''; + example = lib.literalExpression '' + { + decoration = { + shadow_offset = "0 5"; + "col.shadow" = "rgba(00000099)"; + }; + + "$mod" = "SUPER"; + + bindm = [ + # mouse movements + "$mod, mouse:272, movewindow" + "$mod, mouse:273, resizewindow" + "$mod ALT, mouse:272, resizewindow" + ]; + } + ''; + }; + + extraConfig = lib.mkOption { + type = lib.types.lines; + default = ""; + example = '' + # window resize + bind = $mod, S, submap, resize + + submap = resize + binde = , right, resizeactive, 10 0 + binde = , left, resizeactive, -10 0 + binde = , up, resizeactive, 0 -10 + binde = , down, resizeactive, 0 10 + bind = , escape, submap, reset + submap = reset + ''; + description = '' + Extra configuration lines to add to `/etc/xdg/hypr/hyprland.conf`. + ''; + }; + + sourceFirst = + lib.mkEnableOption '' + putting source entries at the top of the configuration + '' + // { + default = true; + }; + + importantPrefixes = lib.mkOption { + type = with lib.types; listOf str; + default = ["$" "bezier" "name"] ++ lib.optionals cfg.sourceFirst ["source"]; + example = ["$" "bezier"]; + description = '' + List of prefix of attributes to source at the top of the config. + ''; + }; }; }; + config = lib.mkMerge [ + { + programs.hyprland = { + package = lib.mkDefault inputs.self.packages.${system}.hyprland; + portalPackage = lib.mkDefault (inputs.self.packages.${system}.xdg-desktop-portal-hyprland.override { + hyprland = cfg.finalPackage; + }); + }; + } + (lib.mkIf cfg.enable { + environment.etc."xdg/hypr/hyprland.conf" = let + shouldGenerate = cfg.extraConfig != "" || cfg.settings != {} || cfg.plugins != []; + + pluginsToHyprconf = plugins: + toHyprconf { + attrs = { + plugin = let + mkEntry = entry: + if lib.types.package.check entry + then "${entry}/lib/lib${entry.pname}.so" + else entry; + in + map mkEntry cfg.plugins; + }; + inherit (cfg) importantPrefixes; + }; + in + lib.mkIf shouldGenerate { + text = + lib.optionalString (cfg.plugins != []) + (pluginsToHyprconf cfg.plugins) + + lib.optionalString (cfg.settings != {}) + (toHyprconf { + attrs = cfg.settings; + inherit (cfg) importantPrefixes; + }) + + lib.optionalString (cfg.extraConfig != "") cfg.extraConfig; + }; + }) + ]; } From 4da9b7cc5b50c346309378fbb5ae8aa07746fd33 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sun, 19 Jan 2025 10:38:42 +0000 Subject: [PATCH 1080/2393] core: reserve vector sizes as much as we can (#9118) avoid reallocations as much as possible with a few edge cases where the reservation overshoots a tiny bit. but a few bytes of memory short term is better used then the overhead of potential reallocation. --- src/Compositor.cpp | 6 ++---- src/desktop/Window.cpp | 2 ++ src/managers/KeybindManager.cpp | 4 +--- src/protocols/DRMLease.cpp | 3 +++ src/protocols/GlobalShortcuts.cpp | 15 +++++++++++++-- src/protocols/Screencopy.cpp | 2 ++ src/protocols/ToplevelExport.cpp | 2 ++ src/render/OpenGL.cpp | 14 +++++++++++--- src/render/decorations/DecorationPositioner.cpp | 3 +++ src/xwayland/Dnd.cpp | 2 ++ src/xwayland/XWM.cpp | 4 ++++ 11 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 496ca4fe..889ae181 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2785,11 +2785,9 @@ PHLWINDOW CCompositor::getForceFocus() { void CCompositor::arrangeMonitors() { static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling"); - std::vector toArrange; + std::vector toArrange(m_vMonitors.begin(), m_vMonitors.end()); std::vector arranged; - - for (auto const& m : m_vMonitors) - toArrange.push_back(m); + arranged.reserve(toArrange.size()); Debug::log(LOG, "arrangeMonitors: {} to arrange", toArrange.size()); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 241a17d7..829f4e2e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -282,6 +282,8 @@ void CWindow::updateWindowDecos() { // make a copy because updateWindow can remove decos. std::vector decos; + // reserve to avoid reallocations + decos.reserve(m_dWindowDecorations.size()); for (auto const& wd : m_dWindowDecorations) { decos.push_back(wd.get()); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index a1979206..65891840 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1891,9 +1891,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { // apply // we make a copy because changeWindowFloatingMode might invalidate the iterator - std::vector ptrs; - for (auto const& w : g_pCompositor->m_vWindows) - ptrs.push_back(w); + std::vector ptrs(g_pCompositor->m_vWindows.begin(), g_pCompositor->m_vWindows.end()); for (auto const& w : ptrs) { if (!w->m_bIsMapped || w->m_pWorkspace != PWORKSPACE || w->isHidden()) diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index fce1e345..6fdbaf4b 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -34,6 +34,9 @@ CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP> outputs; + // reserve to avoid reallocations + outputs.reserve(requested.size()); + for (auto const& m : requested) { outputs.emplace_back(m->monitor->output); } diff --git a/src/protocols/GlobalShortcuts.cpp b/src/protocols/GlobalShortcuts.cpp index 6fac2d7f..9f8f422c 100644 --- a/src/protocols/GlobalShortcuts.cpp +++ b/src/protocols/GlobalShortcuts.cpp @@ -83,8 +83,19 @@ void CGlobalShortcutsProtocol::sendGlobalShortcutEvent(std::string appid, std::s std::vector CGlobalShortcutsProtocol::getAllShortcuts() { std::vector copy; - for (auto const& c : m_vClients) { - for (auto const& sh : c->shortcuts) { + // calculate the total number of shortcuts, precomputing size is linear + // and potential reallocation is more costly then the added precompute overhead of looping + // and finding the total size. + size_t totalShortcuts = 0; + for (const auto& c : m_vClients) { + totalShortcuts += c->shortcuts.size(); + } + + // reserve number of elements to avoid reallocations + copy.reserve(totalShortcuts); + + for (const auto& c : m_vClients) { + for (const auto& sh : c->shortcuts) { copy.push_back(*sh); } } diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8bdaf8f9..5cf54eb4 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -412,6 +412,8 @@ void CScreencopyProtocol::onOutputCommit(PHLMONITOR pMonitor) { } std::vector> framesToRemove; + // reserve number of elements to avoid reallocations + framesToRemove.reserve(m_vFramesAwaitingWrite.size()); // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 2d40cb78..fb49f722 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -393,6 +393,8 @@ void CToplevelExportProtocol::onOutputCommit(PHLMONITOR pMonitor) { return; // nothing to share std::vector> framesToRemove; + // reserve number of elements to avoid reallocations + framesToRemove.reserve(m_vFramesAwaitingWrite.size()); // share frame if correct output for (auto const& f : m_vFramesAwaitingWrite) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index c5bb3620..ceb94c81 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -400,7 +400,10 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len); std::vector result; - bool linearIsExternal = false; + // reserve number of elements to avoid reallocations + result.reserve(mods.size()); + + bool linearIsExternal = false; for (size_t i = 0; i < mods.size(); ++i) { if (external.at(i)) { if (mods.at(i) == DRM_FORMAT_MOD_LINEAR) @@ -449,6 +452,8 @@ void CHyprOpenGLImpl::initDRMFormats() { Debug::log(LOG, "Supported DMA-BUF formats:"); std::vector dmaFormats; + // reserve number of elements to avoid reallocations + dmaFormats.reserve(formats.size()); for (auto const& fmt : formats) { std::vector mods; @@ -472,8 +477,10 @@ void CHyprOpenGLImpl::initDRMFormats() { }); std::vector> modifierData; + // reserve number of elements to avoid reallocations + modifierData.reserve(mods.size()); - auto fmtName = drmGetFormatName(fmt); + auto fmtName = drmGetFormatName(fmt); Debug::log(LOG, "EGL: GPU Supports Format {} (0x{:x})", fmtName ? fmtName : "?unknown?", fmt); for (auto const& mod : mods) { auto modName = drmGetFormatModifierName(mod); @@ -2942,7 +2949,8 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; } - + // reserve number of elements to avoid reallocations + attribs.reserve(3); attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); attribs.push_back(dupFd); attribs.push_back(EGL_NONE); diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index c2d34fb6..2ba3c4a7 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -122,6 +122,9 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { // std::vector datas; + // reserve to avoid reallocations + datas.reserve(pWindow->m_dWindowDecorations.size()); + for (auto const& wd : pWindow->m_dWindowDecorations) { datas.push_back(getDataFor(wd.get(), pWindow)); } diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index 58fc6db3..d4ae3780 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -75,6 +75,8 @@ void CX11DataDevice::sendEnter(uint32_t serial, SP surf, con data.data32[1] |= 1; std::vector targets; + // reserve to avoid reallocations + targets.reserve(SOURCE->mimes().size()); for (auto& mime : SOURCE->mimes()) { targets.emplace_back(g_pXWayland->pWM->mimeToAtom(mime)); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 44485381..ae8e0ccc 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -643,6 +643,8 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { Debug::log(WARN, "[xwm] WARNING: No mimes in TARGETS?"); std::vector atoms; + // reserve to avoid reallocations + atoms.reserve(mimes.size() + 2); atoms.push_back(HYPRATOMS["TIMESTAMP"]); atoms.push_back(HYPRATOMS["TARGETS"]); @@ -989,6 +991,8 @@ void CXWM::sendState(SP surf) { } std::vector props; + // reserve to avoid reallocations + props.reserve(6); // props below if (surf->modal) props.push_back(HYPRATOMS["_NET_WM_STATE_MODAL"]); if (surf->fullscreen) From 086fd7ece8cc8904909f5a597ab69fe73ecac34c Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 19 Jan 2025 04:51:42 -0800 Subject: [PATCH 1081/2393] protocols: do not destroy screencopy resources before client request (#9048) --- src/protocols/Screencopy.cpp | 4 ---- src/protocols/ToplevelExport.cpp | 6 ------ 2 files changed, 10 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 5cf54eb4..e0e3a559 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -28,7 +28,6 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t if (!pMonitor) { LOGM(ERR, "Client requested sharing of a monitor that doesnt exist"); resource->sendFailed(); - PROTO::screencopy->destroyResource(this); return; } @@ -46,7 +45,6 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t if (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture output"); resource->sendFailed(); - PROTO::screencopy->destroyResource(this); return; } @@ -58,7 +56,6 @@ CScreencopyFrame::CScreencopyFrame(SP resource_, int32_t if (!PSHMINFO) { LOGM(ERR, "No pixel format supported by renderer in capture output"); resource->sendFailed(); - PROTO::screencopy->destroyResource(this); return; } @@ -93,7 +90,6 @@ void CScreencopyFrame::copy(CZwlrScreencopyFrameV1* pFrame, wl_resource* buffer_ if UNLIKELY (!g_pCompositor->monitorExists(pMonitor.lock())) { LOGM(ERR, "Client requested sharing of a monitor that is gone"); resource->sendFailed(); - PROTO::screencopy->destroyResource(this); return; } diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index fb49f722..8b835b50 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -86,14 +86,12 @@ CToplevelExportFrame::CToplevelExportFrame(SP re if UNLIKELY (!pWindow) { LOGM(ERR, "Client requested sharing of window handle {:x} which does not exist!", pWindow); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } if UNLIKELY (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable!", pWindow); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } @@ -109,7 +107,6 @@ CToplevelExportFrame::CToplevelExportFrame(SP re if UNLIKELY (shmFormat == DRM_FORMAT_INVALID) { LOGM(ERR, "No format supported by renderer in capture toplevel"); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } @@ -117,7 +114,6 @@ CToplevelExportFrame::CToplevelExportFrame(SP re if UNLIKELY (!PSHMINFO) { LOGM(ERR, "No pixel format supported by renderer in capture toplevel"); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } @@ -146,14 +142,12 @@ void CToplevelExportFrame::copy(CHyprlandToplevelExportFrameV1* pFrame, wl_resou if UNLIKELY (!validMapped(pWindow)) { LOGM(ERR, "Client requested sharing of window handle {:x} which is gone!", pWindow); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } if UNLIKELY (!pWindow->m_bIsMapped) { LOGM(ERR, "Client requested sharing of window handle {:x} which is not shareable (2)!", pWindow); resource->sendFailed(); - PROTO::toplevelExport->destroyResource(this); return; } From 0a0e56d99c3b5f900ec561b3fe9a3c8a64fe1217 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 19 Jan 2025 14:02:47 +0100 Subject: [PATCH 1082/2393] core: use readFileAsString instead of cat for os-release --- src/helpers/MiscFunctions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index fafe1811..5ebb0842 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -5,6 +5,7 @@ #include "../managers/TokenManager.hpp" #include "Monitor.hpp" #include "../config/ConfigManager.hpp" +#include "fs/FsUtils.hpp" #include #include #include @@ -621,7 +622,7 @@ void logSystemInfo() { // log etc Debug::log(LOG, "os-release:"); - Debug::log(NONE, "{}", execAndGet("cat /etc/os-release")); + Debug::log(NONE, "{}", NFsUtils::readFileAsString("/etc/os-release").value_or("error")); } int64_t getPPIDof(int64_t pid) { From 8dd2cd41fb4c5a5eb6886cc190419b36084cabfa Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 19 Jan 2025 15:39:19 +0100 Subject: [PATCH 1083/2393] core: move to inotify for monitoring the config files instead of manually polling every second which is not efficient, use inotify. an added bonus is that inotify is much much faster --- src/Compositor.cpp | 7 +- src/Compositor.hpp | 1 - src/config/ConfigManager.cpp | 70 +++++--------------- src/config/ConfigManager.hpp | 7 +- src/config/ConfigWatcher.cpp | 72 +++++++++++++++++++++ src/config/ConfigWatcher.hpp | 32 +++++++++ src/debug/HyprCtl.cpp | 7 +- src/managers/ThreadManager.cpp | 26 -------- src/managers/ThreadManager.hpp | 16 ----- src/managers/eventLoop/EventLoopManager.cpp | 11 ++++ src/managers/eventLoop/EventLoopManager.hpp | 2 + src/plugins/PluginAPI.cpp | 3 +- src/plugins/PluginSystem.cpp | 5 +- 13 files changed, 143 insertions(+), 116 deletions(-) create mode 100644 src/config/ConfigWatcher.cpp create mode 100644 src/config/ConfigWatcher.hpp delete mode 100644 src/managers/ThreadManager.cpp delete mode 100644 src/managers/ThreadManager.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 889ae181..325bd882 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -4,6 +4,7 @@ #include "debug/Log.hpp" #include "helpers/Splashes.hpp" #include "config/ConfigValue.hpp" +#include "config/ConfigWatcher.hpp" #include "managers/CursorManager.hpp" #include "managers/TokenManager.hpp" #include "managers/PointerManager.hpp" @@ -44,7 +45,6 @@ #include "managers/KeybindManager.hpp" #include "managers/SessionLockManager.hpp" -#include "managers/ThreadManager.hpp" #include "managers/XWaylandManager.hpp" #include "config/ConfigManager.hpp" @@ -551,7 +551,6 @@ void CCompositor::cleanup() { g_pProtocolManager.reset(); g_pHyprRenderer.reset(); g_pHyprOpenGL.reset(); - g_pThreadManager.reset(); g_pConfigManager.reset(); g_pLayoutManager.reset(); g_pHyprError.reset(); @@ -567,6 +566,7 @@ void CCompositor::cleanup() { g_pEventLoopManager.reset(); g_pVersionKeeperMgr.reset(); g_pDonationNagManager.reset(); + g_pConfigWatcher.reset(); if (m_pAqBackend) m_pAqBackend.reset(); @@ -631,9 +631,6 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pSeatManager = std::make_unique(); } break; case STAGE_LATE: { - Debug::log(LOG, "Creating the ThreadManager!"); - g_pThreadManager = std::make_unique(); - Debug::log(LOG, "Creating CHyprCtl"); g_pHyprCtl = std::make_unique(); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 0a701a59..430e583c 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -5,7 +5,6 @@ #include #include "defines.hpp" -#include "managers/ThreadManager.hpp" #include "managers/XWaylandManager.hpp" #include "managers/KeybindManager.hpp" #include "managers/SessionLockManager.hpp" diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 52f2e316..ebeb2397 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1,6 +1,7 @@ #include #include "ConfigManager.hpp" +#include "ConfigWatcher.hpp" #include "../managers/KeybindManager.hpp" #include "../Compositor.hpp" @@ -372,8 +373,8 @@ static Hyprlang::CParseResult handlePlugin(const char* c, const char* v) { CConfigManager::CConfigManager() { const auto ERR = verifyConfigExists(); - configPaths.emplace_back(getMainConfigPath()); - m_pConfig = std::make_unique(configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); + m_configPaths.emplace_back(getMainConfigPath()); + m_pConfig = std::make_unique(m_configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); m_pConfig->addConfigValue("general:border_size", Hyprlang::INT{1}); m_pConfig->addConfigValue("general:no_border_on_floating", Hyprlang::INT{0}); @@ -795,7 +796,7 @@ std::string CConfigManager::getConfigString() { std::string configString; std::string currFileContent; - for (const auto& path : configPaths) { + for (const auto& path : m_configPaths) { std::ifstream configFile(path); configString += ("\n\nConfig File: " + path + ": "); if (!configFile.is_open()) { @@ -883,10 +884,10 @@ std::optional CConfigManager::resetHLConfig() { finalExecRequests.clear(); // paths - configPaths.clear(); + m_configPaths.clear(); std::string mainConfigPath = getMainConfigPath(); Debug::log(LOG, "Using config: {}", mainConfigPath); - configPaths.push_back(mainConfigPath); + m_configPaths.emplace_back(mainConfigPath); const auto RET = verifyConfigExists(); @@ -897,6 +898,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static int prevEnabledExplicit = *PENABLEEXPLICIT; + g_pConfigWatcher->setWatchList(m_configPaths); + for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); } @@ -1029,17 +1032,14 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { void CConfigManager::init() { + g_pConfigWatcher->setOnChange([this](const CConfigWatcher::SConfigWatchEvent& e) { + Debug::log(LOG, "CConfigManager: file {} modified, reloading", e.file); + reload(); + }); + const std::string CONFIGPATH = getMainConfigPath(); reload(); - struct stat fileStat; - int err = stat(CONFIGPATH.c_str(), &fileStat); - if (err != 0) { - Debug::log(WARN, "Error at statting config, error {}", errno); - } - - configModifyTimes[CONFIGPATH] = fileStat.st_mtime; - isFirstLaunch = false; } @@ -1080,37 +1080,6 @@ std::string CConfigManager::parseKeyword(const std::string& COMMAND, const std:: return RET.error ? RET.getError() : ""; } -void CConfigManager::tick() { - std::string CONFIGPATH = getMainConfigPath(); - if (!std::filesystem::exists(CONFIGPATH)) { - Debug::log(ERR, "Config doesn't exist??"); - return; - } - - bool parse = false; - - for (auto const& cf : configPaths) { - struct stat fileStat; - int err = stat(cf.c_str(), &fileStat); - if (err != 0) { - Debug::log(WARN, "Error at ticking config at {}, error {}: {}", cf, err, strerror(err)); - continue; - } - - // check if we need to reload cfg - if (fileStat.st_mtime != configModifyTimes[cf] || m_bForceReload) { - parse = true; - configModifyTimes[cf] = fileStat.st_mtime; - } - } - - if (parse) { - m_bForceReload = false; - - reload(); - } -} - Hyprlang::CConfigValue* CConfigManager::getConfigValueSafeDevice(const std::string& dev, const std::string& val, const std::string& fallback) { const auto VAL = m_pConfig->getSpecialConfigValuePtr("device", val.c_str(), dev.c_str()); @@ -1719,8 +1688,7 @@ void CConfigManager::handlePluginLoads() { if (pluginsChanged) { g_pHyprError->destroy(); - m_bForceReload = true; - tick(); + reload(); } } @@ -2732,16 +2700,8 @@ std::optional CConfigManager::handleSource(const std::string& comma Debug::log(ERR, "source= file doesn't exist: {}", value); return "source= file " + value + " doesn't exist!"; } - configPaths.push_back(value); + m_configPaths.emplace_back(value); - struct stat fileStat; - int err = stat(value.c_str(), &fileStat); - if (err != 0) { - Debug::log(WARN, "Error at ticking config at {}, error {}: {}", value, err, strerror(err)); - return {}; - } - - configModifyTimes[value] = fileStat.st_mtime; auto configCurrentPathBackup = configCurrentPath; configCurrentPath = value; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index bef52584..1962e4d2 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -142,8 +142,8 @@ class CConfigManager { public: CConfigManager(); - void tick(); void init(); + void reload(); int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = ""); @@ -258,15 +258,13 @@ class CConfigManager { {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}}; bool m_bWantsMonitorReload = false; - bool m_bForceReload = false; bool m_bNoMonitorReload = false; bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking private: std::unique_ptr m_pConfig; - std::vector configPaths; // stores all the config paths - std::unordered_map configModifyTimes; // stores modify times + std::vector m_configPaths; Hyprutils::Animation::CAnimationConfigTree m_AnimationTree; @@ -302,7 +300,6 @@ class CConfigManager { std::optional generateConfig(std::string configPath); std::optional verifyConfigExists(); void postConfigReload(const Hyprlang::CParseResult& result); - void reload(); SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); }; diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp new file mode 100644 index 00000000..38191e9e --- /dev/null +++ b/src/config/ConfigWatcher.cpp @@ -0,0 +1,72 @@ +#include "ConfigWatcher.hpp" +#include +#include "../debug/Log.hpp" +#include +#include + +CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { + if (m_inotifyFd < 0) { + Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); + return; + } + + const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); + if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); + close(m_inotifyFd); + m_inotifyFd = -1; + return; + } +} + +CConfigWatcher::~CConfigWatcher() { + if (m_inotifyFd >= 0) + close(m_inotifyFd); +} + +int CConfigWatcher::getInotifyFD() { + return m_inotifyFd; +} + +void CConfigWatcher::setWatchList(const std::vector& paths) { + + // we clear all watches first, because whichever fired is now invalid + // or that is at least what it seems to be. + // since we don't know which fired, + // plus it doesn't matter that much, these ops are done rarely and fast anyways. + + // cleanup old paths + for (auto& watch : m_watches) { + inotify_rm_watch(m_inotifyFd, watch.wd); + } + + m_watches.clear(); + + // add new paths + for (const auto& path : paths) { + m_watches.emplace_back(SInotifyWatch{ + .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .file = path, + }); + } +} + +void CConfigWatcher::setOnChange(const std::function& fn) { + m_watchCallback = fn; +} + +void CConfigWatcher::onInotifyEvent() { + inotify_event ev; + while (read(m_inotifyFd, &ev, sizeof(ev)) > 0) { + const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); + + if (WD == m_watches.end()) { + Debug::log(ERR, "CConfigWatcher: got an event for wd {} which we don't have?!", ev.wd); + return; + } + + m_watchCallback(SConfigWatchEvent{ + .file = WD->file, + }); + } +} diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp new file mode 100644 index 00000000..0a698fc8 --- /dev/null +++ b/src/config/ConfigWatcher.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include + +class CConfigWatcher { + public: + CConfigWatcher(); + ~CConfigWatcher(); + + struct SConfigWatchEvent { + std::string file; + }; + + int getInotifyFD(); + void setWatchList(const std::vector& paths); + void setOnChange(const std::function& fn); + void onInotifyEvent(); + + private: + struct SInotifyWatch { + int wd = -1; + std::string file; + }; + + std::function m_watchCallback; + std::vector m_watches; + int m_inotifyFd = -1; +}; + +inline std::unique_ptr g_pConfigWatcher = std::make_unique(); \ No newline at end of file diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 41b0abe1..cfdba100 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1121,13 +1121,10 @@ static std::string reloadRequest(eHyprCtlOutputFormat format, std::string reques const auto REQMODE = request.substr(request.find_last_of(' ') + 1); - g_pConfigManager->m_bForceReload = true; - - if (REQMODE == "config-only") { + if (REQMODE == "config-only") g_pConfigManager->m_bNoMonitorReload = true; - } - g_pConfigManager->tick(); + g_pConfigManager->reload(); return "ok"; } diff --git a/src/managers/ThreadManager.cpp b/src/managers/ThreadManager.cpp deleted file mode 100644 index bd124c99..00000000 --- a/src/managers/ThreadManager.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "ThreadManager.hpp" -#include "../debug/HyprCtl.hpp" -#include "../Compositor.hpp" -#include "../config/ConfigValue.hpp" - -static int handleTimer(void* data) { - const auto PTM = (CThreadManager*)data; - - static auto PDISABLECFGRELOAD = CConfigValue("misc:disable_autoreload"); - - if (*PDISABLECFGRELOAD != 1) - g_pConfigManager->tick(); - - wl_event_source_timer_update(PTM->m_esConfigTimer, 1000); - - return 0; -} - -CThreadManager::CThreadManager() : m_esConfigTimer(wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this)) { - wl_event_source_timer_update(m_esConfigTimer, 1000); -} - -CThreadManager::~CThreadManager() { - if (m_esConfigTimer) - wl_event_source_remove(m_esConfigTimer); -} diff --git a/src/managers/ThreadManager.hpp b/src/managers/ThreadManager.hpp deleted file mode 100644 index 13e2fcd8..00000000 --- a/src/managers/ThreadManager.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "../defines.hpp" -struct wl_event_source; - -class CThreadManager { - public: - CThreadManager(); - ~CThreadManager(); - - wl_event_source* m_esConfigTimer = nullptr; - - private: -}; - -inline std::unique_ptr g_pThreadManager; \ No newline at end of file diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index db8b49b6..f98efc92 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -1,6 +1,7 @@ #include "EventLoopManager.hpp" #include "../../debug/Log.hpp" #include "../../Compositor.hpp" +#include "../../config/ConfigWatcher.hpp" #include #include @@ -27,6 +28,8 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sWayland.eventSource); if (m_sIdle.eventSource) wl_event_source_remove(m_sIdle.eventSource); + if (m_configWatcherInotifySource) + wl_event_source_remove(m_configWatcherInotifySource); if (m_sTimers.timerfd >= 0) close(m_sTimers.timerfd); } @@ -42,9 +45,17 @@ static int aquamarineFDWrite(int fd, uint32_t mask, void* data) { return 1; } +static int configWatcherWrite(int fd, uint32_t mask, void* data) { + g_pConfigWatcher->onInotifyEvent(); + return 0; +} + void CEventLoopManager::enterLoop() { m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) + m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); + aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); for (auto const& fd : aqPollFDs) { m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 39d8bbeb..90402de2 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -51,6 +51,8 @@ class CEventLoopManager { SIdleData m_sIdle; std::vector> aqPollFDs; + wl_event_source* m_configWatcherInotifySource = nullptr; + friend class CSyncTimeline; }; diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index b6bbc460..fbb1ec1b 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -4,6 +4,7 @@ #include "../plugins/PluginSystem.hpp" #include "../managers/HookSystemManager.hpp" #include "../managers/LayoutManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../config/ConfigManager.hpp" #include "../debug/HyprNotificationOverlay.hpp" #include @@ -72,7 +73,7 @@ APICALL bool HyprlandAPI::removeLayout(HANDLE handle, IHyprLayout* layout) { } APICALL bool HyprlandAPI::reloadConfig() { - g_pConfigManager->m_bForceReload = true; + g_pEventLoopManager->doLater([] { g_pConfigManager->reload(); }); return true; } diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index ce7dd7c7..e849bf11 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -5,6 +5,7 @@ #include "../config/ConfigManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/HookSystemManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" CPluginSystem::CPluginSystem() { g_pFunctionHookSystem = std::make_unique(); @@ -82,7 +83,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) { PLUGIN->version = PLUGINDATA.version; PLUGIN->name = PLUGINDATA.name; - g_pConfigManager->m_bForceReload = true; + g_pEventLoopManager->doLater([] { g_pConfigManager->reload(); }); Debug::log(LOG, R"( [PluginSystem] Plugin {} loaded. Handle: {:x}, path: "{}", author: "{}", description: "{}", version: "{}")", PLUGINDATA.name, (uintptr_t)MODULE, path, PLUGINDATA.author, PLUGINDATA.description, PLUGINDATA.version); @@ -137,7 +138,7 @@ void CPluginSystem::unloadPlugin(const CPlugin* plugin, bool eject) { Debug::log(LOG, " [PluginSystem] Plugin {} unloaded.", PLNAME); // reload config to fix some stuf like e.g. unloadedPluginVars - g_pConfigManager->m_bForceReload = true; + g_pEventLoopManager->doLater([] { g_pConfigManager->reload(); }); } void CPluginSystem::unloadAllPlugins() { From 407453166ce2a52433c7b0b4ee92a41e47ef8f6d Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sun, 19 Jan 2025 18:21:36 +0000 Subject: [PATCH 1084/2393] protocols: add hyprland_lock_notify_v1 implementation (#9092) --- CMakeLists.txt | 3 +- flake.lock | 6 +-- protocols/meson.build | 3 +- src/managers/ProtocolManager.cpp | 5 +- src/protocols/LockNotify.cpp | 88 ++++++++++++++++++++++++++++++++ src/protocols/LockNotify.hpp | 50 ++++++++++++++++++ src/protocols/SessionLock.cpp | 4 ++ subprojects/hyprland-protocols | 2 +- 8 files changed, 154 insertions(+), 7 deletions(-) create mode 100644 src/protocols/LockNotify.cpp create mode 100644 src/protocols/LockNotify.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a36d70fe..c022f3ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,7 +298,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) -pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.0) if(hyprland_protocols_dep_FOUND) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") @@ -329,6 +329,7 @@ protocolnew("protocols" "frog-color-management-v1" true) protocolnew("protocols" "wayland-drm" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true) protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false) diff --git a/flake.lock b/flake.lock index f16ecaa7..7b85bd17 100644 --- a/flake.lock +++ b/flake.lock @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1735774328, - "narHash": "sha256-vIRwLS9w+N99EU1aJ+XNOU6mJTxrUBa31i1r82l0V7s=", + "lastModified": 1737127640, + "narHash": "sha256-mIQ3/axCZ4g8ySwWRbW4fJcyC9v55uAii3cqlJRtW8g=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "e3b6af97ddcfaafbda8e2828c719a5af84f662cb", + "rev": "455c055883d9639d4fcbfcedb4c6d12ce313791e", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index fdbbf181..aa20940d 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,7 +7,7 @@ wayland_protos = dependency( hyprland_protos = dependency( 'hyprland-protocols', - version: '>=0.4', + version: '>=0.6', fallback: 'hyprland-protocols', ) @@ -40,6 +40,7 @@ protocols = [ hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml', + hyprland_protocol_dir / 'protocols/hyprland-lock-notify-v1.xml', wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml', wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml', wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index b7d61f67..8e32bdec 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -20,6 +20,7 @@ #include "../protocols/OutputPower.hpp" #include "../protocols/XDGActivation.hpp" #include "../protocols/IdleNotify.hpp" +#include "../protocols/LockNotify.hpp" #include "../protocols/SessionLock.hpp" #include "../protocols/InputMethodV2.hpp" #include "../protocols/VirtualKeyboard.hpp" @@ -145,6 +146,7 @@ CProtocolManager::CProtocolManager() { PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation"); PROTO::idle = std::make_unique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); + PROTO::lockNotify = std::make_unique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = std::make_unique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); PROTO::virtualKeyboard = std::make_unique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); @@ -224,6 +226,7 @@ CProtocolManager::~CProtocolManager() { PROTO::outputPower.reset(); PROTO::activation.reset(); PROTO::idle.reset(); + PROTO::lockNotify.reset(); PROTO::sessionLock.reset(); PROTO::ime.reset(); PROTO::virtualKeyboard.reset(); @@ -296,7 +299,7 @@ bool CProtocolManager::isGlobalPrivileged(const wl_global* global) { PROTO::xdgDialog->getGlobal(), PROTO::singlePixel->getGlobal(), PROTO::primarySelection->getGlobal(), - PROTO::hyprlandSurface->getGlobal(), + PROTO::hyprlandSurface->getGlobal(), PROTO::sync ? PROTO::sync->getGlobal() : nullptr, PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr, PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr, diff --git a/src/protocols/LockNotify.cpp b/src/protocols/LockNotify.cpp new file mode 100644 index 00000000..adcd0b2d --- /dev/null +++ b/src/protocols/LockNotify.cpp @@ -0,0 +1,88 @@ +#include "LockNotify.hpp" + +CHyprlandLockNotification::CHyprlandLockNotification(SP resource_) : m_resource(resource_) { + if UNLIKELY (!m_resource->resource()) + return; + + m_resource->setDestroy([this](CHyprlandLockNotificationV1* r) { PROTO::lockNotify->destroyNotification(this); }); + m_resource->setOnDestroy([this](CHyprlandLockNotificationV1* r) { PROTO::lockNotify->destroyNotification(this); }); +} + +bool CHyprlandLockNotification::good() { + return m_resource->resource(); +} + +void CHyprlandLockNotification::onLocked() { + if LIKELY (!m_locked) + m_resource->sendLocked(); + + m_locked = true; +} + +void CHyprlandLockNotification::onUnlocked() { + if LIKELY (m_locked) + m_resource->sendUnlocked(); + + m_locked = false; +} + +CLockNotifyProtocol::CLockNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CLockNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_managers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CHyprlandLockNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CHyprlandLockNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetLockNotification([this](CHyprlandLockNotifierV1* pMgr, uint32_t id) { this->onGetNotification(pMgr, id); }); +} + +void CLockNotifyProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_managers, [&](const auto& other) { return other->resource() == res; }); +} + +void CLockNotifyProtocol::destroyNotification(CHyprlandLockNotification* notif) { + std::erase_if(m_notifications, [&](const auto& other) { return other.get() == notif; }); +} + +void CLockNotifyProtocol::onGetNotification(CHyprlandLockNotifierV1* pMgr, uint32_t id) { + const auto CLIENT = pMgr->client(); + const auto RESOURCE = m_notifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id))).get(); + + if UNLIKELY (!RESOURCE->good()) { + pMgr->noMemory(); + m_notifications.pop_back(); + return; + } + + // Already locked?? Send locked right away + if UNLIKELY (m_isLocked) + m_notifications.back()->onLocked(); +} + +void CLockNotifyProtocol::onLocked() { + if UNLIKELY (m_isLocked) { + LOGM(ERR, "Not sending lock notification. Already locked!"); + return; + } + + for (auto const& n : m_notifications) { + n->onLocked(); + } + + m_isLocked = true; +} + +void CLockNotifyProtocol::onUnlocked() { + if UNLIKELY (!m_isLocked) { + LOGM(ERR, "Not sending unlock notification. Not locked!"); + return; + } + + for (auto const& n : m_notifications) { + n->onUnlocked(); + } + + m_isLocked = false; +} diff --git a/src/protocols/LockNotify.hpp b/src/protocols/LockNotify.hpp new file mode 100644 index 00000000..ec71034b --- /dev/null +++ b/src/protocols/LockNotify.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "hyprland-lock-notify-v1.hpp" + +class CEventLoopTimer; + +class CHyprlandLockNotification { + public: + CHyprlandLockNotification(SP resource_); + ~CHyprlandLockNotification() = default; + + bool good(); + void onLocked(); + void onUnlocked(); + + private: + SP m_resource; + bool m_locked = false; +}; + +class CLockNotifyProtocol : public IWaylandProtocol { + public: + CLockNotifyProtocol(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); + + void onLocked(); + void onUnlocked(); + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyNotification(CHyprlandLockNotification* notif); + void onGetNotification(CHyprlandLockNotifierV1* pMgr, uint32_t id); + + bool m_isLocked = false; + + // + std::vector> m_managers; + std::vector> m_notifications; + + friend class CHyprlandLockNotification; +}; + +namespace PROTO { + inline UP lockNotify; +}; diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index db65ee5f..8e215ffa 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -2,6 +2,7 @@ #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" #include "FractionalScale.hpp" +#include "LockNotify.hpp" #include "core/Compositor.hpp" #include "core/Output.hpp" #include "../helpers/Monitor.hpp" @@ -115,6 +116,8 @@ CSessionLock::CSessionLock(SP resource_) : resource(resource_ PROTO::sessionLock->locked = false; + PROTO::lockNotify->onUnlocked(); + events.unlockAndDestroy.emit(); inert = true; @@ -128,6 +131,7 @@ CSessionLock::~CSessionLock() { void CSessionLock::sendLocked() { resource->sendLocked(); + PROTO::lockNotify->onLocked(); } bool CSessionLock::good() { diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 271df559..455c0558 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 271df559dd30e4bc5ec6af02d017ac0aaabd63a7 +Subproject commit 455c055883d9639d4fcbfcedb4c6d12ce313791e From 2d82a923241c0d7cb6209ee035bbac581d4dc555 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:48:04 +0000 Subject: [PATCH 1085/2393] config: fix float animation speeds < 0 (#9123) --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ebeb2397..0347ced4 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2083,7 +2083,7 @@ std::optional CConfigManager::handleAnimation(const std::string& co return {}; } - int64_t speed = -1; + float speed = -1; // speed if (isNumber(ARGS[2], true)) { From 9e8d9791c7f9b7d1183110da370772a8b2c1b6f4 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Tue, 21 Jan 2025 01:53:29 +0800 Subject: [PATCH 1086/2393] xwayland: support sending clipboard change notification on focus (#9111) --- src/xwayland/XWM.cpp | 13 ++++++++++++- src/xwayland/XWM.hpp | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index ae8e0ccc..3486b286 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1144,7 +1144,8 @@ void CXWM::initSelection() { XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; xcb_xfixes_select_selection_input(connection, clipboard.window, HYPRATOMS["CLIPBOARD"], mask2); - clipboard.listeners.setSelection = g_pSeatManager->events.setSelection.registerListener([this](std::any d) { clipboard.onSelection(); }); + clipboard.listeners.setSelection = g_pSeatManager->events.setSelection.registerListener([this](std::any d) { clipboard.onSelection(); }); + clipboard.listeners.keyboardFocusChange = g_pSeatManager->events.keyboardFocusChange.registerListener([this](std::any d) { clipboard.onKeyboardFocus(); }); dndSelection.window = xcb_generate_id(connection); xcb_create_window(connection, XCB_COPY_FROM_PARENT, dndSelection.window, screen->root, 0, 0, 8192, 8192, 0, XCB_WINDOW_CLASS_INPUT_ONLY, screen->root_visual, XCB_CW_EVENT_MASK, @@ -1287,6 +1288,16 @@ void SXSelection::onSelection() { if (g_pSeatManager->selection.currentSelection) { xcb_set_selection_owner(g_pXWayland->pWM->connection, g_pXWayland->pWM->clipboard.window, HYPRATOMS["CLIPBOARD"], XCB_TIME_CURRENT_TIME); xcb_flush(g_pXWayland->pWM->connection); + g_pXWayland->pWM->clipboard.notifyOnFocus = true; + } +} + +void SXSelection::onKeyboardFocus() { + if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient) + return; + if (g_pXWayland->pWM->clipboard.notifyOnFocus) { + onSelection(); + g_pXWayland->pWM->clipboard.notifyOnFocus = false; } } diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index bc5aa47b..0455c761 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -44,13 +44,16 @@ struct SXSelection { xcb_window_t owner = 0; xcb_timestamp_t timestamp = 0; SP dataSource; + bool notifyOnFocus = false; void onSelection(); + void onKeyboardFocus(); bool sendData(xcb_selection_request_event_t* e, std::string mime); int onRead(int fd, uint32_t mask); struct { CHyprSignalListener setSelection; + CHyprSignalListener keyboardFocusChange; } listeners; std::unique_ptr transfer; From a661203bb6d4714b211572759e2f74b1da194972 Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Mon, 20 Jan 2025 13:40:51 -0500 Subject: [PATCH 1087/2393] xwayland: fix crash when trying to initialize without Xwayland installed (#9077) --- src/Compositor.cpp | 2 +- src/Compositor.hpp | 2 +- src/config/ConfigManager.cpp | 22 ++++++---------------- src/xwayland/XWayland.cpp | 34 ++++++++++++++++++++++++++++------ src/xwayland/XWayland.hpp | 6 +++++- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 325bd882..cd0c7c61 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -669,7 +669,7 @@ void CCompositor::initManagers(eManagersInitStage stage) { g_pDonationNagManager = std::make_unique(); Debug::log(LOG, "Starting XWayland"); - g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); + g_pXWayland = std::make_unique(g_pCompositor->m_bWantsXwayland); } break; default: UNREACHABLE(); } diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 430e583c..ebcca5d0 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -74,7 +74,7 @@ class CCompositor { bool m_bIsShuttingDown = false; bool m_bFinalRequests = false; bool m_bDesktopEnvSet = false; - bool m_bEnableXwayland = true; + bool m_bWantsXwayland = true; // ------------------------------------------------- // diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 0347ced4..40f8d9ef 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -950,26 +950,16 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { } #ifndef NO_XWAYLAND - const auto PENABLEXWAYLAND = std::any_cast(m_pConfig->getConfigValue("xwayland:enabled")); + const auto PENABLEXWAYLAND = std::any_cast(m_pConfig->getConfigValue("xwayland:enabled")); + g_pCompositor->m_bWantsXwayland = PENABLEXWAYLAND; // enable/disable xwayland usage if (!isFirstLaunch) { - bool prevEnabledXwayland = g_pCompositor->m_bEnableXwayland; - if (PENABLEXWAYLAND != prevEnabledXwayland) { - g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; - if (PENABLEXWAYLAND) { - Debug::log(LOG, "xwayland has been enabled"); - } else { - Debug::log(LOG, "xwayland has been disabled, cleaning up..."); - for (auto& w : g_pCompositor->m_vWindows) { - if (w->m_pXDGSurface || !w->m_bIsX11) - continue; - g_pCompositor->closeWindow(w); - } - } - g_pXWayland = std::make_unique(g_pCompositor->m_bEnableXwayland); + bool prevEnabledXwayland = g_pXWayland->enabled(); + if (g_pCompositor->m_bWantsXwayland != prevEnabledXwayland) { + g_pXWayland = std::make_unique(g_pCompositor->m_bWantsXwayland); } } else - g_pCompositor->m_bEnableXwayland = PENABLEXWAYLAND; + g_pCompositor->m_bWantsXwayland = PENABLEXWAYLAND; #endif if (!isFirstLaunch && !g_pCompositor->m_bUnsafeState) diff --git a/src/xwayland/XWayland.cpp b/src/xwayland/XWayland.cpp index 8cdb1fca..6b8a630b 100644 --- a/src/xwayland/XWayland.cpp +++ b/src/xwayland/XWayland.cpp @@ -1,21 +1,39 @@ #include "XWayland.hpp" +#include "../Compositor.hpp" #include "../debug/Log.hpp" +#include "../helpers/fs/FsUtils.hpp" -CXWayland::CXWayland(const bool enabled) { +CXWayland::CXWayland(const bool wantsEnabled) { #ifndef NO_XWAYLAND + // Disable Xwayland and clean up if the user disabled it. + if (!wantsEnabled) { + Debug::log(LOG, "XWayland has been disabled, cleaning up..."); + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsX11) + continue; + g_pCompositor->closeWindow(w); + } + unsetenv("DISPLAY"); + m_enabled = false; + return; + } + + if (!NFsUtils::executableExistsInPath("Xwayland")) { + // If Xwayland doesn't exist, don't try to start it. + Debug::log(LOG, "Unable to find XWayland; not starting it."); + return; + } + Debug::log(LOG, "Starting up the XWayland server"); pServer = std::make_unique(); - if (!enabled) { - unsetenv("DISPLAY"); - return; - } - if (!pServer->create()) { Debug::log(ERR, "XWayland failed to start: it will not work."); return; } + + m_enabled = true; #else Debug::log(LOG, "Not starting XWayland: disabled at compile time"); #endif @@ -31,3 +49,7 @@ void CXWayland::setCursor(unsigned char* pixData, uint32_t stride, const Vector2 pWM->setCursor(pixData, stride, size, hotspot); #endif } + +bool CXWayland::enabled() { + return m_enabled; +} diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index 113ca4d4..8347a6a7 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -17,18 +17,22 @@ class CXWM; class CXWayland { public: - CXWayland(const bool enabled); + CXWayland(const bool wantsEnabled); #ifndef NO_XWAYLAND std::unique_ptr pServer; std::unique_ptr pWM; #endif + bool enabled(); void setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot); struct { CSignal newSurface; } events; + + private: + bool m_enabled = false; }; inline std::unique_ptr g_pXWayland; From da6e9663135aa492252fe8684747ff734730a323 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:17:07 +0300 Subject: [PATCH 1088/2393] keybinds: add visible arg for cyclenext (#9045) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- src/Compositor.cpp | 89 ++++++++++++--------------------- src/Compositor.hpp | 5 +- src/managers/KeybindManager.cpp | 13 ++--- 3 files changed, 41 insertions(+), 66 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cd0c7c61..f5f1d1f9 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2,6 +2,7 @@ #include "Compositor.hpp" #include "debug/Log.hpp" +#include "desktop/DesktopTypes.hpp" #include "helpers/Splashes.hpp" #include "config/ConfigValue.hpp" #include "config/ConfigWatcher.hpp" @@ -12,6 +13,7 @@ #include "managers/VersionKeeperManager.hpp" #include "managers/DonationNagManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" +#include #include #include #include @@ -19,13 +21,13 @@ #include #include #include +#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" #ifdef USES_SYSTEMD #include // for SdNotify #endif -#include #include "helpers/varlist/VarList.hpp" #include "helpers/fs/FsUtils.hpp" #include "protocols/FractionalScale.hpp" @@ -1638,62 +1640,37 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks return nullptr; } -PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { - bool gotToWindow = false; - for (auto const& w : m_vWindows) { - if (w != pWindow && !gotToWindow) - continue; - - if (w == pWindow) { - gotToWindow = true; - continue; - } - - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) - return w; - } - - for (auto const& w : m_vWindows) { - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) - return w; - } - - return nullptr; +PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { + auto it = std::ranges::find(m_vWindows, pWindow); + const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; + const auto IN_RIGHT = std::find_if(it, m_vWindows.end(), FINDER); + if (IN_RIGHT != m_vWindows.end()) + return *IN_RIGHT; + const auto IN_LEFT = std::find_if(m_vWindows.begin(), it, FINDER); + return *IN_LEFT; } -PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating) { - bool gotToWindow = false; - for (auto const& w : m_vWindows | std::views::reverse) { - if (w != pWindow && !gotToWindow) - continue; +PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { + auto it = std::ranges::find(std::ranges::reverse_view(m_vWindows), pWindow); + const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; + const auto IN_LEFT = std::find_if(it, m_vWindows.rend(), FINDER); + if (IN_LEFT != m_vWindows.rend()) + return *IN_LEFT; + const auto IN_RIGHT = std::find_if(m_vWindows.rbegin(), it, FINDER); + return *IN_RIGHT; +} - if (w == pWindow) { - gotToWindow = true; - continue; - } +inline static bool isWorkspaceMatches(PHLWINDOW pWindow, const PHLWINDOW w, bool anyWorkspace) { + return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace; +} - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; +inline static bool isFloatingMatches(PHLWINDOW w, std::optional floating) { + return !floating.has_value() || w->m_bIsFloating == floating.value(); +}; - if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) - return w; - } - - for (auto const& w : m_vWindows | std::views::reverse) { - if (floating.has_value() && w->m_bIsFloating != floating.value()) - continue; - - if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())) - return w; - } - - return nullptr; +bool CCompositor::isWindowAvailableForCycle(PHLWINDOW pWindow, const PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace) { + return isFloatingMatches(w, floating) && w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && + (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()); } WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { @@ -1728,12 +1705,8 @@ PHLWORKSPACE CCompositor::getWorkspaceByString(const std::string& str) { } bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) { - for (auto const& m : m_vMonitors) { - if (VECINRECT(point, m->vecPosition.x, m->vecPosition.y, m->vecSize.x + m->vecPosition.x, m->vecSize.y + m->vecPosition.y)) - return true; - } - - return false; + return std::ranges::any_of( + m_vMonitors, [&](const PHLMONITOR& m) { return VECINRECT(point, m->vecPosition.x, m->vecPosition.y, m->vecSize.x + m->vecPosition.x, m->vecSize.y + m->vecPosition.y); }); } bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR pMonitor) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index ebcca5d0..0a87ec33 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -106,8 +106,8 @@ class CCompositor { void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); - PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); - PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}); + PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); + PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); @@ -163,6 +163,7 @@ class CCompositor { void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); + bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace = false); uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 65891840..0816de2a 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -750,7 +750,7 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k->handler); } else { // call the dispatcher - Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym); + Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {}, {})", modmask, key.keyName, key.keysym, DISPATCHER->first); m_iPassPressed = (int)pressed; @@ -2201,7 +2201,6 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) { } SDispatchResult CKeybindManager::circleNext(std::string arg) { - if (g_pCompositor->m_pLastWindow.expired()) { // if we have a clear focus, find the first window and get the next focusable. const auto PWS = g_pCompositor->m_pLastMonitor->activeWorkspace; @@ -2221,10 +2220,12 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) { else if (args.contains("float") || args.contains("floating")) floatStatus = true; - if (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) - switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); - else - switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus)); + const auto VISIBLE = args.contains("visible") || args.contains("v"); + const auto& w = (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) ? + g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE) : + g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE); + + switchToWindow(w); return {}; } From ce48bc540824fcaefd777959703df9908e258d0a Mon Sep 17 00:00:00 2001 From: Christoph Hrdinka Date: Tue, 21 Jan 2025 20:21:00 +0100 Subject: [PATCH 1089/2393] flake.lock: update (#9128) --- flake.lock | 68 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index 7b85bd17..31dc720b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1736102453, - "narHash": "sha256-5qb4kb7Xbt8jJFL/oDqOor9Z2+E+A+ql3PiyDvsfWZ0=", + "lastModified": 1736702516, + "narHash": "sha256-NbJiiPFnmciji3JHpqF/L0SdMQXKXn+q3Q/D8RjF/ak=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "4846091641f3be0ad7542086d52769bb7932bde6", + "rev": "e7719f9b9f5321c7100733773ad9f38cb6db6b6f", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1734906540, - "narHash": "sha256-vQ/L9hZFezC0LquLo4TWXkyniWtYBlFHAKIsDc7PYJE=", + "lastModified": 1737391116, + "narHash": "sha256-wOlplOftCnD2J1VwkRiAzASiXi80LypWqhVJcBYuLG8=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "69270ba8f057d55b0e6c2dca0e165d652856e613", + "rev": "3219b311283803d4dbdacb3c5cc10cf9e9b7c2b5", "type": "github" }, "original": { @@ -141,8 +141,34 @@ "type": "github" } }, + "hyprland-qt-support": { + "inputs": { + "nixpkgs": [ + "hyprland-qtutils", + "nixpkgs" + ], + "systems": [ + "hyprland-qtutils", + "systems" + ] + }, + "locked": { + "lastModified": 1736376766, + "narHash": "sha256-tZG+mkJJzqoi/gH8nN6P/yY1/PEYtom9+2WdYKKv5YM=", + "owner": "hyprwm", + "repo": "hyprland-qt-support", + "rev": "0ecf224f213497c45b12c4dc7bdc2c2edd0e3084", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprland-qt-support", + "type": "github" + } + }, "hyprland-qtutils": { "inputs": { + "hyprland-qt-support": "hyprland-qt-support", "hyprutils": [ "hyprutils" ], @@ -154,11 +180,11 @@ ] }, "locked": { - "lastModified": 1736114838, - "narHash": "sha256-FxbuGQExtN37ToWYnGmO6weOYN6WPHN/RAqbr7gNPek=", + "lastModified": 1736774415, + "narHash": "sha256-pb8v7axHdVKFGhQHEAxIuZP/9REsmlyuDW5eLGIplLc=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "6997fe382dcf396704227d2b98ffdd5066da6959", + "rev": "534cd1badc46ec9bdd986ab41ad2408bf845961e", "type": "github" }, "original": { @@ -203,11 +229,11 @@ ] }, "locked": { - "lastModified": 1736164519, - "narHash": "sha256-1LimBKvDpBbeX+qW7T240WEyw+DBVpDotZB4JYm8Aps=", + "lastModified": 1736613432, + "narHash": "sha256-x7nMS1dFtlzgG13QoguKMZ6SKwSIQw82OANA5ZKF0d0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "3c895da64b0eb19870142196fa48c07090b441c4", + "rev": "72dfbf52967e4040693164319a027d8ac6315887", "type": "github" }, "original": { @@ -241,11 +267,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1736012469, - "narHash": "sha256-/qlNWm/IEVVH7GfgAIyP6EsVZI6zjAx1cV5zNyrs+rI=", + "lastModified": 1737062831, + "narHash": "sha256-Tbk1MZbtV2s5aG+iM99U8FqwxU/YNArMcWAv6clcsBc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "8f3e1f807051e32d8c95cd12b9b421623850a34d", + "rev": "5df43628fdf08d642be8ba5b3625a6c70731c19c", "type": "github" }, "original": { @@ -264,11 +290,11 @@ ] }, "locked": { - "lastModified": 1735882644, - "narHash": "sha256-3FZAG+pGt3OElQjesCAWeMkQ7C/nB1oTHLRQ8ceP110=", + "lastModified": 1737465171, + "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "a5a961387e75ae44cc20f0a57ae463da5e959656", + "rev": "9364dc02281ce2d37a1f55b6e51f7c0f65a75f17", "type": "github" }, "original": { @@ -330,11 +356,11 @@ ] }, "locked": { - "lastModified": 1734907020, - "narHash": "sha256-p6HxwpRKVl1KIiY5xrJdjcEeK3pbmc///UOyV6QER+w=", + "lastModified": 1736421203, + "narHash": "sha256-BNe2xnHsSsTZiHp8OWl9UUf697w0gVtzh67AYe+pP+g=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "d7f18dda5e511749fa1511185db3536208fb1a63", + "rev": "7613351375de66ca0d56689e333d460e2db05454", "type": "github" }, "original": { From c8a0443adc2711744e080c28e763443b1eef115e Mon Sep 17 00:00:00 2001 From: amnesiacsardine <56002958+amnesiacsardine@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:16:46 +0100 Subject: [PATCH 1090/2393] config/ConfigManager.cpp: add instruction to edit config (#9130) --- src/config/ConfigManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 40f8d9ef..60b818f0 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -930,7 +930,7 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { g_pHyprError->queueCreate(result.getError(), CHyprColor(1.0, 50.0 / 255.0, 50.0 / 255.0, 1.0)); else if (std::any_cast(m_pConfig->getConfigValue("autogenerated")) == 1) g_pHyprError->queueCreate( - "Warning: You're using an autogenerated config! (config file: " + getMainConfigPath() + + "Warning: You're using an autogenerated config! Edit the config file to get rid of this message. (config file: " + getMainConfigPath() + " )\nSUPER+Q -> kitty (if it doesn't launch, make sure it's installed or choose a different terminal in the config)\nSUPER+M -> exit Hyprland", CHyprColor(1.0, 1.0, 70.0 / 255.0, 1.0)); else if (*PENABLEEXPLICIT != prevEnabledExplicit) From d335c8f10135e165a1085fd14134c659e4caf05a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 22 Jan 2025 10:41:04 +0000 Subject: [PATCH 1091/2393] fractional-scale: avoid redundant and duplicate scale events fixes #9126 --- example/launch.json | 1 + src/protocols/FractionalScale.cpp | 29 +++++++++++++++-------------- src/protocols/FractionalScale.hpp | 12 +++++------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/example/launch.json b/example/launch.json index c47bdb72..e60cc900 100644 --- a/example/launch.json +++ b/example/launch.json @@ -22,5 +22,6 @@ } ] }, + ] } \ No newline at end of file diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index d1e0a604..3b24becd 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -41,13 +41,14 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* return; } - PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); - PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); + PADDON->m_resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); + PADDON->m_resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); - if (std::find_if(m_mSurfaceScales.begin(), m_mSurfaceScales.end(), [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end()) + if (std::ranges::find_if(m_mSurfaceScales, [surface](const auto& e) { return e.first == surface; }) == m_mSurfaceScales.end()) m_mSurfaceScales.emplace(surface, 1.F); - PADDON->setScale(m_mSurfaceScales.at(surface)); + if (surface->mapped) + PADDON->setScale(m_mSurfaceScales.at(surface)); // clean old std::erase_if(m_mSurfaceScales, [](const auto& e) { return e.first.expired(); }); @@ -59,23 +60,23 @@ void CFractionalScaleProtocol::sendScale(SP surf, const floa m_mAddons[surf]->setScale(scale); } -CFractionalScaleAddon::CFractionalScaleAddon(SP resource_, SP surf_) : resource(resource_), surface(surf_) { - resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); - resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); -} - -void CFractionalScaleAddon::onSurfaceDestroy() { - surfaceGone = true; +CFractionalScaleAddon::CFractionalScaleAddon(SP resource_, SP surf_) : m_resource(resource_), m_surface(surf_) { + m_resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); + m_resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); } void CFractionalScaleAddon::setScale(const float& scale) { - resource->sendPreferredScale(std::round(scale * 120.0)); + if (m_scale == scale) + return; + + m_scale = scale; + m_resource->sendPreferredScale(std::round(scale * 120.0)); } bool CFractionalScaleAddon::good() { - return resource->resource(); + return m_resource->resource(); } SP CFractionalScaleAddon::surf() { - return surface.lock(); + return m_surface.lock(); } diff --git a/src/protocols/FractionalScale.hpp b/src/protocols/FractionalScale.hpp index f6d1f96f..98cd7eaa 100644 --- a/src/protocols/FractionalScale.hpp +++ b/src/protocols/FractionalScale.hpp @@ -13,25 +13,23 @@ class CFractionalScaleAddon { CFractionalScaleAddon(SP resource_, SP surf_); void setScale(const float& scale); - void onSurfaceDestroy(); bool good(); SP surf(); bool operator==(const wl_resource* other) const { - return other == resource->resource(); + return other == m_resource->resource(); } bool operator==(const CFractionalScaleAddon* other) const { - return other->resource == resource; + return other->m_resource == m_resource; } private: - SP resource; - float scale = 1.F; - WP surface; - bool surfaceGone = false; + SP m_resource; + float m_scale = -1.F; // unset + WP m_surface; friend class CFractionalScaleProtocol; }; From c90dbfab6f0f7f295b8b4b211223ea6e82a1021d Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Wed, 22 Jan 2025 22:26:53 +0800 Subject: [PATCH 1092/2393] xwayland: fix clipboard mime name and atom mismatch (#9137) --- src/xwayland/XDataSource.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 54b23937..181955a8 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -34,7 +34,8 @@ CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { continue; mimeTypes.push_back(type); - } + } else + continue; mimeAtoms.push_back(value[i]); } From fda5626594c3f31bbab08e877a797a623c98c450 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Wed, 22 Jan 2025 22:27:46 +0800 Subject: [PATCH 1093/2393] xwayland: fix sending large clipboard data (#9134) --- src/xwayland/XWM.cpp | 55 +++++++++++++++++++++++++++----------------- src/xwayland/XWM.hpp | 1 + 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 3486b286..71a7c44c 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1168,6 +1168,11 @@ void CXWM::setClipboardToWayland(SXSelection& sel) { g_pSeatManager->setCurrentSelection(sel.dataSource); } +static int writeDataSource(int fd, uint32_t mask, void* data) { + auto selection = (SXSelection*)data; + return selection->onWrite(); +} + void CXWM::getTransferData(SXSelection& sel) { Debug::log(LOG, "[xwm] getTransferData"); @@ -1179,26 +1184,9 @@ void CXWM::getTransferData(SXSelection& sel) { sel.transfer.reset(); return; } else { - char* property = (char*)xcb_get_property_value(sel.transfer->propertyReply); - int remainder = xcb_get_property_value_length(sel.transfer->propertyReply) - sel.transfer->propertyStart; - - ssize_t len = write(sel.transfer->wlFD, property + sel.transfer->propertyStart, remainder); - if (len == -1) { - Debug::log(ERR, "[xwm] write died in transfer get"); - close(sel.transfer->wlFD); - sel.transfer.reset(); - return; - } - - if (len < remainder) { - sel.transfer->propertyStart += len; - Debug::log(ERR, "[xwm] wl client read partially: len {}", len); - return; - } else { - Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(sel.transfer->wlFD); - sel.transfer.reset(); - } + sel.onWrite(); + if (sel.transfer) + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1370,7 +1358,8 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { fcntl(p[0], F_SETFD, FD_CLOEXEC); fcntl(p[0], F_SETFL, O_NONBLOCK); fcntl(p[1], F_SETFD, FD_CLOEXEC); - fcntl(p[1], F_SETFL, O_NONBLOCK); + // the wayland client might not expect a non-blocking fd + // fcntl(p[1], F_SETFL, O_NONBLOCK); transfer->wlFD = p[0]; @@ -1383,6 +1372,30 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { return true; } +int SXSelection::onWrite() { + char* property = (char*)xcb_get_property_value(transfer->propertyReply); + int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; + + ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + if (len == -1) { + Debug::log(ERR, "[xwm] write died in transfer get"); + close(transfer->wlFD); + transfer.reset(); + return 0; + } + + if (len < remainder) { + transfer->propertyStart += len; + Debug::log(LOG, "[xwm] wl client read partially: len {}", len); + } else { + Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); + close(transfer->wlFD); + transfer.reset(); + } + + return 1; +} + SXTransfer::~SXTransfer() { if (wlFD) close(wlFD); diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 0455c761..02ade80d 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -50,6 +50,7 @@ struct SXSelection { void onKeyboardFocus(); bool sendData(xcb_selection_request_event_t* e, std::string mime); int onRead(int fd, uint32_t mask); + int onWrite(); struct { CHyprSignalListener setSelection; From f1bd62806e538fa2bfa7899c2b2ad02d6a5ca2db Mon Sep 17 00:00:00 2001 From: maround95 <39220886+maround95@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:08:19 +0200 Subject: [PATCH 1094/2393] core/renderer: Add GPU hotplug support (#8980) --- src/managers/eventLoop/EventLoopManager.cpp | 32 +++++++++++++++++---- src/managers/eventLoop/EventLoopManager.hpp | 29 +++++++++++++------ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index f98efc92..4021c171 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -20,8 +21,8 @@ CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEvent } CEventLoopManager::~CEventLoopManager() { - for (auto const& eventSource : m_sWayland.aqEventSources) { - wl_event_source_remove(eventSource); + for (auto const& [_, eventSourceData] : aqEventSources) { + wl_event_source_remove(eventSourceData.eventSource); } if (m_sWayland.eventSource) @@ -56,10 +57,8 @@ void CEventLoopManager::enterLoop() { if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); - aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); - for (auto const& fd : aqPollFDs) { - m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get())); - } + syncPollFDs(); + m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); // if we have a session, dispatch it to get the pending input devices if (g_pCompositor->m_pAqBackend->hasSession()) @@ -144,3 +143,24 @@ void CEventLoopManager::doLater(const std::function& fn) { }, &m_sIdle); } + +void CEventLoopManager::syncPollFDs() { + auto aqPollFDs = g_pCompositor->m_pAqBackend->getPollFDs(); + + std::erase_if(aqEventSources, [&](const auto& item) { + auto const& [fd, eventSourceData] = item; + + // If no pollFD has the same fd, remove this event source + const bool shouldRemove = std::ranges::none_of(aqPollFDs, [&](const auto& pollFD) { return pollFD->fd == fd; }); + + if (shouldRemove) + wl_event_source_remove(eventSourceData.eventSource); + + return shouldRemove; + }); + + for (auto& fd : aqPollFDs | std::views::filter([&](SP fd) { return !aqEventSources.contains(fd->fd); })) { + auto eventSource = wl_event_loop_add_fd(m_sWayland.loop, fd->fd, WL_EVENT_READABLE, aquamarineFDWrite, fd.get()); + aqEventSources[fd->fd] = {.pollFD = fd, .eventSource = eventSource}; + } +} diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 90402de2..e1c243d3 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include #include #include #include +#include "helpers/signal/Signal.hpp" #include "EventLoopTimer.hpp" @@ -36,11 +38,18 @@ class CEventLoopManager { }; private: + // Manages the event sources after AQ pollFDs change. + void syncPollFDs(); + + struct SEventSourceData { + SP pollFD; + wl_event_source* eventSource = nullptr; + }; + struct { - wl_event_loop* loop = nullptr; - wl_display* display = nullptr; - wl_event_source* eventSource = nullptr; - std::vector aqEventSources; + wl_event_loop* loop = nullptr; + wl_display* display = nullptr; + wl_event_source* eventSource = nullptr; } m_sWayland; struct { @@ -48,12 +57,16 @@ class CEventLoopManager { int timerfd = -1; } m_sTimers; - SIdleData m_sIdle; - std::vector> aqPollFDs; + SIdleData m_sIdle; + std::map aqEventSources; - wl_event_source* m_configWatcherInotifySource = nullptr; + struct { + CHyprSignalListener pollFDsChanged; + } m_sListeners; + + wl_event_source* m_configWatcherInotifySource = nullptr; friend class CSyncTimeline; }; -inline std::unique_ptr g_pEventLoopManager; \ No newline at end of file +inline std::unique_ptr g_pEventLoopManager; From ecae3c5e4be11531c2296a22f177e9e7dedb441d Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Thu, 23 Jan 2025 20:32:44 +0800 Subject: [PATCH 1095/2393] ci: fix "Resource not accessible by integration" for cf workflow (#9144) --- .github/workflows/ci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 65bfa1ca..34c45d6b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -107,6 +107,7 @@ jobs: run: make release clang-format: + permissions: read-all if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork name: "Code Style (Arch)" runs-on: ubuntu-latest From ae4e38d9d5faddd6e1dbc1750f589ef33d5ac16c Mon Sep 17 00:00:00 2001 From: Junxuan Liao <70618504+MikeWalrus@users.noreply.github.com> Date: Thu, 23 Jan 2025 06:35:13 -0600 Subject: [PATCH 1096/2393] tablet: send `motion`s on tip events (#9132) Typically, the position of the tool tip also changes on tool tip events, so we should forward this update to the clients. --- src/managers/input/Tablets.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index f61d8184..0952a7d4 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -159,12 +159,13 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { void CInputManager::onTabletTip(CTablet::STipEvent e) { const auto PTAB = e.tablet; const auto PTOOL = ensureTabletToolPresent(e.tool); + const auto POS = e.tip; + g_pPointerManager->warpAbsolute(POS, PTAB); + refocusTablet(PTAB, PTOOL, true); - if (e.in) { - simulateMouseMovement(); - refocusTablet(PTAB, PTOOL); + if (e.in) PROTO::tablet->down(PTOOL); - } else + else PROTO::tablet->up(PTOOL); PTOOL->isDown = e.in; From ae403e6a05452336abd97e61be2706f6a930d827 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 23 Jan 2025 14:48:37 +0200 Subject: [PATCH 1097/2393] flake.lock: update --- flake.lock | 121 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 33 deletions(-) diff --git a/flake.lock b/flake.lock index 31dc720b..ed1702d1 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1736702516, - "narHash": "sha256-NbJiiPFnmciji3JHpqF/L0SdMQXKXn+q3Q/D8RjF/ak=", + "lastModified": 1737636397, + "narHash": "sha256-F5MbBj3QVorycVSFE9qjuOTLtIQBqt2VWbXa0uwzm98=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "e7719f9b9f5321c7100733773ad9f38cb6db6b6f", + "rev": "7fe006981fae53e931f513026fc754e322f13145", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1737391116, - "narHash": "sha256-wOlplOftCnD2J1VwkRiAzASiXi80LypWqhVJcBYuLG8=", + "lastModified": 1737634937, + "narHash": "sha256-Ffw4ujFpi++6pPHe+gCBOfDgAoNlzVPZN6MReC1beu8=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "3219b311283803d4dbdacb3c5cc10cf9e9b7c2b5", + "rev": "9c5dd1f7c825ee47f72727ad0a4e16ca46a2688e", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1736115290, - "narHash": "sha256-Jcn6yAzfUMcxy3tN/iZRbi/QgrYm7XLyVRl9g/nbUl4=", + "lastModified": 1737634889, + "narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "52202272d89da32a9f866c0d10305a5e3d954c50", + "rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1737127640, - "narHash": "sha256-mIQ3/axCZ4g8ySwWRbW4fJcyC9v55uAii3cqlJRtW8g=", + "lastModified": 1737556638, + "narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "455c055883d9639d4fcbfcedb4c6d12ce313791e", + "rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5", "type": "github" }, "original": { @@ -143,6 +143,7 @@ }, "hyprland-qt-support": { "inputs": { + "hyprlang": "hyprlang", "nixpkgs": [ "hyprland-qtutils", "nixpkgs" @@ -153,11 +154,11 @@ ] }, "locked": { - "lastModified": 1736376766, - "narHash": "sha256-tZG+mkJJzqoi/gH8nN6P/yY1/PEYtom9+2WdYKKv5YM=", + "lastModified": 1737634706, + "narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=", "owner": "hyprwm", "repo": "hyprland-qt-support", - "rev": "0ecf224f213497c45b12c4dc7bdc2c2edd0e3084", + "rev": "8810df502cdee755993cb803eba7b23f189db795", "type": "github" }, "original": { @@ -180,11 +181,11 @@ ] }, "locked": { - "lastModified": 1736774415, - "narHash": "sha256-pb8v7axHdVKFGhQHEAxIuZP/9REsmlyuDW5eLGIplLc=", + "lastModified": 1737634810, + "narHash": "sha256-ZIJ03DeisbQuDaADSgmbgyocjecaozK4yGTa0/9bOr0=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "534cd1badc46ec9bdd986ab41ad2408bf845961e", + "rev": "a9852dbf5a1ec77cf617543728144c1362709e46", "type": "github" }, "original": { @@ -194,6 +195,29 @@ } }, "hyprlang": { + "inputs": { + "hyprutils": [ + "hyprland-qtutils", + "hyprutils" + ], + "nixpkgs": "nixpkgs", + "systems": "systems" + }, + "locked": { + "lastModified": 1737634606, + "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", + "owner": "hyprwm", + "repo": "hyprlang", + "rev": "f41271d35cc0f370d300413d756c2677f386af9d", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprlang", + "type": "github" + } + }, + "hyprlang_2": { "inputs": { "hyprutils": [ "hyprutils" @@ -206,11 +230,11 @@ ] }, "locked": { - "lastModified": 1735393019, - "narHash": "sha256-NPpqA8rtmDLsEmZOmz+qR67zsB6Y503Jnv+nSFLKJZ8=", + "lastModified": 1737634606, + "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "55608efdaa387af7bfdc0eddb404c409958efa43", + "rev": "f41271d35cc0f370d300413d756c2677f386af9d", "type": "github" }, "original": { @@ -229,11 +253,11 @@ ] }, "locked": { - "lastModified": 1736613432, - "narHash": "sha256-x7nMS1dFtlzgG13QoguKMZ6SKwSIQw82OANA5ZKF0d0=", + "lastModified": 1737632363, + "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "72dfbf52967e4040693164319a027d8ac6315887", + "rev": "006620eb29d54ea9086538891404c78563d1bae1", "type": "github" }, "original": { @@ -267,11 +291,27 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737062831, - "narHash": "sha256-Tbk1MZbtV2s5aG+iM99U8FqwxU/YNArMcWAv6clcsBc=", + "lastModified": 1737469691, + "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "5df43628fdf08d642be8ba5b3625a6c70731c19c", + "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1737469691, + "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", "type": "github" }, "original": { @@ -310,12 +350,12 @@ "hyprgraphics": "hyprgraphics", "hyprland-protocols": "hyprland-protocols", "hyprland-qtutils": "hyprland-qtutils", - "hyprlang": "hyprlang", + "hyprlang": "hyprlang_2", "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "pre-commit-hooks": "pre-commit-hooks", - "systems": "systems", + "systems": "systems_2", "xdph": "xdph" } }, @@ -334,6 +374,21 @@ "type": "github" } }, + "systems_2": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, "xdph": { "inputs": { "hyprland-protocols": [ @@ -356,11 +411,11 @@ ] }, "locked": { - "lastModified": 1736421203, - "narHash": "sha256-BNe2xnHsSsTZiHp8OWl9UUf697w0gVtzh67AYe+pP+g=", + "lastModified": 1737634991, + "narHash": "sha256-dBAnb7Kbnier30cA7AgxVSxxARmxKZ1vHZT33THSIr8=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "7613351375de66ca0d56689e333d460e2db05454", + "rev": "e09dfe2726c8008f983e45a0aa1a3b7416aaeb8a", "type": "github" }, "original": { From 0a1ae48a9fd6eb76baad27de98c00f653a55e4ac Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:55:41 +0100 Subject: [PATCH 1098/2393] core: move all shared_ptrs from the STL to hyprutils (#9143) --- CMakeLists.txt | 2 +- src/Compositor.cpp | 56 ++++----- src/Compositor.hpp | 4 +- src/config/ConfigManager.cpp | 10 +- src/config/ConfigManager.hpp | 4 +- src/config/ConfigWatcher.hpp | 4 +- src/debug/HyprCtl.hpp | 2 +- src/debug/HyprDebugOverlay.hpp | 2 +- src/debug/HyprNotificationOverlay.cpp | 2 +- src/debug/HyprNotificationOverlay.hpp | 18 +-- src/desktop/LayerRule.cpp | 2 +- src/desktop/LayerSurface.cpp | 2 +- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 2 +- src/desktop/Popup.hpp | 6 +- src/desktop/Rule.cpp | 5 +- src/desktop/Rule.hpp | 6 +- src/desktop/Subsurface.cpp | 4 +- src/desktop/Subsurface.hpp | 16 +-- src/desktop/Window.cpp | 18 +-- src/desktop/Window.hpp | 12 +- src/helpers/Monitor.hpp | 2 +- src/helpers/SdDaemon.cpp | 2 +- src/helpers/Watchdog.cpp | 2 +- src/helpers/Watchdog.hpp | 6 +- src/helpers/memory/Memory.hpp | 2 +- src/hyprerror/HyprError.hpp | 2 +- src/layout/IHyprLayout.cpp | 4 +- src/main.cpp | 2 +- src/managers/AnimationManager.hpp | 2 +- src/managers/CursorManager.cpp | 6 +- src/managers/CursorManager.hpp | 27 +++-- src/managers/DonationNagManager.hpp | 4 +- src/managers/EventManager.hpp | 2 +- src/managers/HookSystemManager.hpp | 2 +- src/managers/KeybindManager.cpp | 2 +- src/managers/KeybindManager.hpp | 2 +- src/managers/LayoutManager.hpp | 2 +- src/managers/ProtocolManager.cpp | 108 +++++++++--------- src/managers/ProtocolManager.hpp | 2 +- src/managers/SessionLockManager.cpp | 4 +- src/managers/SessionLockManager.hpp | 10 +- src/managers/TokenManager.hpp | 2 +- src/managers/VersionKeeperManager.hpp | 4 +- src/managers/XCursorManager.cpp | 1 + src/managers/XWaylandManager.hpp | 2 +- src/managers/eventLoop/EventLoopManager.hpp | 2 +- src/managers/input/IdleInhibitor.cpp | 2 +- src/managers/input/InputManager.hpp | 4 +- src/managers/input/InputMethodRelay.cpp | 6 +- src/managers/input/InputMethodRelay.hpp | 6 +- src/managers/input/TextInput.hpp | 1 - src/pch/pch.hpp | 2 +- src/plugins/HookSystem.cpp | 2 +- src/plugins/HookSystem.hpp | 8 +- src/plugins/PluginAPI.cpp | 2 +- src/plugins/PluginAPI.hpp | 2 +- src/plugins/PluginSystem.cpp | 4 +- src/plugins/PluginSystem.hpp | 6 +- src/protocols/AlphaModifier.cpp | 7 +- src/protocols/AlphaModifier.hpp | 1 - src/protocols/CTMControl.cpp | 2 +- src/protocols/CTMControl.hpp | 3 +- src/protocols/ColorManagement.hpp | 1 - src/protocols/CursorShape.cpp | 2 +- src/protocols/CursorShape.hpp | 1 - src/protocols/DRMLease.hpp | 1 - src/protocols/DRMSyncobj.hpp | 1 - src/protocols/DataDeviceWlr.hpp | 1 - src/protocols/FocusGrab.cpp | 7 +- src/protocols/ForeignToplevel.cpp | 2 +- src/protocols/ForeignToplevel.hpp | 1 - src/protocols/ForeignToplevelWlr.cpp | 2 +- src/protocols/ForeignToplevelWlr.hpp | 1 - src/protocols/FractionalScale.cpp | 4 +- src/protocols/FractionalScale.hpp | 1 - src/protocols/FrogColorManagement.hpp | 1 - src/protocols/GammaControl.cpp | 4 +- src/protocols/GammaControl.hpp | 1 - src/protocols/HyprlandSurface.cpp | 6 +- src/protocols/HyprlandSurface.hpp | 1 - src/protocols/IdleInhibit.cpp | 2 +- src/protocols/IdleInhibit.hpp | 1 - src/protocols/IdleNotify.cpp | 2 +- src/protocols/IdleNotify.hpp | 1 - src/protocols/InputMethodV2.cpp | 2 +- src/protocols/InputMethodV2.hpp | 1 - src/protocols/LayerShell.cpp | 2 +- src/protocols/LayerShell.hpp | 1 - src/protocols/LinuxDMABUF.cpp | 4 +- src/protocols/LinuxDMABUF.hpp | 1 - src/protocols/LockNotify.cpp | 2 +- src/protocols/MesaDRM.hpp | 1 - src/protocols/OutputManagement.hpp | 1 - src/protocols/OutputPower.cpp | 4 +- src/protocols/OutputPower.hpp | 1 - src/protocols/PointerConstraints.cpp | 2 +- src/protocols/PointerConstraints.hpp | 1 - src/protocols/PointerGestures.cpp | 8 +- src/protocols/PointerGestures.hpp | 1 - src/protocols/PresentationTime.cpp | 2 +- src/protocols/PresentationTime.hpp | 1 - src/protocols/PrimarySelection.hpp | 1 - src/protocols/RelativePointer.cpp | 4 +- src/protocols/RelativePointer.hpp | 1 - src/protocols/SecurityContext.hpp | 1 - src/protocols/ServerDecorationKDE.cpp | 5 +- src/protocols/ServerDecorationKDE.hpp | 1 - src/protocols/SessionLock.cpp | 2 +- src/protocols/SessionLock.hpp | 1 - src/protocols/ShortcutsInhibit.cpp | 4 +- src/protocols/ShortcutsInhibit.hpp | 1 - src/protocols/SinglePixel.hpp | 1 - src/protocols/Tablet.cpp | 2 +- src/protocols/Tablet.hpp | 1 - src/protocols/TearingControl.cpp | 4 +- src/protocols/TearingControl.hpp | 1 - src/protocols/TextInputV3.cpp | 2 +- src/protocols/TextInputV3.hpp | 1 - src/protocols/Viewporter.hpp | 1 - src/protocols/VirtualKeyboard.cpp | 2 +- src/protocols/VirtualKeyboard.hpp | 1 - src/protocols/VirtualPointer.cpp | 2 +- src/protocols/VirtualPointer.hpp | 1 - src/protocols/WaylandProtocol.hpp | 1 + src/protocols/XDGActivation.cpp | 4 +- src/protocols/XDGActivation.hpp | 1 - src/protocols/XDGDecoration.cpp | 4 +- src/protocols/XDGDecoration.hpp | 1 - src/protocols/XDGDialog.hpp | 1 - src/protocols/XDGOutput.cpp | 4 +- src/protocols/XDGShell.hpp | 1 - src/protocols/XWaylandShell.hpp | 1 - src/protocols/core/Compositor.hpp | 1 - src/protocols/core/DataDevice.hpp | 1 - src/protocols/core/Output.hpp | 1 - src/protocols/core/Seat.hpp | 1 - src/protocols/core/Shm.hpp | 1 - src/protocols/core/Subcompositor.hpp | 1 - src/protocols/types/WLBuffer.hpp | 1 - src/render/OpenGL.hpp | 2 +- src/render/Renderer.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 12 +- .../decorations/CHyprGroupBarDecoration.hpp | 4 +- .../decorations/DecorationPositioner.cpp | 2 +- .../decorations/DecorationPositioner.hpp | 14 +-- src/xwayland/Server.cpp | 2 +- src/xwayland/XDataSource.cpp | 2 +- src/xwayland/XWM.cpp | 8 +- src/xwayland/XWM.hpp | 2 +- src/xwayland/XWayland.cpp | 2 +- src/xwayland/XWayland.hpp | 7 +- 152 files changed, 297 insertions(+), 349 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c022f3ba..3cfb8688 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.3.3) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.4.0) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/src/Compositor.cpp b/src/Compositor.cpp index f5f1d1f9..aeec2830 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -586,92 +586,92 @@ void CCompositor::initManagers(eManagersInitStage stage) { switch (stage) { case STAGE_PRIORITY: { Debug::log(LOG, "Creating the EventLoopManager!"); - g_pEventLoopManager = std::make_unique(m_sWLDisplay, m_sWLEventLoop); + g_pEventLoopManager = makeUnique(m_sWLDisplay, m_sWLEventLoop); Debug::log(LOG, "Creating the HookSystem!"); - g_pHookSystem = std::make_unique(); + g_pHookSystem = makeUnique(); Debug::log(LOG, "Creating the KeybindManager!"); - g_pKeybindManager = std::make_unique(); + g_pKeybindManager = makeUnique(); Debug::log(LOG, "Creating the AnimationManager!"); - g_pAnimationManager = std::make_unique(); + g_pAnimationManager = makeUnique(); Debug::log(LOG, "Creating the ConfigManager!"); - g_pConfigManager = std::make_unique(); + g_pConfigManager = makeUnique(); Debug::log(LOG, "Creating the CHyprError!"); - g_pHyprError = std::make_unique(); + g_pHyprError = makeUnique(); Debug::log(LOG, "Creating the LayoutManager!"); - g_pLayoutManager = std::make_unique(); + g_pLayoutManager = makeUnique(); Debug::log(LOG, "Creating the TokenManager!"); - g_pTokenManager = std::make_unique(); + g_pTokenManager = makeUnique(); g_pConfigManager->init(); - g_pWatchdog = std::make_unique(); // requires config + g_pWatchdog = makeUnique(); // requires config // wait for watchdog to initialize to not hit data races in reading config values. while (!g_pWatchdog->m_bWatchdogInitialized) { std::this_thread::yield(); } Debug::log(LOG, "Creating the PointerManager!"); - g_pPointerManager = std::make_unique(); + g_pPointerManager = makeUnique(); Debug::log(LOG, "Creating the EventManager!"); - g_pEventManager = std::make_unique(); + g_pEventManager = makeUnique(); } break; case STAGE_BASICINIT: { Debug::log(LOG, "Creating the CHyprOpenGLImpl!"); - g_pHyprOpenGL = std::make_unique(); + g_pHyprOpenGL = makeUnique(); Debug::log(LOG, "Creating the ProtocolManager!"); - g_pProtocolManager = std::make_unique(); + g_pProtocolManager = makeUnique(); Debug::log(LOG, "Creating the SeatManager!"); - g_pSeatManager = std::make_unique(); + g_pSeatManager = makeUnique(); } break; case STAGE_LATE: { Debug::log(LOG, "Creating CHyprCtl"); - g_pHyprCtl = std::make_unique(); + g_pHyprCtl = makeUnique(); Debug::log(LOG, "Creating the InputManager!"); - g_pInputManager = std::make_unique(); + g_pInputManager = makeUnique(); Debug::log(LOG, "Creating the HyprRenderer!"); - g_pHyprRenderer = std::make_unique(); + g_pHyprRenderer = makeUnique(); Debug::log(LOG, "Creating the XWaylandManager!"); - g_pXWaylandManager = std::make_unique(); + g_pXWaylandManager = makeUnique(); Debug::log(LOG, "Creating the SessionLockManager!"); - g_pSessionLockManager = std::make_unique(); + g_pSessionLockManager = makeUnique(); Debug::log(LOG, "Creating the HyprDebugOverlay!"); - g_pDebugOverlay = std::make_unique(); + g_pDebugOverlay = makeUnique(); Debug::log(LOG, "Creating the HyprNotificationOverlay!"); - g_pHyprNotificationOverlay = std::make_unique(); + g_pHyprNotificationOverlay = makeUnique(); Debug::log(LOG, "Creating the PluginSystem!"); - g_pPluginSystem = std::make_unique(); + g_pPluginSystem = makeUnique(); g_pConfigManager->handlePluginLoads(); Debug::log(LOG, "Creating the DecorationPositioner!"); - g_pDecorationPositioner = std::make_unique(); + g_pDecorationPositioner = makeUnique(); Debug::log(LOG, "Creating the CursorManager!"); - g_pCursorManager = std::make_unique(); + g_pCursorManager = makeUnique(); Debug::log(LOG, "Creating the VersionKeeper!"); - g_pVersionKeeperMgr = std::make_unique(); + g_pVersionKeeperMgr = makeUnique(); Debug::log(LOG, "Creating the DonationNag!"); - g_pDonationNagManager = std::make_unique(); + g_pDonationNagManager = makeUnique(); Debug::log(LOG, "Starting XWayland"); - g_pXWayland = std::make_unique(g_pCompositor->m_bWantsXwayland); + g_pXWayland = makeUnique(g_pCompositor->m_bWantsXwayland); } break; default: UNREACHABLE(); } @@ -2701,7 +2701,7 @@ void CCompositor::moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWor g_pLayoutManager->getCurrentLayout()->recalculateWindow(pWindow); if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); } else { if (!pWindow->m_bIsFloating) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 0a87ec33..f2e2ca14 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -10,6 +9,7 @@ #include "managers/SessionLockManager.hpp" #include "desktop/Window.hpp" #include "protocols/types/ColorManagement.hpp" +#include "helpers/memory/Memory.hpp" #include #include @@ -170,4 +170,4 @@ class CCompositor { rlimit m_sOriginalNofile = {0}; }; -inline std::unique_ptr g_pCompositor; +inline UP g_pCompositor; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 60b818f0..08f0f33f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -44,6 +44,7 @@ #include #include #include +#include using namespace Hyprutils::String; using namespace Hyprutils::Animation; @@ -374,7 +375,7 @@ CConfigManager::CConfigManager() { const auto ERR = verifyConfigExists(); m_configPaths.emplace_back(getMainConfigPath()); - m_pConfig = std::make_unique(m_configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); + m_pConfig = makeUnique(m_configPaths.begin()->c_str(), Hyprlang::SConfigOptions{.throwAllErrors = true, .allowMissingConfig = true}); m_pConfig->addConfigValue("general:border_size", Hyprlang::INT{1}); m_pConfig->addConfigValue("general:no_border_on_floating", Hyprlang::INT{0}); @@ -955,9 +956,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { // enable/disable xwayland usage if (!isFirstLaunch) { bool prevEnabledXwayland = g_pXWayland->enabled(); - if (g_pCompositor->m_bWantsXwayland != prevEnabledXwayland) { - g_pXWayland = std::make_unique(g_pCompositor->m_bWantsXwayland); - } + if (g_pCompositor->m_bWantsXwayland != prevEnabledXwayland) + g_pXWayland = makeUnique(g_pCompositor->m_bWantsXwayland); } else g_pCompositor->m_bWantsXwayland = PENABLEXWAYLAND; #endif @@ -1659,7 +1659,7 @@ void CConfigManager::addExecRule(const SExecRequestedRule& rule) { } void CConfigManager::handlePluginLoads() { - if (g_pPluginSystem == nullptr) + if (!g_pPluginSystem) return; bool pluginsChanged = false; diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 1962e4d2..31ad81cd 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -262,7 +262,7 @@ class CConfigManager { bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking private: - std::unique_ptr m_pConfig; + UP m_pConfig; std::vector m_configPaths; @@ -303,4 +303,4 @@ class CConfigManager { SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); }; -inline std::unique_ptr g_pConfigManager; +inline UP g_pConfigManager; diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp index 0a698fc8..c36ecd17 100644 --- a/src/config/ConfigWatcher.hpp +++ b/src/config/ConfigWatcher.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include "../helpers/memory/Memory.hpp" #include #include #include @@ -29,4 +29,4 @@ class CConfigWatcher { int m_inotifyFd = -1; }; -inline std::unique_ptr g_pConfigWatcher = std::make_unique(); \ No newline at end of file +inline UP g_pConfigWatcher = makeUnique(); \ No newline at end of file diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index 2603612c..eed8265c 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -38,4 +38,4 @@ class CHyprCtl { std::string m_socketPath; }; -inline std::unique_ptr g_pHyprCtl; +inline UP g_pHyprCtl; diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index a58ecffc..f4ef122f 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -48,4 +48,4 @@ class CHyprDebugOverlay { friend class CHyprRenderer; }; -inline std::unique_ptr g_pDebugOverlay; +inline UP g_pDebugOverlay; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 09125243..66c68d08 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -40,7 +40,7 @@ CHyprNotificationOverlay::~CHyprNotificationOverlay() { } void CHyprNotificationOverlay::addNotification(const std::string& text, const CHyprColor& color, const float timeMs, const eIcons icon, const float fontSize) { - const auto PNOTIF = m_vNotifications.emplace_back(std::make_unique()).get(); + const auto PNOTIF = m_vNotifications.emplace_back(makeUnique()).get(); PNOTIF->text = icon != eIcons::ICON_NONE ? " " + text /* tiny bit of padding otherwise icon touches text */ : text; PNOTIF->color = color == CHyprColor(0) ? ICONS_COLORS[icon] : color; diff --git a/src/debug/HyprNotificationOverlay.hpp b/src/debug/HyprNotificationOverlay.hpp index 2546d04f..b04cb73b 100644 --- a/src/debug/HyprNotificationOverlay.hpp +++ b/src/debug/HyprNotificationOverlay.hpp @@ -46,18 +46,18 @@ class CHyprNotificationOverlay { bool hasAny(); private: - CBox drawNotifications(PHLMONITOR pMonitor); - CBox m_bLastDamage; + CBox drawNotifications(PHLMONITOR pMonitor); + CBox m_bLastDamage; - std::vector> m_vNotifications; + std::vector> m_vNotifications; - cairo_surface_t* m_pCairoSurface = nullptr; - cairo_t* m_pCairo = nullptr; + cairo_surface_t* m_pCairoSurface = nullptr; + cairo_t* m_pCairo = nullptr; - PHLMONITORREF m_pLastMonitor; - Vector2D m_vecLastSize = Vector2D(-1, -1); + PHLMONITORREF m_pLastMonitor; + Vector2D m_vecLastSize = Vector2D(-1, -1); - SP m_pTexture; + SP m_pTexture; }; -inline std::unique_ptr g_pHyprNotificationOverlay; +inline UP g_pHyprNotificationOverlay; diff --git a/src/desktop/LayerRule.cpp b/src/desktop/LayerRule.cpp index 23371947..791a557e 100644 --- a/src/desktop/LayerRule.cpp +++ b/src/desktop/LayerRule.cpp @@ -1,7 +1,7 @@ +#include #include "LayerRule.hpp" #include #include -#include #include "../debug/Log.hpp" static const auto RULES = std::unordered_set{"noanim", "blur", "blurpopups", "dimaround"}; diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index c572f6b2..dd30aa7c 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -32,7 +32,7 @@ PHLLS CLayerSurface::create(SP resource) { pLS->szNamespace = resource->layerNamespace; pLS->layer = resource->current.layer; - pLS->popupHead = std::make_unique(pLS); + pLS->popupHead = makeUnique(pLS); pLS->monitor = pMonitor; pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 591dfd99..ab259733 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -59,7 +59,7 @@ class CLayerSurface { CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; - std::unique_ptr popupHead; + UP popupHead; void onDestroy(); void onMap(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index ce6ab9a0..831619a5 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -89,7 +89,7 @@ void CPopup::onMap() { g_pInputManager->simulateMouseMovement(); - m_pSubsurfaceHead = std::make_unique(this); + m_pSubsurfaceHead = makeUnique(this); //unconstrain(); sendScale(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index e9b3e0f0..2b7b4e82 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -1,9 +1,9 @@ #pragma once #include -#include #include "Subsurface.hpp" #include "../helpers/signal/Signal.hpp" +#include "../helpers/memory/Memory.hpp" class CXDGPopupResource; @@ -61,8 +61,8 @@ class CPopup { bool m_bInert = false; // - std::vector> m_vChildren; - std::unique_ptr m_pSubsurfaceHead; + std::vector> m_vChildren; + UP m_pSubsurfaceHead; struct { CHyprSignalListener newPopup; diff --git a/src/desktop/Rule.cpp b/src/desktop/Rule.cpp index ae280642..aa87a483 100644 --- a/src/desktop/Rule.cpp +++ b/src/desktop/Rule.cpp @@ -1,12 +1,13 @@ -#include "Rule.hpp" #include +#include "../helpers/memory/Memory.hpp" +#include "Rule.hpp" #include "../debug/Log.hpp" CRuleRegexContainer::CRuleRegexContainer(const std::string& regex_) { const bool NEGATIVE = regex_.starts_with("negative:"); negative = NEGATIVE; - regex = std::make_unique(NEGATIVE ? regex_.substr(9) : regex_); + regex = makeUnique(NEGATIVE ? regex_.substr(9) : regex_); // TODO: maybe pop an error? if (!regex->ok()) diff --git a/src/desktop/Rule.hpp b/src/desktop/Rule.hpp index 4b178ee8..858b4ded 100644 --- a/src/desktop/Rule.hpp +++ b/src/desktop/Rule.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include //NOLINTNEXTLINE namespace re2 { @@ -16,6 +16,6 @@ class CRuleRegexContainer { bool passes(const std::string& str) const; private: - std::unique_ptr regex; - bool negative = false; + Hyprutils::Memory::CUniquePointer regex; + bool negative = false; }; \ No newline at end of file diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 26638f7a..9cdf3685 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -126,9 +126,9 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { CSubsurface* PSUBSURFACE = nullptr; if (!m_pWindowParent.expired()) - PSUBSURFACE = m_vChildren.emplace_back(std::make_unique(pSubsurface, m_pWindowParent.lock())).get(); + PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pWindowParent.lock())).get(); else if (m_pPopupParent) - PSUBSURFACE = m_vChildren.emplace_back(std::make_unique(pSubsurface, m_pPopupParent)).get(); + PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pPopupParent)).get(); ASSERT(PSUBSURFACE); diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index 7829c489..aacbad91 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -48,16 +48,16 @@ class CSubsurface { Vector2D m_vLastSize = {}; // if nullptr, means it's a dummy node - CSubsurface* m_pParent = nullptr; + CSubsurface* m_pParent = nullptr; - PHLWINDOWREF m_pWindowParent; - CPopup* m_pPopupParent = nullptr; + PHLWINDOWREF m_pWindowParent; + CPopup* m_pPopupParent = nullptr; - std::vector> m_vChildren; + std::vector> m_vChildren; - bool m_bInert = false; + bool m_bInert = false; - void initSignals(); - void initExistingSubsurfaces(SP pSurface); - void checkSiblingDamage(); + void initSignals(); + void initExistingSubsurfaces(SP pSurface); + void checkSiblingDamage(); }; \ No newline at end of file diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 829f4e2e..fb5904be 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -47,8 +47,8 @@ PHLWINDOW CWindow::create(SP surface) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->addWindowDeco(std::make_unique(pWindow)); - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); return pWindow; } @@ -70,8 +70,8 @@ PHLWINDOW CWindow::create(SP resource) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); - pWindow->addWindowDeco(std::make_unique(pWindow)); - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); pWindow->m_pWLSurface->assign(pWindow->m_pXDGSurface->surface.lock(), pWindow); @@ -296,7 +296,7 @@ void CWindow::updateWindowDecos() { } } -void CWindow::addWindowDeco(std::unique_ptr deco) { +void CWindow::addWindowDeco(UP deco) { m_dWindowDecorations.emplace_back(std::move(deco)); g_pDecorationPositioner->forceRecalcFor(m_pSelf.lock()); updateWindowDecos(); @@ -567,8 +567,8 @@ void CWindow::onMap() { if (m_bIsX11) return; - m_pSubsurfaceHead = std::make_unique(m_pSelf.lock()); - m_pPopupHead = std::make_unique(m_pSelf.lock()); + m_pSubsurfaceHead = makeUnique(m_pSelf.lock()); + m_pPopupHead = makeUnique(m_pSelf.lock()); } void CWindow::onBorderAngleAnimEnd(WP pav) { @@ -870,7 +870,7 @@ void CWindow::createGroup() { m_sGroupData.locked = false; m_sGroupData.deny = false; - addWindowDeco(std::make_unique(m_pSelf.lock())); + addWindowDeco(makeUnique(m_pSelf.lock())); if (m_pWorkspace) { m_pWorkspace->updateWindows(); @@ -1052,7 +1052,7 @@ void CWindow::insertWindowToGroup(PHLWINDOW pWindow) { const auto ENDAT = m_sGroupData.pNextWindow.lock(); if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); if (!pWindow->m_sGroupData.pNextWindow.lock()) { BEGINAT->m_sGroupData.pNextWindow = pWindow; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ebda235c..5b4ad654 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -296,8 +296,8 @@ class CWindow { uint64_t m_eSuppressedEvents = SUPPRESS_NONE; // desktop components - std::unique_ptr m_pSubsurfaceHead; - std::unique_ptr m_pPopupHead; + UP m_pSubsurfaceHead; + UP m_pPopupHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; @@ -328,14 +328,14 @@ class CWindow { // Window decorations // TODO: make this a SP. - std::vector> m_dWindowDecorations; - std::vector m_vDecosToRemove; + std::vector> m_dWindowDecorations; + std::vector m_vDecosToRemove; // Special render data, rules, etc SWindowData m_sWindowData; // Transformers - std::vector> m_vTransformers; + std::vector> m_vTransformers; // for alpha PHLANIMVAR m_fActiveInactiveAlpha; @@ -396,7 +396,7 @@ class CWindow { SBoxExtents getFullWindowExtents(); CBox getWindowBoxUnified(uint64_t props); CBox getWindowIdealBoundingBoxIgnoreReserved(); - void addWindowDeco(std::unique_ptr deco); + void addWindowDeco(UP deco); void updateWindowDecos(); void removeWindowDeco(IHyprWindowDecoration* deco); void uncacheWindowDecos(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index b33725d5..e07d62c6 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -8,7 +8,7 @@ #include "WLClasses.hpp" #include #include -#include + #include #include "Timer.hpp" #include "math/Math.hpp" diff --git a/src/helpers/SdDaemon.cpp b/src/helpers/SdDaemon.cpp index 018165c0..1cf15741 100644 --- a/src/helpers/SdDaemon.cpp +++ b/src/helpers/SdDaemon.cpp @@ -1,7 +1,7 @@ #include "SdDaemon.hpp" +#include "memory/Memory.hpp" #include - #include #include #include diff --git a/src/helpers/Watchdog.cpp b/src/helpers/Watchdog.cpp index b919bbc7..0956eed5 100644 --- a/src/helpers/Watchdog.cpp +++ b/src/helpers/Watchdog.cpp @@ -14,7 +14,7 @@ CWatchdog::~CWatchdog() { CWatchdog::CWatchdog() : m_iMainThreadPID(pthread_self()) { - m_pWatchdog = std::make_unique([this] { + m_pWatchdog = makeUnique([this] { static auto PTIMEOUT = CConfigValue("debug:watchdog_timeout"); m_bWatchdogInitialized = true; diff --git a/src/helpers/Watchdog.hpp b/src/helpers/Watchdog.hpp index b16cb518..51b71d13 100644 --- a/src/helpers/Watchdog.hpp +++ b/src/helpers/Watchdog.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include "memory/Memory.hpp" #include #include #include @@ -24,11 +24,11 @@ class CWatchdog { std::atomic m_bWatching = false; std::atomic m_bWillWatch = false; - std::unique_ptr m_pWatchdog; + UP m_pWatchdog; std::mutex m_mWatchdogMutex; std::atomic m_bNotified = false; std::atomic m_bExitThread = false; std::condition_variable m_cvWatchdogCondition; }; -inline std::unique_ptr g_pWatchdog; \ No newline at end of file +inline UP g_pWatchdog; \ No newline at end of file diff --git a/src/helpers/memory/Memory.hpp b/src/helpers/memory/Memory.hpp index 07f41154..e67c2c81 100644 --- a/src/helpers/memory/Memory.hpp +++ b/src/helpers/memory/Memory.hpp @@ -7,4 +7,4 @@ using namespace Hyprutils::Memory; #define SP Hyprutils::Memory::CSharedPointer #define WP Hyprutils::Memory::CWeakPointer -#define UP std::unique_ptr +#define UP Hyprutils::Memory::CUniquePointer diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 9a662423..771e50f0 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -32,4 +32,4 @@ class CHyprError { bool m_bMonitorChanged = false; }; -inline std::unique_ptr g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time. +inline UP g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time. diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 156141f6..576d80eb 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -215,7 +215,7 @@ bool IHyprLayout::onWindowCreatedAutoGroup(PHLWINDOW pWindow) { recalculateWindow(pWindow); if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); return true; } @@ -374,7 +374,7 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->updateWindowDecos(); if (!DRAGGINGWINDOW->getDecorationByType(DECORATION_GROUPBAR)) - DRAGGINGWINDOW->addWindowDeco(std::make_unique(DRAGGINGWINDOW)); + DRAGGINGWINDOW->addWindowDeco(makeUnique(DRAGGINGWINDOW)); } } } diff --git a/src/main.cpp b/src/main.cpp index ebae055b..bb5e5622 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -155,7 +155,7 @@ int main(int argc, char** argv) { // let's init the compositor. // it initializes basic Wayland stuff in the constructor. try { - g_pCompositor = std::make_unique(); + g_pCompositor = makeUnique(); g_pCompositor->explicitConfigPath = configPath; } catch (const std::exception& e) { std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what()); diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 10eeef05..067fa676 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -61,4 +61,4 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { void animationSlide(PHLWINDOW, std::string force = "", bool close = false); }; -inline std::unique_ptr g_pAnimationManager; +inline UP g_pAnimationManager; diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index d6584f35..160ef2eb 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -64,8 +64,8 @@ void CCursorBuffer::endDataPtr() { } CCursorManager::CCursorManager() { - m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); - m_pXcursor = std::make_unique(); + m_pHyprcursor = makeUnique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), hcLogger); + m_pXcursor = makeUnique(); static auto PUSEHYPRCURSOR = CConfigValue("cursor:enable_hyprcursor"); if (m_pHyprcursor->valid() && *PUSEHYPRCURSOR) { @@ -323,7 +323,7 @@ bool CCursorManager::changeTheme(const std::string& name, const int size) { m_szTheme = name.empty() ? "" : name; m_iSize = size; - m_pHyprcursor = std::make_unique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); + m_pHyprcursor = makeUnique(m_szTheme.empty() ? nullptr : m_szTheme.c_str(), options); if (!m_pHyprcursor->valid()) { Debug::log(ERR, "Hyprcursor failed loading theme \"{}\", falling back to XCursor.", m_szTheme); m_pXcursor->loadTheme(m_szTheme.empty() ? xcursor_theme : m_szTheme, m_iSize, m_fCursorScale); diff --git a/src/managers/CursorManager.hpp b/src/managers/CursorManager.hpp index 796ab10e..c5ded5da 100644 --- a/src/managers/CursorManager.hpp +++ b/src/managers/CursorManager.hpp @@ -2,7 +2,6 @@ #include #include -#include #include "../includes.hpp" #include "../helpers/math/Math.hpp" #include "../helpers/memory/Memory.hpp" @@ -58,22 +57,22 @@ class CCursorManager { void tickAnimatedCursor(); private: - bool m_bOurBufferConnected = false; - std::vector> m_vCursorBuffers; + bool m_bOurBufferConnected = false; + std::vector> m_vCursorBuffers; - std::unique_ptr m_pHyprcursor; - std::unique_ptr m_pXcursor; - SP m_currentXcursor; + UP m_pHyprcursor; + UP m_pXcursor; + SP m_currentXcursor; - std::string m_szTheme = ""; - int m_iSize = 0; - float m_fCursorScale = 1.0; + std::string m_szTheme = ""; + int m_iSize = 0; + float m_fCursorScale = 1.0; - Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo; + Hyprcursor::SCursorStyleInfo m_sCurrentStyleInfo; - SP m_pAnimationTimer; - int m_iCurrentAnimationFrame = 0; - Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; + SP m_pAnimationTimer; + int m_iCurrentAnimationFrame = 0; + Hyprcursor::SCursorShapeData m_sCurrentCursorShapeData; }; -inline std::unique_ptr g_pCursorManager; +inline UP g_pCursorManager; diff --git a/src/managers/DonationNagManager.hpp b/src/managers/DonationNagManager.hpp index e296d815..357f979f 100644 --- a/src/managers/DonationNagManager.hpp +++ b/src/managers/DonationNagManager.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include "../helpers/memory/Memory.hpp" class CDonationNagManager { public: @@ -13,4 +13,4 @@ class CDonationNagManager { bool m_bFired = false; }; -inline std::unique_ptr g_pDonationNagManager; \ No newline at end of file +inline UP g_pDonationNagManager; \ No newline at end of file diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 37716e63..5a88963e 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -42,4 +42,4 @@ class CEventManager { std::vector m_vClients; }; -inline std::unique_ptr g_pEventManager; +inline UP g_pEventManager; diff --git a/src/managers/HookSystemManager.hpp b/src/managers/HookSystemManager.hpp index 5a9d0c00..6d72a02d 100644 --- a/src/managers/HookSystemManager.hpp +++ b/src/managers/HookSystemManager.hpp @@ -57,4 +57,4 @@ class CHookSystemManager { std::unordered_map> m_mRegisteredHooks; }; -inline std::unique_ptr g_pHookSystem; +inline UP g_pHookSystem; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 0816de2a..f4a55a73 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -2840,7 +2840,7 @@ void CKeybindManager::moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowIn pWindow->warpCursor(); if (!pWindow->getDecorationByType(DECORATION_GROUPBAR)) - pWindow->addWindowDeco(std::make_unique(pWindow)); + pWindow->addWindowDeco(makeUnique(pWindow)); g_pEventManager->postEvent(SHyprIPCEvent{"moveintogroup", std::format("{:x}", (uintptr_t)pWindow.get())}); } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index d01ec75b..1848ca78 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -229,4 +229,4 @@ class CKeybindManager { friend class CPointerManager; }; -inline std::unique_ptr g_pKeybindManager; +inline UP g_pKeybindManager; diff --git a/src/managers/LayoutManager.hpp b/src/managers/LayoutManager.hpp index 6042b3b2..63e54baa 100644 --- a/src/managers/LayoutManager.hpp +++ b/src/managers/LayoutManager.hpp @@ -28,4 +28,4 @@ class CLayoutManager { std::vector> m_vLayouts; }; -inline std::unique_ptr g_pLayoutManager; +inline UP g_pLayoutManager; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 8e32bdec..f73a6d3c 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -119,75 +119,75 @@ CProtocolManager::CProtocolManager() { }); // Core - PROTO::seat = std::make_unique(&wl_seat_interface, 9, "WLSeat"); - PROTO::data = std::make_unique(&wl_data_device_manager_interface, 3, "WLDataDevice"); - PROTO::compositor = std::make_unique(&wl_compositor_interface, 6, "WLCompositor"); - PROTO::subcompositor = std::make_unique(&wl_subcompositor_interface, 1, "WLSubcompositor"); - PROTO::shm = std::make_unique(&wl_shm_interface, 1, "WLSHM"); + PROTO::seat = makeUnique(&wl_seat_interface, 9, "WLSeat"); + PROTO::data = makeUnique(&wl_data_device_manager_interface, 3, "WLDataDevice"); + PROTO::compositor = makeUnique(&wl_compositor_interface, 6, "WLCompositor"); + PROTO::subcompositor = makeUnique(&wl_subcompositor_interface, 1, "WLSubcompositor"); + PROTO::shm = makeUnique(&wl_shm_interface, 1, "WLSHM"); // Extensions - PROTO::viewport = std::make_unique(&wp_viewporter_interface, 1, "Viewporter"); - 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"); - PROTO::shortcutsInhibit = std::make_unique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); - PROTO::textInputV1 = std::make_unique(&zwp_text_input_manager_v1_interface, 1, "TextInputV1"); - PROTO::textInputV3 = std::make_unique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); - PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); - PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); - PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation"); - PROTO::idle = std::make_unique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); - PROTO::lockNotify = std::make_unique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); - PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); - PROTO::ime = std::make_unique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); - PROTO::virtualKeyboard = std::make_unique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); - PROTO::virtualPointer = std::make_unique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); - PROTO::outputManagement = std::make_unique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); - PROTO::serverDecorationKDE = std::make_unique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); - PROTO::focusGrab = std::make_unique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); - PROTO::tablet = std::make_unique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); - PROTO::layerShell = std::make_unique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); - PROTO::presentation = std::make_unique(&wp_presentation_interface, 1, "Presentation"); - PROTO::xdgShell = std::make_unique(&xdg_wm_base_interface, 6, "XDGShell"); - PROTO::dataWlr = std::make_unique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); - PROTO::primarySelection = std::make_unique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); - PROTO::xwaylandShell = std::make_unique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); - PROTO::screencopy = std::make_unique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); - PROTO::toplevelExport = std::make_unique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); - PROTO::globalShortcuts = std::make_unique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); - PROTO::xdgDialog = std::make_unique(&xdg_dialog_v1_interface, 1, "XDGDialog"); - PROTO::singlePixel = std::make_unique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); - PROTO::securityContext = std::make_unique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); - PROTO::ctm = std::make_unique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); - PROTO::hyprlandSurface = std::make_unique(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface"); + PROTO::viewport = makeUnique(&wp_viewporter_interface, 1, "Viewporter"); + PROTO::tearing = makeUnique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); + PROTO::fractional = makeUnique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); + PROTO::xdgOutput = makeUnique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); + PROTO::cursorShape = makeUnique(&wp_cursor_shape_manager_v1_interface, 1, "CursorShape"); + PROTO::idleInhibit = makeUnique(&zwp_idle_inhibit_manager_v1_interface, 1, "IdleInhibit"); + PROTO::relativePointer = makeUnique(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer"); + PROTO::xdgDecoration = makeUnique(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration"); + PROTO::alphaModifier = makeUnique(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier"); + PROTO::gamma = makeUnique(&zwlr_gamma_control_manager_v1_interface, 1, "GammaControl"); + PROTO::foreignToplevel = makeUnique(&ext_foreign_toplevel_list_v1_interface, 1, "ForeignToplevel"); + PROTO::pointerGestures = makeUnique(&zwp_pointer_gestures_v1_interface, 3, "PointerGestures"); + PROTO::foreignToplevelWlr = makeUnique(&zwlr_foreign_toplevel_manager_v1_interface, 3, "ForeignToplevelWlr"); + PROTO::shortcutsInhibit = makeUnique(&zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1, "ShortcutsInhibit"); + PROTO::textInputV1 = makeUnique(&zwp_text_input_manager_v1_interface, 1, "TextInputV1"); + PROTO::textInputV3 = makeUnique(&zwp_text_input_manager_v3_interface, 1, "TextInputV3"); + PROTO::constraints = makeUnique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); + PROTO::outputPower = makeUnique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); + PROTO::activation = makeUnique(&xdg_activation_v1_interface, 1, "XDGActivation"); + PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); + PROTO::lockNotify = makeUnique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); + PROTO::sessionLock = makeUnique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); + PROTO::ime = makeUnique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); + PROTO::virtualKeyboard = makeUnique(&zwp_virtual_keyboard_manager_v1_interface, 1, "VirtualKeyboard"); + PROTO::virtualPointer = makeUnique(&zwlr_virtual_pointer_manager_v1_interface, 2, "VirtualPointer"); + PROTO::outputManagement = makeUnique(&zwlr_output_manager_v1_interface, 4, "OutputManagement"); + PROTO::serverDecorationKDE = makeUnique(&org_kde_kwin_server_decoration_manager_interface, 1, "ServerDecorationKDE"); + PROTO::focusGrab = makeUnique(&hyprland_focus_grab_manager_v1_interface, 1, "FocusGrab"); + PROTO::tablet = makeUnique(&zwp_tablet_manager_v2_interface, 1, "TabletV2"); + PROTO::layerShell = makeUnique(&zwlr_layer_shell_v1_interface, 5, "LayerShell"); + PROTO::presentation = makeUnique(&wp_presentation_interface, 1, "Presentation"); + PROTO::xdgShell = makeUnique(&xdg_wm_base_interface, 6, "XDGShell"); + PROTO::dataWlr = makeUnique(&zwlr_data_control_manager_v1_interface, 2, "DataDeviceWlr"); + PROTO::primarySelection = makeUnique(&zwp_primary_selection_device_manager_v1_interface, 1, "PrimarySelection"); + PROTO::xwaylandShell = makeUnique(&xwayland_shell_v1_interface, 1, "XWaylandShell"); + PROTO::screencopy = makeUnique(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); + PROTO::toplevelExport = makeUnique(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); + PROTO::globalShortcuts = makeUnique(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); + PROTO::xdgDialog = makeUnique(&xdg_dialog_v1_interface, 1, "XDGDialog"); + PROTO::singlePixel = makeUnique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); + PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); + PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); + PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface"); if (*PENABLEXXCM) { - PROTO::colorManagement = std::make_unique(&xx_color_manager_v4_interface, 1, "ColorManagement"); - PROTO::frogColorManagement = std::make_unique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); + PROTO::colorManagement = makeUnique(&xx_color_manager_v4_interface, 1, "ColorManagement"); + PROTO::frogColorManagement = makeUnique(&frog_color_management_factory_v1_interface, 1, "FrogColorManagement"); } for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) { if (b->type() != Aquamarine::AQ_BACKEND_DRM) continue; - PROTO::lease = std::make_unique(&wp_drm_lease_device_v1_interface, 1, "DRMLease"); + PROTO::lease = makeUnique(&wp_drm_lease_device_v1_interface, 1, "DRMLease"); if (*PENABLEEXPLICIT) - PROTO::sync = std::make_unique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); + PROTO::sync = makeUnique(&wp_linux_drm_syncobj_manager_v1_interface, 1, "DRMSyncobj"); break; } if (g_pHyprOpenGL->getDRMFormats().size() > 0) { - PROTO::mesaDRM = std::make_unique(&wl_drm_interface, 2, "MesaDRM"); - PROTO::linuxDma = std::make_unique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); + PROTO::mesaDRM = makeUnique(&wl_drm_interface, 2, "MesaDRM"); + PROTO::linuxDma = makeUnique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); } else Debug::log(WARN, "ProtocolManager: Not binding linux-dmabuf and MesaDRM: DMABUF not available"); } diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 6ceff9ad..1ec8db4a 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -18,4 +18,4 @@ class CProtocolManager { void onMonitorModeChange(PHLMONITOR pMonitor); }; -inline std::unique_ptr g_pProtocolManager; +inline UP g_pProtocolManager; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 3d77f05a..ea0d8dfc 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -57,7 +57,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { Debug::log(LOG, "Session got locked by {:x}", (uintptr_t)pLock.get()); - m_pSessionLock = std::make_unique(); + m_pSessionLock = makeUnique(); m_pSessionLock->lock = pLock; m_pSessionLock->mLockTimer.reset(); @@ -66,7 +66,7 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { const auto PMONITOR = SURFACE->monitor(); - const auto NEWSURFACE = m_pSessionLock->vSessionLockSurfaces.emplace_back(std::make_unique(SURFACE)).get(); + const auto NEWSURFACE = m_pSessionLock->vSessionLockSurfaces.emplace_back(makeUnique(SURFACE)).get(); NEWSURFACE->iMonitorID = PMONITOR->ID; PROTO::fractional->sendScale(SURFACE->surface(), PMONITOR->scale); }); diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index 59090605..aaf78819 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -28,11 +28,11 @@ struct SSessionLockSurface { }; struct SSessionLock { - WP lock; - CTimer mLockTimer; + WP lock; + CTimer mLockTimer; - std::vector> vSessionLockSurfaces; - std::unordered_map mMonitorsWithoutMappedSurfaceTimers; + std::vector> vSessionLockSurfaces; + std::unordered_map mMonitorsWithoutMappedSurfaceTimers; struct { CHyprSignalListener newSurface; @@ -74,4 +74,4 @@ class CSessionLockManager { void onNewSessionLock(SP pWlrLock); }; -inline std::unique_ptr g_pSessionLockManager; +inline UP g_pSessionLockManager; diff --git a/src/managers/TokenManager.hpp b/src/managers/TokenManager.hpp index 92638e9b..aaf068bc 100644 --- a/src/managers/TokenManager.hpp +++ b/src/managers/TokenManager.hpp @@ -35,4 +35,4 @@ class CTokenManager { std::unordered_map> m_mTokens; }; -inline std::unique_ptr g_pTokenManager; \ No newline at end of file +inline UP g_pTokenManager; \ No newline at end of file diff --git a/src/managers/VersionKeeperManager.hpp b/src/managers/VersionKeeperManager.hpp index eb404d88..250a36b8 100644 --- a/src/managers/VersionKeeperManager.hpp +++ b/src/managers/VersionKeeperManager.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include "../helpers/memory/Memory.hpp" class CVersionKeeperManager { public: @@ -15,4 +15,4 @@ class CVersionKeeperManager { bool m_bFired = false; }; -inline std::unique_ptr g_pVersionKeeperMgr; \ No newline at end of file +inline UP g_pVersionKeeperMgr; \ No newline at end of file diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 42c5e427..3473df44 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -9,6 +9,7 @@ #include "../managers/CursorManager.hpp" #include "debug/Log.hpp" #include "XCursorManager.hpp" +#include // clang-format off static std::vector HYPR_XCURSOR_PIXELS = { diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 18627a78..8ce239f6 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -25,4 +25,4 @@ class CHyprXWaylandManager { Vector2D waylandToXWaylandCoords(const Vector2D&); }; -inline std::unique_ptr g_pXWaylandManager; \ No newline at end of file +inline UP g_pXWaylandManager; \ No newline at end of file diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index e1c243d3..95cc6109 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -69,4 +69,4 @@ class CEventLoopManager { friend class CSyncTimeline; }; -inline std::unique_ptr g_pEventLoopManager; +inline UP g_pEventLoopManager; diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp index 74760c0a..67837c17 100644 --- a/src/managers/input/IdleInhibitor.cpp +++ b/src/managers/input/IdleInhibitor.cpp @@ -5,7 +5,7 @@ #include "../../protocols/core/Compositor.hpp" void CInputManager::newIdleInhibitor(std::any inhibitor) { - const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique()).get(); + const auto PINHIBIT = m_vIdleInhibitors.emplace_back(makeUnique()).get(); PINHIBIT->inhibitor = std::any_cast>(inhibitor); Debug::log(LOG, "New idle inhibitor registered for surface {:x}", (uintptr_t)PINHIBIT->inhibitor->surface.get()); diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 36c8144d..c0f1939e 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -268,7 +268,7 @@ class CInputManager { bool nonDesktop = false; CHyprSignalListener surfaceDestroyListener; }; - std::vector> m_vIdleInhibitors; + std::vector> m_vIdleInhibitors; // swipe void beginWorkspaceSwipe(); @@ -304,4 +304,4 @@ class CInputManager { friend class CWLSurface; }; -inline std::unique_ptr g_pInputManager; +inline UP g_pInputManager; diff --git a/src/managers/input/InputMethodRelay.cpp b/src/managers/input/InputMethodRelay.cpp index 58cff043..5f6c4354 100644 --- a/src/managers/input/InputMethodRelay.cpp +++ b/src/managers/input/InputMethodRelay.cpp @@ -50,7 +50,7 @@ void CInputMethodRelay::onNewIME(SP pIME) { }); listeners.newPopup = pIME->events.newPopup.registerListener([this](std::any d) { - m_vIMEPopups.emplace_back(std::make_unique(std::any_cast>(d))); + m_vIMEPopups.emplace_back(makeUnique(std::any_cast>(d))); Debug::log(LOG, "New input popup"); }); @@ -86,11 +86,11 @@ CTextInput* CInputMethodRelay::getFocusedTextInput() { } void CInputMethodRelay::onNewTextInput(WP tiv3) { - m_vTextInputs.emplace_back(std::make_unique(tiv3)); + m_vTextInputs.emplace_back(makeUnique(tiv3)); } void CInputMethodRelay::onNewTextInput(WP pTIV1) { - m_vTextInputs.emplace_back(std::make_unique(pTIV1)); + m_vTextInputs.emplace_back(makeUnique(pTIV1)); } void CInputMethodRelay::removeTextInput(CTextInput* pInput) { diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 998e1fc6..602a939a 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -40,10 +40,10 @@ class CInputMethodRelay { WP m_pIME; private: - std::vector> m_vTextInputs; - std::vector> m_vIMEPopups; + std::vector> m_vTextInputs; + std::vector> m_vIMEPopups; - WP m_pLastKbFocus; + WP m_pLastKbFocus; struct { CHyprSignalListener newTIV3; diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index c0b590ac..37b471af 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -3,7 +3,6 @@ #include "../../helpers/math/Math.hpp" #include "../../helpers/signal/Signal.hpp" #include "../../helpers/memory/Memory.hpp" -#include struct wl_client; diff --git a/src/pch/pch.hpp b/src/pch/pch.hpp index 8dc98fac..f9d5b130 100644 --- a/src/pch/pch.hpp +++ b/src/pch/pch.hpp @@ -11,7 +11,7 @@ #include #include #include -#include + #include #include #include diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index c19f6f46..9fa61561 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -253,7 +253,7 @@ bool CFunctionHook::unhook() { } CFunctionHook* CHookSystem::initHook(HANDLE owner, void* source, void* destination) { - return m_vHooks.emplace_back(std::make_unique(owner, source, destination)).get(); + return m_vHooks.emplace_back(makeUnique(owner, source, destination)).get(); } bool CHookSystem::removeHook(CFunctionHook* hook) { diff --git a/src/plugins/HookSystem.hpp b/src/plugins/HookSystem.hpp index f0a5a11d..93ca4ff5 100644 --- a/src/plugins/HookSystem.hpp +++ b/src/plugins/HookSystem.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include "../helpers/memory/Memory.hpp" #define HANDLE void* #define HOOK_TRAMPOLINE_MAX_SIZE 64 @@ -60,9 +60,9 @@ class CHookSystem { void removeAllHooksFrom(HANDLE handle); private: - std::vector> m_vHooks; + std::vector> m_vHooks; - uint64_t getAddressForTrampo(); + uint64_t getAddressForTrampo(); struct SAllocatedPage { uint64_t addr = 0; @@ -75,4 +75,4 @@ class CHookSystem { friend class CFunctionHook; }; -inline std::unique_ptr g_pFunctionHookSystem; \ No newline at end of file +inline UP g_pFunctionHookSystem; \ No newline at end of file diff --git a/src/plugins/PluginAPI.cpp b/src/plugins/PluginAPI.cpp index fbb1ec1b..92f043fd 100644 --- a/src/plugins/PluginAPI.cpp +++ b/src/plugins/PluginAPI.cpp @@ -106,7 +106,7 @@ APICALL bool HyprlandAPI::removeFunctionHook(HANDLE handle, CFunctionHook* hook) return g_pFunctionHookSystem->removeHook(hook); } -APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, PHLWINDOW pWindow, std::unique_ptr pDecoration) { +APICALL bool HyprlandAPI::addWindowDecoration(HANDLE handle, PHLWINDOW pWindow, UP pDecoration) { auto* const PLUGIN = g_pPluginSystem->getPluginByHandle(handle); if (!PLUGIN) diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index 96c32bf1..c8c9e563 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -223,7 +223,7 @@ namespace HyprlandAPI { returns: true on success. False otherwise. */ - APICALL bool addWindowDecoration(HANDLE handle, PHLWINDOW pWindow, std::unique_ptr pDecoration); + APICALL bool addWindowDecoration(HANDLE handle, PHLWINDOW pWindow, UP pDecoration); /* Removes a window decoration diff --git a/src/plugins/PluginSystem.cpp b/src/plugins/PluginSystem.cpp index e849bf11..87b9e8ef 100644 --- a/src/plugins/PluginSystem.cpp +++ b/src/plugins/PluginSystem.cpp @@ -8,7 +8,7 @@ #include "../managers/eventLoop/EventLoopManager.hpp" CPluginSystem::CPluginSystem() { - g_pFunctionHookSystem = std::make_unique(); + g_pFunctionHookSystem = makeUnique(); } CPlugin* CPluginSystem::loadPlugin(const std::string& path) { @@ -21,7 +21,7 @@ CPlugin* CPluginSystem::loadPlugin(const std::string& path) { return nullptr; } - auto* const PLUGIN = m_vLoadedPlugins.emplace_back(std::make_unique()).get(); + auto* const PLUGIN = m_vLoadedPlugins.emplace_back(makeUnique()).get(); PLUGIN->path = path; diff --git a/src/plugins/PluginSystem.hpp b/src/plugins/PluginSystem.hpp index 336c484d..95841bef 100644 --- a/src/plugins/PluginSystem.hpp +++ b/src/plugins/PluginSystem.hpp @@ -44,9 +44,9 @@ class CPluginSystem { std::string m_szLastError = ""; private: - std::vector> m_vLoadedPlugins; + std::vector> m_vLoadedPlugins; - jmp_buf m_jbPluginFaultJumpBuf; + jmp_buf m_jbPluginFaultJumpBuf; }; -inline std::unique_ptr g_pPluginSystem; +inline UP g_pPluginSystem; diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index dc32bb8c..e8766405 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -64,7 +64,7 @@ CAlphaModifierProtocol::CAlphaModifierProtocol(const wl_interface* iface, const } void CAlphaModifierProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CWpAlphaModifierV1* manager) { destroyManager(manager); }); RESOURCE->setDestroy([this](CWpAlphaModifierV1* manager) { destroyManager(manager); }); @@ -93,9 +93,8 @@ void CAlphaModifierProtocol::getSurface(CWpAlphaModifierV1* manager, uint32_t id alphaModifier = iter->second.get(); } } else { - alphaModifier = - m_mAlphaModifiers.emplace(surface, std::make_unique(makeShared(manager->client(), manager->version(), id), surface)) - .first->second.get(); + alphaModifier = m_mAlphaModifiers.emplace(surface, makeUnique(makeShared(manager->client(), manager->version(), id), surface)) + .first->second.get(); } if UNLIKELY (!alphaModifier->good()) { diff --git a/src/protocols/AlphaModifier.hpp b/src/protocols/AlphaModifier.hpp index 43f78bef..9a7873ae 100644 --- a/src/protocols/AlphaModifier.hpp +++ b/src/protocols/AlphaModifier.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 91f4501f..5560271f 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -106,7 +106,7 @@ void CHyprlandCTMControlProtocol::setCTM(PHLMONITOR monitor, const Mat3x3& ctm) std::erase_if(m_mCTMDatas, [](const auto& el) { return !el.first; }); if (!m_mCTMDatas.contains(monitor)) - m_mCTMDatas[monitor] = std::make_unique(); + m_mCTMDatas[monitor] = makeUnique(); auto& data = m_mCTMDatas.at(monitor); diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index 2639d176..2c168acd 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" @@ -45,7 +44,7 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { Mat3x3 ctmFrom = Mat3x3::identity(), ctmTo = Mat3x3::identity(); PHLANIMVAR progress; }; - std::map> m_mCTMDatas; + std::map> m_mCTMDatas; friend class CHyprlandCTMControlResource; }; diff --git a/src/protocols/ColorManagement.hpp b/src/protocols/ColorManagement.hpp index e387b3b7..39e3f486 100644 --- a/src/protocols/ColorManagement.hpp +++ b/src/protocols/ColorManagement.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 429d604f..e7eb6159 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -15,7 +15,7 @@ void CCursorShapeProtocol::onDeviceResourceDestroy(wl_resource* res) { } void CCursorShapeProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CWpCursorShapeManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpCursorShapeManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/CursorShape.hpp b/src/protocols/CursorShape.hpp index 9fcca28d..37b7e6c8 100644 --- a/src/protocols/CursorShape.hpp +++ b/src/protocols/CursorShape.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "../helpers/signal/Signal.hpp" diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index 37de40e3..ec1e73f2 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index bc89a3d3..42ecdb3e 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "linux-drm-syncobj-v1.hpp" diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 193e918c..5eef163c 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index ee30343f..ab9d22ef 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -5,7 +5,6 @@ #include "../managers/SeatManager.hpp" #include "core/Compositor.hpp" #include -#include #include CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SP surface) { @@ -77,7 +76,7 @@ void CFocusGrab::finish(bool sendCleared) { void CFocusGrab::addSurface(SP surface) { auto iter = std::find_if(m_mSurfaces.begin(), m_mSurfaces.end(), [surface](const auto& e) { return e.first == surface; }); if (iter == m_mSurfaces.end()) - m_mSurfaces.emplace(surface, std::make_unique(this, surface)); + m_mSurfaces.emplace(surface, makeUnique(this, surface)); } void CFocusGrab::removeSurface(SP surface) { @@ -151,7 +150,7 @@ CFocusGrabProtocol::CFocusGrabProtocol(const wl_interface* iface, const int& ver } void CFocusGrabProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CHyprlandFocusGrabManagerV1* p) { onManagerResourceDestroy(p->resource()); }); @@ -167,7 +166,7 @@ void CFocusGrabProtocol::destroyGrab(CFocusGrab* grab) { } void CFocusGrabProtocol::onCreateGrab(CHyprlandFocusGrabManagerV1* pMgr, uint32_t id) { - m_vGrabs.push_back(std::make_unique(makeShared(pMgr->client(), pMgr->version(), id))); + m_vGrabs.push_back(makeUnique(makeShared(pMgr->client(), pMgr->version(), id))); const auto RESOURCE = m_vGrabs.back().get(); if UNLIKELY (!RESOURCE->good()) { diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index 6880164f..4e5fda48 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -147,7 +147,7 @@ CForeignToplevelProtocol::CForeignToplevelProtocol(const wl_interface* iface, co } void CForeignToplevelProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(makeShared(client, ver, id))).get(); if UNLIKELY (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); diff --git a/src/protocols/ForeignToplevel.hpp b/src/protocols/ForeignToplevel.hpp index 076bfd7c..712b32e0 100644 --- a/src/protocols/ForeignToplevel.hpp +++ b/src/protocols/ForeignToplevel.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index e18f6e23..e50c85d9 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -376,7 +376,7 @@ CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* ifa } void CForeignToplevelWlrProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(makeShared(client, ver, id))).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(makeShared(client, ver, id))).get(); if UNLIKELY (!RESOURCE->good()) { LOGM(ERR, "Couldn't create a foreign list"); diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp index 880b7a14..d0479d98 100644 --- a/src/protocols/ForeignToplevelWlr.hpp +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "wlr-foreign-toplevel-management-unstable-v1.hpp" diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 3b24becd..494de9c5 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -7,7 +7,7 @@ CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, co } void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CWpFractionalScaleManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -33,7 +33,7 @@ void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* } const auto PADDON = - m_mAddons.emplace(surface, std::make_unique(makeShared(pMgr->client(), pMgr->version(), id), surface)).first->second.get(); + m_mAddons.emplace(surface, makeUnique(makeShared(pMgr->client(), pMgr->version(), id), surface)).first->second.get(); if UNLIKELY (!PADDON->good()) { m_mAddons.erase(surface); diff --git a/src/protocols/FractionalScale.hpp b/src/protocols/FractionalScale.hpp index 98cd7eaa..ba896c01 100644 --- a/src/protocols/FractionalScale.hpp +++ b/src/protocols/FractionalScale.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "fractional-scale-v1.hpp" diff --git a/src/protocols/FrogColorManagement.hpp b/src/protocols/FrogColorManagement.hpp index 6c00e38d..db467b1d 100644 --- a/src/protocols/FrogColorManagement.hpp +++ b/src/protocols/FrogColorManagement.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "protocols/core/Compositor.hpp" diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 299d7717..43ba9d41 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -160,7 +160,7 @@ CGammaControlProtocol::CGammaControlProtocol(const wl_interface* iface, const in } void CGammaControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwlrGammaControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwlrGammaControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -177,7 +177,7 @@ void CGammaControlProtocol::destroyGammaControl(CGammaControl* gamma) { void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vGammaControllers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), output)).get(); + const auto RESOURCE = m_vGammaControllers.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id), output)).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 5cfcd60a..9e21ef08 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp index bcf4905c..ca133b78 100644 --- a/src/protocols/HyprlandSurface.cpp +++ b/src/protocols/HyprlandSurface.cpp @@ -70,7 +70,7 @@ CHyprlandSurfaceProtocol::CHyprlandSurfaceProtocol(const wl_interface* iface, co } void CHyprlandSurfaceProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - auto manager = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + auto manager = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); manager->setOnDestroy([this](CHyprlandSurfaceManagerV1* manager) { destroyManager(manager); }); manager->setDestroy([this](CHyprlandSurfaceManagerV1* manager) { destroyManager(manager); }); @@ -100,8 +100,8 @@ void CHyprlandSurfaceProtocol::getSurface(CHyprlandSurfaceManagerV1* manager, ui hyprlandSurface = iter->second.get(); } } else { - hyprlandSurface = m_mSurfaces.emplace(surface, std::make_unique(makeShared(manager->client(), manager->version(), id), surface)) - .first->second.get(); + hyprlandSurface = + m_mSurfaces.emplace(surface, makeUnique(makeShared(manager->client(), manager->version(), id), surface)).first->second.get(); } if UNLIKELY (!hyprlandSurface->good()) { diff --git a/src/protocols/HyprlandSurface.hpp b/src/protocols/HyprlandSurface.hpp index f67de115..a5812b89 100644 --- a/src/protocols/HyprlandSurface.hpp +++ b/src/protocols/HyprlandSurface.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/IdleInhibit.cpp b/src/protocols/IdleInhibit.cpp index 89eb3108..a015cdd0 100644 --- a/src/protocols/IdleInhibit.cpp +++ b/src/protocols/IdleInhibit.cpp @@ -31,7 +31,7 @@ void CIdleInhibitProtocol::onManagerResourceDestroy(wl_resource* res) { } void CIdleInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpIdleInhibitManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpIdleInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/IdleInhibit.hpp b/src/protocols/IdleInhibit.hpp index 3cbfd78d..2e024a7a 100644 --- a/src/protocols/IdleInhibit.hpp +++ b/src/protocols/IdleInhibit.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "idle-inhibit-unstable-v1.hpp" diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index 85a9f8e2..bc5aabb1 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -59,7 +59,7 @@ CIdleNotifyProtocol::CIdleNotifyProtocol(const wl_interface* iface, const int& v } void CIdleNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CExtIdleNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CExtIdleNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/IdleNotify.hpp b/src/protocols/IdleNotify.hpp index d0b40775..e3dcdc98 100644 --- a/src/protocols/IdleNotify.hpp +++ b/src/protocols/IdleNotify.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index cf777f45..796cec06 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -334,7 +334,7 @@ CInputMethodV2Protocol::CInputMethodV2Protocol(const wl_interface* iface, const } void CInputMethodV2Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpInputMethodManagerV2* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpInputMethodManagerV2* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index 0b2c7a49..0c249c6c 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 82d00a30..1533a7c0 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -201,7 +201,7 @@ CLayerShellProtocol::CLayerShellProtocol(const wl_interface* iface, const int& v } void CLayerShellProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwlrLayerShellV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwlrLayerShellV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/LayerShell.hpp b/src/protocols/LayerShell.hpp index 5e74c91b..b634c63c 100644 --- a/src/protocols/LayerShell.hpp +++ b/src/protocols/LayerShell.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 85f7b1c6..82d31c84 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -469,7 +469,7 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const }); } - formatTable = std::make_unique(eglTranche, tches); + formatTable = makeUnique(eglTranche, tches); drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { @@ -501,7 +501,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { LOGM(LOG, "Resetting format table"); // this might be a big copy - auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); + auto newFormatTable = makeUnique(formatTable->rendererTranche, formatTable->monitorTranches); for (auto const& feedback : m_vFeedbacks) { feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index e4941a6d..8c574dbc 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/LockNotify.cpp b/src/protocols/LockNotify.cpp index adcd0b2d..1855f891 100644 --- a/src/protocols/LockNotify.cpp +++ b/src/protocols/LockNotify.cpp @@ -31,7 +31,7 @@ CLockNotifyProtocol::CLockNotifyProtocol(const wl_interface* iface, const int& v } void CLockNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_managers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_managers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CHyprlandLockNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CHyprlandLockNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp index 46811d68..bfa604cf 100644 --- a/src/protocols/MesaDRM.hpp +++ b/src/protocols/MesaDRM.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index b9e7ce98..1594df5d 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index f97babc2..24106817 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -43,7 +43,7 @@ COutputPowerProtocol::COutputPowerProtocol(const wl_interface* iface, const int& } void COutputPowerProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwlrOutputPowerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwlrOutputPowerManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -68,7 +68,7 @@ void COutputPowerProtocol::onGetOutputPower(CZwlrOutputPowerManagerV1* pMgr, uin } const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vOutputPowers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.lock())).get(); + const auto RESOURCE = m_vOutputPowers.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id), OUTPUT->monitor.lock())).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/OutputPower.hpp b/src/protocols/OutputPower.hpp index 91f2c5f3..c61eaa3d 100644 --- a/src/protocols/OutputPower.hpp +++ b/src/protocols/OutputPower.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index c0531799..30ab0a55 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -199,7 +199,7 @@ CPointerConstraintsProtocol::CPointerConstraintsProtocol(const wl_interface* ifa } void CPointerConstraintsProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpPointerConstraintsV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpPointerConstraintsV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 964bf672..1cd2fca9 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -2,7 +2,6 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/PointerGestures.cpp b/src/protocols/PointerGestures.cpp index 4df51b47..8de73ffa 100644 --- a/src/protocols/PointerGestures.cpp +++ b/src/protocols/PointerGestures.cpp @@ -44,7 +44,7 @@ CPointerGesturesProtocol::CPointerGesturesProtocol(const wl_interface* iface, co } void CPointerGesturesProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpPointerGesturesV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setRelease([this](CZwpPointerGesturesV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -71,7 +71,7 @@ void CPointerGesturesProtocol::onGestureDestroy(CPointerGestureHold* gesture) { void CPointerGesturesProtocol::onGetPinchGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vPinches.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vPinches.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); @@ -82,7 +82,7 @@ void CPointerGesturesProtocol::onGetPinchGesture(CZwpPointerGesturesV1* pMgr, ui void CPointerGesturesProtocol::onGetSwipeGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vSwipes.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vSwipes.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); @@ -93,7 +93,7 @@ void CPointerGesturesProtocol::onGetSwipeGesture(CZwpPointerGesturesV1* pMgr, ui void CPointerGesturesProtocol::onGetHoldGesture(CZwpPointerGesturesV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vHolds.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vHolds.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/PointerGestures.hpp b/src/protocols/PointerGestures.hpp index f907a49f..5211ecf3 100644 --- a/src/protocols/PointerGestures.hpp +++ b/src/protocols/PointerGestures.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include "WaylandProtocol.hpp" #include "pointer-gestures-unstable-v1.hpp" diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 1654041c..a9139ac0 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -79,7 +79,7 @@ CPresentationProtocol::CPresentationProtocol(const wl_interface* iface, const in } void CPresentationProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CWpPresentation* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpPresentation* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/PresentationTime.hpp b/src/protocols/PresentationTime.hpp index d9b45448..03b59b89 100644 --- a/src/protocols/PresentationTime.hpp +++ b/src/protocols/PresentationTime.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp index c33a00e8..aeebe03c 100644 --- a/src/protocols/PrimarySelection.hpp +++ b/src/protocols/PrimarySelection.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/RelativePointer.cpp b/src/protocols/RelativePointer.cpp index 842af894..f002fac1 100644 --- a/src/protocols/RelativePointer.cpp +++ b/src/protocols/RelativePointer.cpp @@ -31,7 +31,7 @@ CRelativePointerProtocol::CRelativePointerProtocol(const wl_interface* iface, co } void CRelativePointerProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpRelativePointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpRelativePointerManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -48,7 +48,7 @@ void CRelativePointerProtocol::destroyRelativePointer(CRelativePointer* pointer) void CRelativePointerProtocol::onGetRelativePointer(CZwpRelativePointerManagerV1* pMgr, uint32_t id, wl_resource* pointer) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vRelativePointers.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vRelativePointers.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/RelativePointer.hpp b/src/protocols/RelativePointer.hpp index 453ce157..ce060ed3 100644 --- a/src/protocols/RelativePointer.hpp +++ b/src/protocols/RelativePointer.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index d675d660..2bec08d4 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/ServerDecorationKDE.cpp b/src/protocols/ServerDecorationKDE.cpp index 3e33db52..0726c8a5 100644 --- a/src/protocols/ServerDecorationKDE.cpp +++ b/src/protocols/ServerDecorationKDE.cpp @@ -21,7 +21,7 @@ CServerDecorationKDEProtocol::CServerDecorationKDEProtocol(const wl_interface* i } void CServerDecorationKDEProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](COrgKdeKwinServerDecorationManager* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setCreate([this](COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* pointer) { this->createDecoration(pMgr, id, pointer); }); @@ -41,8 +41,7 @@ void CServerDecorationKDEProtocol::destroyResource(CServerDecorationKDE* hayperl void CServerDecorationKDEProtocol::createDecoration(COrgKdeKwinServerDecorationManager* pMgr, uint32_t id, wl_resource* surf) { const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_vDecos.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))) - .get(); + m_vDecos.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id), CWLSurfaceResource::fromResource(surf))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/ServerDecorationKDE.hpp b/src/protocols/ServerDecorationKDE.hpp index ab082b17..0d0fa898 100644 --- a/src/protocols/ServerDecorationKDE.hpp +++ b/src/protocols/ServerDecorationKDE.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index 8e215ffa..d87775e9 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -148,7 +148,7 @@ CSessionLockProtocol::CSessionLockProtocol(const wl_interface* iface, const int& } void CSessionLockProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CExtSessionLockManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CExtSessionLockManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp index a1df6fcf..670e5e1d 100644 --- a/src/protocols/SessionLock.hpp +++ b/src/protocols/SessionLock.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/ShortcutsInhibit.cpp b/src/protocols/ShortcutsInhibit.cpp index a0d29f92..5786de26 100644 --- a/src/protocols/ShortcutsInhibit.cpp +++ b/src/protocols/ShortcutsInhibit.cpp @@ -28,7 +28,7 @@ CKeyboardShortcutsInhibitProtocol::CKeyboardShortcutsInhibitProtocol(const wl_in } void CKeyboardShortcutsInhibitProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpKeyboardShortcutsInhibitManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpKeyboardShortcutsInhibitManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -57,7 +57,7 @@ void CKeyboardShortcutsInhibitProtocol::onInhibit(CZwpKeyboardShortcutsInhibitMa } const auto RESOURCE = - m_vInhibitors.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id), surf)).get(); + m_vInhibitors.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id), surf)).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/ShortcutsInhibit.hpp b/src/protocols/ShortcutsInhibit.hpp index ba1c134c..c093ac6e 100644 --- a/src/protocols/ShortcutsInhibit.hpp +++ b/src/protocols/ShortcutsInhibit.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp index b20f582a..2a86d050 100644 --- a/src/protocols/SinglePixel.hpp +++ b/src/protocols/SinglePixel.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 62e8b2d2..de2ed71b 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -315,7 +315,7 @@ CTabletV2Protocol::CTabletV2Protocol(const wl_interface* iface, const int& ver, } void CTabletV2Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpTabletManagerV2* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpTabletManagerV2* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 1ebcb1e5..264c7633 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/TearingControl.cpp b/src/protocols/TearingControl.cpp index 14c80052..16e85352 100644 --- a/src/protocols/TearingControl.cpp +++ b/src/protocols/TearingControl.cpp @@ -11,7 +11,7 @@ CTearingControlProtocol::CTearingControlProtocol(const wl_interface* iface, cons } void CTearingControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CWpTearingControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CWpTearingControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -25,7 +25,7 @@ void CTearingControlProtocol::onManagerResourceDestroy(wl_resource* res) { } void CTearingControlProtocol::onGetController(wl_client* client, CWpTearingControlManagerV1* pMgr, uint32_t id, SP surf) { - const auto CONTROLLER = m_vTearingControllers.emplace_back(std::make_unique(makeShared(client, pMgr->version(), id), surf)).get(); + const auto CONTROLLER = m_vTearingControllers.emplace_back(makeUnique(makeShared(client, pMgr->version(), id), surf)).get(); if UNLIKELY (!CONTROLLER->good()) { pMgr->noMemory(); diff --git a/src/protocols/TearingControl.hpp b/src/protocols/TearingControl.hpp index d81a27cd..7763214e 100644 --- a/src/protocols/TearingControl.hpp +++ b/src/protocols/TearingControl.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include "WaylandProtocol.hpp" #include "tearing-control-v1.hpp" diff --git a/src/protocols/TextInputV3.cpp b/src/protocols/TextInputV3.cpp index 71ef6dac..06aea5ae 100644 --- a/src/protocols/TextInputV3.cpp +++ b/src/protocols/TextInputV3.cpp @@ -110,7 +110,7 @@ CTextInputV3Protocol::CTextInputV3Protocol(const wl_interface* iface, const int& } void CTextInputV3Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpTextInputManagerV3* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwpTextInputManagerV3* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); diff --git a/src/protocols/TextInputV3.hpp b/src/protocols/TextInputV3.hpp index ba8b75e6..6cece521 100644 --- a/src/protocols/TextInputV3.hpp +++ b/src/protocols/TextInputV3.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp index 3c2a4eef..6824f2ae 100644 --- a/src/protocols/Viewporter.hpp +++ b/src/protocols/Viewporter.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 7da1fe01..4fec57c0 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -124,7 +124,7 @@ CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, co } void CVirtualKeyboardProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwpVirtualKeyboardManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setCreateVirtualKeyboard([this](CZwpVirtualKeyboardManagerV1* pMgr, wl_resource* seat, uint32_t id) { this->onCreateKeeb(pMgr, seat, id); }); diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 93b63bb5..8157b276 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 3e0b00eb..33641a7b 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -107,7 +107,7 @@ CVirtualPointerProtocol::CVirtualPointerProtocol(const wl_interface* iface, cons } void CVirtualPointerProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZwlrVirtualPointerManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 68fe124e..ac8bcae2 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/src/protocols/WaylandProtocol.hpp b/src/protocols/WaylandProtocol.hpp index e3507708..918ac70f 100644 --- a/src/protocols/WaylandProtocol.hpp +++ b/src/protocols/WaylandProtocol.hpp @@ -1,6 +1,7 @@ #pragma once #include "../defines.hpp" +#include "../helpers/memory/Memory.hpp" #include diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index c49dc3dc..4062847b 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -62,7 +62,7 @@ CXDGActivationProtocol::CXDGActivationProtocol(const wl_interface* iface, const } void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CXdgActivationV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CXdgActivationV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -100,7 +100,7 @@ void CXDGActivationProtocol::destroyToken(CXDGActivationToken* token) { void CXDGActivationProtocol::onGetToken(CXdgActivationV1* pMgr, uint32_t id) { const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vTokens.emplace_back(std::make_unique(makeShared(CLIENT, pMgr->version(), id))).get(); + const auto RESOURCE = m_vTokens.emplace_back(makeUnique(makeShared(CLIENT, pMgr->version(), id))).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/XDGActivation.hpp b/src/protocols/XDGActivation.hpp index 80af988d..1db16b3c 100644 --- a/src/protocols/XDGActivation.hpp +++ b/src/protocols/XDGActivation.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/XDGDecoration.cpp b/src/protocols/XDGDecoration.cpp index 8ec0d5b0..f9dbf411 100644 --- a/src/protocols/XDGDecoration.cpp +++ b/src/protocols/XDGDecoration.cpp @@ -41,7 +41,7 @@ CXDGDecorationProtocol::CXDGDecorationProtocol(const wl_interface* iface, const } void CXDGDecorationProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagers.emplace_back(makeUnique(client, ver, id)).get(); RESOURCE->setOnDestroy([this](CZxdgDecorationManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CZxdgDecorationManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); @@ -64,7 +64,7 @@ void CXDGDecorationProtocol::onGetDecoration(CZxdgDecorationManagerV1* pMgr, uin const auto CLIENT = pMgr->client(); const auto RESOURCE = - m_mDecorations.emplace(xdgToplevel, std::make_unique(makeShared(CLIENT, pMgr->version(), id), xdgToplevel)).first->second.get(); + m_mDecorations.emplace(xdgToplevel, makeUnique(makeShared(CLIENT, pMgr->version(), id), xdgToplevel)).first->second.get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); diff --git a/src/protocols/XDGDecoration.hpp b/src/protocols/XDGDecoration.hpp index cbd74be4..33a9b663 100644 --- a/src/protocols/XDGDecoration.hpp +++ b/src/protocols/XDGDecoration.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/XDGDialog.hpp b/src/protocols/XDGDialog.hpp index a635bfac..1b29e692 100644 --- a/src/protocols/XDGDialog.hpp +++ b/src/protocols/XDGDialog.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 5be16d07..544deed0 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -21,7 +21,7 @@ void CXDGOutputProtocol::onOutputResourceDestroy(wl_resource* res) { } void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagerResources.emplace_back(std::make_unique(client, ver, id)).get(); + const auto RESOURCE = m_vManagerResources.emplace_back(makeUnique(client, ver, id)).get(); if UNLIKELY (!RESOURCE->resource()) { LOGM(LOG, "Couldn't bind XDGOutputMgr"); @@ -44,7 +44,7 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 const auto PMONITOR = OUTPUT->monitor.lock(); const auto CLIENT = mgr->client(); - CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); + CXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(makeUnique(makeShared(CLIENT, mgr->version(), id), PMONITOR)).get(); #ifndef NO_XWAYLAND if (g_pXWayland && g_pXWayland->pServer && g_pXWayland->pServer->xwaylandClient == CLIENT) pXDGOutput->isXWayland = true; diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 6eef99bb..4c2b8100 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/src/protocols/XWaylandShell.hpp b/src/protocols/XWaylandShell.hpp index c8c0c04a..f6f91c49 100644 --- a/src/protocols/XWaylandShell.hpp +++ b/src/protocols/XWaylandShell.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "WaylandProtocol.hpp" diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index b347eb64..20614813 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -8,7 +8,6 @@ - wl_callback */ -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index ae22e474..5101862e 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -8,7 +8,6 @@ - wl_data_device_manager */ -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index a4c81d72..8ade5178 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index b5670237..a4889379 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -8,7 +8,6 @@ - wl_touch */ -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 9f4e18f9..23a465fb 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -7,7 +7,6 @@ - wl_buffer with shm */ -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/core/Subcompositor.hpp b/src/protocols/core/Subcompositor.hpp index 2e6b10bb..dc713044 100644 --- a/src/protocols/core/Subcompositor.hpp +++ b/src/protocols/core/Subcompositor.hpp @@ -7,7 +7,6 @@ - wl_subcompositor */ -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index 787abe1f..3894affc 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "../WaylandProtocol.hpp" diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 8098485e..3dc3b43a 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -328,4 +328,4 @@ class CHyprOpenGLImpl { friend class CSurfacePassElement; }; -inline std::unique_ptr g_pHyprOpenGL; +inline UP g_pHyprOpenGL; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 7aef96e6..1ef1eecc 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -155,4 +155,4 @@ class CHyprRenderer { friend class CMonitor; }; -inline std::unique_ptr g_pHyprRenderer; +inline UP g_pHyprRenderer; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4a411b6c..36846fd4 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -176,11 +176,11 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); if (!pTitleTex) - pTitleTex = m_sTitleTexs.titleTexs - .emplace_back(std::make_unique(m_dwGroupMembers[WINDOWINDEX].lock(), - Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, - pMonitor->scale)) - .get(); + pTitleTex = + m_sTitleTexs.titleTexs + .emplace_back(makeUnique(m_dwGroupMembers[WINDOWINDEX].lock(), + Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) + .get(); rect.y += std::ceil((rect.height - pTitleTex->texSize.y) / 2.0); rect.height = pTitleTex->texSize.y; rect.width = pTitleTex->texSize.x; @@ -421,7 +421,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND g_pLayoutManager->getCurrentLayout()->recalculateWindow(pDraggedWindow); if (!pDraggedWindow->getDecorationByType(DECORATION_GROUPBAR)) - pDraggedWindow->addWindowDeco(std::make_unique(pDraggedWindow)); + pDraggedWindow->addWindowDeco(makeUnique(pDraggedWindow)); return true; } diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 653cd11c..7277955d 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -5,7 +5,7 @@ #include #include "../Texture.hpp" #include -#include +#include "../../helpers/memory/Memory.hpp" class CTitleTex { public: @@ -70,6 +70,6 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { struct STitleTexs { // STitleTexs* overriden = nullptr; // TODO: make shit shared in-group to decrease VRAM usage. - std::vector> titleTexs; + std::vector> titleTexs; } m_sTitleTexs; }; diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 2ba3c4a7..9dbb12a6 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -79,7 +79,7 @@ CDecorationPositioner::SWindowPositioningData* CDecorationPositioner::getDataFor if (it != m_vWindowPositioningDatas.end()) return it->get(); - const auto DATA = m_vWindowPositioningDatas.emplace_back(std::make_unique(pWindow, pDecoration)).get(); + const auto DATA = m_vWindowPositioningDatas.emplace_back(makeUnique(pWindow, pDecoration)).get(); DATA->positioningInfo = pDecoration->getPositioningInfo(); diff --git a/src/render/decorations/DecorationPositioner.hpp b/src/render/decorations/DecorationPositioner.hpp index c2d69881..787c6d1f 100644 --- a/src/render/decorations/DecorationPositioner.hpp +++ b/src/render/decorations/DecorationPositioner.hpp @@ -87,13 +87,13 @@ class CDecorationPositioner { bool needsRecalc = false; }; - std::map m_mWindowDatas; - std::vector> m_vWindowPositioningDatas; + std::map m_mWindowDatas; + std::vector> m_vWindowPositioningDatas; - SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow); - void onWindowUnmap(PHLWINDOW pWindow); - void onWindowMap(PHLWINDOW pWindow); - void sanitizeDatas(); + SWindowPositioningData* getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow); + void onWindowUnmap(PHLWINDOW pWindow); + void onWindowMap(PHLWINDOW pWindow); + void sanitizeDatas(); }; -inline std::unique_ptr g_pDecorationPositioner; \ No newline at end of file +inline UP g_pDecorationPositioner; \ No newline at end of file diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index c67d5830..d5dce333 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -442,7 +442,7 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { // start the wm if (!g_pXWayland->pWM) - g_pXWayland->pWM = std::make_unique(); + g_pXWayland->pWM = makeUnique(); g_pCursorManager->setXWaylandCursor(); diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 181955a8..4b0c5a29 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -71,7 +71,7 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); - selection.transfer = std::make_unique(selection); + selection.transfer = makeUnique(selection); selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, selection.transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 71a7c44c..ef139b38 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -225,7 +225,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ } } else if (atom == HYPRATOMS["WM_HINTS"]) { if (reply->value_len != 0) { - XSURF->hints = std::make_unique(); + XSURF->hints = makeUnique(); xcb_icccm_get_wm_hints_from_reply(XSURF->hints.get(), reply); if (!(XSURF->hints->flags & XCB_ICCCM_WM_HINT_INPUT)) @@ -254,7 +254,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ } } else if (atom == HYPRATOMS["WM_NORMAL_HINTS"]) { if (reply->type == HYPRATOMS["WM_SIZE_HINTS"] && reply->value_len > 0) { - XSURF->sizeHints = std::make_unique(); + XSURF->sizeHints = makeUnique(); std::memset(XSURF->sizeHints.get(), 0, sizeof(xcb_size_hints_t)); xcb_icccm_get_wm_size_hints_from_reply(XSURF->sizeHints.get(), reply); @@ -735,7 +735,7 @@ int CXWM::onEvent(int fd, uint32_t mask) { g_pXWayland->pWM.reset(); g_pXWayland->pServer.reset(); // Attempt to create fresh instance - g_pEventLoopManager->doLater([]() { g_pXWayland = std::make_unique(true); }); + g_pEventLoopManager->doLater([]() { g_pXWayland = makeUnique(true); }); return 0; } @@ -1346,7 +1346,7 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { mime = *MIMES.begin(); } - transfer = std::make_unique(*this); + transfer = makeUnique(*this); transfer->request = *e; int p[2]; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 02ade80d..dfaf33b9 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -57,7 +57,7 @@ struct SXSelection { CHyprSignalListener keyboardFocusChange; } listeners; - std::unique_ptr transfer; + UP transfer; }; class CXCBConnection { diff --git a/src/xwayland/XWayland.cpp b/src/xwayland/XWayland.cpp index 6b8a630b..9d2a0ea4 100644 --- a/src/xwayland/XWayland.cpp +++ b/src/xwayland/XWayland.cpp @@ -26,7 +26,7 @@ CXWayland::CXWayland(const bool wantsEnabled) { Debug::log(LOG, "Starting up the XWayland server"); - pServer = std::make_unique(); + pServer = makeUnique(); if (!pServer->create()) { Debug::log(ERR, "XWayland failed to start: it will not work."); diff --git a/src/xwayland/XWayland.hpp b/src/xwayland/XWayland.hpp index 8347a6a7..af8d957c 100644 --- a/src/xwayland/XWayland.hpp +++ b/src/xwayland/XWayland.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include "../helpers/signal/Signal.hpp" #include "../helpers/memory/Memory.hpp" #include "../macros.hpp" @@ -20,8 +19,8 @@ class CXWayland { CXWayland(const bool wantsEnabled); #ifndef NO_XWAYLAND - std::unique_ptr pServer; - std::unique_ptr pWM; + UP pServer; + UP pWM; #endif bool enabled(); @@ -35,7 +34,7 @@ class CXWayland { bool m_enabled = false; }; -inline std::unique_ptr g_pXWayland; +inline UP g_pXWayland; inline std::unordered_map HYPRATOMS = { #ifndef NO_XWAYLAND From 1a0a22ad038bbd51c4e1514868d6dcd505af0242 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 23 Jan 2025 21:27:11 +0000 Subject: [PATCH 1099/2393] configmgr: fix crash on very early plugin loads --- src/config/ConfigManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 08f0f33f..b0665db9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -954,7 +954,8 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { const auto PENABLEXWAYLAND = std::any_cast(m_pConfig->getConfigValue("xwayland:enabled")); g_pCompositor->m_bWantsXwayland = PENABLEXWAYLAND; // enable/disable xwayland usage - if (!isFirstLaunch) { + if (!isFirstLaunch && + g_pXWayland /* XWayland has to be initialized by CCompositor::initManagers for this to make sense, and it doesn't have to be (e.g. very early plugin load) */) { bool prevEnabledXwayland = g_pXWayland->enabled(); if (g_pCompositor->m_bWantsXwayland != prevEnabledXwayland) g_pXWayland = makeUnique(g_pCompositor->m_bWantsXwayland); From 465cf66df14c28427ba30580253be6e3908bd28c Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Thu, 23 Jan 2025 13:57:33 -0800 Subject: [PATCH 1100/2393] protocols: add hyprland_surface_v1.set_visible_region implementation (#9120) --- src/desktop/WLSurface.hpp | 3 +- src/managers/ProtocolManager.cpp | 2 +- src/protocols/HyprlandSurface.cpp | 23 +++++++++++- src/protocols/HyprlandSurface.hpp | 5 ++- src/render/OpenGL.cpp | 17 +++++++-- src/render/OpenGL.hpp | 1 + src/render/pass/SurfacePassElement.cpp | 50 ++++++++++++++++++++++++++ src/render/pass/SurfacePassElement.hpp | 1 + subprojects/hyprland-protocols | 2 +- 9 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/desktop/WLSurface.hpp b/src/desktop/WLSurface.hpp index 057a6f90..5f8da715 100644 --- a/src/desktop/WLSurface.hpp +++ b/src/desktop/WLSurface.hpp @@ -87,7 +87,8 @@ class CWLSurface { float m_fAlphaModifier = 1.F; // used by the hyprland-surface protocol - float m_fOverallOpacity = 1.F; + float m_fOverallOpacity = 1.F; + CRegion m_visibleRegion; struct { CSignal destroy; diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index f73a6d3c..d3270fe2 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -168,7 +168,7 @@ CProtocolManager::CProtocolManager() { PROTO::singlePixel = makeUnique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); - PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 1, "HyprlandSurface"); + PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); if (*PENABLEXXCM) { PROTO::colorManagement = makeUnique(&xx_color_manager_v4_interface, 1, "ColorManagement"); diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp index ca133b78..e3716f10 100644 --- a/src/protocols/HyprlandSurface.cpp +++ b/src/protocols/HyprlandSurface.cpp @@ -3,6 +3,8 @@ #include "../render/Renderer.hpp" #include "core/Compositor.hpp" #include "hyprland-surface-v1.hpp" +#include +#include CHyprlandSurface::CHyprlandSurface(SP resource, SP surface) : m_pSurface(surface) { setResource(std::move(resource)); @@ -36,11 +38,25 @@ void CHyprlandSurface::setResource(SP resource) { m_fOpacity = fOpacity; }); + m_pResource->setSetVisibleRegion([this](CHyprlandSurfaceV1* resource, wl_resource* region) { + if (!region) { + if (!m_visibleRegion.empty()) + m_bVisibleRegionChanged = true; + + m_visibleRegion.clear(); + return; + } + + m_bVisibleRegionChanged = true; + m_visibleRegion = CWLRegionResource::fromResource(region)->region; + }); + listeners.surfaceCommitted = m_pSurface->events.commit.registerListener([this](std::any data) { auto surface = CWLSurface::fromResource(m_pSurface.lock()); - if (surface && surface->m_fOverallOpacity != m_fOpacity) { + if (surface && (surface->m_fOverallOpacity != m_fOpacity || m_bVisibleRegionChanged)) { surface->m_fOverallOpacity = m_fOpacity; + surface->m_visibleRegion = m_visibleRegion; auto box = surface->getSurfaceBoxGlobal(); if (box.has_value()) @@ -61,6 +77,11 @@ void CHyprlandSurface::destroy() { m_pResource.reset(); m_fOpacity = 1.F; + if (!m_visibleRegion.empty()) + m_bVisibleRegionChanged = true; + + m_visibleRegion.clear(); + if (!m_pSurface) PROTO::hyprlandSurface->destroySurface(this); } diff --git a/src/protocols/HyprlandSurface.hpp b/src/protocols/HyprlandSurface.hpp index a5812b89..5c1181c4 100644 --- a/src/protocols/HyprlandSurface.hpp +++ b/src/protocols/HyprlandSurface.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include "WaylandProtocol.hpp" @@ -19,7 +20,9 @@ class CHyprlandSurface { private: SP m_pResource; WP m_pSurface; - float m_fOpacity = 1.0; + float m_fOpacity = 1.0; + bool m_bVisibleRegionChanged = false; + CRegion m_visibleRegion; void destroy(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ceb94c81..8ae667d2 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1556,9 +1556,15 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); - if (m_RenderData.clipBox.width != 0 && m_RenderData.clipBox.height != 0) { - CRegion damageClip{m_RenderData.clipBox.x, m_RenderData.clipBox.y, m_RenderData.clipBox.width, m_RenderData.clipBox.height}; - damageClip.intersect(damage); + if (!m_RenderData.clipBox.empty() || !m_RenderData.clipRegion.empty()) { + CRegion damageClip = m_RenderData.clipBox; + + if (!m_RenderData.clipRegion.empty()) { + if (m_RenderData.clipBox.empty()) + damageClip = m_RenderData.clipRegion; + else + damageClip.intersect(m_RenderData.clipRegion); + } if (!damageClip.empty()) { for (auto const& RECT : damageClip.getRects()) { @@ -2079,6 +2085,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float CRegion texDamage{m_RenderData.damage}; texDamage.intersect(pBox->x, pBox->y, pBox->width, pBox->height); + // While renderTextureInternalWithDamage will clip the blur as well, + // clipping texDamage here allows blur generation to be optimized. + if (!m_RenderData.clipRegion.empty()) + texDamage.intersect(m_RenderData.clipRegion); + if (texDamage.empty()) return; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 3dc3b43a..fd84d478 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -133,6 +133,7 @@ struct SCurrentRenderData { Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); CBox clipBox = {}; // scaled coordinates + CRegion clipRegion; uint32_t discardMode = DISCARD_OPAQUE; float discardOpacity = 0.f; diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index d720081f..b79407c8 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -7,6 +7,8 @@ #include "../../managers/input/InputManager.hpp" #include "../Renderer.hpp" +#include +#include #include using namespace Hyprutils::Utils; @@ -28,6 +30,7 @@ void CSurfacePassElement::draw(const CRegion& damage) { g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; g_pHyprOpenGL->m_RenderData.clipBox = {}; + g_pHyprOpenGL->m_RenderData.clipRegion = {}; g_pHyprOpenGL->m_RenderData.discardMode = 0; g_pHyprOpenGL->m_RenderData.discardOpacity = 0; g_pHyprOpenGL->m_RenderData.useNearestNeighbor = false; @@ -84,6 +87,11 @@ void CSurfacePassElement::draw(const CRegion& damage) { Debug::log(TRACE, "FIXME: rendering surface with color management enabled, should apply necessary transformations"); g_pHyprRenderer->calculateUVForSurface(data.pWindow, data.surface, data.pMonitor->self.lock(), data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); + auto cancelRender = false; + g_pHyprOpenGL->m_RenderData.clipRegion = visibleRegion(cancelRender); + if (cancelRender) + return; + // check for fractional scale surfaces misaligning the buffer size // in those cases it's better to just force nearest neighbor // as long as the window is not animated. During those it'd look weird. @@ -229,6 +237,48 @@ CRegion CSurfacePassElement::opaqueRegion() { return data.texture && data.texture->m_bOpaque ? boundingBox()->expand(-data.rounding) : CRegion{}; } +CRegion CSurfacePassElement::visibleRegion(bool& cancel) { + auto PSURFACE = CWLSurface::fromResource(data.surface); + if (!PSURFACE) + return {}; + + const auto& bufferSize = data.surface->current.bufferSize; + + auto visibleRegion = PSURFACE->m_visibleRegion.copy(); + if (visibleRegion.empty()) + return {}; + + visibleRegion.intersect(CBox(Vector2D(), bufferSize)); + + if (visibleRegion.empty()) { + cancel = true; + return visibleRegion; + } + + // deal with any rounding errors that might come from scaling + visibleRegion.expand(1); + + auto uvTL = g_pHyprOpenGL->m_RenderData.primarySurfaceUVTopLeft; + auto uvBR = g_pHyprOpenGL->m_RenderData.primarySurfaceUVBottomRight; + + if (uvTL == Vector2D(-1, -1)) + uvTL = Vector2D(0, 0); + + if (uvBR == Vector2D(-1, -1)) + uvBR = Vector2D(1, 1); + + visibleRegion.translate(-uvTL * bufferSize); + + auto texBox = getTexBox(); + texBox.scale(data.pMonitor->scale); + texBox.round(); + + visibleRegion.scale((Vector2D(1, 1) / (uvBR - uvTL)) * (texBox.size() / bufferSize)); + visibleRegion.translate((data.pos + data.localPos) * data.pMonitor->scale - data.pMonitor->vecPosition); + + return visibleRegion; +} + void CSurfacePassElement::discard() { if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) { Debug::log(TRACE, "discard for invisible surface"); diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp index 12387367..1b6ddb0b 100644 --- a/src/render/pass/SurfacePassElement.hpp +++ b/src/render/pass/SurfacePassElement.hpp @@ -57,6 +57,7 @@ class CSurfacePassElement : public IPassElement { virtual std::optional boundingBox(); virtual CRegion opaqueRegion(); virtual void discard(); + CRegion visibleRegion(bool& cancel); virtual const char* passName() { return "CSurfacePassElement"; diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 455c0558..4c75dd5c 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 455c055883d9639d4fcbfcedb4c6d12ce313791e +Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 From a8c2d5a616b2ac9c0cf66a0bc999ae57338b60d9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 23 Jan 2025 22:15:09 +0000 Subject: [PATCH 1101/2393] layout: damage window properly on float mode changes fixes #8849 --- src/layout/IHyprLayout.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 576d80eb..9fc84b22 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -717,6 +717,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_bPinned = false; + g_pHyprRenderer->damageWindow(pWindow); + const auto TILED = isWindowTiled(pWindow); // event @@ -788,6 +790,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); pWindow->updateToplevel(); + + g_pHyprRenderer->damageWindow(pWindow); } void IHyprLayout::moveActiveWindow(const Vector2D& delta, PHLWINDOW pWindow) { From dadb2e0949e61d43ace69c5ae65358c6c38e32b4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 23 Jan 2025 22:41:46 +0000 Subject: [PATCH 1102/2393] opengl: use uv to avoid rendering the entire blurbox additionally can use smoothing for rounding fixes #9086 --- src/render/OpenGL.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 8ae667d2..0fe9565f 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1547,11 +1547,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { + if (allowCustomUV && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, verts); - } else { + else glVertexAttribPointer(shader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); - } glEnableVertexAttribArray(shader->posAttrib); glEnableVertexAttribArray(shader->texAttrib); @@ -2156,15 +2155,25 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float // stencil done. Render everything. CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; // render our great blurred FB + // calculate the uv for it + const auto LASTTL = m_RenderData.primarySurfaceUVTopLeft; + const auto LASTBR = m_RenderData.primarySurfaceUVBottomRight; + + m_RenderData.primarySurfaceUVTopLeft = pBox->pos() / MONITORBOX.size(); + m_RenderData.primarySurfaceUVBottomRight = (pBox->pos() + pBox->size()) / MONITORBOX.size(); + static auto PBLURIGNOREOPACITY = CConfigValue("decoration:blur:ignore_opacity"); setMonitorTransformEnabled(true); if (!USENEWOPTIMIZE) setRenderModifEnabled(false); - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, 0, 2.0f, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), pBox, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, round, roundingPower, false, false, true); if (!USENEWOPTIMIZE) setRenderModifEnabled(true); setMonitorTransformEnabled(false); + m_RenderData.primarySurfaceUVTopLeft = LASTTL; + m_RenderData.primarySurfaceUVBottomRight = LASTBR; + // render the window, but clear stencil glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); From bb099e5733ae92c1b563efdb32d3d56a1540ab4a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 23 Jan 2025 22:57:14 +0000 Subject: [PATCH 1103/2393] pass/rect: fix box shrinking with bb fixes #9084 --- src/render/pass/RectPassElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index a57c959e..fe2f1f78 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -24,7 +24,7 @@ bool CRectPassElement::needsPrecomputeBlur() { } std::optional CRectPassElement::boundingBox() { - return data.box.expand(-data.round); + return data.box.copy().expand(-data.round); } CRegion CRectPassElement::opaqueRegion() { From d075d1cab9e8836be4544229486fec004236f3fa Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 23 Jan 2025 22:59:06 +0000 Subject: [PATCH 1104/2393] pass/rect: fix bounding box --- src/render/pass/RectPassElement.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index fe2f1f78..55471e78 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -24,9 +24,9 @@ bool CRectPassElement::needsPrecomputeBlur() { } std::optional CRectPassElement::boundingBox() { - return data.box.copy().expand(-data.round); + return data.box; } CRegion CRectPassElement::opaqueRegion() { - return data.color.a >= 1.F ? *boundingBox() : CRegion{}; + return data.color.a >= 1.F ? boundingBox()->expand(-data.round) : CRegion{}; } From 5d8261aee243fd1bd53f9e0eb27f1a460eac83d6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 00:25:14 +0000 Subject: [PATCH 1105/2393] xwayland: avoid sending value of real size to xwayland --- src/managers/XWaylandManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index ab0bfb88..5a933236 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - setWindowSize(pWindow, pWindow->m_vRealSize->value()); // update xwayland output pos + setWindowSize(pWindow, pWindow->m_vRealSize->goal()); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) From 4a1b960cbedb3e2893eeadecdf2b4a7314634306 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 00:49:47 +0000 Subject: [PATCH 1106/2393] layout: set window size after toggling floating --- src/layout/IHyprLayout.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 9fc84b22..49633d94 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -788,9 +788,8 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { } g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); - pWindow->updateToplevel(); - + g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize->goal()); g_pHyprRenderer->damageWindow(pWindow); } From 944e36ea2e71db20cf3f8b2e5cbf978a5bf5268b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 13:23:23 +0000 Subject: [PATCH 1107/2393] config: fix misc:disable_autoreload fixes #9139 --- src/config/ConfigManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index b0665db9..f5c9b3ee 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -897,9 +897,10 @@ std::optional CConfigManager::resetHLConfig() { void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static const auto PDISABLEAUTORELOAD = CConfigValue("misc:disable_autoreload"); static int prevEnabledExplicit = *PENABLEEXPLICIT; - g_pConfigWatcher->setWatchList(m_configPaths); + g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); From 57a39984dddd00fd1aca436e149b7566e5e48d95 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 13:37:23 +0000 Subject: [PATCH 1108/2393] input: abord dnd op on escape pressed ref #9154 --- src/managers/KeybindManager.cpp | 4 ++++ src/protocols/core/DataDevice.cpp | 6 ++++++ src/protocols/core/DataDevice.hpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index f4a55a73..4706c1e1 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -4,6 +4,7 @@ #include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../protocols/GlobalShortcuts.hpp" +#include "../protocols/core/DataDevice.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "KeybindManager.hpp" #include "PointerManager.hpp" @@ -432,6 +433,9 @@ bool CKeybindManager::onKeyEvent(std::any event, SP pKeyboard) { const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbSymState : m_pXKBTranslationState, KEYCODE); const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE); + if (keysym == XKB_KEY_Escape || internalKeysym == XKB_KEY_Escape) + PROTO::data->abortDndIfPresent(); + // handleInternalKeybinds returns true when the key should be suppressed, // while this function returns true when the key event should be sent if (handleInternalKeybinds(internalKeysym)) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index ade16498..36437dd4 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -814,3 +814,9 @@ void CWLDataDeviceProtocol::renderDND(PHLMONITOR pMonitor, timespec* when) { bool CWLDataDeviceProtocol::dndActive() { return dnd.currentSource; } + +void CWLDataDeviceProtocol::abortDndIfPresent() { + if (!dndActive()) + return; + abortDrag(); +} diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index 5101862e..d8bc2b9c 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -144,6 +144,9 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { // TODO: move handling to seatmgr bool dndActive(); + // called on an escape key pressed, for moments where it gets stuck + void abortDndIfPresent(); + private: void destroyResource(CWLDataDeviceManagerResource* resource); void destroyResource(CWLDataDeviceResource* resource); From 0e5d03a5574efb78f06f2723b345bac867d98696 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Fri, 24 Jan 2025 15:50:15 +0000 Subject: [PATCH 1109/2393] datadevice: do the unfocus surface stuff before dndActive is true (#9157) --- src/managers/SeatManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 8fee6b16..6d2b906f 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -194,7 +194,7 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocus == surf) return; - if (PROTO::data->dndActive()) { + if (PROTO::data->dndActive() && surf) { if (state.dndPointerFocus == surf) return; Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd, but setting dndPointerFocus"); From 9b3f71390c3db14fd2fa2ff14d533eee34538c55 Mon Sep 17 00:00:00 2001 From: heather7283 <142042427+heather7283@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:51:31 +0400 Subject: [PATCH 1110/2393] layershell: check if layer is valid (#9156) fixes compositor crash when client tried to create a layer surface with invalid layer argument --- src/protocols/LayerShell.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 1533a7c0..c88dc925 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -233,6 +233,11 @@ void CLayerShellProtocol::onGetLayerSurface(CZwlrLayerShellV1* pMgr, uint32_t id return; } + if UNLIKELY (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) { + pMgr->error(ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER, "Invalid layer"); + return; + } + const auto RESOURCE = m_vLayers.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), SURF, namespace_, PMONITOR, layer)); if UNLIKELY (!RESOURCE->good()) { From fda9790cde5eb2bd15c19a1e67211eabbebf9024 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 17:51:11 +0000 Subject: [PATCH 1111/2393] layout: force full damage on toggling floating mode fixes #8849 --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 49633d94..ffc08e46 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -717,7 +717,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { pWindow->m_bPinned = false; - g_pHyprRenderer->damageWindow(pWindow); + g_pHyprRenderer->damageWindow(pWindow, true); const auto TILED = isWindowTiled(pWindow); From 80b2fd135b45f2c2e41ceb312314908f6a3e7b30 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:22:05 +0000 Subject: [PATCH 1112/2393] animations: fix borderangle once (#9149) --- src/Compositor.cpp | 5 +---- src/desktop/Window.cpp | 8 ++++++++ src/desktop/Window.hpp | 1 + 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index aeec2830..cb0665e5 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1155,6 +1155,7 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface g_pXWaylandManager->activateWindow(pWindow, true); // sets the m_pLastWindow pWindow->updateDynamicRules(); + pWindow->onFocusAnimUpdate(); updateWindowAnimatedDecorationValues(pWindow); @@ -1851,10 +1852,6 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } } - // tick angle if it's not running (aka dead) - if (!pWindow->m_fBorderAngleAnimationProgress->isBeingAnimated()) - pWindow->m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); - // opacity const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index fb5904be..5306bbb4 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1274,6 +1274,14 @@ void CWindow::onWorkspaceAnimUpdate() { m_vFloatingOffset = offset; } +void CWindow::onFocusAnimUpdate() { + // borderangle once + if (m_fBorderAngleAnimationProgress->enabled() && !m_fBorderAngleAnimationProgress->isBeingAnimated()) { + m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + *m_fBorderAngleAnimationProgress = 1.f; + } +} + int CWindow::popupsCount() { if (m_bIsX11) return 0; diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 5b4ad654..cff13b03 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -454,6 +454,7 @@ class CWindow { void switchWithWindowInGroup(PHLWINDOW pWindow); void setAnimationsToMove(); void onWorkspaceAnimUpdate(); + void onFocusAnimUpdate(); void onUpdateState(); void onUpdateMeta(); void onX11Configure(CBox box); From d8f79d7678f428738f3173020109bd7b7fbd0840 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 24 Jan 2025 20:30:12 +0000 Subject: [PATCH 1113/2393] core: add --verify-config to verify the config with Hyprland fixes #9135 --- src/Compositor.cpp | 18 ++++++++++++++++-- src/Compositor.hpp | 11 ++++++----- src/config/ConfigManager.cpp | 30 +++++++++++++++++++++++------- src/config/ConfigManager.hpp | 8 +++++--- src/main.cpp | 17 ++++++++++++----- src/managers/AnimationManager.cpp | 3 ++- src/managers/KeybindManager.cpp | 7 +++++-- 7 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index cb0665e5..ab9c16f7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" @@ -162,7 +163,10 @@ void CCompositor::restoreNofile() { Debug::log(ERR, "Failed restoring NOFILE limits"); } -CCompositor::CCompositor() : m_iHyprlandPID(getpid()) { +CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) { + if (onlyConfig) + return; + m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { @@ -226,7 +230,7 @@ CCompositor::CCompositor() : m_iHyprlandPID(getpid()) { } CCompositor::~CCompositor() { - if (!m_bIsShuttingDown) + if (!m_bIsShuttingDown && !m_bOnlyConfigVerification) cleanup(); } @@ -262,6 +266,16 @@ static bool filterGlobals(const wl_client* client, const wl_global* global, void // void CCompositor::initServer(std::string socketName, int socketFd) { + if (m_bOnlyConfigVerification) { + g_pHookSystem = makeUnique(); + g_pKeybindManager = makeUnique(); + g_pAnimationManager = makeUnique(); + g_pConfigManager = makeUnique(); + + std::println("\n\n======== Config parsing result:\n\n{}", g_pConfigManager->verify()); + return; + } + m_sWLDisplay = wl_display_create(); wl_display_set_global_filter(m_sWLDisplay, ::filterGlobals, nullptr); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index f2e2ca14..295878df 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -24,7 +24,7 @@ enum eManagersInitStage : uint8_t { class CCompositor { public: - CCompositor(); + CCompositor(bool onlyConfig = false); ~CCompositor(); wl_display* m_sWLDisplay; @@ -71,10 +71,11 @@ class CCompositor { bool m_bUnsafeState = false; // unsafe state is when there is no monitors. bool m_bNextIsUnsafe = false; PHLMONITORREF m_pUnsafeOutput; // fallback output for the unsafe state - bool m_bIsShuttingDown = false; - bool m_bFinalRequests = false; - bool m_bDesktopEnvSet = false; - bool m_bWantsXwayland = true; + bool m_bIsShuttingDown = false; + bool m_bFinalRequests = false; + bool m_bDesktopEnvSet = false; + bool m_bWantsXwayland = true; + bool m_bOnlyConfigVerification = false; // ------------------------------------------------- // diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f5c9b3ee..c5d70329 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -19,6 +19,7 @@ #include "../render/Renderer.hpp" #include "../hyprerror/HyprError.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/eventLoop/EventLoopManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../debug/HyprNotificationOverlay.hpp" @@ -730,15 +731,18 @@ CConfigManager::CConfigManager() { resetHLConfig(); - Debug::log(INFO, - "!!!!HEY YOU, YES YOU!!!!: further logs to stdout / logfile are disabled by default. BEFORE SENDING THIS LOG, ENABLE THEM. Use debug:disable_logs = false to do so: " - "https://wiki.hyprland.org/Configuring/Variables/#debug"); + if (!g_pCompositor->m_bOnlyConfigVerification) { + Debug::log( + INFO, + "!!!!HEY YOU, YES YOU!!!!: further logs to stdout / logfile are disabled by default. BEFORE SENDING THIS LOG, ENABLE THEM. Use debug:disable_logs = false to do so: " + "https://wiki.hyprland.org/Configuring/Variables/#debug"); + } Debug::disableLogs = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_logs")->getDataStaticPtr()); Debug::disableTime = reinterpret_cast(m_pConfig->getConfigValuePtr("debug:disable_time")->getDataStaticPtr()); - if (ERR.has_value()) - g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); + if (g_pEventLoopManager && ERR.has_value()) + g_pEventLoopManager->doLater([ERR] { g_pHyprError->queueCreate(ERR.value(), CHyprColor{1.0, 0.1, 0.1, 1.0}); }); } std::optional CConfigManager::generateConfig(std::string configPath) { @@ -820,11 +824,23 @@ void CConfigManager::reload() { EMIT_HOOK_EVENT("preConfigReload", nullptr); setDefaultAnimationVars(); resetHLConfig(); - configCurrentPath = getMainConfigPath(); - const auto ERR = m_pConfig->parse(); + configCurrentPath = getMainConfigPath(); + const auto ERR = m_pConfig->parse(); + m_bLastConfigVerificationWasSuccessful = !ERR.error; postConfigReload(ERR); } +std::string CConfigManager::verify() { + setDefaultAnimationVars(); + resetHLConfig(); + configCurrentPath = getMainConfigPath(); + const auto ERR = m_pConfig->parse(); + m_bLastConfigVerificationWasSuccessful = !ERR.error; + if (ERR.error) + return ERR.getError(); + return "config ok"; +} + void CConfigManager::setDefaultAnimationVars() { m_AnimationTree.createNode("__internal_fadeCTM"); m_AnimationTree.createNode("global"); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 31ad81cd..564c1ebf 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -144,6 +144,7 @@ class CConfigManager { void init(); void reload(); + std::string verify(); int getDeviceInt(const std::string&, const std::string&, const std::string& fallback = ""); float getDeviceFloat(const std::string&, const std::string&, const std::string& fallback = ""); @@ -257,9 +258,10 @@ class CConfigManager { {"scrollmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollMouse; }}, {"scrolltouchpad", [](const PHLWINDOW& pWindow) { return &pWindow->m_sWindowData.scrollTouchpad; }}}; - bool m_bWantsMonitorReload = false; - bool m_bNoMonitorReload = false; - bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + bool m_bWantsMonitorReload = false; + bool m_bNoMonitorReload = false; + bool isLaunchingExecOnce = false; // For exec-once to skip initial ws tracking + bool m_bLastConfigVerificationWasSuccessful = true; private: UP m_pConfig; diff --git a/src/main.cpp b/src/main.cpp index bb5e5622..d244f10f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,7 @@ static void help() { --wayland-fd FD - Sets the Wayland socket fd (for Wayland socket handover) --systeminfo - Prints system infos --i-am-really-stupid - Omits root user privileges check (why would you do that?) + --verify-config - Do not run Hyprland, only print if the config has any errors --version -v - Print this binary's version)"); } @@ -49,7 +50,7 @@ int main(int argc, char** argv) { std::string configPath; std::string socketName; int socketFd = -1; - bool ignoreSudo = false; + bool ignoreSudo = false, verifyConfig = false; std::vector args{argv + 1, argv + argc}; @@ -124,6 +125,9 @@ int main(int argc, char** argv) { } else if (*it == "--systeminfo") { std::println("{}", systemInfoRequest(eHyprCtlOutputFormat::FORMAT_NORMAL, "")); return 0; + } else if (*it == "--verify-config") { + verifyConfig = true; + continue; } else { std::println(stderr, "[ ERROR ] Unknown option '{}' !", *it); help(); @@ -138,9 +142,8 @@ int main(int argc, char** argv) { " Hint: Use the --i-am-really-stupid flag to omit that check."); return 1; - } else if (ignoreSudo && NInit::isSudo()) { + } else if (ignoreSudo && NInit::isSudo()) std::println("Superuser privileges check is omitted. I hope you know what you're doing."); - } if (socketName.empty() ^ (socketFd == -1)) { std::println(stderr, @@ -150,12 +153,13 @@ int main(int argc, char** argv) { return 1; } - std::println("Welcome to Hyprland!"); + if (!verifyConfig) + std::println("Welcome to Hyprland!"); // let's init the compositor. // it initializes basic Wayland stuff in the constructor. try { - g_pCompositor = makeUnique(); + g_pCompositor = makeUnique(verifyConfig); g_pCompositor->explicitConfigPath = configPath; } catch (const std::exception& e) { std::println(stderr, "Hyprland threw in ctor: {}\nCannot continue.", e.what()); @@ -164,6 +168,9 @@ int main(int argc, char** argv) { g_pCompositor->initServer(socketName, socketFd); + if (verifyConfig) + return !g_pConfigManager->m_bLastConfigVerificationWasSuccessful; + if (!envEnabled("HYPRLAND_NO_RT")) NInit::gainRealTime(); diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f884acdd..964f7cfa 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -34,7 +34,8 @@ static int wlTick(SP self, void* data) { CHyprAnimationManager::CHyprAnimationManager() { m_pAnimationTimer = SP(new CEventLoopTimer(std::chrono::microseconds(500), wlTick, nullptr)); - g_pEventLoopManager->addTimer(m_pAnimationTimer); + if (g_pEventLoopManager) // null in --verify-config mode + g_pEventLoopManager->addTimer(m_pAnimationTimer); addBezierWithName("linear", Vector2D(0.0, 0.0), Vector2D(1.0, 1.0)); } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4706c1e1..e2191bc6 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -172,8 +172,11 @@ CKeybindManager::CKeybindManager() { }, nullptr); - g_pEventLoopManager->addTimer(m_pLongPressTimer); - g_pEventLoopManager->addTimer(m_pRepeatKeyTimer); + // null in --verify-config mode + if (g_pEventLoopManager) { + g_pEventLoopManager->addTimer(m_pLongPressTimer); + g_pEventLoopManager->addTimer(m_pRepeatKeyTimer); + } static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { // clear cuz realloc'd From 1815f9a2e5e12cafa670e0f4f7eb10dc9436868c Mon Sep 17 00:00:00 2001 From: heather7283 <142042427+heather7283@users.noreply.github.com> Date: Sat, 25 Jan 2025 03:26:46 +0400 Subject: [PATCH 1114/2393] compositor: fix incorrect cast, use lambda capture instead (#9161) --- src/Compositor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ab9c16f7..fa73be66 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2519,13 +2519,13 @@ PHLLS CCompositor::getLayerSurfaceFromSurface(SP pSurface) { continue; ls->layerSurface->surface->breadthfirst( - [](SP surf, const Vector2D& offset, void* data) { - if (surf == ((std::pair, bool>*)data)->first) { - *(bool*)data = true; + [&result](SP surf, const Vector2D& offset, void* data) { + if (surf == result.first) { + result.second = true; return; } }, - &result); + nullptr); if (result.second) return ls; From 089fdd1ea0d991da5b068db51531f54c90a2df25 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Fri, 24 Jan 2025 23:27:24 +0000 Subject: [PATCH 1115/2393] window: only set m_iMonitorMovedFrom, when moving to a different monitor (#9160) --- src/Compositor.cpp | 1 - src/desktop/Window.cpp | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index fa73be66..e1ded6b6 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1867,7 +1867,6 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // opacity - const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5306bbb4..4be8fac5 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -420,12 +420,13 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); - const auto OLDWORKSPACE = m_pWorkspace; + const auto OLDWORKSPACE = m_pWorkspace; + const bool TOANOTHERMONITOR = OLDWORKSPACE && OLDWORKSPACE->monitorID() != pWorkspace->monitorID(); m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); *m_fMovingToWorkspaceAlpha = 0.F; m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); - m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; + m_iMonitorMovedFrom = TOANOTHERMONITOR ? OLDWORKSPACE->monitorID() : -1; m_pWorkspace = pWorkspace; From 354d4594de6a14e89ab337681dac2d898bc18cbf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 25 Jan 2025 02:35:41 +0000 Subject: [PATCH 1116/2393] xwayland: various window handling fixes I hate this fucking garbage --- src/desktop/Window.cpp | 8 ++++---- src/events/Windows.cpp | 5 ++++- src/managers/XWaylandManager.cpp | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 4be8fac5..97d7ecc0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1556,10 +1556,10 @@ void CWindow::onX11Configure(CBox box) { } } - m_vPosition = m_vRealPosition->value(); - m_vSize = m_vRealSize->value(); + m_vPosition = m_vRealPosition->goal(); + m_vSize = m_vRealSize->goal(); - m_pXWaylandSurface->configure(box); + g_pXWaylandManager->setWindowSize(m_pSelf.lock(), box.size(), true); m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); @@ -1569,7 +1569,7 @@ void CWindow::onX11Configure(CBox box) { if (!m_pWorkspace || !m_pWorkspace->isVisible()) return; // further things are only for visible windows - m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->value() + m_vRealSize->value() / 2.f)->activeWorkspace; + m_pWorkspace = g_pCompositor->getMonitorFromVector(m_vRealPosition->goal() + m_vRealSize->goal() / 2.f)->activeWorkspace; g_pCompositor->changeWindowZOrder(m_pSelf.lock(), true); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index cadd4cbc..525adc02 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -43,7 +43,7 @@ static void setVector2DAnimToMove(WP pav) { animvar->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsMove")); const auto PHLWINDOW = animvar->m_Context.pWindow.lock(); - if (PHLWINDOW && !PHLWINDOW->m_vRealPosition->isBeingAnimated() && !PHLWINDOW->m_vRealSize->isBeingAnimated()) + if (PHLWINDOW) PHLWINDOW->m_bAnimatingIn = false; } @@ -680,6 +680,9 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; + + if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) + g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); } void Events::listener_unmapWindow(void* owner, void* data) { diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 5a933236..8956cf3a 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - setWindowSize(pWindow, pWindow->m_vRealSize->goal()); // update xwayland output pos + setWindowSize(pWindow, pWindow->m_vRealSize->value(), true); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) @@ -162,7 +162,9 @@ bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (a == HYPRATOMS["_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"] || a == HYPRATOMS["_NET_WM_WINDOW_TYPE_MENU"]) pWindow->m_bX11ShouldntFocus = true; - pWindow->m_bNoInitialFocus = true; + if (a != HYPRATOMS["_NET_WM_WINDOW_TYPE_DIALOG"]) + pWindow->m_bNoInitialFocus = true; + return true; } From 065e89648b27017871c38831cf34def94feb72d6 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 25 Jan 2025 15:33:27 +0200 Subject: [PATCH 1117/2393] flake.lock: update --- flake.lock | 91 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/flake.lock b/flake.lock index ed1702d1..34249b0a 100644 --- a/flake.lock +++ b/flake.lock @@ -181,11 +181,11 @@ ] }, "locked": { - "lastModified": 1737634810, - "narHash": "sha256-ZIJ03DeisbQuDaADSgmbgyocjecaozK4yGTa0/9bOr0=", + "lastModified": 1737811848, + "narHash": "sha256-WZ7LeiKHk5Y94MU5gHIWn0r8asWxYOvie4LqfCjVIZU=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "a9852dbf5a1ec77cf617543728144c1362709e46", + "rev": "9c0831ff98856c0f312fcb8b57553fbe3dd34d5b", "type": "github" }, "original": { @@ -196,12 +196,17 @@ }, "hyprlang": { "inputs": { - "hyprutils": [ + "hyprutils": "hyprutils", + "nixpkgs": [ "hyprland-qtutils", - "hyprutils" + "hyprland-qt-support", + "nixpkgs" ], - "nixpkgs": "nixpkgs", - "systems": "systems" + "systems": [ + "hyprland-qtutils", + "hyprland-qt-support", + "systems" + ] }, "locked": { "lastModified": 1737634606, @@ -246,9 +251,15 @@ "hyprutils": { "inputs": { "nixpkgs": [ + "hyprland-qtutils", + "hyprland-qt-support", + "hyprlang", "nixpkgs" ], "systems": [ + "hyprland-qtutils", + "hyprland-qt-support", + "hyprlang", "systems" ] }, @@ -266,6 +277,29 @@ "type": "github" } }, + "hyprutils_2": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1737725508, + "narHash": "sha256-jGmcPc6y/prg/4A8KGYqJ27nSPaProCMiFadaxNAKvA=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "fb0c2d1de3d1ef7396d19c18ac09e12bd956929e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ @@ -291,27 +325,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", + "lastModified": 1737632463, + "narHash": "sha256-38J9QfeGSej341ouwzqf77WIHAScihAKCt8PQJ+NH28=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1737469691, - "narHash": "sha256-nmKOgAU48S41dTPIXAq0AHZSehWUn6ZPrUKijHAMmIk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9e4d5190a9482a1fb9d18adf0bdb83c6e506eaab", + "rev": "0aa475546ed21629c4f5bbf90e38c846a99ec9e9", "type": "github" }, "original": { @@ -351,11 +369,11 @@ "hyprland-protocols": "hyprland-protocols", "hyprland-qtutils": "hyprland-qtutils", "hyprlang": "hyprlang_2", - "hyprutils": "hyprutils", + "hyprutils": "hyprutils_2", "hyprwayland-scanner": "hyprwayland-scanner", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs", "pre-commit-hooks": "pre-commit-hooks", - "systems": "systems_2", + "systems": "systems", "xdph": "xdph" } }, @@ -374,21 +392,6 @@ "type": "github" } }, - "systems_2": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, "xdph": { "inputs": { "hyprland-protocols": [ From 107723bdf448223385034a4ea724328de7ba50cc Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 25 Jan 2025 18:23:36 +0000 Subject: [PATCH 1118/2393] config: disable borderangle by default (#9165) --- src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index c5d70329..fd4783da 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -882,6 +882,7 @@ void CConfigManager::setDefaultAnimationVars() { // init the root nodes m_AnimationTree.setConfigForNode("global", 1, 8.f, "", "default"); m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "", "linear"); + m_AnimationTree.setConfigForNode("borderangle", 0, 0.f, "", "default"); } std::optional CConfigManager::resetHLConfig() { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 97d7ecc0..962386c8 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -552,9 +552,11 @@ void CWindow::onMap() { m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); - m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); - m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); - *m_fBorderAngleAnimationProgress = 1.f; + if (m_fBorderAngleAnimationProgress->enabled()) { + m_fBorderAngleAnimationProgress->setValueAndWarp(0.f); + m_fBorderAngleAnimationProgress->setCallbackOnEnd([&](WP p) { onBorderAngleAnimEnd(p); }, false); + *m_fBorderAngleAnimationProgress = 1.f; + } m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); From f3fc8d599a7812a25f2d53957c0692d339359b43 Mon Sep 17 00:00:00 2001 From: heather7283 <142042427+heather7283@users.noreply.github.com> Date: Sat, 25 Jan 2025 22:23:53 +0400 Subject: [PATCH 1119/2393] config/ConfigWatcher.cpp: add missing include needed for clang (#9166) --- src/config/ConfigWatcher.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index 38191e9e..c0a9c591 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -3,6 +3,7 @@ #include "../debug/Log.hpp" #include #include +#include CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { if (m_inotifyFd < 0) { From bce58d9d6554f1b69ecf38e19f0921230e37ab6d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 25 Jan 2025 18:34:10 +0000 Subject: [PATCH 1120/2393] dwindle: fix possible crash on null ws --- src/layout/DwindleLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index c6cf2b4c..6d06a3a1 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -105,8 +105,8 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for break; } } - } else - PMONITOR = g_pCompositor->getWorkspaceByID(pNode->workspaceID)->m_pMonitor.lock(); + } else if (const auto WS = g_pCompositor->getWorkspaceByID(pNode->workspaceID); WS) + PMONITOR = WS->m_pMonitor.lock(); if (!PMONITOR) { Debug::log(ERR, "Orphaned Node {}!!", pNode); From 9199a9746d7a9355fd349909cb0f773b513ae912 Mon Sep 17 00:00:00 2001 From: Junxuan Liao <70618504+MikeWalrus@users.noreply.github.com> Date: Sat, 25 Jan 2025 12:44:13 -0600 Subject: [PATCH 1121/2393] input: pass touch events to lock screens (#9129) * refactor: use weak pointers for session lock surfaces * input: pass touch events to lock screens --- src/managers/SessionLockManager.cpp | 10 +++++----- src/managers/SessionLockManager.hpp | 18 ++++++++--------- src/managers/input/InputManager.hpp | 10 ++++++---- src/managers/input/Touch.cpp | 30 ++++++++++++++++++++++++----- src/render/Renderer.cpp | 2 +- src/render/Renderer.hpp | 2 +- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index ea0d8dfc..996860a1 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -95,20 +95,20 @@ bool CSessionLockManager::isSessionLocked() { return PROTO::sessionLock->isLocked(); } -SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64_t id) { +WP CSessionLockManager::getSessionLockSurfaceForMonitor(uint64_t id) { if (!m_pSessionLock) - return nullptr; + return {}; for (auto const& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->iMonitorID == id) { if (sls->mapped) - return sls.get(); + return sls; else - return nullptr; + return {}; } } - return nullptr; + return {}; } // We don't want the red screen to flash. diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index aaf78819..51d4cefb 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -49,20 +49,20 @@ class CSessionLockManager { CSessionLockManager(); ~CSessionLockManager() = default; - SSessionLockSurface* getSessionLockSurfaceForMonitor(uint64_t); + WP getSessionLockSurfaceForMonitor(uint64_t); - float getRedScreenAlphaForMonitor(uint64_t); + float getRedScreenAlphaForMonitor(uint64_t); - bool isSessionLocked(); - bool isSessionLockPresent(); - bool isSurfaceSessionLock(SP); - bool anySessionLockSurfacesPresent(); + bool isSessionLocked(); + bool isSessionLockPresent(); + bool isSurfaceSessionLock(SP); + bool anySessionLockSurfacesPresent(); - void removeSessionLockSurface(SSessionLockSurface*); + void removeSessionLockSurface(SSessionLockSurface*); - void onLockscreenRenderedOnMonitor(uint64_t id); + void onLockscreenRenderedOnMonitor(uint64_t id); - bool shallConsiderLockMissing(); + bool shallConsiderLockMissing(); private: UP m_pSessionLock; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index c0f1939e..3afb1b88 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -10,6 +10,7 @@ #include "../../devices/IPointer.hpp" #include "../../devices/ITouch.hpp" #include "../../devices/Tablet.hpp" +#include "../SessionLockManager.hpp" class CPointerConstraint; class CWindow; @@ -52,10 +53,11 @@ enum eBorderIconDirection : uint8_t { }; struct STouchData { - PHLWINDOWREF touchFocusWindow; - PHLLSREF touchFocusLS; - WP touchFocusSurface; - Vector2D touchSurfaceOrigin; + WP touchFocusLockSurface; + PHLWINDOWREF touchFocusWindow; + PHLLSREF touchFocusLS; + WP touchFocusSurface; + Vector2D touchSurfaceOrigin; }; // The third row is always 0 0 1 and is not expected by `libinput_device_config_calibration_set_matrix` diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index 990fbc41..3d35764e 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -1,4 +1,6 @@ #include "InputManager.hpp" +#include "../SessionLockManager.hpp" +#include "../../protocols/SessionLock.hpp" #include "../../Compositor.hpp" #include "../../desktop/LayerSurface.hpp" #include "../../config/ConfigValue.hpp" @@ -6,6 +8,7 @@ #include "../SeatManager.hpp" #include "managers/AnimationManager.hpp" #include "../HookSystemManager.hpp" +#include "debug/Log.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { m_bLastInputTouch = true; @@ -57,13 +60,25 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } } - m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus; - m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus; - m_sTouchData.touchFocusLS = m_pFoundLSToFocus; + if (g_pSessionLockManager->isSessionLocked()) { + m_sTouchData.touchFocusLockSurface = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID); + if (!m_sTouchData.touchFocusLockSurface) + Debug::log(WARN, "The session is locked but can't find a lock surface"); + else + m_sTouchData.touchFocusSurface = m_sTouchData.touchFocusLockSurface->surface->surface(); + } else { + m_sTouchData.touchFocusLockSurface.reset(); + m_sTouchData.touchFocusWindow = m_pFoundWindowToFocus; + m_sTouchData.touchFocusSurface = m_pFoundSurfaceToFocus; + m_sTouchData.touchFocusLS = m_pFoundLSToFocus; + } Vector2D local; - if (!m_sTouchData.touchFocusWindow.expired()) { + if (m_sTouchData.touchFocusLockSurface) { + local = g_pInputManager->getMouseCoordsInternal() - PMONITOR->vecPosition; + m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local; + } else if (!m_sTouchData.touchFocusWindow.expired()) { if (m_sTouchData.touchFocusWindow->m_bIsX11) { local = (g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusWindow->m_vRealPosition->goal()) * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy; m_sTouchData.touchSurfaceOrigin = m_sTouchData.touchFocusWindow->m_vRealPosition->goal(); @@ -126,7 +141,12 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x))); return; } - if (validMapped(m_sTouchData.touchFocusWindow)) { + if (m_sTouchData.touchFocusLockSurface) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLockSurface->iMonitorID); + g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); + auto local = g_pInputManager->getMouseCoordsInternal() - PMONITOR->vecPosition; + g_pSeatManager->sendTouchMotion(e.timeMs, e.touchID, local); + } else if (validMapped(m_sTouchData.touchFocusWindow)) { const auto PMONITOR = m_sTouchData.touchFocusWindow->m_pMonitor.lock(); g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 384db1e6..d82d79d1 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -768,7 +768,7 @@ void CHyprRenderer::renderIMEPopup(CInputPopup* pPopup, PHLMONITOR pMonitor, tim &renderdata); } -void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, PHLMONITOR pMonitor, timespec* time) { +void CHyprRenderer::renderSessionLockSurface(WP pSurface, PHLMONITOR pMonitor, timespec* time) { CSurfacePassElement::SRenderData renderdata = {pMonitor, time, pMonitor->vecPosition, pMonitor->vecPosition}; renderdata.blur = false; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 1ef1eecc..30fba3ca 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -120,7 +120,7 @@ class CHyprRenderer { void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, timespec*); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special) void renderWindow(PHLWINDOW, PHLMONITOR, timespec*, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false); void renderLayer(PHLLS, PHLMONITOR, timespec*, bool popups = false); - void renderSessionLockSurface(SSessionLockSurface*, PHLMONITOR, timespec*); + void renderSessionLockSurface(WP, PHLMONITOR, timespec*); void renderDragIcon(PHLMONITOR, timespec*); void renderIMEPopup(CInputPopup*, PHLMONITOR, timespec*); void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry); From 45c3787e75323999d2f43b6f83972f4cb11a81f9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 25 Jan 2025 19:37:33 +0000 Subject: [PATCH 1122/2393] window: revert only set m_iMonitorMovedFrom, when moving to a different monitor This reverts commit 089fdd1ea0d991da5b068db51531f54c90a2df25. Great commit. --- src/Compositor.cpp | 1 + src/desktop/Window.cpp | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e1ded6b6..fa73be66 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1867,6 +1867,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { } // opacity + const auto PWORKSPACE = pWindow->m_pWorkspace; if (pWindow->isEffectiveInternalFSMode(FSMODE_FULLSCREEN)) { *pWindow->m_fActiveInactiveAlpha = pWindow->m_sWindowData.alphaFullscreen.valueOrDefault().applyAlpha(*PFULLSCREENALPHA); } else { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 962386c8..5f84aa3a 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -420,13 +420,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { static auto PCLOSEONLASTSPECIAL = CConfigValue("misc:close_special_on_empty"); - const auto OLDWORKSPACE = m_pWorkspace; - const bool TOANOTHERMONITOR = OLDWORKSPACE && OLDWORKSPACE->monitorID() != pWorkspace->monitorID(); + const auto OLDWORKSPACE = m_pWorkspace; m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); *m_fMovingToWorkspaceAlpha = 0.F; m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); - m_iMonitorMovedFrom = TOANOTHERMONITOR ? OLDWORKSPACE->monitorID() : -1; + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; m_pWorkspace = pWorkspace; From 445acec2a29adbb30196d8b92f86270a038b7ee5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 25 Jan 2025 20:36:44 +0000 Subject: [PATCH 1123/2393] core: move sendWindowSize off of xwaylandmgr additionally fixes that one weird x11 issue with floating windows being mis-sized on open --- src/Compositor.cpp | 2 +- src/desktop/Window.cpp | 45 +++++++++++++++++-- src/desktop/Window.hpp | 2 + src/desktop/Workspace.cpp | 2 +- src/events/Windows.cpp | 10 +++-- src/layout/DwindleLayout.cpp | 4 +- src/layout/IHyprLayout.cpp | 10 ++--- src/layout/MasterLayout.cpp | 4 +- src/managers/KeybindManager.cpp | 2 +- src/managers/XWaylandManager.cpp | 40 +---------------- src/managers/XWaylandManager.hpp | 1 - .../decorations/CHyprGroupBarDecoration.cpp | 2 +- 12 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index fa73be66..3f9126b7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2325,7 +2325,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS updateFullscreenFadeOnWorkspace(PWORKSPACE); - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); PWORKSPACE->forceReportSizesToWindows(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5f84aa3a..96b87205 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -453,7 +453,7 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } // update xwayland coords - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->goal()); + sendWindowSize(m_vRealSize->goal()); if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) @@ -1309,7 +1309,7 @@ void CWindow::clampWindowSize(const std::optional minSize, const std:: *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; *m_vRealSize = NEWSIZE; - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), NEWSIZE); + sendWindowSize(NEWSIZE); } bool CWindow::isFullscreen() { @@ -1533,7 +1533,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), m_vRealSize->goal(), true); + sendWindowSize(m_vRealSize->goal(), true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); return; @@ -1560,7 +1560,7 @@ void CWindow::onX11Configure(CBox box) { m_vPosition = m_vRealPosition->goal(); m_vSize = m_vRealSize->goal(); - g_pXWaylandManager->setWindowSize(m_pSelf.lock(), box.size(), true); + sendWindowSize(box.size(), true); m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); @@ -1690,3 +1690,40 @@ Vector2D CWindow::requestedMaxSize() { return maxSize; } + +void CWindow::sendWindowSize(Vector2D size, bool force, std::optional overridePos) { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + const auto PMONITOR = m_pMonitor.lock(); + + size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + + // calculate pos + // TODO: this should be decoupled from setWindowSize IMO + Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); + + if (m_bIsX11 && PMONITOR) { + windowPos -= PMONITOR->vecPosition; // normalize to monitor + if (*PXWLFORCESCALEZERO) + windowPos *= PMONITOR->scale; // scale if applicable + windowPos += PMONITOR->vecXWaylandPosition; // move to correct position for xwayland + } + + if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) + return; + + m_vReportedPosition = windowPos; + m_vPendingReportedSize = size; + + m_fX11SurfaceScaledBy = 1.0f; + + if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) { + size *= PMONITOR->scale; + m_fX11SurfaceScaledBy = PMONITOR->scale; + } + + if (m_bIsX11 && m_pXWaylandSurface) + m_pXWaylandSurface->configure({windowPos, size}); + else if (m_pXDGSurface && m_pXDGSurface->toplevel) + m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index cff13b03..ce2f8eb2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "../config/ConfigDataValues.hpp" #include "../helpers/AnimatedVariable.hpp" @@ -468,6 +469,7 @@ class CWindow { bool isModal(); Vector2D requestedMinSize(); Vector2D requestedMaxSize(); + void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 99ba441d..8dbf30b7 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -624,7 +624,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - g_pXWaylandManager->setWindowSize(w, w->m_vRealSize->goal(), true); + w->sendWindowSize(w->m_vRealSize->goal(), true); } } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 525adc02..9ecf3652 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -681,8 +681,12 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; - if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); + // Fix some X11 popups being invisible / having incorrect size on open. + // What the ACTUAL FUCK is going on?????? I HATE X11 + if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) { + PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true, PWINDOW->m_vRealPosition->goal() - Vector2D{1, 1}); + PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); + } } void Events::listener_unmapWindow(void* owner, void* data) { @@ -949,7 +953,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { - g_pXWaylandManager->setWindowSize(PWINDOW, PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); g_pHyprRenderer->damageWindow(PWINDOW); return; } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 6d06a3a1..df6c3bde 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -199,7 +199,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); + PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess @@ -207,7 +207,7 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for *PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealPosition = wb.pos(); - g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); + PWINDOW->sendWindowSize(wb.size()); } if (force) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index ffc08e46..81392be9 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -179,7 +179,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } if (!pWindow->isX11OverrideRedirect()) { - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize->goal()); + pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); g_pCompositor->changeWindowZOrder(pWindow, true); } else { @@ -365,7 +365,7 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_bDraggingTiled = false; if (pWindow->m_bIsFloating) - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, pWindow->m_vRealSize->goal()); // match the size of the window + DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); // match the size of the window static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); @@ -611,7 +611,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { else DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); + DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { @@ -683,7 +683,7 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); } - g_pXWaylandManager->setWindowSize(DRAGGINGWINDOW, DRAGGINGWINDOW->m_vRealSize->goal()); + DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); } @@ -789,7 +789,7 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); pWindow->updateToplevel(); - g_pXWaylandManager->setWindowSize(pWindow, pWindow->m_vRealSize->goal()); + pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); g_pHyprRenderer->damageWindow(pWindow); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 3b8ff734..8aa15e42 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -679,7 +679,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); + PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess @@ -687,7 +687,7 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - g_pXWaylandManager->setWindowSize(PWINDOW, wb.size()); + PWINDOW->sendWindowSize(wb.size()); } if (m_bForceWarps && !*PANIMATE) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index e2191bc6..2cb77d21 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1914,7 +1914,7 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { if (PWORKSPACE->m_bDefaultFloating) { w->m_vRealPosition->setValueAndWarp(SAVEDPOS); w->m_vRealSize->setValueAndWarp(SAVEDSIZE); - g_pXWaylandManager->setWindowSize(w, SAVEDSIZE); + w->sendWindowSize(SAVEDSIZE); *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 8956cf3a..ea2a47ea 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - setWindowSize(pWindow, pWindow->m_vRealSize->value(), true); // update xwayland output pos + pWindow->sendWindowSize(pWindow->m_vRealSize->value(), true); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) @@ -113,44 +113,6 @@ void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) { pWindow->m_pXDGSurface->toplevel->close(); } -void CHyprXWaylandManager::setWindowSize(PHLWINDOW pWindow, Vector2D size, bool force) { - - static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - - const auto PMONITOR = pWindow->m_pMonitor.lock(); - - size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); - - // calculate pos - // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = pWindow->m_vRealPosition->goal(); - - if (pWindow->m_bIsX11 && PMONITOR) { - windowPos -= PMONITOR->vecPosition; // normalize to monitor - if (*PXWLFORCESCALEZERO) - windowPos *= PMONITOR->scale; // scale if applicable - windowPos += PMONITOR->vecXWaylandPosition; // move to correct position for xwayland - } - - if (!force && pWindow->m_vPendingReportedSize == size && (windowPos == pWindow->m_vReportedPosition || !pWindow->m_bIsX11)) - return; - - pWindow->m_vReportedPosition = windowPos; - pWindow->m_vPendingReportedSize = size; - - pWindow->m_fX11SurfaceScaledBy = 1.0f; - - if (*PXWLFORCESCALEZERO && pWindow->m_bIsX11 && PMONITOR) { - size *= PMONITOR->scale; - pWindow->m_fX11SurfaceScaledBy = PMONITOR->scale; - } - - if (pWindow->m_bIsX11) - pWindow->m_pXWaylandSurface->configure({windowPos, size}); - else if (pWindow->m_pXDGSurface->toplevel) - pWindow->m_vPendingSizeAcks.emplace_back(pWindow->m_pXDGSurface->toplevel->setSize(size), size.floor()); -} - bool CHyprXWaylandManager::shouldBeFloated(PHLWINDOW pWindow, bool pending) { if (pWindow->m_bIsX11) { for (const auto& a : pWindow->m_pXWaylandSurface->atoms) diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index 8ce239f6..edbdd243 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -17,7 +17,6 @@ class CHyprXWaylandManager { void activateWindow(PHLWINDOW, bool); void getGeometryForWindow(PHLWINDOW, CBox*); void sendCloseWindow(PHLWINDOW); - void setWindowSize(PHLWINDOW, Vector2D, bool force = false); void setWindowFullscreen(PHLWINDOW, bool); bool shouldBeFloated(PHLWINDOW, bool pending = false); void checkBorders(PHLWINDOW); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 36846fd4..7cef21b8 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -408,7 +408,7 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window if (pWindowInsertAfter->m_bIsFloating) - g_pXWaylandManager->setWindowSize(pDraggedWindow, pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window + pDraggedWindow->sendWindowSize(pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); From 8b1d6e3009c540457068e23e6c2bc201d20ce4d1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 25 Jan 2025 21:57:58 +0000 Subject: [PATCH 1124/2393] subsurface: damage the entire parent on size change the previous method doesn't exactly work, idk todo fix fixes #8784 --- src/desktop/Subsurface.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 9cdf3685..eb18ee39 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -101,10 +101,19 @@ void CSubsurface::onCommit() { checkSiblingDamage(); if (m_vLastSize != m_pWLSurface->resource()->current.size) { - CBox box{COORDS, m_vLastSize}; - g_pHyprRenderer->damageBox(&box); - m_vLastSize = m_pWLSurface->resource()->current.size; - box = {COORDS, m_vLastSize}; + // TODO: fix this + // CBox box{COORDS, m_vLastSize}; + // g_pHyprRenderer->damageBox(&box); + // m_vLastSize = m_pWLSurface->resource()->current.size; + // box = {COORDS, m_vLastSize}; + // g_pHyprRenderer->damageBox(&box); + + CBox box; + if (m_pPopupParent) + box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{}); + else if (m_pWindowParent) + box = m_pWindowParent->getWindowMainSurfaceBox(); + g_pHyprRenderer->damageBox(&box); } } From 3cd6e3960f0cbf500786497017ff3084cc9deb17 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sun, 26 Jan 2025 12:23:39 +0000 Subject: [PATCH 1125/2393] xwayland: fix pointer mismatches with multiple monitors (#9179) --- src/desktop/Window.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 96b87205..b1b3c66c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1702,11 +1702,9 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional // TODO: this should be decoupled from setWindowSize IMO Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); - if (m_bIsX11 && PMONITOR) { - windowPos -= PMONITOR->vecPosition; // normalize to monitor - if (*PXWLFORCESCALEZERO) - windowPos *= PMONITOR->scale; // scale if applicable - windowPos += PMONITOR->vecXWaylandPosition; // move to correct position for xwayland + if (m_bIsX11) { + if (const auto XWAYLANDPOS = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); XWAYLANDPOS != Vector2D{}) + windowPos = XWAYLANDPOS; } if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) From 0a28e13787a83a48cbca9641a02b8ea4857c733c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 12:54:32 +0000 Subject: [PATCH 1126/2393] desktop: move desktop types to memory-safe pointers --- src/Compositor.cpp | 1 - src/desktop/LayerSurface.cpp | 11 ++++++----- src/desktop/Popup.cpp | 35 +++++++++++++++++++---------------- src/desktop/Popup.hpp | 11 ++++++----- src/desktop/Subsurface.cpp | 14 ++++++++------ src/desktop/Subsurface.hpp | 30 ++++++++++++++++-------------- src/desktop/Window.cpp | 12 +++++++----- src/main.cpp | 2 ++ src/render/Renderer.cpp | 4 ++-- 9 files changed, 66 insertions(+), 54 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3f9126b7..43efdac1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -571,7 +571,6 @@ void CCompositor::cleanup() { g_pLayoutManager.reset(); g_pHyprError.reset(); g_pConfigManager.reset(); - g_pAnimationManager.reset(); g_pKeybindManager.reset(); g_pHookSystem.reset(); g_pWatchdog.reset(); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index dd30aa7c..c2b07c5d 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -31,9 +31,10 @@ PHLLS CLayerSurface::create(SP resource) { pLS->szNamespace = resource->layerNamespace; - pLS->layer = resource->current.layer; - pLS->popupHead = makeUnique(pLS); - pLS->monitor = pMonitor; + pLS->layer = resource->current.layer; + pLS->popupHead = makeUnique(pLS); + pLS->popupHead->m_pSelf = pLS->popupHead; + pLS->monitor = pMonitor; pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); @@ -331,7 +332,7 @@ void CLayerSurface::onCommit() { nullptr); if (!WASLASTFOCUS && popupHead) { popupHead->breadthfirst( - [&WASLASTFOCUS](CPopup* popup, void* data) { + [&WASLASTFOCUS](WP popup, void* data) { WASLASTFOCUS = WASLASTFOCUS || (popup->m_pWLSurface && g_pSeatManager->state.keyboardFocus == popup->m_pWLSurface->resource()); }, nullptr); @@ -576,7 +577,7 @@ int CLayerSurface::popupsCount() { return 0; int no = -1; // we have one dummy - popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); + popupHead->breadthfirst([](WP p, void* data) { *(int*)data += 1; }, &no); return no; } diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 831619a5..0c7c72a4 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -20,7 +20,8 @@ CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { initAllSignals(); } -CPopup::CPopup(SP popup, CPopup* pOwner) : m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { +CPopup::CPopup(SP popup, WP pOwner) : + m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { m_pWLSurface = CWLSurface::create(); m_pWLSurface->assign(popup->surface->surface.lock(), this); @@ -58,7 +59,8 @@ void CPopup::initAllSignals() { } void CPopup::onNewPopup(SP popup) { - const auto POPUP = m_vChildren.emplace_back(makeShared(popup, this)).get(); + const auto& POPUP = m_vChildren.emplace_back(makeShared(popup, m_pSelf)); + POPUP->m_pSelf = POPUP; Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } @@ -89,7 +91,8 @@ void CPopup::onMap() { g_pInputManager->simulateMouseMovement(); - m_pSubsurfaceHead = makeUnique(this); + m_pSubsurfaceHead = makeUnique(m_pSelf); + m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; //unconstrain(); sendScale(); @@ -126,7 +129,7 @@ void CPopup::onUnmap() { // damage all children breadthfirst( - [](CPopup* p, void* data) { + [](WP p, void* data) { if (!p->m_pResource) return; @@ -223,7 +226,7 @@ Vector2D CPopup::coordsRelativeToParent() { if (!m_pResource) return {}; - CPopup* current = this; + WP current = m_pSelf; offset -= current->m_pResource->surface->current.geometry.pos(); while (current->m_pParent && current->m_pResource) { @@ -256,7 +259,7 @@ Vector2D CPopup::t1ParentCoords() { } void CPopup::recheckTree() { - CPopup* curr = this; + WP curr = m_pSelf; while (curr->m_pParent) { curr = curr->m_pParent; } @@ -296,17 +299,17 @@ bool CPopup::visible() { return false; } -void CPopup::bfHelper(std::vector const& nodes, std::function fn, void* data) { +void CPopup::bfHelper(std::vector> const& nodes, std::function, void*)> fn, void* data) { for (auto const& n : nodes) { fn(n, data); } - std::vector nodes2; + std::vector> nodes2; nodes2.reserve(nodes.size() * 2); for (auto const& n : nodes) { for (auto const& c : n->m_vChildren) { - nodes2.push_back(c.get()); + nodes2.push_back(c->m_pSelf); } } @@ -314,15 +317,15 @@ void CPopup::bfHelper(std::vector const& nodes, std::function fn, void* data) { - std::vector popups; - popups.push_back(this); +void CPopup::breadthfirst(std::function, void*)> fn, void* data) { + std::vector> popups; + popups.push_back(m_pSelf); bfHelper(popups, fn, data); } -CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { - std::vector popups; - breadthfirst([](CPopup* popup, void* data) { ((std::vector*)data)->push_back(popup); }, &popups); +WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { + std::vector> popups; + breadthfirst([](WP popup, void* data) { ((std::vector>*)data)->push_back(popup); }, &popups); for (auto const& p : popups | std::views::reverse) { if (!p->m_pResource || !p->m_bMapped) @@ -344,5 +347,5 @@ CPopup* CPopup::at(const Vector2D& globalCoords, bool allowsInput) { } } - return nullptr; + return {}; } diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 2b7b4e82..6051f7eb 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -14,7 +14,7 @@ class CPopup { CPopup(PHLLS pOwner); // real nodes - CPopup(SP popup, CPopup* pOwner); + CPopup(SP popup, WP pOwner); ~CPopup(); @@ -36,11 +36,12 @@ class CPopup { bool visible(); // will also loop over this node - void breadthfirst(std::function fn, void* data); - CPopup* at(const Vector2D& globalCoords, bool allowsInput = false); + void breadthfirst(std::function, void*)> fn, void* data); + WP at(const Vector2D& globalCoords, bool allowsInput = false); // SP m_pWLSurface; + WP m_pSelf; bool m_bMapped = false; private: @@ -49,7 +50,7 @@ class CPopup { PHLLSREF m_pLayerOwner; // T2 owners - CPopup* m_pParent = nullptr; + WP m_pParent; WP m_pResource; @@ -81,5 +82,5 @@ class CPopup { Vector2D localToGlobal(const Vector2D& rel); Vector2D t1ParentCoords(); - static void bfHelper(std::vector const& nodes, std::function fn, void* data); + static void bfHelper(std::vector> const& nodes, std::function, void*)> fn, void* data); }; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index eb18ee39..5657cb39 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -12,7 +12,7 @@ CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } -CSubsurface::CSubsurface(CPopup* pOwner) : m_pPopupParent(pOwner) { +CSubsurface::CSubsurface(WP pOwner) : m_pPopupParent(pOwner) { initSignals(); initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); } @@ -24,7 +24,7 @@ CSubsurface::CSubsurface(SP pSubsurface, PHLWINDOW pOwner initExistingSubsurfaces(pSubsurface->surface.lock()); } -CSubsurface::CSubsurface(SP pSubsurface, CPopup* pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { +CSubsurface::CSubsurface(SP pSubsurface, WP pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { m_pWLSurface = CWLSurface::create(); m_pWLSurface->assign(pSubsurface->surface.lock(), this); initSignals(); @@ -132,16 +132,18 @@ void CSubsurface::onDestroy() { } void CSubsurface::onNewSubsurface(SP pSubsurface) { - CSubsurface* PSUBSURFACE = nullptr; + WP PSUBSURFACE; if (!m_pWindowParent.expired()) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pWindowParent.lock())).get(); + PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pWindowParent.lock())); else if (m_pPopupParent) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pPopupParent)).get(); + PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pPopupParent)); + + PSUBSURFACE->m_pSelf = PSUBSURFACE; ASSERT(PSUBSURFACE); - PSUBSURFACE->m_pParent = this; + PSUBSURFACE->m_pParent = PSUBSURFACE; } void CSubsurface::onMap() { diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index aacbad91..f16a11ea 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -11,28 +11,30 @@ class CSubsurface { public: // root dummy nodes CSubsurface(PHLWINDOW pOwner); - CSubsurface(CPopup* pOwner); + CSubsurface(WP pOwner); // real nodes CSubsurface(SP pSubsurface, PHLWINDOW pOwner); - CSubsurface(SP pSubsurface, CPopup* pOwner); + CSubsurface(SP pSubsurface, WP pOwner); ~CSubsurface(); - Vector2D coordsRelativeToParent(); - Vector2D coordsGlobal(); + Vector2D coordsRelativeToParent(); + Vector2D coordsGlobal(); - Vector2D size(); + Vector2D size(); - void onCommit(); - void onDestroy(); - void onNewSubsurface(SP pSubsurface); - void onMap(); - void onUnmap(); + void onCommit(); + void onDestroy(); + void onNewSubsurface(SP pSubsurface); + void onMap(); + void onUnmap(); - bool visible(); + bool visible(); - void recheckDamageForSubsurfaces(); + void recheckDamageForSubsurfaces(); + + WP m_pSelf; private: struct { @@ -48,10 +50,10 @@ class CSubsurface { Vector2D m_vLastSize = {}; // if nullptr, means it's a dummy node - CSubsurface* m_pParent = nullptr; + WP m_pParent; PHLWINDOWREF m_pWindowParent; - CPopup* m_pPopupParent = nullptr; + WP m_pPopupParent; std::vector> m_vChildren; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b1b3c66c..9dcdb385 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -154,7 +154,7 @@ SBoxExtents CWindow::getFullWindowExtents() { CBox surfaceExtents = {0, 0, 0, 0}; // TODO: this could be better, perhaps make a getFullWindowRegion? m_pPopupHead->breadthfirst( - [](CPopup* popup, void* data) { + [](WP popup, void* data) { if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource()) return; @@ -569,8 +569,10 @@ void CWindow::onMap() { if (m_bIsX11) return; - m_pSubsurfaceHead = makeUnique(m_pSelf.lock()); - m_pPopupHead = makeUnique(m_pSelf.lock()); + m_pSubsurfaceHead = makeUnique(m_pSelf.lock()); + m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; + m_pPopupHead = makeUnique(m_pSelf.lock()); + m_pPopupHead->m_pSelf = m_pPopupHead; } void CWindow::onBorderAngleAnimEnd(WP pav) { @@ -847,7 +849,7 @@ bool CWindow::hasPopupAt(const Vector2D& pos) { if (m_bIsX11) return false; - CPopup* popup = m_pPopupHead->at(pos); + auto popup = m_pPopupHead->at(pos); return popup && popup->m_pWLSurface->resource(); } @@ -1289,7 +1291,7 @@ int CWindow::popupsCount() { return 0; int no = -1; - m_pPopupHead->breadthfirst([](CPopup* p, void* d) { *((int*)d) += 1; }, &no); + m_pPopupHead->breadthfirst([](WP p, void* d) { *((int*)d) += 1; }, &no); return no; } diff --git a/src/main.cpp b/src/main.cpp index d244f10f..464ed978 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -181,6 +181,8 @@ int main(int argc, char** argv) { g_pCompositor->cleanup(); + g_pCompositor.reset(); + Debug::log(LOG, "Hyprland has reached the end."); return EXIT_SUCCESS; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d82d79d1..f897379a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -615,7 +615,7 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe renderdata.surfaceCounter = 0; pWindow->m_pPopupHead->breadthfirst( - [this, &renderdata](CPopup* popup, void* data) { + [this, &renderdata](WP popup, void* data) { if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource() || !popup->m_bMapped) return; const auto pos = popup->coordsRelativeToParent(); @@ -718,7 +718,7 @@ void CHyprRenderer::renderLayer(PHLLS pLayer, PHLMONITOR pMonitor, timespec* tim renderdata.surfaceCounter = 0; if (popups) { pLayer->popupHead->breadthfirst( - [this, &renderdata](CPopup* popup, void* data) { + [this, &renderdata](WP popup, void* data) { if (!popup->m_pWLSurface || !popup->m_pWLSurface->resource() || !popup->m_bMapped) return; From 4abf9155ee67ee09116948b1d9efef58c08697d9 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sun, 26 Jan 2025 13:00:52 +0000 Subject: [PATCH 1127/2393] window: only set m_iMonitorMovedFrom when the workspace is visible (#9178) --- src/desktop/Window.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 9dcdb385..e59a8d4e 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -422,10 +422,12 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { const auto OLDWORKSPACE = m_pWorkspace; - m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); - *m_fMovingToWorkspaceAlpha = 0.F; - m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); - m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; + if (OLDWORKSPACE->isVisible()) { + m_fMovingToWorkspaceAlpha->setValueAndWarp(1.F); + *m_fMovingToWorkspaceAlpha = 0.F; + m_fMovingToWorkspaceAlpha->setCallbackOnEnd([this](auto) { m_iMonitorMovedFrom = -1; }); + m_iMonitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE->monitorID() : -1; + } m_pWorkspace = pWorkspace; From 74d0f34cf396f4fc41ee98b000e7d0a4e277c066 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 14:25:49 +0000 Subject: [PATCH 1128/2393] pointer: always scale the cpu cursor to the right size fixes #9003 --- src/managers/PointerManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index df145f6d..5fdfa553 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -507,6 +507,10 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->transform; + // we need to scale the cursor to the right size, because it might not be (esp with XCursor) + const auto SCALE = texture->m_vSize / (currentCursorImage.size / currentCursorImage.scale * state->monitor->scale); + cairo_matrix_scale(&matrixPre, SCALE.x, SCALE.y); + if (TR) { cairo_matrix_rotate(&matrixPre, M_PI_2 * (double)TR); From 16aeb24bc1395b46d675ec3522ed452e487f5b69 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 14:40:42 +0000 Subject: [PATCH 1129/2393] core: make persistent workspaces always follow the config instead of just staying after open, they will now be enforced on their respective monitors fixes #8769 --- src/Compositor.cpp | 43 ++++++++++++++++++++++++++++++++++++ src/Compositor.hpp | 2 ++ src/config/ConfigManager.cpp | 8 +++++++ src/config/ConfigManager.hpp | 1 + src/helpers/Monitor.cpp | 2 ++ 5 files changed, 56 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 43efdac1..3421c314 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3024,3 +3024,46 @@ bool CCompositor::shouldChangePreferredImageDescription() { Debug::log(WARN, "FIXME: color management protocol is enabled and outputs changed, check preferred image description changes"); return false; } + +void CCompositor::ensurePersistentWorkspacesPresent(const std::vector& rules) { + for (const auto& rule : rules) { + if (!rule.isPersistent) + continue; + + const auto PMONITOR = getMonitorFromString(rule.monitor); + + if (!PMONITOR) { + Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve monitor for {}, skipping", rule.monitor); + continue; + } + + WORKSPACEID id = rule.workspaceId; + std::string wsname = rule.workspaceName; + if (id == WORKSPACE_INVALID) { + const auto R = getWorkspaceIDNameFromString(rule.workspaceString); + id = R.id; + wsname = R.name; + } + + if (id == WORKSPACE_INVALID) { + Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); + continue; + } + + if (const auto PWORKSPACE = getWorkspaceByID(id); PWORKSPACE) { + if (PWORKSPACE->m_pMonitor == PMONITOR) { + Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} already on {}", rule.workspaceString, PMONITOR->szName); + continue; + } + + Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} not on {}, moving", rule.workspaceString, PMONITOR->szName); + moveWorkspaceToMonitor(PWORKSPACE, PMONITOR); + continue; + } + + createNewWorkspace(id, PMONITOR ? PMONITOR : m_pLastMonitor.lock(), wsname, false); + } + + // cleanup old + sanityCheckWorkspaces(); +} diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 295878df..e55d7e1e 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -15,6 +15,7 @@ #include class CWLSurfaceResource; +struct SWorkspaceRule; enum eManagersInitStage : uint8_t { STAGE_PRIORITY = 0, @@ -151,6 +152,7 @@ class CCompositor { void setPreferredTransformForSurface(SP pSurface, wl_output_transform transform); void updateSuspendedStates(); void onNewMonitor(SP output); + void ensurePersistentWorkspacesPresent(const std::vector& rules); SImageDescription getPreferredImageDescription(); bool shouldChangePreferredImageDescription(); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index fd4783da..93289bf7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1034,6 +1034,10 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { // update plugins handlePluginLoads(); + // update persistent workspaces + if (!isFirstLaunch) + ensurePersistentWorkspacesPresent(); + EMIT_HOOK_EVENT("configReloaded", nullptr); if (g_pEventManager) g_pEventManager->postEvent(SHyprIPCEvent{"configreloaded", ""}); @@ -2830,3 +2834,7 @@ std::string SConfigOptionDescription::jsonify() const { return json; } + +void CConfigManager::ensurePersistentWorkspacesPresent() { + g_pCompositor->ensurePersistentWorkspacesPresent(m_vWorkspaceRules); +} diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 564c1ebf..ae0ba759 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -169,6 +169,7 @@ class CConfigManager { std::vector> getMatchingRules(PHLWINDOW, bool dynamic = true, bool shadowExec = false); std::vector> getMatchingRules(PHLLS); + void ensurePersistentWorkspacesPresent(); const std::vector& getAllDescriptions(); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 1f00e4ad..6fcaeeee 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -51,6 +51,8 @@ void CMonitor::onConnect(bool noRule) { EMIT_HOOK_EVENT("preMonitorAdded", self.lock()); CScopeGuard x = {[]() { g_pCompositor->arrangeMonitors(); }}; + g_pEventLoopManager->doLater([] { g_pConfigManager->ensurePersistentWorkspacesPresent(); }); + if (output->supportsExplicit) { inTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); outTimeline = CSyncTimeline::create(output->getBackend()->drmFD()); From e9510115039e7ae9fcf2778e8455e7beed3424ea Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 15:05:34 +0000 Subject: [PATCH 1130/2393] renderer/internal: stop using box pointers in favor of const refs --- src/debug/HyprDebugOverlay.cpp | 4 +- src/debug/HyprNotificationOverlay.cpp | 6 +- src/desktop/LayerSurface.cpp | 10 +- src/desktop/Popup.cpp | 10 +- src/desktop/Subsurface.cpp | 10 +- src/events/Windows.cpp | 5 +- src/helpers/Monitor.cpp | 8 +- src/helpers/Monitor.hpp | 4 +- src/hyprerror/HyprError.cpp | 4 +- src/layout/IHyprLayout.cpp | 8 +- src/managers/AnimationManager.cpp | 8 +- src/managers/PointerManager.cpp | 6 +- src/managers/XWaylandManager.cpp | 24 ++- src/managers/XWaylandManager.hpp | 2 +- src/managers/input/InputMethodPopup.cpp | 2 +- src/protocols/AlphaModifier.cpp | 2 +- src/protocols/HyprlandSurface.cpp | 2 +- src/protocols/Screencopy.cpp | 4 +- src/protocols/core/DataDevice.cpp | 2 +- src/render/OpenGL.cpp | 182 ++++++++---------- src/render/OpenGL.hpp | 130 ++++++------- src/render/Renderer.cpp | 25 ++- src/render/Renderer.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 16 +- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- src/render/pass/BorderPassElement.cpp | 4 +- src/render/pass/Pass.cpp | 14 +- src/render/pass/RectPassElement.cpp | 4 +- src/render/pass/SurfacePassElement.cpp | 8 +- src/render/pass/TexPassElement.cpp | 2 +- src/render/pass/TextureMatteElement.cpp | 4 +- 32 files changed, 252 insertions(+), 264 deletions(-) diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 6e7a0407..9ea7f1bc 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -198,10 +198,10 @@ int CHyprMonitorDebugOverlay::draw(int offset) { double posX = 0, posY = 0; cairo_get_current_point(cr, &posX, &posY); - g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); + g_pHyprRenderer->damageBox(m_wbLastDrawnBox); m_wbLastDrawnBox = {(int)g_pCompositor->m_vMonitors.front()->vecPosition.x + MARGIN_LEFT - 1, (int)g_pCompositor->m_vMonitors.front()->vecPosition.y + offset + MARGIN_TOP - 1, (int)maxTextW + 2, posY - offset - MARGIN_TOP + 2}; - g_pHyprRenderer->damageBox(&m_wbLastDrawnBox); + g_pHyprRenderer->damageBox(m_wbLastDrawnBox); return posY - offset; } diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 66c68d08..4081af84 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -26,7 +26,7 @@ CHyprNotificationOverlay::CHyprNotificationOverlay() { if (m_vNotifications.size() == 0) return; - g_pHyprRenderer->damageBox(&m_bLastDamage); + g_pHyprRenderer->damageBox(m_bLastDamage); }); m_pTexture = makeShared(); @@ -225,8 +225,8 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { CBox damage = drawNotifications(pMonitor); - g_pHyprRenderer->damageBox(&damage); - g_pHyprRenderer->damageBox(&m_bLastDamage); + g_pHyprRenderer->damageBox(damage); + g_pHyprRenderer->damageBox(m_bLastDamage); g_pCompositor->scheduleFrameForMonitor(pMonitor); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index c2b07c5d..e2d0177b 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -115,7 +115,7 @@ void CLayerSurface::onDestroy() { // and damage CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; - g_pHyprRenderer->damageBox(&geomFixed); + g_pHyprRenderer->damageBox(geomFixed); } readyToDelete = true; @@ -179,7 +179,7 @@ void CLayerSurface::onMap() { position = Vector2D(geometry.x, geometry.y); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; - g_pHyprRenderer->damageBox(&geomFixed); + g_pHyprRenderer->damageBox(geomFixed); const bool FULLSCREEN = PMONITOR->activeWorkspace && PMONITOR->activeWorkspace->m_bHasFullscreenWindow && PMONITOR->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; startAnimation(!(layer == ZWLR_LAYER_SHELL_V1_LAYER_TOP && FULLSCREEN && !GRABSFOCUS)); @@ -240,11 +240,11 @@ void CLayerSurface::onUnmap() { g_pSeatManager->setKeyboardFocus(g_pCompositor->m_pLastFocus.lock()); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; - g_pHyprRenderer->damageBox(&geomFixed); + g_pHyprRenderer->damageBox(geomFixed); geomFixed = {geometry.x + (int)PMONITOR->vecPosition.x, geometry.y + (int)PMONITOR->vecPosition.y, (int)layerSurface->surface->current.size.x, (int)layerSurface->surface->current.size.y}; - g_pHyprRenderer->damageBox(&geomFixed); + g_pHyprRenderer->damageBox(geomFixed); g_pInputManager->simulateMouseMovement(); @@ -275,7 +275,7 @@ void CLayerSurface::onCommit() { g_pHyprOpenGL->markBlurDirtyForMonitor(PMONITOR); // so that blur is recalc'd CBox geomFixed = {geometry.x, geometry.y, geometry.width, geometry.height}; - g_pHyprRenderer->damageBox(&geomFixed); + g_pHyprRenderer->damageBox(geomFixed); if (layerSurface->current.committed != 0) { if (layerSurface->current.committed & CLayerShellResource::eCommittedState::STATE_LAYER) { diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 0c7c72a4..93a810ff 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -85,7 +85,7 @@ void CPopup::onMap() { CBox box = m_pWLSurface->resource()->extends(); box.translate(COORDS).expand(4); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); m_vLastPos = coordsRelativeToParent(); @@ -120,7 +120,7 @@ void CPopup::onUnmap() { CBox box = m_pWLSurface->resource()->extends(); box.translate(COORDS).expand(4); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); m_pSubsurfaceHead.reset(); @@ -134,7 +134,7 @@ void CPopup::onUnmap() { return; auto box = CBox{p->coordsGlobal(), p->size()}; - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); }, nullptr); @@ -173,10 +173,10 @@ void CPopup::onCommit(bool ignoreSiblings) { if (m_vLastSize != m_pResource->surface->surface->current.size || m_bRequestedReposition || m_vLastPos != COORDSLOCAL) { CBox box = {localToGlobal(m_vLastPos), m_vLastSize}; - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); m_vLastSize = m_pResource->surface->surface->current.size; box = {COORDS, m_vLastSize}; - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); m_vLastPos = COORDSLOCAL; } diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 5657cb39..a68cf8f3 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -103,10 +103,10 @@ void CSubsurface::onCommit() { if (m_vLastSize != m_pWLSurface->resource()->current.size) { // TODO: fix this // CBox box{COORDS, m_vLastSize}; - // g_pHyprRenderer->damageBox(&box); + // g_pHyprRenderer->damageBox(box); // m_vLastSize = m_pWLSurface->resource()->current.size; // box = {COORDS, m_vLastSize}; - // g_pHyprRenderer->damageBox(&box); + // g_pHyprRenderer->damageBox(box); CBox box; if (m_pPopupParent) @@ -114,7 +114,7 @@ void CSubsurface::onCommit() { else if (m_pWindowParent) box = m_pWindowParent->getWindowMainSurfaceBox(); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); } } @@ -152,7 +152,7 @@ void CSubsurface::onMap() { const auto COORDS = coordsGlobal(); CBox box{COORDS, m_vLastSize}; box.expand(4); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); if (!m_pWindowParent.expired()) m_pWindowParent->updateSurfaceScaleTransformDetails(); @@ -162,7 +162,7 @@ void CSubsurface::onUnmap() { const auto COORDS = coordsGlobal(); CBox box{COORDS, m_vLastSize}; box.expand(4); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); if (m_pWLSurface->resource() == g_pCompositor->m_pLastFocus) g_pInputManager->releaseAllMouseButtons(); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 9ecf3652..f6ef9ced 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -376,9 +376,8 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PWORKSPACE->m_bDefaultPseudo) { PWINDOW->m_bIsPseudotiled = true; - CBox desiredGeometry = {0}; - g_pXWaylandManager->getGeometryForWindow(PWINDOW, &desiredGeometry); - PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); + CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(PWINDOW); + PWINDOW->m_vPseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height); } PWINDOW->updateWindowData(); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 6fcaeeee..19d68a56 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -766,18 +766,18 @@ void CMonitor::addDamage(const pixman_region32_t* rg) { g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } -void CMonitor::addDamage(const CRegion* rg) { - addDamage(const_cast(rg)->pixman()); +void CMonitor::addDamage(const CRegion& rg) { + addDamage(const_cast(&rg)->pixman()); } -void CMonitor::addDamage(const CBox* box) { +void CMonitor::addDamage(const CBox& box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == self) { damage.damageEntire(); g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } - if (damage.damage(*box)) + if (damage.damage(box)) g_pCompositor->scheduleFrameForMonitor(self.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index e07d62c6..7c19b57c 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -166,8 +166,8 @@ class CMonitor { void onDisconnect(bool destroy = false); bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false); void addDamage(const pixman_region32_t* rg); - void addDamage(const CRegion* rg); - void addDamage(const CBox* box); + void addDamage(const CRegion& rg); + void addDamage(const CBox& box); bool shouldSkipScheduleFrameOnMouseEvent(); void setMirror(const std::string&); bool isMirror(); diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index d14173bf..4076ed3a 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -26,7 +26,7 @@ CHyprError::CHyprError() { return; if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) - g_pHyprRenderer->damageBox(&m_bDamageBox); + g_pHyprRenderer->damageBox(m_bDamageBox); }); m_pTexture = makeShared(); @@ -203,7 +203,7 @@ void CHyprError::draw() { m_bDamageBox.y = (int)PMONITOR->vecPosition.y; if (m_fFadeOpacity->isBeingAnimated() || m_bMonitorChanged) - g_pHyprRenderer->damageBox(&m_bDamageBox); + g_pHyprRenderer->damageBox(m_bDamageBox); m_bMonitorChanged = false; diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 81392be9..5e5669b8 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -14,8 +14,7 @@ #include "../managers/HookSystemManager.hpp" void IHyprLayout::onWindowCreated(PHLWINDOW pWindow, eDirection direction) { - CBox desiredGeometry = {}; - g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); + CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow); if (desiredGeometry.width <= 5 || desiredGeometry.height <= 5) { const auto PMONITOR = pWindow->m_pMonitor.lock(); @@ -91,9 +90,8 @@ void IHyprLayout::onWindowRemovedFloating(PHLWINDOW pWindow) { void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { - CBox desiredGeometry = {0}; - g_pXWaylandManager->getGeometryForWindow(pWindow, &desiredGeometry); - const auto PMONITOR = pWindow->m_pMonitor.lock(); + CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(pWindow); + const auto PMONITOR = pWindow->m_pMonitor.lock(); if (pWindow->m_bIsX11) { Vector2D xy = {desiredGeometry.x, desiredGeometry.y}; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 964f7cfa..5be7aa33 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -41,7 +41,7 @@ CHyprAnimationManager::CHyprAnimationManager() { } template -void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { +static void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { if (warp || av.value() == av.goal()) { av.warp(); return; @@ -51,7 +51,7 @@ void updateVariable(CAnimatedVariable& av, const float POINTY, bool war av.value() = av.begun() + DELTA * POINTY; } -void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { +static void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { if (warp || av.value() == av.goal()) { av.warp(); return; @@ -137,7 +137,7 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { // "some fucking layers miss 1 pixel???" -- vaxry CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); + g_pHyprRenderer->damageBox(expandBox); PMONITOR = g_pCompositor->getMonitorFromVector(PLAYER->realPosition->goal() + PLAYER->realSize->goal() / 2.F); if (!PMONITOR) @@ -180,7 +180,7 @@ static void handleUpdate(CAnimatedVariable& av, bool warp) { // some fucking layers miss 1 pixel??? CBox expandBox = CBox{PLAYER->realPosition->value(), PLAYER->realSize->value()}; expandBox.expand(5); - g_pHyprRenderer->damageBox(&expandBox); + g_pHyprRenderer->damageBox(expandBox); } break; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 5fdfa553..48ef5e16 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -566,7 +566,7 @@ SP CPointerManager::renderHWCursorBuffer(SPmonitor->szName, currentCursorImage.size, cursorSize, currentCursorImage.scale, state->monitor->scale, xbox.size()); - g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F); + g_pHyprOpenGL->renderTexture(texture, xbox, 1.F); g_pHyprOpenGL->end(); glFlush(); @@ -730,7 +730,7 @@ void CPointerManager::damageIfSoftware() { continue; if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { - g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); + g_pHyprRenderer->damageBox(b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } } @@ -1143,7 +1143,7 @@ void CPointerManager::damageCursor(PHLMONITOR pMonitor) { if (b.empty()) return; - g_pHyprRenderer->damageBox(&b); + g_pHyprRenderer->damageBox(b); return; } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index ea2a47ea..f103266d 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -76,9 +76,11 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { pWindow->m_pWorkspace->m_pLastFocusedWindow = pWindow; } -void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { +CBox CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow) { if (!pWindow) - return; + return {}; + + CBox box; if (pWindow->m_bIsX11) { const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); @@ -86,24 +88,26 @@ void CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow, CBox* pbox) { if (SIZEHINTS && !pWindow->isX11OverrideRedirect()) { // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property - pbox->x = pWindow->m_pXWaylandSurface->geometry.x; - pbox->y = pWindow->m_pXWaylandSurface->geometry.y; + box.x = pWindow->m_pXWaylandSurface->geometry.x; + box.y = pWindow->m_pXWaylandSurface->geometry.y; constexpr int ICCCM_USSize = 0x2; constexpr int ICCCM_PSize = 0x8; if ((SIZEHINTS->flags & ICCCM_USSize) || (SIZEHINTS->flags & ICCCM_PSize)) { - pbox->w = SIZEHINTS->base_width; - pbox->h = SIZEHINTS->base_height; + box.w = SIZEHINTS->base_width; + box.h = SIZEHINTS->base_height; } else { - pbox->w = pWindow->m_pXWaylandSurface->geometry.w; - pbox->h = pWindow->m_pXWaylandSurface->geometry.h; + box.w = pWindow->m_pXWaylandSurface->geometry.w; + box.h = pWindow->m_pXWaylandSurface->geometry.h; } } else - *pbox = pWindow->m_pXWaylandSurface->geometry; + box = pWindow->m_pXWaylandSurface->geometry; } else if (pWindow->m_pXDGSurface) - *pbox = pWindow->m_pXDGSurface->current.geometry; + box = pWindow->m_pXDGSurface->current.geometry; + + return box; } void CHyprXWaylandManager::sendCloseWindow(PHLWINDOW pWindow) { diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index edbdd243..e4f1e17a 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -15,7 +15,7 @@ class CHyprXWaylandManager { SP getWindowSurface(PHLWINDOW); void activateSurface(SP, bool); void activateWindow(PHLWINDOW, bool); - void getGeometryForWindow(PHLWINDOW, CBox*); + CBox getGeometryForWindow(PHLWINDOW); void sendCloseWindow(PHLWINDOW); void setWindowFullscreen(PHLWINDOW, bool); bool shouldBeFloated(PHLWINDOW, bool pending = false); diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index 8c55416b..db08c026 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -61,7 +61,7 @@ void CInputPopup::damageEntire() { return; } CBox box = globalBox(); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); } void CInputPopup::damageSurface() { diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index e8766405..60037632 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -38,7 +38,7 @@ void CAlphaModifier::setResource(SP resource) { auto box = surface->getSurfaceBoxGlobal(); if (box.has_value()) - g_pHyprRenderer->damageBox(&*box); + g_pHyprRenderer->damageBox(*box); if (!m_pResource) PROTO::alphaModifier->destroyAlphaModifier(this); diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp index e3716f10..8b65f0fa 100644 --- a/src/protocols/HyprlandSurface.cpp +++ b/src/protocols/HyprlandSurface.cpp @@ -60,7 +60,7 @@ void CHyprlandSurface::setResource(SP resource) { auto box = surface->getSurfaceBoxGlobal(); if (box.has_value()) - g_pHyprRenderer->damageBox(&*box); + g_pHyprRenderer->damageBox(*box); if (!m_pResource) PROTO::hyprlandSurface->destroySurface(this); diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index e0e3a559..e086cc76 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -214,7 +214,7 @@ bool CScreencopyFrame::copyDmabuf() { .transform(wlTransformToHyprutils(invertTransform(pMonitor->transform)), pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); @@ -247,7 +247,7 @@ bool CScreencopyFrame::copyShm() { CBox monbox = CBox{0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y}.translate({-box.x, -box.y}); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); + g_pHyprOpenGL->renderTexture(TEXTURE, monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 36437dd4..e17b5612 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -806,7 +806,7 @@ void CWLDataDeviceProtocol::renderDND(PHLMONITOR pMonitor, timespec* when) { g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); box = CBox{POS, dnd.dndSurface->current.size}.translate(g_pPointerManager->cursorSizeLogical() / 2.F).expand(5); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); dnd.dndSurface->frame(when); } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 0fe9565f..f0b2f447 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -935,15 +935,15 @@ void CHyprOpenGLImpl::end() { // copy the damaged areas into the mirror buffer // we can't use the offloadFB for mirroring, as it contains artifacts from blurring if (!m_RenderData.pMonitor->mirrors.empty() && !m_bFakeFrame) - saveBufferForMirror(&monbox); + saveBufferForMirror(monbox); m_RenderData.outFB->bind(); blend(false); if (m_sFinalScreenShader.program < 1 && !g_pHyprRenderer->m_bCrashingInProgress) - renderTexturePrimitive(m_RenderData.pCurrentMonData->offloadFB.getTexture(), &monbox); + renderTexturePrimitive(m_RenderData.pCurrentMonData->offloadFB.getTexture(), monbox); else - renderTexture(m_RenderData.pCurrentMonData->offloadFB.getTexture(), &monbox, 1.f); + renderTexture(m_RenderData.pCurrentMonData->offloadFB.getTexture(), monbox, 1.f); blend(true); @@ -1214,7 +1214,7 @@ void CHyprOpenGLImpl::clear(const CHyprColor& color) { } } - scissor((CBox*)nullptr); + scissor(nullptr); } void CHyprOpenGLImpl::blend(bool enabled) { @@ -1227,22 +1227,19 @@ void CHyprOpenGLImpl::blend(bool enabled) { m_bBlend = enabled; } -void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) { +void CHyprOpenGLImpl::scissor(const CBox& originalBox, bool transform) { RASSERT(m_RenderData.pMonitor, "Tried to scissor without begin()!"); - if (!pBox) { - glDisable(GL_SCISSOR_TEST); + if (transform) { + CBox box = originalBox; + const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); + box.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); + glScissor(box.x, box.y, box.width, box.height); + glEnable(GL_SCISSOR_TEST); return; } - CBox newBox = *pBox; - - if (transform) { - const auto TR = wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)); - newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); - } - - glScissor(newBox.x, newBox.y, newBox.width, newBox.height); + glScissor(originalBox.x, originalBox.y, originalBox.width, originalBox.height); glEnable(GL_SCISSOR_TEST); } @@ -1256,32 +1253,32 @@ void CHyprOpenGLImpl::scissor(const pixman_box32* pBox, bool transform) { CBox newBox = {pBox->x1, pBox->y1, pBox->x2 - pBox->x1, pBox->y2 - pBox->y1}; - scissor(&newBox, transform); + scissor(newBox, transform); } void CHyprOpenGLImpl::scissor(const int x, const int y, const int w, const int h, bool transform) { CBox box = {x, y, w, h}; - scissor(&box, transform); + scissor(box, transform); } -void CHyprOpenGLImpl::renderRect(CBox* box, const CHyprColor& col, int round, float roundingPower) { +void CHyprOpenGLImpl::renderRect(const CBox& box, const CHyprColor& col, int round, float roundingPower) { if (!m_RenderData.damage.empty()) renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int round, float roundingPower, float blurA, bool xray) { +void CHyprOpenGLImpl::renderRectWithBlur(const CBox& box, const CHyprColor& col, int round, float roundingPower, float blurA, bool xray) { if (m_RenderData.damage.empty()) return; CRegion damage{m_RenderData.damage}; - damage.intersect(*box); + damage.intersect(box); CFramebuffer* POUTFB = xray ? &m_RenderData.pCurrentMonData->blurFB : blurMainFramebufferWithDamage(blurA, &damage); m_RenderData.currentFB->bind(); // make a stencil for rounded corners to work with blur - scissor((CBox*)nullptr); // allow the entire window and stencil to render + scissor(nullptr); // allow the entire window and stencil to render glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -1302,7 +1299,7 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r m_bEndFrame = true; // fix transformed const auto SAVEDRENDERMODIF = m_RenderData.renderModif; m_RenderData.renderModif = {}; // fix shit - renderTextureInternalWithDamage(POUTFB->getTexture(), &MONITORBOX, blurA, damage, 0, 2.0f, false, false, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), MONITORBOX, blurA, damage, 0, 2.0f, false, false, false); m_bEndFrame = false; m_RenderData.renderModif = SAVEDRENDERMODIF; @@ -1311,22 +1308,20 @@ void CHyprOpenGLImpl::renderRectWithBlur(CBox* box, const CHyprColor& col, int r glDisable(GL_STENCIL_TEST); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); - scissor((CBox*)nullptr); + scissor(nullptr); renderRectWithDamage(box, col, m_RenderData.damage, round, roundingPower); } -void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, const CRegion& damage, int round, float roundingPower) { - RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); +void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& col, const CRegion& damage, int round, float roundingPower) { + RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); TRACY_GPU_ZONE("RenderRectWithDamage"); - CBox newBox = *box; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); - box = &newBox; - Mat3x3 matrix = m_RenderData.monitorProjection.projectBox( newBox, wlTransformToHyprutils(invertTransform(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform)), newBox.rot); Mat3x3 glMatrix = m_RenderData.projection.copy().multiply(matrix); @@ -1343,7 +1338,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con // premultiply the color as well as we don't work with straight alpha glUniform4f(m_RenderData.pCurrentMonData->m_shQUAD.color, col.r * col.a, col.g * col.a, col.b * col.a, col.a); - CBox transformedBox = *box; + CBox transformedBox = box; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -1379,27 +1374,27 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CHyprColor& col, con glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shQUAD.posAttrib); - scissor((CBox*)nullptr); + scissor(nullptr); } -void CHyprOpenGLImpl::renderTexture(SP tex, CBox* pBox, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, box, alpha, m_RenderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true); - scissor((CBox*)nullptr); + scissor(nullptr); } -void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, CBox* pBox, const CRegion& damage, float alpha, int round, float roundingPower, bool discardActive, +void CHyprOpenGLImpl::renderTextureWithDamage(SP tex, const CBox& box, const CRegion& damage, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); + renderTextureInternalWithDamage(tex, box, alpha, damage, round, roundingPower, discardActive, false, allowCustomUV, true, waitTimeline, waitPoint); - scissor((CBox*)nullptr); + scissor(nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pBox, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, +void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CBox& box, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, bool noAA, bool allowCustomUV, bool allowDim, SP waitTimeline, uint64_t waitPoint) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1411,7 +1406,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB if (damage.empty()) return; - CBox newBox = *pBox; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); static auto PDT = CConfigValue("debug:damage_tracking"); @@ -1584,7 +1579,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, CBox* pB glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { +void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, const CBox& box) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1593,7 +1588,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { if (m_RenderData.damage.empty()) return; - CBox newBox = *pBox; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); // get transform @@ -1627,7 +1622,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - scissor((CBox*)nullptr); + scissor(nullptr); glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); @@ -1635,7 +1630,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(SP tex, CBox* pBox) { glBindTexture(tex->m_iTarget, 0); } -void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte) { +void CHyprOpenGLImpl::renderTextureMatte(SP tex, const CBox& box, CFramebuffer& matte) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_iTexID > 0), "Attempted to draw nullptr texture!"); @@ -1644,7 +1639,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf if (m_RenderData.damage.empty()) return; - CBox newBox = *pBox; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); // get transform @@ -1683,7 +1678,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP tex, CBox* pBox, CFramebuf glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } - scissor((CBox*)nullptr); + scissor(nullptr); glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); @@ -2013,8 +2008,7 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { // make the fake dmg CRegion fakeDamage{0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - CBox wholeMonitor = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage); + const auto POUTFB = blurMainFramebufferWithDamage(1, &fakeDamage); // render onto blurFB m_RenderData.pCurrentMonData->blurFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, @@ -2024,7 +2018,8 @@ void CHyprOpenGLImpl::preBlurForCurrentMonitor() { clear(CHyprColor(0, 0, 0, 0)); m_bEndFrame = true; // fix transformed - renderTextureInternalWithDamage(POUTFB->getTexture(), &wholeMonitor, 1, fakeDamage, 0, 2.0f, false, true, false); + renderTextureInternalWithDamage(POUTFB->getTexture(), CBox{0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}, 1, fakeDamage, 0, + 2.0f, false, true, false); m_bEndFrame = false; m_RenderData.currentFB->bind(); @@ -2072,7 +2067,7 @@ bool CHyprOpenGLImpl::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWin return false; } -void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float a, SP pSurface, int round, float roundingPower, bool blockBlurOptimization, +void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, const CBox& box, float a, SP pSurface, int round, float roundingPower, bool blockBlurOptimization, float blurA, float overallA) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); @@ -2082,7 +2077,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float // make a damage region for this window CRegion texDamage{m_RenderData.damage}; - texDamage.intersect(pBox->x, pBox->y, pBox->width, pBox->height); + texDamage.intersect(box.x, box.y, box.width, box.height); // While renderTextureInternalWithDamage will clip the blur as well, // clipping texDamage here allows blur generation to be optimized. @@ -2095,24 +2090,23 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.renderModif.applyToRegion(texDamage); if (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) { - renderTexture(tex, pBox, a, round, roundingPower, false, true); + renderTexture(tex, box, a, round, roundingPower, false, true); return; } // amazing hack: the surface has an opaque region! CRegion inverseOpaque; - if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == pBox->w && - std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == pBox->h) { + if (a >= 1.f && std::round(pSurface->current.size.x * m_RenderData.pMonitor->scale) == box.w && std::round(pSurface->current.size.y * m_RenderData.pMonitor->scale) == box.h) { pixman_box32_t surfbox = {0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale}; inverseOpaque = pSurface->current.opaque; inverseOpaque.invert(&surfbox).intersect(0, 0, pSurface->current.size.x * pSurface->current.scale, pSurface->current.size.y * pSurface->current.scale); if (inverseOpaque.empty()) { - renderTexture(tex, pBox, a, round, roundingPower, false, true); + renderTexture(tex, box, a, round, roundingPower, false, true); return; } } else { - inverseOpaque = {0, 0, pBox->width, pBox->height}; + inverseOpaque = {0, 0, box.width, box.height}; } inverseOpaque.scale(m_RenderData.pMonitor->scale); @@ -2122,7 +2116,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float CFramebuffer* POUTFB = nullptr; if (!USENEWOPTIMIZE) { - inverseOpaque.translate({pBox->x, pBox->y}); + inverseOpaque.translate(box.pos()); m_RenderData.renderModif.applyToRegion(inverseOpaque); inverseOpaque.intersect(texDamage); @@ -2133,7 +2127,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float m_RenderData.currentFB->bind(); // make a stencil for rounded corners to work with blur - scissor((CBox*)nullptr); // allow the entire window and stencil to render + scissor(nullptr); // allow the entire window and stencil to render glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -2144,9 +2138,9 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); if (USENEWOPTIMIZE && !(m_RenderData.discardMode & DISCARD_ALPHA)) - renderRect(pBox, CHyprColor(0, 0, 0, 0), round, roundingPower); + renderRect(box, CHyprColor(0, 0, 0, 0), round, roundingPower); else - renderTexture(tex, pBox, a, round, roundingPower, true, true); // discard opaque + renderTexture(tex, box, a, round, roundingPower, true, true); // discard opaque glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 1, 0xFF); @@ -2159,14 +2153,14 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float const auto LASTTL = m_RenderData.primarySurfaceUVTopLeft; const auto LASTBR = m_RenderData.primarySurfaceUVBottomRight; - m_RenderData.primarySurfaceUVTopLeft = pBox->pos() / MONITORBOX.size(); - m_RenderData.primarySurfaceUVBottomRight = (pBox->pos() + pBox->size()) / MONITORBOX.size(); + m_RenderData.primarySurfaceUVTopLeft = box.pos() / MONITORBOX.size(); + m_RenderData.primarySurfaceUVBottomRight = (box.pos() + box.size()) / MONITORBOX.size(); static auto PBLURIGNOREOPACITY = CConfigValue("decoration:blur:ignore_opacity"); setMonitorTransformEnabled(true); if (!USENEWOPTIMIZE) setRenderModifEnabled(false); - renderTextureInternalWithDamage(POUTFB->getTexture(), pBox, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, round, roundingPower, false, false, true); + renderTextureInternalWithDamage(POUTFB->getTexture(), box, (*PBLURIGNOREOPACITY ? blurA : a * blurA) * overallA, texDamage, round, roundingPower, false, false, true); if (!USENEWOPTIMIZE) setRenderModifEnabled(true); setMonitorTransformEnabled(false); @@ -2180,15 +2174,15 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, CBox* pBox, float // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a * overallA, texDamage, round, roundingPower, false, false, true, true); + renderTextureInternalWithDamage(tex, box, a * overallA, texDamage, round, roundingPower, false, false, true, true); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 1, 0xFF); - scissor((CBox*)nullptr); + scissor(nullptr); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, int round, float roundingPower, int borderSize, float a, int outerRound) { - RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); +void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& grad, int round, float roundingPower, int borderSize, float a, int outerRound) { + RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); TRACY_GPU_ZONE("RenderBorder"); @@ -2196,11 +2190,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in if (m_RenderData.damage.empty() || (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.noBorder.valueOrDefault())) return; - CBox newBox = *box; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); - box = &newBox; - if (borderSize < 1) return; @@ -2208,10 +2200,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in scaledBorderSize = std::round(scaledBorderSize * m_RenderData.renderModif.combinedScale()); // adjust box - box->x -= scaledBorderSize; - box->y -= scaledBorderSize; - box->width += 2 * scaledBorderSize; - box->height += 2 * scaledBorderSize; + newBox.x -= scaledBorderSize; + newBox.y -= scaledBorderSize; + newBox.width += 2 * scaledBorderSize; + newBox.height += 2 * scaledBorderSize; round += round == 0 ? 0 : scaledBorderSize; @@ -2237,7 +2229,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, 0); - CBox transformedBox = *box; + CBox transformedBox = box; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -2246,7 +2238,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box.width, (float)box.height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); @@ -2281,9 +2273,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in blend(BLEND); } -void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, float roundingPower, int borderSize, float a, - int outerRound) { - RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); +void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& grad1, const CGradientValueData& grad2, float lerp, int round, float roundingPower, int borderSize, + float a, int outerRound) { + RASSERT((box.width > 0 && box.height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); TRACY_GPU_ZONE("RenderBorder2"); @@ -2291,11 +2283,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c if (m_RenderData.damage.empty() || (m_RenderData.currentWindow && m_RenderData.currentWindow->m_sWindowData.noBorder.valueOrDefault())) return; - CBox newBox = *box; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); - box = &newBox; - if (borderSize < 1) return; @@ -2303,10 +2293,10 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c scaledBorderSize = std::round(scaledBorderSize * m_RenderData.renderModif.combinedScale()); // adjust box - box->x -= scaledBorderSize; - box->y -= scaledBorderSize; - box->width += 2 * scaledBorderSize; - box->height += 2 * scaledBorderSize; + newBox.x -= scaledBorderSize; + newBox.y -= scaledBorderSize; + newBox.width += 2 * scaledBorderSize; + newBox.height += 2 * scaledBorderSize; round += round == 0 ? 0 : scaledBorderSize; @@ -2336,7 +2326,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp, lerp); - CBox transformedBox = *box; + CBox transformedBox = box; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -2345,7 +2335,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box->width, (float)box->height); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box.width, (float)box.height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); @@ -2380,9 +2370,9 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad1, c blend(BLEND); } -void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPower, int range, const CHyprColor& color, float a) { +void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roundingPower, int range, const CHyprColor& color, float a) { RASSERT(m_RenderData.pMonitor, "Tried to render shadow without begin()!"); - RASSERT((box->width > 0 && box->height > 0), "Tried to render shadow with width/height < 0!"); + RASSERT((box.width > 0 && box.height > 0), "Tried to render shadow with width/height < 0!"); RASSERT(m_RenderData.currentWindow, "Tried to render shadow without a window!"); if (m_RenderData.damage.empty()) @@ -2390,11 +2380,9 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPo TRACY_GPU_ZONE("RenderShadow"); - CBox newBox = *box; + CBox newBox = box; m_RenderData.renderModif.applyToBox(newBox); - box = &newBox; - static auto PSHADOWPOWER = CConfigValue("decoration:shadow:render_power"); const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); @@ -2418,8 +2406,8 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPo glUniform4f(m_RenderData.pCurrentMonData->m_shSHADOW.color, col.r, col.g, col.b, col.a * a); const auto TOPLEFT = Vector2D(range + round, range + round); - const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); - const auto FULLSIZE = Vector2D(box->width, box->height); + const auto BOTTOMRIGHT = Vector2D(newBox.width - (range + round), newBox.height - (range + round)); + const auto FULLSIZE = Vector2D(newBox.width, newBox.height); // Rounded corners glUniform2f(m_RenderData.pCurrentMonData->m_shSHADOW.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); @@ -2457,7 +2445,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, float roundingPo glDisableVertexAttribArray(m_RenderData.pCurrentMonData->m_shSHADOW.texAttrib); } -void CHyprOpenGLImpl::saveBufferForMirror(CBox* box) { +void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) { if (!m_RenderData.pCurrentMonData->monitorMirrorFB.isAllocated()) m_RenderData.pCurrentMonData->monitorMirrorFB.alloc(m_RenderData.pMonitor->vecPixelSize.x, m_RenderData.pMonitor->vecPixelSize.y, @@ -2850,11 +2838,11 @@ void CHyprOpenGLImpl::createBGTextureForMonitor(PHLMONITOR pMonitor) { } CBox texbox = CBox{origin, m_pBackgroundTexture->m_vSize * scale}; - renderTextureInternalWithDamage(m_pBackgroundTexture, &texbox, 1.0, fakeDamage); + renderTextureInternalWithDamage(m_pBackgroundTexture, texbox, 1.0, fakeDamage); } CBox monbox = {{}, pMonitor->vecPixelSize}; - renderTextureInternalWithDamage(tex, &monbox, 1.0, fakeDamage); + renderTextureInternalWithDamage(tex, monbox, 1.0, fakeDamage); // bind back if (m_RenderData.currentFB) @@ -2936,7 +2924,7 @@ void CHyprOpenGLImpl::bindOffMain() { void CHyprOpenGLImpl::renderOffToMain(CFramebuffer* off) { CBox monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - renderTexturePrimitive(off->getTexture(), &monbox); + renderTexturePrimitive(off->getTexture(), monbox); } void CHyprOpenGLImpl::bindBackOnMain() { diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index fd84d478..1ebb0162 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -166,86 +166,86 @@ class CHyprOpenGLImpl { CHyprOpenGLImpl(); ~CHyprOpenGLImpl(); - void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); - void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); - void end(); + void begin(PHLMONITOR, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, CFramebuffer* fb = nullptr); + void end(); - void renderRect(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f); - void renderRectWithBlur(CBox*, const CHyprColor&, int round = 0, float roundingPower = 2.0f, float blurA = 1.f, bool xray = false); - void renderRectWithDamage(CBox*, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); - void renderTexture(SP, CBox*, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); - void renderTextureWithDamage(SP, CBox*, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, - bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); - void renderTextureWithBlur(SP, CBox*, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, - float blurA = 1.f, float overallA = 1.f); - void renderRoundedShadow(CBox*, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); - void renderBorder(CBox*, const CGradientValueData&, int round, float roundingPower, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); - void renderBorder(CBox*, const CGradientValueData&, const CGradientValueData&, float lerp, int round, float roundingPower, int borderSize, float a = 1.0, - int outerRound = -1 /* use round */); - void renderTextureMatte(SP tex, CBox* pBox, CFramebuffer& matte); + void renderRect(const CBox&, const CHyprColor&, int round = 0, float roundingPower = 2.0f); + void renderRectWithBlur(const CBox&, const CHyprColor&, int round = 0, float roundingPower = 2.0f, float blurA = 1.f, bool xray = false); + void renderRectWithDamage(const CBox&, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); + void renderTexture(SP, const CBox&, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); + void renderTextureWithDamage(SP, const CBox&, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, + bool allowCustomUV = false, SP waitTimeline = nullptr, uint64_t waitPoint = 0); + void renderTextureWithBlur(SP, const CBox&, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, + float blurA = 1.f, float overallA = 1.f); + void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); + void renderBorder(const CBox&, const CGradientValueData&, int round, float roundingPower, int borderSize, float a = 1.0, int outerRound = -1 /* use round */); + void renderBorder(const CBox&, const CGradientValueData&, const CGradientValueData&, float lerp, int round, float roundingPower, int borderSize, float a = 1.0, + int outerRound = -1 /* use round */); + void renderTextureMatte(SP tex, const CBox& pBox, CFramebuffer& matte); - void setMonitorTransformEnabled(bool enabled); - void setRenderModifEnabled(bool enabled); + void setMonitorTransformEnabled(bool enabled); + void setRenderModifEnabled(bool enabled); - void saveMatrix(); - void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); - void restoreMatrix(); + void saveMatrix(); + void setMatrixScaleTranslate(const Vector2D& translate, const float& scale); + void restoreMatrix(); - void blend(bool enabled); + void blend(bool enabled); - bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - void clear(const CHyprColor&); - void clearWithTex(); - void scissor(const CBox*, bool transform = true); - void scissor(const pixman_box32*, bool transform = true); - void scissor(const int x, const int y, const int w, const int h, bool transform = true); + void clear(const CHyprColor&); + void clearWithTex(); + void scissor(const CBox&, bool transform = true); + void scissor(const pixman_box32*, bool transform = true); + void scissor(const int x, const int y, const int w, const int h, bool transform = true); - void destroyMonitorResources(PHLMONITOR); + void destroyMonitorResources(PHLMONITOR); - void markBlurDirtyForMonitor(PHLMONITOR); + void markBlurDirtyForMonitor(PHLMONITOR); - void preWindowPass(); - bool preBlurQueued(); - void preRender(PHLMONITOR); + void preWindowPass(); + bool preBlurQueued(); + void preRender(PHLMONITOR); - void saveBufferForMirror(CBox*); - void renderMirrored(); + void saveBufferForMirror(const CBox&); + void renderMirrored(); - void applyScreenShader(const std::string& path); + void applyScreenShader(const std::string& path); - void bindOffMain(); - void renderOffToMain(CFramebuffer* off); - void bindBackOnMain(); + void bindOffMain(); + void renderOffToMain(CFramebuffer* off); + void bindBackOnMain(); - SP loadAsset(const std::string& file); - SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); + SP loadAsset(const std::string& file); + SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0); - void setDamage(const CRegion& damage, std::optional finalDamage = {}); + void setDamage(const CRegion& damage, std::optional finalDamage = {}); - void ensureBackgroundTexturePresence(); + void ensureBackgroundTexturePresence(); - uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); - std::vector getDRMFormats(); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); - bool waitForTimelinePoint(SP timeline, uint64_t point); + uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); + std::vector getDRMFormats(); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + SP createEGLSync(int fenceFD); + bool waitForTimelinePoint(SP timeline, uint64_t point); - SCurrentRenderData m_RenderData; + SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; + GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; - gbm_device* m_pGbmDevice = nullptr; - EGLContext m_pEglContext = nullptr; - EGLDisplay m_pEglDisplay = nullptr; - EGLDeviceEXT m_pEglDevice = nullptr; - uint failedAssetsNo = 0; + int m_iGBMFD = -1; + gbm_device* m_pGbmDevice = nullptr; + EGLContext m_pEglContext = nullptr; + EGLDisplay m_pEglDisplay = nullptr; + EGLDeviceEXT m_pEglDevice = nullptr; + uint failedAssetsNo = 0; - bool m_bReloadScreenShader = true; // at launch it can be set + bool m_bReloadScreenShader = true; // at launch it can be set - std::map m_mWindowFramebuffers; - std::map m_mLayerFramebuffers; + std::map m_mWindowFramebuffers; + std::map m_mLayerFramebuffers; std::map m_mMonitorRenderResources; std::map m_mMonitorBGFBs; @@ -314,14 +314,14 @@ class CHyprOpenGLImpl { // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); - void renderTextureInternalWithDamage(SP, CBox* pBox, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, - bool noAA = false, bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); - void renderTexturePrimitive(SP tex, CBox* pBox); - void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); + void renderTextureInternalWithDamage(SP, const CBox& box, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, + bool noAA = false, bool allowCustomUV = false, bool allowDim = false, SP = nullptr, uint64_t waitPoint = 0); + void renderTexturePrimitive(SP tex, const CBox& box); + void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); - void preBlurForCurrentMonitor(); + void preBlurForCurrentMonitor(); - bool passRequiresIntrospection(PHLMONITOR pMonitor); + bool passRequiresIntrospection(PHLMONITOR pMonitor); friend class CHyprRenderer; friend class CTexPassElement; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f897379a..41ab0b37 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -978,15 +978,15 @@ void CHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { if (ANY_PRESENT) { // render image2, without instructions. Lock still "alive", unless texture dead - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, &monbox, ALPHA); + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDead2Texture, monbox, ALPHA); } else { // render image, with instructions. Lock is gone. - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, &monbox, ALPHA); + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockDeadTexture, monbox, ALPHA); // also render text for the tty number if (g_pHyprOpenGL->m_pLockTtyTextTexture) { CBox texbox = {{}, g_pHyprOpenGL->m_pLockTtyTextTexture->m_vSize}; - g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, &texbox, 1.F); + g_pHyprOpenGL->renderTexture(g_pHyprOpenGL->m_pLockTtyTextTexture, texbox, 1.F); } } @@ -1836,7 +1836,7 @@ void CHyprRenderer::damageSurface(SP pSurface, double x, dou damageBoxForEach.set(damageBox); damageBoxForEach.translate({-m->vecPosition.x, -m->vecPosition.y}).scale(m->scale); - m->addDamage(&damageBoxForEach); + m->addDamage(damageBoxForEach); } static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -1860,7 +1860,7 @@ void CHyprRenderer::damageWindow(PHLWINDOW pWindow, bool forceFull) { if (forceFull || shouldRenderWindow(pWindow, m)) { // only damage if window is rendered on monitor CBox fixedDamageBox = {windowBox.x - m->vecPosition.x, windowBox.y - m->vecPosition.y, windowBox.width, windowBox.height}; fixedDamageBox.scale(m->scale); - m->addDamage(&fixedDamageBox); + m->addDamage(fixedDamageBox); } } @@ -1878,7 +1878,7 @@ void CHyprRenderer::damageMonitor(PHLMONITOR pMonitor) { return; CBox damageBox = {0, 0, INT16_MAX, INT16_MAX}; - pMonitor->addDamage(&damageBox); + pMonitor->addDamage(damageBox); static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); @@ -1886,7 +1886,7 @@ void CHyprRenderer::damageMonitor(PHLMONITOR pMonitor) { Debug::log(LOG, "Damage: Monitor {}", pMonitor->szName); } -void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { +void CHyprRenderer::damageBox(const CBox& box, bool skipFrameSchedule) { if (g_pCompositor->m_bUnsafeState) return; @@ -1895,21 +1895,20 @@ void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { continue; // don't damage mirrors traditionally if (!skipFrameSchedule) { - CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; - damageBox.scale(m->scale); - m->addDamage(&damageBox); + CBox damageBox = box.copy().translate(-m->vecPosition).scale(m->scale); + m->addDamage(damageBox); } } static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Box: xy: {}, {} wh: {}, {}", pBox->x, pBox->y, pBox->width, pBox->height); + Debug::log(LOG, "Damage: Box: xy: {}, {} wh: {}, {}", box.x, box.y, box.w, box.h); } void CHyprRenderer::damageBox(const int& x, const int& y, const int& w, const int& h) { CBox box = {x, y, w, h}; - damageBox(&box); + damageBox(box); } void CHyprRenderer::damageRegion(const CRegion& rg) { @@ -1936,7 +1935,7 @@ void CHyprRenderer::damageMirrorsWith(PHLMONITOR pMonitor, const CRegion& pRegio transformed.transform(wlTransformToHyprutils(pMonitor->transform), pMonitor->vecPixelSize.x * scale, pMonitor->vecPixelSize.y * scale); transformed.translate(Vector2D(monbox.x, monbox.y)); - mirror->addDamage(&transformed); + mirror->addDamage(transformed); g_pCompositor->scheduleFrameForMonitor(mirror.lock(), Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE); } diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 30fba3ca..e64d41c1 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -53,7 +53,7 @@ class CHyprRenderer { void arrangeLayersForMonitor(const MONITORID&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*, bool skipFrameSchedule = false); + void damageBox(const CBox&, bool skipFrameSchedule = false); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageRegion(const CRegion&); void damageMonitor(PHLMONITOR); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index c576b966..8a934086 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -149,7 +149,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { if (fullBox.width < 1 || fullBox.height < 1) return; // don't draw invisible shadows - g_pHyprOpenGL->scissor((CBox*)nullptr); + g_pHyprOpenGL->scissor(nullptr); g_pHyprOpenGL->m_RenderData.currentWindow = m_pWindow; // we'll take the liberty of using this as it should not be used rn @@ -191,18 +191,18 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { // build the matte // 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest. // first, clear region of interest with black (fully transparent) - g_pHyprOpenGL->renderRect(&fullBox, CHyprColor(0, 0, 0, 1), 0); + g_pHyprOpenGL->renderRect(fullBox, CHyprColor(0, 0, 0, 1), 0); // render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit) - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor->value().a), a); + drawShadowInternal(fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, CHyprColor(1, 1, 1, PWINDOW->m_cRealShadowColor->value().a), a); // render black window box ("clip") - g_pHyprOpenGL->renderRect(&windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); + g_pHyprOpenGL->renderRect(windowBox, CHyprColor(0, 0, 0, 1.0), (ROUNDING + 1 /* This fixes small pixel gaps. */) * pMonitor->scale, ROUNDINGPOWER); alphaSwapFB.bind(); // alpha swap just has the shadow color. It will be the "texture" to render. - g_pHyprOpenGL->renderRect(&fullBox, PWINDOW->m_cRealShadowColor->value().stripA(), 0); + g_pHyprOpenGL->renderRect(fullBox, PWINDOW->m_cRealShadowColor->value().stripA(), 0); LASTFB->bind(); @@ -210,13 +210,13 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.getTexture(), &monbox, alphaFB); + g_pHyprOpenGL->renderTextureMatte(alphaSwapFB.getTexture(), monbox, alphaFB); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); g_pHyprOpenGL->m_RenderData.damage = saveDamage; } else - drawShadowInternal(&fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor->value(), a); + drawShadowInternal(fullBox, ROUNDING * pMonitor->scale, ROUNDINGPOWER, *PSHADOWSIZE * pMonitor->scale, PWINDOW->m_cRealShadowColor->value(), a); if (m_seExtents != m_seReportedExtents) g_pDecorationPositioner->repositionDeco(this); @@ -228,7 +228,7 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { return DECORATION_LAYER_BOTTOM; } -void CHyprDropShadowDecoration::drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a) { +void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) { static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); g_pHyprOpenGL->blend(true); diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 93fa3d1a..3b1c67c5 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -36,7 +36,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { Vector2D m_vLastWindowPos; Vector2D m_vLastWindowSize; - void drawShadowInternal(CBox* box, int round, float roundingPower, int range, CHyprColor color, float a); + void drawShadowInternal(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a); CBox m_bLastWindowBox = {0}; CBox m_bLastWindowBoxWithDecos = {0}; diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 7cef21b8..4e7c3cbc 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -94,7 +94,7 @@ void CHyprGroupBarDecoration::updateWindow(PHLWINDOW pWindow) { void CHyprGroupBarDecoration::damageEntire() { auto box = assignedBoxGlobal(); box.translate(m_pWindow->m_vFloatingOffset); - g_pHyprRenderer->damageBox(&box); + g_pHyprRenderer->damageBox(box); } void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { diff --git a/src/render/pass/BorderPassElement.cpp b/src/render/pass/BorderPassElement.cpp index ceeec6f3..31042c28 100644 --- a/src/render/pass/BorderPassElement.cpp +++ b/src/render/pass/BorderPassElement.cpp @@ -7,9 +7,9 @@ CBorderPassElement::CBorderPassElement(const CBorderPassElement::SBorderData& da void CBorderPassElement::draw(const CRegion& damage) { if (data.hasGrad2) - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.grad2, data.lerp, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(data.box, data.grad1, data.grad2, data.lerp, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); else - g_pHyprOpenGL->renderBorder(&data.box, data.grad1, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); + g_pHyprOpenGL->renderBorder(data.box, data.grad1, data.round, data.roundingPower, data.borderSize, data.a, data.outerRound); } bool CBorderPassElement::needsLiveBlur() { diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 5b133b7d..81b918ac 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -202,9 +202,9 @@ CRegion CRenderPass::render(const CRegion& damage_) { void CRenderPass::renderDebugData() { CBox box = {{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize}; for (const auto& rg : occludedRegions) { - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::RED.modifyA(0.1F), rg); + g_pHyprOpenGL->renderRectWithDamage(box, Colors::RED.modifyA(0.1F), rg); } - g_pHyprOpenGL->renderRectWithDamage(&box, Colors::GREEN.modifyA(0.1F), totalLiveBlurRegion); + g_pHyprOpenGL->renderRectWithDamage(box, Colors::GREEN.modifyA(0.1F), totalLiveBlurRegion); std::unordered_map offsets; @@ -227,7 +227,7 @@ void CRenderPass::renderDebugData() { if (box.intersection(CBox{{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize}).empty()) return; - g_pHyprOpenGL->renderRectWithDamage(&box, color, CRegion{0, 0, INT32_MAX, INT32_MAX}); + g_pHyprOpenGL->renderRectWithDamage(box, color, CRegion{0, 0, INT32_MAX, INT32_MAX}); if (offsets.contains(surface.get())) box.translate(Vector2D{0.F, offsets[surface.get()]}); @@ -235,8 +235,8 @@ void CRenderPass::renderDebugData() { offsets[surface.get()] = 0; box = {box.pos(), texture->m_vSize}; - g_pHyprOpenGL->renderRectWithDamage(&box, CHyprColor{0.F, 0.F, 0.F, 0.2F}, CRegion{0, 0, INT32_MAX, INT32_MAX}, std::min(5.0, box.size().y)); - g_pHyprOpenGL->renderTexture(texture, &box, 1.F); + g_pHyprOpenGL->renderRectWithDamage(box, CHyprColor{0.F, 0.F, 0.F, 0.2F}, CRegion{0, 0, INT32_MAX, INT32_MAX}, std::min(5.0, box.size().y)); + g_pHyprOpenGL->renderTexture(texture, box, 1.F); offsets[surface.get()] += texture->m_vSize.y; }; @@ -253,7 +253,7 @@ void CRenderPass::renderDebugData() { if (tex) { box = CBox{{0.F, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale); - g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + g_pHyprOpenGL->renderTexture(tex, box, 1.F); } std::string passStructure; @@ -271,7 +271,7 @@ void CRenderPass::renderDebugData() { if (tex) { box = CBox{{g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.x - tex->m_vSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecSize.y - tex->m_vSize.y}, tex->m_vSize}.scale( g_pHyprOpenGL->m_RenderData.pMonitor->scale); - g_pHyprOpenGL->renderTexture(tex, &box, 1.F); + g_pHyprOpenGL->renderTexture(tex, box, 1.F); } } diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index 55471e78..a9ab737d 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -10,9 +10,9 @@ void CRectPassElement::draw(const CRegion& damage) { return; if (data.color.a == 1.F || !data.blur) - g_pHyprOpenGL->renderRectWithDamage(&data.box, data.color, damage, data.round, data.roundingPower); + g_pHyprOpenGL->renderRectWithDamage(data.box, data.color, damage, data.round, data.roundingPower); else - g_pHyprOpenGL->renderRectWithBlur(&data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); + g_pHyprOpenGL->renderRectWithBlur(data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); } bool CRectPassElement::needsLiveBlur() { diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index b79407c8..a5d3d7c0 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -122,14 +122,14 @@ void CSurfacePassElement::draw(const CRegion& damage) { // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) if (data.surfaceCounter == 0 && !data.popup) { if (BLUR) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, windowBox, ALPHA, data.surface, rounding, roundingPower, data.blockBlurOptimization, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } else { if (BLUR && data.popup) - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, ALPHA, data.surface, rounding, roundingPower, true, data.fadeAlpha, OVERALL_ALPHA); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, windowBox, ALPHA, data.surface, rounding, roundingPower, true, data.fadeAlpha, OVERALL_ALPHA); else - g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); + g_pHyprOpenGL->renderTexture(TEXTURE, windowBox, ALPHA * OVERALL_ALPHA, rounding, roundingPower, false, true); } if (!g_pHyprRenderer->m_bBlockSurfaceFeedback) diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index 0624a786..c7eab292 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -18,7 +18,7 @@ void CTexPassElement::draw(const CRegion& damage) { if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection; - g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, &data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, + g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, data.syncPoint); if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = g_pHyprOpenGL->m_RenderData.pMonitor->projMatrix; diff --git a/src/render/pass/TextureMatteElement.cpp b/src/render/pass/TextureMatteElement.cpp index 5aed1c9a..3d927357 100644 --- a/src/render/pass/TextureMatteElement.cpp +++ b/src/render/pass/TextureMatteElement.cpp @@ -9,11 +9,11 @@ void CTextureMatteElement::draw(const CRegion& damage) { if (data.disableTransformAndModify) { g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); - g_pHyprOpenGL->renderTextureMatte(data.tex, &data.box, *data.fb); + g_pHyprOpenGL->renderTextureMatte(data.tex, data.box, *data.fb); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); } else - g_pHyprOpenGL->renderTextureMatte(data.tex, &data.box, *data.fb); + g_pHyprOpenGL->renderTextureMatte(data.tex, data.box, *data.fb); } bool CTextureMatteElement::needsLiveBlur() { From efe29a24616d4de41dd8f2f70e1493ed6b581e33 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 15:15:54 +0000 Subject: [PATCH 1131/2393] shadow: avoid drawing empty shadows --- src/render/decorations/CHyprDropShadowDecoration.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 8a934086..0b2a96d9 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -231,6 +231,9 @@ eDecorationLayer CHyprDropShadowDecoration::getDecorationLayer() { void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) { static auto PSHADOWSHARP = CConfigValue("decoration:shadow:sharp"); + if (box.w < 1 || box.h < 1) + return; + g_pHyprOpenGL->blend(true); color.a *= a; From bb5b09def0645838456eb7eb1f52b471441acba1 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 15:19:42 +0000 Subject: [PATCH 1132/2393] renderer: fix funky corners oopsie --- src/render/OpenGL.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index f0b2f447..ee5d9a86 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2229,7 +2229,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); glUniform1i(m_RenderData.pCurrentMonData->m_shBORDER1.gradient2Length, 0); - CBox transformedBox = box; + CBox transformedBox = newBox; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -2238,7 +2238,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box.width, (float)box.height); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); @@ -2326,7 +2326,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.alpha, a); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.gradientLerp, lerp); - CBox transformedBox = box; + CBox transformedBox = newBox; transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y); @@ -2335,7 +2335,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.topLeft, (float)TOPLEFT.x, (float)TOPLEFT.y); glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSize, (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)box.width, (float)box.height); + glUniform2f(m_RenderData.pCurrentMonData->m_shBORDER1.fullSizeUntransformed, (float)newBox.width, (float)newBox.height); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radius, round); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.radiusOuter, outerRound == -1 ? round : outerRound); glUniform1f(m_RenderData.pCurrentMonData->m_shBORDER1.roundingPower, roundingPower); From 6bd6c5512e1e413013044257e54581c237ca6fa0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 18:35:35 +0000 Subject: [PATCH 1133/2393] hooksystem: avoid huge include for HANDLE --- src/managers/HookSystemManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/HookSystemManager.hpp b/src/managers/HookSystemManager.hpp index 6d72a02d..c679c380 100644 --- a/src/managers/HookSystemManager.hpp +++ b/src/managers/HookSystemManager.hpp @@ -9,7 +9,7 @@ #include -#include "../plugins/PluginAPI.hpp" +#define HANDLE void* // global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally. From 3b207d29bdaf4c718a8878456bb17f2a67f2d9f4 Mon Sep 17 00:00:00 2001 From: user111111111111111111111111111111111 <192911676+user111111111111111111111111111111111@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:06:50 +0000 Subject: [PATCH 1134/2393] core: update groups on movewindow (#9183) --- src/layout/DwindleLayout.cpp | 9 +++++++++ src/layout/MasterLayout.cpp | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index df6c3bde..8aaafaa3 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -847,6 +847,15 @@ void CHyprDwindleLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, pWindow->m_pMonitor = PMONITORFOCAL; } + pWindow->updateGroupOutputs(); + if (!pWindow->m_sGroupData.pNextWindow.expired()) { + PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock(); + while (next != pWindow) { + next->updateToplevel(); + next = next->m_sGroupData.pNextWindow.lock(); + } + } + onWindowCreatedTiling(pWindow); m_vOverrideFocalPoint.reset(); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 8aa15e42..4773147f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -945,6 +945,15 @@ void CHyprMasterLayout::moveWindowTo(PHLWINDOW pWindow, const std::string& dir, if (silent) g_pCompositor->focusWindow(PWINDOW2); } + + pWindow->updateGroupOutputs(); + if (!pWindow->m_sGroupData.pNextWindow.expired()) { + PHLWINDOW next = pWindow->m_sGroupData.pNextWindow.lock(); + while (next != pWindow) { + next->updateToplevel(); + next = next->m_sGroupData.pNextWindow.lock(); + } + } } void CHyprMasterLayout::switchWindows(PHLWINDOW pWindow, PHLWINDOW pWindow2) { From 2f55806d6f11a1e81e3e821cb0327779d5cc50e6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 26 Jan 2025 21:06:19 +0000 Subject: [PATCH 1135/2393] renderer: fix rare case when a tiled window would be rendered over fs --- src/render/Renderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 41ab0b37..3f6448d5 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -337,7 +337,7 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR // then render windows over fullscreen. for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) + if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || !w->m_bIsFloating || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) continue; if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) From 04ac46c54357278fc68f0a95d26347ea0db99496 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 27 Jan 2025 11:43:43 +0000 Subject: [PATCH 1136/2393] version: bump to 0.47.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 30109231..421ab545 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.46.0 +0.47.0 From 2a478c30cab89c8c608936ca966155da5b16728d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 27 Jan 2025 13:41:38 +0000 Subject: [PATCH 1137/2393] core: fix clang-format --- src/render/Renderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 3f6448d5..67d8b58b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -337,7 +337,8 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR // then render windows over fullscreen. for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || !w->m_bIsFloating || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) + if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || !w->m_bIsFloating || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || + w->isFullscreen()) continue; if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) From cb7ed4f62b195ab7d5f21fa393218170cfbb95c8 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 28 Jan 2025 00:41:26 +0800 Subject: [PATCH 1138/2393] ci: clang-format fix (#9145) * move * revert, comment via peter-evans/commit-comment@v3 * remove --- .github/workflows/ci.yaml | 24 --------------- .github/workflows/clang-format.yml | 48 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/clang-format.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 34c45d6b..416ea93b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,27 +127,3 @@ jobs: - name: clang-format check run: ninja -C build clang-format-check - - - name: clang-format apply - if: ${{ failure() && github.event_name == 'pull_request' }} - run: ninja -C build clang-format - - - name: Create patch - if: ${{ failure() && github.event_name == 'pull_request' }} - run: | - echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch - echo '
' >> clang-format.patch - echo 'clang-format.patch' >> clang-format.patch - echo >> clang-format.patch - echo '```diff' >> clang-format.patch - git diff >> clang-format.patch - echo '```' >> clang-format.patch - echo >> clang-format.patch - echo '
' >> clang-format.patch - - - name: Comment patch - if: ${{ failure() && github.event_name == 'pull_request' }} - uses: mshick/add-pr-comment@v2 - with: - message-path: | - clang-format.patch diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 00000000..e935a605 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,48 @@ +name: clang-format +on: pull_request_target +jobs: + clang-format: + permissions: write-all + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork + name: "Code Style (Arch)" + runs-on: ubuntu-latest + container: + image: archlinux + steps: + - name: Checkout repository actions + uses: actions/checkout@v4 + with: + sparse-checkout: .github/actions + + - name: Setup base + uses: ./.github/actions/setup_base + + - name: Configure + run: meson setup build -Ddefault_library=static + + - name: clang-format check + run: ninja -C build clang-format-check + + - name: clang-format apply + if: ${{ failure() && github.event_name == 'pull_request' }} + run: ninja -C build clang-format + + - name: Create patch + if: ${{ failure() && github.event_name == 'pull_request' }} + run: | + echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch + echo '
' >> clang-format.patch + echo 'clang-format.patch' >> clang-format.patch + echo >> clang-format.patch + echo '```diff' >> clang-format.patch + git diff >> clang-format.patch + echo '```' >> clang-format.patch + echo >> clang-format.patch + echo '
' >> clang-format.patch + + - name: Comment patch + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: mshick/add-pr-comment@v2 + with: + message-path: | + clang-format.patch From e7a72de9b5550784ea804c7bb4e84a28a74326a8 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Tue, 28 Jan 2025 00:45:15 +0800 Subject: [PATCH 1139/2393] xwayland: send synthetic configure events (#9193) --- src/xwayland/XSurface.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index b5ee75f6..91f20be5 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -169,6 +169,22 @@ void CXWaylandSurface::configure(const CBox& box) { uint32_t values[] = {box.x, box.y, box.width, box.height, 0}; xcb_configure_window(g_pXWayland->pWM->connection, xID, mask, values); + if (geometry.width == box.width && geometry.height == box.height) { + // ICCCM requires a synthetic event when window size is not changed + xcb_configure_notify_event_t e; + e.response_type = XCB_CONFIGURE_NOTIFY; + e.event = xID; + e.window = xID; + e.x = box.x; + e.y = box.y; + e.width = box.width; + e.height = box.height; + e.border_width = 0; + e.above_sibling = XCB_NONE; + e.override_redirect = overrideRedirect; + xcb_send_event(g_pXWayland->pWM->connection, false, xID, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char*)&e); + } + g_pXWayland->pWM->updateClientList(); xcb_flush(g_pXWayland->pWM->connection); From 25d5ce4833a481325a2a948f51cabb6f4a6e1896 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 27 Jan 2025 22:25:27 +0200 Subject: [PATCH 1140/2393] CI/setup_base: add libspng --- .github/actions/setup_base/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index 6df442b3..b4c9cf78 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -35,6 +35,7 @@ runs: libinput \ libjxl \ libliftoff \ + libspng \ libwebp \ libxcursor \ libxcvt \ From 5fd90548dc99d79dd2677e027a620c8ada9f4869 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Mon, 27 Jan 2025 14:19:47 -0500 Subject: [PATCH 1141/2393] nix: fix duplicate inputs and update flake.lock --- flake.lock | 95 +++++++++++++----------------------------------------- flake.nix | 2 +- 2 files changed, 24 insertions(+), 73 deletions(-) diff --git a/flake.lock b/flake.lock index 34249b0a..ac73e5f7 100644 --- a/flake.lock +++ b/flake.lock @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1737634889, - "narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=", + "lastModified": 1737985436, + "narHash": "sha256-zx8FdI4zr2GhNyD1YGAqa2ymodAObTSAdwuWwVucewo=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591", + "rev": "23783b96036f5506fdaf8b2250a1ef849d57f0d3", "type": "github" }, "original": { @@ -143,7 +143,10 @@ }, "hyprland-qt-support": { "inputs": { - "hyprlang": "hyprlang", + "hyprlang": [ + "hyprland-qtutils", + "hyprlang" + ], "nixpkgs": [ "hyprland-qtutils", "nixpkgs" @@ -170,7 +173,12 @@ "hyprland-qtutils": { "inputs": { "hyprland-qt-support": "hyprland-qt-support", + "hyprlang": [ + "hyprlang" + ], "hyprutils": [ + "hyprland-qtutils", + "hyprlang", "hyprutils" ], "nixpkgs": [ @@ -181,11 +189,11 @@ ] }, "locked": { - "lastModified": 1737811848, - "narHash": "sha256-WZ7LeiKHk5Y94MU5gHIWn0r8asWxYOvie4LqfCjVIZU=", + "lastModified": 1737981711, + "narHash": "sha256-lh6cL5D8nPplB3WovCQjLUZ7k7MViiBrMlpkfm4R7/c=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "9c0831ff98856c0f312fcb8b57553fbe3dd34d5b", + "rev": "96bf0677fa9cd13508294e3d4559dfbbc8beff73", "type": "github" }, "original": { @@ -195,34 +203,6 @@ } }, "hyprlang": { - "inputs": { - "hyprutils": "hyprutils", - "nixpkgs": [ - "hyprland-qtutils", - "hyprland-qt-support", - "nixpkgs" - ], - "systems": [ - "hyprland-qtutils", - "hyprland-qt-support", - "systems" - ] - }, - "locked": { - "lastModified": 1737634606, - "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", - "owner": "hyprwm", - "repo": "hyprlang", - "rev": "f41271d35cc0f370d300413d756c2677f386af9d", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprlang", - "type": "github" - } - }, - "hyprlang_2": { "inputs": { "hyprutils": [ "hyprutils" @@ -249,35 +229,6 @@ } }, "hyprutils": { - "inputs": { - "nixpkgs": [ - "hyprland-qtutils", - "hyprland-qt-support", - "hyprlang", - "nixpkgs" - ], - "systems": [ - "hyprland-qtutils", - "hyprland-qt-support", - "hyprlang", - "systems" - ] - }, - "locked": { - "lastModified": 1737632363, - "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=", - "owner": "hyprwm", - "repo": "hyprutils", - "rev": "006620eb29d54ea9086538891404c78563d1bae1", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprutils", - "type": "github" - } - }, - "hyprutils_2": { "inputs": { "nixpkgs": [ "nixpkgs" @@ -287,11 +238,11 @@ ] }, "locked": { - "lastModified": 1737725508, - "narHash": "sha256-jGmcPc6y/prg/4A8KGYqJ27nSPaProCMiFadaxNAKvA=", + "lastModified": 1737978343, + "narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "fb0c2d1de3d1ef7396d19c18ac09e12bd956929e", + "rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab", "type": "github" }, "original": { @@ -325,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737632463, - "narHash": "sha256-38J9QfeGSej341ouwzqf77WIHAScihAKCt8PQJ+NH28=", + "lastModified": 1737885589, + "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0aa475546ed21629c4f5bbf90e38c846a99ec9e9", + "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", "type": "github" }, "original": { @@ -368,8 +319,8 @@ "hyprgraphics": "hyprgraphics", "hyprland-protocols": "hyprland-protocols", "hyprland-qtutils": "hyprland-qtutils", - "hyprlang": "hyprlang_2", - "hyprutils": "hyprutils_2", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "pre-commit-hooks": "pre-commit-hooks", diff --git a/flake.nix b/flake.nix index 821a5f90..c1c580ae 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,7 @@ url = "github:hyprwm/hyprland-qtutils"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; - inputs.hyprutils.follows = "hyprutils"; + inputs.hyprlang.follows = "hyprlang"; }; hyprlang = { From d2773d7a4ecde7111af4ec71b51b1996ec1d96bf Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 27 Jan 2025 22:06:48 +0000 Subject: [PATCH 1142/2393] deps: add libinotify-kqueue on BSDs after 8dd2cd41fb4c (#9197) src/config/ConfigWatcher.cpp:2:10: fatal error: 'sys/inotify.h' file not found 2 | #include | ^~~~~~~~~~~~~~~ --- CMakeLists.txt | 6 ++++++ meson.build | 1 + src/meson.build | 1 + 3 files changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cfb8688..a34d677c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,12 @@ if(NOT HAS_TIMERFD AND epoll_FOUND) target_link_libraries(Hyprland PkgConfig::epoll) endif() +check_include_file("sys/inotify.h" HAS_INOTIFY) +pkg_check_modules(inotify IMPORTED_TARGET libinotify) +if(NOT HAS_INOTIFY AND inotify_FOUND) + target_link_libraries(Hyprland PkgConfig::inotify) +endif() + if(LEGACY_RENDERER) message(STATUS "Using the legacy GLES2 renderer!") add_compile_definitions(LEGACY_RENDERER) diff --git a/meson.build b/meson.build index 6b50ff2d..ae6e3940 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,7 @@ endif backtrace_dep = cpp_compiler.find_library('execinfo', required: false) epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs +inotify_dep = dependency('libinotify', required: false) # inotify on BSDs re2 = dependency('re2', required: true) diff --git a/src/meson.build b/src/meson.build index 7054d8e4..3973dc4c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -32,6 +32,7 @@ executable( xcb_xfixes_dep, backtrace_dep, epoll_dep, + inotify_dep, gio_dep, tracy, From d3042e5358a91287d6ff9d8c745dc70af1ebdc90 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Tue, 28 Jan 2025 18:04:57 +0800 Subject: [PATCH 1143/2393] xwayland: respect window size set by configure requests (#9190) --- src/managers/XWaylandManager.cpp | 26 +++----------------------- src/xwayland/XWM.cpp | 4 ++-- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index f103266d..a5506329 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -82,29 +82,9 @@ CBox CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow) { CBox box; - if (pWindow->m_bIsX11) { - const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); - - if (SIZEHINTS && !pWindow->isX11OverrideRedirect()) { - // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. - // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property - box.x = pWindow->m_pXWaylandSurface->geometry.x; - box.y = pWindow->m_pXWaylandSurface->geometry.y; - - constexpr int ICCCM_USSize = 0x2; - constexpr int ICCCM_PSize = 0x8; - - if ((SIZEHINTS->flags & ICCCM_USSize) || (SIZEHINTS->flags & ICCCM_PSize)) { - box.w = SIZEHINTS->base_width; - box.h = SIZEHINTS->base_height; - } else { - box.w = pWindow->m_pXWaylandSurface->geometry.w; - box.h = pWindow->m_pXWaylandSurface->geometry.h; - } - } else - box = pWindow->m_pXWaylandSurface->geometry; - - } else if (pWindow->m_pXDGSurface) + if (pWindow->m_bIsX11) + box = pWindow->m_pXWaylandSurface->geometry; + else if (pWindow->m_pXDGSurface) box = pWindow->m_pXDGSurface->current.geometry; return box; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index ef139b38..6673105e 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -102,8 +102,8 @@ void CXWM::handleMapRequest(xcb_map_request_event_t* e) { const bool HAS_HINTS = XSURF->sizeHints && Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} > Vector2D{5, 5}; const auto DESIREDSIZE = HAS_HINTS ? Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} : Vector2D{800, 800}; - // if it's too small, or its base size is set, configure it. - if ((SMALL || HAS_HINTS) && !XSURF->overrideRedirect) // default to 800 x 800 + // if it's too small, configure it. + if (SMALL && !XSURF->overrideRedirect) // default to 800 x 800 XSURF->configure({XSURF->geometry.pos(), DESIREDSIZE}); Debug::log(LOG, "[xwm] Mapping window {} in X (geometry {}x{} at {}x{}))", e->window, XSURF->geometry.width, XSURF->geometry.height, XSURF->geometry.x, XSURF->geometry.y); From 529ad4eaf450e558998e7417db5db6602e7fb497 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 28 Jan 2025 10:15:08 +0100 Subject: [PATCH 1144/2393] ikeyboard: free xkbSymState in clearManuallyAllocd asan reported a leak on xkbSymState on destruction, because it wasnt beeing unrefed, was only being unrefed on calls to updateXKBTranslationState. --- src/devices/IKeyboard.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index d1119772..4623fe84 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -44,6 +44,10 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymapFD >= 0) close(xkbKeymapFD); + if (xkbSymState) + xkb_state_unref(xkbSymState); + + xkbSymState = nullptr; xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; From 1d3904c3e7a8b74ea83669f73ee408bd38390b11 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 28 Jan 2025 10:20:54 +0100 Subject: [PATCH 1145/2393] configmgr: properly free glob memory globfree is only freeing internally allocated resources, so also call free the on glob_t memory we allocated. --- src/config/ConfigManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 93289bf7..daff9285 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2690,8 +2690,14 @@ std::optional CConfigManager::handleSource(const std::string& comma Debug::log(ERR, "source= path garbage"); return "source= path " + rawpath + " bogus!"; } - std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }}; - memset(glob_buf.get(), 0, sizeof(glob_t)); + + std::unique_ptr glob_buf{static_cast(calloc(1, sizeof(glob_t))), // allocate and zero-initialize + [](glob_t* g) { + if (g) { + globfree(g); // free internal resources allocated by glob() + free(g); // free the memory for the glob_t structure + } + }}; if (auto r = glob(absolutePath(rawpath, configCurrentPath).c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) { std::string err = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory"); From 3d1dd6b5c7b90e513e86c1ad27c6c01a5c69e4f8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 28 Jan 2025 23:43:26 +0000 Subject: [PATCH 1146/2393] presentation: log a fixme when there is a feedback leak ref #8087 --- src/protocols/PresentationTime.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index a9139ac0..05fda8ea 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -130,6 +130,11 @@ void CPresentationProtocol::onPresented(PHLMONITOR pMonitor, timespec* when, uin } } + if (m_vFeedbacks.size() > 10000 /* arbitrary number I chose as fitting */) { + LOGM(ERR, "FIXME: presentation has a feedback leak, and has grown to {} pending entries!!! Dropping!!!!!", m_vFeedbacks.size()); + m_vFeedbacks = {m_vFeedbacks.begin() + 9000, m_vFeedbacks.end()}; + } + std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor || other->done; }); } From b884f1f7c88b798ba5d1b6a794615bf046ff1f14 Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 29 Jan 2025 03:41:56 -0500 Subject: [PATCH 1147/2393] renderer: calculate UV using both pixel and monitor dimensions (#9210) --- src/render/OpenGL.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ee5d9a86..78b53c9b 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2147,14 +2147,20 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, const CBox& box, f glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // stencil done. Render everything. - CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - // render our great blurred FB - // calculate the uv for it const auto LASTTL = m_RenderData.primarySurfaceUVTopLeft; const auto LASTBR = m_RenderData.primarySurfaceUVBottomRight; - m_RenderData.primarySurfaceUVTopLeft = box.pos() / MONITORBOX.size(); - m_RenderData.primarySurfaceUVBottomRight = (box.pos() + box.size()) / MONITORBOX.size(); + CBox transformedBox = box; + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + m_RenderData.pMonitor->vecTransformedSize.y); + + CBox monitorSpaceBox = {transformedBox.pos().x / m_RenderData.pMonitor->vecPixelSize.x * m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.pos().y / m_RenderData.pMonitor->vecPixelSize.y * m_RenderData.pMonitor->vecTransformedSize.y, + transformedBox.width / m_RenderData.pMonitor->vecPixelSize.x * m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.height / m_RenderData.pMonitor->vecPixelSize.y * m_RenderData.pMonitor->vecTransformedSize.y}; + + m_RenderData.primarySurfaceUVTopLeft = monitorSpaceBox.pos() / m_RenderData.pMonitor->vecTransformedSize; + m_RenderData.primarySurfaceUVBottomRight = (monitorSpaceBox.pos() + monitorSpaceBox.size()) / m_RenderData.pMonitor->vecTransformedSize; static auto PBLURIGNOREOPACITY = CConfigValue("decoration:blur:ignore_opacity"); setMonitorTransformEnabled(true); From d41135d07c15f122d1ca2a03ace9ed3e080b2e28 Mon Sep 17 00:00:00 2001 From: "Owen L." <32573897+mageowl@users.noreply.github.com> Date: Wed, 29 Jan 2025 01:27:34 -0800 Subject: [PATCH 1148/2393] input: change window grab cursor to closed hand (#9196) --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 5e5669b8..57ae5f40 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -307,7 +307,7 @@ void IHyprLayout::onBeginDragWindow() { } if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO) - g_pInputManager->setCursorImageUntilUnset("grab"); + g_pInputManager->setCursorImageUntilUnset("grabbing"); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); From 344e32d71bf115a32434da3fa72b2b6238706625 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 29 Jan 2025 10:42:46 +0000 Subject: [PATCH 1149/2393] pass/rect: fix bounding / opaque regions fixes #9212 --- src/render/pass/PassElement.hpp | 4 ++-- src/render/pass/RectPassElement.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/pass/PassElement.hpp b/src/render/pass/PassElement.hpp index b45970aa..a006ce9e 100644 --- a/src/render/pass/PassElement.hpp +++ b/src/render/pass/PassElement.hpp @@ -13,7 +13,7 @@ class IPassElement { virtual const char* passName() = 0; virtual void discard(); virtual bool undiscardable(); - virtual std::optional boundingBox(); - virtual CRegion opaqueRegion(); + virtual std::optional boundingBox(); // in monitor-local logical coordinates + virtual CRegion opaqueRegion(); // in monitor-local logical coordinates virtual bool disableSimplification(); }; diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index a9ab737d..fba06286 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -24,7 +24,7 @@ bool CRectPassElement::needsPrecomputeBlur() { } std::optional CRectPassElement::boundingBox() { - return data.box; + return data.box.copy().scale(1.F / g_pHyprOpenGL->m_RenderData.pMonitor->scale).round(); } CRegion CRectPassElement::opaqueRegion() { From aaa5573c73636a76dd3ae4758bfd89ae4d5eeb8a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 29 Jan 2025 10:50:39 +0000 Subject: [PATCH 1150/2393] config/hyprctl: fix keyword not updating autoreload ref #9139 --- src/config/ConfigManager.cpp | 8 ++++++-- src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index daff9285..047c58d9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -912,12 +912,16 @@ std::optional CConfigManager::resetHLConfig() { return RET; } +void CConfigManager::updateWatcher() { + static const auto PDISABLEAUTORELOAD = CConfigValue("misc:disable_autoreload"); + g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); +} + void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); - static const auto PDISABLEAUTORELOAD = CConfigValue("misc:disable_autoreload"); static int prevEnabledExplicit = *PENABLEEXPLICIT; - g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); + updateWatcher(); for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index ae0ba759..f0696882 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -190,6 +190,7 @@ class CConfigManager { void ensureVRR(PHLMONITOR pMonitor = nullptr); bool shouldUseSoftwareCursors(); + void updateWatcher(); std::string parseKeyword(const std::string&, const std::string&); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cfdba100..359428b1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1100,6 +1100,9 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) } } + if (COMMAND.contains("misc:disable_autoreload")) + g_pConfigManager->updateWatcher(); + // decorations will probably need a repaint if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" || COMMAND.starts_with("windowrule")) { From 61319197155cbcb3b8d5f004f46c2249029ec1f3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 13:16:50 +0000 Subject: [PATCH 1151/2393] monitor: round refresh rates in sorting modes fixes #9209 --- src/helpers/Monitor.cpp | 7 ++++--- src/helpers/Monitor.hpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 19d68a56..9ea85bca 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -456,9 +456,9 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { // sort prioritizing refresh rate 1st and resolution 2nd, then add best 3 addBest3Modes([](auto const& a, auto const& b) { - if (a->refreshRate > b->refreshRate) + if (std::round(a->refreshRate) > std::round(b->refreshRate)) return true; - else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1000) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) + else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1.F) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) return true; return false; }); @@ -469,7 +469,8 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { addBest3Modes([](auto const& a, auto const& b) { if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) return true; - else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) && a->refreshRate > b->refreshRate) + else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) && + std::round(a->refreshRate) > std::round(b->refreshRate)) return true; return false; }); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7c19b57c..1b207f7d 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -33,7 +33,7 @@ struct SMonitorRule { Vector2D resolution = Vector2D(1280, 720); Vector2D offset = Vector2D(0, 0); float scale = 1; - float refreshRate = 60; + float refreshRate = 60; // Hz bool disabled = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; std::string mirrorOf = ""; @@ -92,7 +92,7 @@ class CMonitor { CDamageRing damage; SP output; - float refreshRate = 60; + float refreshRate = 60; // Hz int forceFullFrames = 0; bool scheduledRecalc = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; From 6fc9c8e4797a272c688fc74b872db5d828c21f02 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 29 Jan 2025 22:45:38 +0200 Subject: [PATCH 1152/2393] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index ac73e5f7..dfdd8c5b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1737636397, - "narHash": "sha256-F5MbBj3QVorycVSFE9qjuOTLtIQBqt2VWbXa0uwzm98=", + "lastModified": 1738183445, + "narHash": "sha256-C1He3N1SA8D2u+TSlldbA9wiYwDvXI4GxX3zKaeD7qU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7fe006981fae53e931f513026fc754e322f13145", + "rev": "48a000cf35dd10bfeb231152735aebbe875f4b74", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1737634937, - "narHash": "sha256-Ffw4ujFpi++6pPHe+gCBOfDgAoNlzVPZN6MReC1beu8=", + "lastModified": 1738178255, + "narHash": "sha256-+D6Nu2ewXbMTFzx/Q4jDOo+LAOUPr0cxQJg5k33daIE=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "9c5dd1f7c825ee47f72727ad0a4e16ca46a2688e", + "rev": "dcadd3398abe146d60c67e0d9ee6e27b301cae82", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1737985436, - "narHash": "sha256-zx8FdI4zr2GhNyD1YGAqa2ymodAObTSAdwuWwVucewo=", + "lastModified": 1738018829, + "narHash": "sha256-5Ol5iahMlELx3lWuChyZsqqLk6sP6aqaJCJFw92OZGo=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "23783b96036f5506fdaf8b2250a1ef849d57f0d3", + "rev": "12cd7034e441a5ebfdef1a090c0788413b4a635b", "type": "github" }, "original": { From 09ec1cca51e1880dfc855c168a0dd810ff1ddcd6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 23:05:54 +0000 Subject: [PATCH 1153/2393] popup: stop refocusing at unmap fixes #9018 --- src/desktop/Popup.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 93a810ff..dea94f55 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -138,10 +138,11 @@ void CPopup::onUnmap() { }, nullptr); - const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource(); + // TODO: probably refocus, but without a motion event? + // const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource(); - if (WASLASTFOCUS) - g_pInputManager->simulateMouseMovement(); + // if (WASLASTFOCUS) + // g_pInputManager->simulateMouseMovement(); } void CPopup::onCommit(bool ignoreSiblings) { From d462cc7fa166e1e6a6f14b58a2dd1e8b92e15426 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 23:16:25 +0000 Subject: [PATCH 1154/2393] subsurface: fix invalid parent typo fixes #9224 --- src/desktop/Subsurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index a68cf8f3..d7a53954 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -143,7 +143,7 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { ASSERT(PSUBSURFACE); - PSUBSURFACE->m_pParent = PSUBSURFACE; + PSUBSURFACE->m_pParent = m_pSelf; } void CSubsurface::onMap() { From 7d1c78f4a3720b693fedeb5d4f2d3f4da37f7fd3 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:07:06 +0500 Subject: [PATCH 1155/2393] core,hyprctl: clang, clang-tidy, typo fixes and dtors changes (#9233) * declare dtor once + DMABBUF typo fix * dup include + clang moment * linux-dmabuf: last minute nit change --- hyprctl/main.cpp | 3 --- src/Compositor.cpp | 1 - src/config/ConfigDataValues.hpp | 2 +- src/config/ConfigManager.cpp | 4 ---- src/desktop/Subsurface.cpp | 4 ---- src/desktop/Subsurface.hpp | 4 ++-- src/helpers/Monitor.cpp | 4 ---- src/helpers/Monitor.hpp | 3 +-- src/hyprerror/HyprError.cpp | 2 -- src/hyprerror/HyprError.hpp | 2 +- src/layout/IHyprLayout.cpp | 2 -- src/layout/IHyprLayout.hpp | 2 +- src/layout/MasterLayout.hpp | 1 - src/managers/EventManager.hpp | 1 - src/managers/XCursorManager.hpp | 8 +++---- src/protocols/FocusGrab.cpp | 4 ---- src/protocols/FocusGrab.hpp | 2 +- src/protocols/LinuxDMABUF.cpp | 22 ++++++------------- src/protocols/LinuxDMABUF.hpp | 16 +++++++------- src/protocols/SinglePixel.cpp | 8 ------- src/protocols/SinglePixel.hpp | 6 ++--- src/protocols/core/Shm.cpp | 4 ---- src/protocols/core/Shm.hpp | 2 +- .../decorations/CHyprBorderDecoration.cpp | 4 ---- .../decorations/CHyprBorderDecoration.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 -- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 4 ---- .../decorations/CHyprGroupBarDecoration.hpp | 4 ++-- .../decorations/IHyprWindowDecoration.cpp | 2 -- .../decorations/IHyprWindowDecoration.hpp | 2 +- 31 files changed, 35 insertions(+), 94 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 16d66223..4cc73bdf 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -21,13 +21,10 @@ #include #include #include -#include #include #include #include -#include #include -#include using namespace Hyprutils::String; #include "Strings.hpp" diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3421c314..1daccbfd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 80e45a05..901fb317 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t { class ICustomConfigValueData { public: - virtual ~ICustomConfigValueData() = 0; + virtual ~ICustomConfigValueData() = default; virtual eConfigValueDataTypes getDataType() = 0; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 047c58d9..86581b10 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1709,10 +1709,6 @@ void CConfigManager::handlePluginLoads() { } } -ICustomConfigValueData::~ICustomConfigValueData() { - ; // empty -} - const std::unordered_map>& CConfigManager::getAnimationConfig() { return m_AnimationTree.getFullConfig(); } diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index d7a53954..1d938f39 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -31,10 +31,6 @@ CSubsurface::CSubsurface(SP pSubsurface, WP pOwne initExistingSubsurfaces(pSubsurface->surface.lock()); } -CSubsurface::~CSubsurface() { - ; -} - void CSubsurface::initSignals() { if (m_pSubsurface) { listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index f16a11ea..41958671 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -17,7 +17,7 @@ class CSubsurface { CSubsurface(SP pSubsurface, PHLWINDOW pOwner); CSubsurface(SP pSubsurface, WP pOwner); - ~CSubsurface(); + ~CSubsurface() = default; Vector2D coordsRelativeToParent(); Vector2D coordsGlobal(); @@ -62,4 +62,4 @@ class CSubsurface { void initSignals(); void initExistingSubsurfaces(SP pSurface); void checkSiblingDamage(); -}; \ No newline at end of file +}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9ea85bca..42acf485 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1434,10 +1434,6 @@ CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) { ; } -CMonitorState::~CMonitorState() { - ; -} - void CMonitorState::ensureBufferPresent() { const auto STATE = m_pOwner->output->state->state(); if (!STATE.enabled) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 1b207f7d..2b02c30a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -6,7 +6,6 @@ #include "../SharedDefs.hpp" #include "MiscFunctions.hpp" #include "WLClasses.hpp" -#include #include #include @@ -48,7 +47,7 @@ class CSyncTimeline; class CMonitorState { public: CMonitorState(CMonitor* owner); - ~CMonitorState(); + ~CMonitorState() = default; bool commit(); bool test(); diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 4076ed3a..9f889fdf 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -32,8 +32,6 @@ CHyprError::CHyprError() { m_pTexture = makeShared(); } -CHyprError::~CHyprError() = default; - void CHyprError::queueCreate(std::string message, const CHyprColor& color) { m_szQueued = message; m_cQueued = color; diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 771e50f0..12de0c81 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -9,7 +9,7 @@ class CHyprError { public: CHyprError(); - ~CHyprError(); + ~CHyprError() = default; void queueCreate(std::string message, const CHyprColor& color); void draw(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 57ae5f40..9a0ba6ee 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -950,5 +950,3 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) { return sizePredicted; } - -IHyprLayout::~IHyprLayout() = default; diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index ab188b9b..e31bb63e 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -43,7 +43,7 @@ enum eDirection : int8_t { class IHyprLayout { public: - virtual ~IHyprLayout() = 0; + virtual ~IHyprLayout() = default; virtual void onEnable() = 0; virtual void onDisable() = 0; diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 381ccc9d..f658fdaa 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -5,7 +5,6 @@ #include "../helpers/varlist/VarList.hpp" #include #include -#include #include enum eFullscreenMode : int8_t; diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 5a88963e..6b506d33 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 2517e85e..3052206f 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -13,10 +13,10 @@ extern "C" { // gangsta bootleg XCursor impl. adidas balkanized struct SXCursorImage { - Vector2D size; - Vector2D hotspot; - std::vector pixels; // XPixel is a u32 - uint32_t delay; // animation delay to next frame (ms) + Hyprutils::Math::Vector2D size; + Hyprutils::Math::Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + uint32_t delay; // animation delay to next frame (ms) }; struct SXCursors { diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index ab9d22ef..bef69f62 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -11,10 +11,6 @@ CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SPevents.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } -CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { - ; -} - CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) { if UNLIKELY (!resource->resource()) return; diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 3c907ed0..1445a24c 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -15,7 +15,7 @@ class CWLSurfaceResource; class CFocusGrabSurfaceState { public: CFocusGrabSurfaceState(CFocusGrab* grab, SP surface); - ~CFocusGrabSurfaceState(); + ~CFocusGrabSurfaceState() = default; enum State { PendingAddition, diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 82d31c84..d3135da0 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -125,7 +125,7 @@ bool CLinuxDMABuffer::good() { return buffer && buffer->good(); } -CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP resource_) : resource(resource_) { +CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -197,15 +197,11 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SPresource(); } -void CLinuxDMABBUFParamsResource::create(uint32_t id) { +void CLinuxDMABUFParamsResource::create(uint32_t id) { used = true; if UNLIKELY (!verify()) { @@ -237,7 +233,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { createdBuffer = buf; } -bool CLinuxDMABBUFParamsResource::commence() { +bool CLinuxDMABUFParamsResource::commence() { if (PROTO::linuxDma->mainDeviceFD < 0) return true; @@ -258,7 +254,7 @@ bool CLinuxDMABBUFParamsResource::commence() { return true; } -bool CLinuxDMABBUFParamsResource::verify() { +bool CLinuxDMABUFParamsResource::verify() { if UNLIKELY (attrs->planes <= 0) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added"); return false; @@ -311,10 +307,6 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPresource(); } @@ -384,7 +376,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : re }); resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) { - const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); @@ -550,7 +542,7 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFFeedbackResource* resou std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == resource; }); } -void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resource) { +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFParamsResource* resource) { std::erase_if(m_vParams, [&](const auto& other) { return other.get() == resource; }); } diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 8c574dbc..91cf3283 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -27,7 +27,7 @@ class CLinuxDMABuffer { CHyprSignalListener bufferResourceDestroy; } listeners; - friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABUFParamsResource; }; #pragma pack(push, 1) @@ -56,10 +56,10 @@ class CDMABUFFormatTable { std::vector> monitorTranches; }; -class CLinuxDMABBUFParamsResource { +class CLinuxDMABUFParamsResource { public: - CLinuxDMABBUFParamsResource(SP resource_); - ~CLinuxDMABBUFParamsResource(); + CLinuxDMABUFParamsResource(SP resource_); + ~CLinuxDMABUFParamsResource() = default; bool good(); void create(uint32_t id); // 0 means not immed @@ -78,7 +78,7 @@ class CLinuxDMABBUFParamsResource { class CLinuxDMABUFFeedbackResource { public: CLinuxDMABUFFeedbackResource(SP resource_, SP surface_); - ~CLinuxDMABUFFeedbackResource(); + ~CLinuxDMABUFFeedbackResource() = default; bool good(); void sendDefaultFeedback(); @@ -115,7 +115,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { private: void destroyResource(CLinuxDMABUFResource* resource); void destroyResource(CLinuxDMABUFFeedbackResource* resource); - void destroyResource(CLinuxDMABBUFParamsResource* resource); + void destroyResource(CLinuxDMABUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); void resetFormatTable(); @@ -123,7 +123,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { // std::vector> m_vManagers; std::vector> m_vFeedbacks; - std::vector> m_vParams; + std::vector> m_vParams; std::vector> m_vBuffers; UP formatTable; @@ -132,7 +132,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; - friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABUFParamsResource; friend class CLinuxDMABuffer; }; diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 2fbfc93d..4d643a53 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -24,10 +24,6 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColo Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); } -CSinglePixelBuffer::~CSinglePixelBuffer() { - ; -} - Aquamarine::eBufferCapability CSinglePixelBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } @@ -74,10 +70,6 @@ CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* c }); } -CSinglePixelBufferResource::~CSinglePixelBufferResource() { - ; -} - bool CSinglePixelBufferResource::good() { return buffer->good(); } diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp index 2a86d050..bd0607d6 100644 --- a/src/protocols/SinglePixel.hpp +++ b/src/protocols/SinglePixel.hpp @@ -9,7 +9,7 @@ class CSinglePixelBuffer : public IHLBuffer { public: CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col); - virtual ~CSinglePixelBuffer(); + virtual ~CSinglePixelBuffer() = default; virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); @@ -33,7 +33,7 @@ class CSinglePixelBuffer : public IHLBuffer { class CSinglePixelBufferResource { public: CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color); - ~CSinglePixelBufferResource(); + ~CSinglePixelBufferResource() = default; bool good(); @@ -75,4 +75,4 @@ class CSinglePixelProtocol : public IWaylandProtocol { namespace PROTO { inline UP singlePixel; -}; \ No newline at end of file +}; diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 28585aeb..1649f82f 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -36,10 +36,6 @@ CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t of Debug::log(ERR, "Failed creating a shm texture: null texture id"); } -CWLSHMBuffer::~CWLSHMBuffer() { - ; -} - Aquamarine::eBufferCapability CWLSHMBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 23a465fb..d7e81367 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -31,7 +31,7 @@ class CSHMPool { class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); - virtual ~CWLSHMBuffer(); + virtual ~CWLSHMBuffer() = default; virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 6fb0ff88..5f2fdbda 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -10,10 +10,6 @@ CHyprBorderDecoration::CHyprBorderDecoration(PHLWINDOW pWindow) : IHyprWindowDec ; } -CHyprBorderDecoration::~CHyprBorderDecoration() { - ; -} - SDecorationPositioningInfo CHyprBorderDecoration::getPositioningInfo() { const auto BORDERSIZE = m_pWindow->getRealBorderSize(); m_seExtents = {{BORDERSIZE, BORDERSIZE}, {BORDERSIZE, BORDERSIZE}}; diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index bc9d7836..332c08b7 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -5,7 +5,7 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { public: CHyprBorderDecoration(PHLWINDOW); - virtual ~CHyprBorderDecoration(); + virtual ~CHyprBorderDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 0b2a96d9..60b1b33a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -9,8 +9,6 @@ CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprW ; } -CHyprDropShadowDecoration::~CHyprDropShadowDecoration() = default; - eDecorationType CHyprDropShadowDecoration::getDecorationType() { return DECORATION_SHADOW; } diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 3b1c67c5..b5ee7276 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -5,7 +5,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { public: CHyprDropShadowDecoration(PHLWINDOW); - virtual ~CHyprDropShadowDecoration(); + virtual ~CHyprDropShadowDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4e7c3cbc..88501d74 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -29,8 +29,6 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindo refreshGroupBarGradients(); } -CHyprGroupBarDecoration::~CHyprGroupBarDecoration() = default; - SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { static auto PHEIGHT = CConfigValue("group:groupbar:height"); static auto PENABLED = CConfigValue("group:groupbar:enabled"); @@ -231,8 +229,6 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float texSize = tex->m_vSize; } -CTitleTex::~CTitleTex() = default; - void renderGradientTo(SP tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 7277955d..0cdf8a6b 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -10,7 +10,7 @@ class CTitleTex { public: CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); - ~CTitleTex(); + ~CTitleTex() = default; SP tex; std::string szContent; @@ -24,7 +24,7 @@ void refreshGroupBarGradients(); class CHyprGroupBarDecoration : public IHyprWindowDecoration { public: CHyprGroupBarDecoration(PHLWINDOW); - virtual ~CHyprGroupBarDecoration(); + virtual ~CHyprGroupBarDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/IHyprWindowDecoration.cpp b/src/render/decorations/IHyprWindowDecoration.cpp index cb9e166b..c71ee186 100644 --- a/src/render/decorations/IHyprWindowDecoration.cpp +++ b/src/render/decorations/IHyprWindowDecoration.cpp @@ -6,8 +6,6 @@ IHyprWindowDecoration::IHyprWindowDecoration(PHLWINDOW pWindow) : m_pWindow(pWin ; } -IHyprWindowDecoration::~IHyprWindowDecoration() = default; - bool IHyprWindowDecoration::onInputOnDeco(const eInputType, const Vector2D&, std::any) { return false; } diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 10145f40..2703eb61 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -33,7 +33,7 @@ class CDecorationPositioner; class IHyprWindowDecoration { public: IHyprWindowDecoration(PHLWINDOW); - virtual ~IHyprWindowDecoration() = 0; + virtual ~IHyprWindowDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo() = 0; From 32c0fa2f2fe02254d5887b38cf2cffa72ddfd769 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 30 Jan 2025 12:30:12 +0100 Subject: [PATCH 1156/2393] core: begin using CFileDescriptor from hyprutils (#9122) * config: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * hyprctl: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * ikeyboard: make fd use CFileDescriptor make use of the new CFileDescriptor instead of manual FD handling, also in sendKeymap remove dead code, it already early returns if keyboard isnt valid, and dont try to close the FD that ikeyboard owns. * core: make SHMFile functions use CFileDescriptor make SHMFile misc functions use CFileDescriptor and its associated usage in dmabuf and keyboard. * core: make explicit sync use CFileDescriptor begin using CFileDescriptor in explicit sync and its timelines and eglsync usage in opengl, there is still a bit left with manual handling that requires future aquamarine change aswell. * eventmgr: make fd and sockets use CFileDescriptor make use of the hyprutils CFileDescriptor instead of manual FD and socket handling and closing. * eventloopmgr: make timerfd use CFileDescriptor make the timerfd use CFileDescriptor instead of manual fd handling * opengl: make gbm fd use CFileDescriptor make the gbm rendernode fd use CFileDescriptor instead of manual fd handling * core: make selection source/offer use CFileDescriptor make data selection source and offers use CFileDescriptor and its associated use in xwm and protocols * protocols: convert protocols fd to CFileDescriptor make most fd handling use CFileDescriptor in protocols * shm: make SHMPool use CfileDescriptor make SHMPool use CFileDescriptor instead of manual fd handling. * opengl: duplicate fd with CFileDescriptor duplicate fenceFD with CFileDescriptor duplicate instead. * xwayland: make sockets and fds use CFileDescriptor instead of manual opening/closing make sockets and fds use CFileDescriptor * keybindmgr: make sockets and fds use CFileDescriptor make sockets and fds use CFileDescriptor instead of manual handling. --- src/config/ConfigWatcher.cpp | 25 ++- src/config/ConfigWatcher.hpp | 15 +- src/debug/HyprCtl.cpp | 18 +- src/debug/HyprCtl.hpp | 11 +- src/devices/IKeyboard.cpp | 26 ++- src/devices/IKeyboard.hpp | 3 +- src/helpers/MiscFunctions.cpp | 44 +++-- src/helpers/MiscFunctions.hpp | 5 +- src/helpers/Monitor.cpp | 17 +- src/helpers/Monitor.hpp | 1 + src/helpers/sync/SyncTimeline.cpp | 26 ++- src/helpers/sync/SyncTimeline.hpp | 28 ++-- src/managers/EventManager.cpp | 44 +++-- src/managers/EventManager.hpp | 14 +- src/managers/KeybindManager.cpp | 29 ++-- src/managers/eventLoop/EventLoopManager.cpp | 13 +- src/managers/eventLoop/EventLoopManager.hpp | 3 +- src/protocols/DRMLease.cpp | 17 +- src/protocols/DRMLease.hpp | 1 + src/protocols/DRMSyncobj.cpp | 12 +- src/protocols/DRMSyncobj.hpp | 7 +- src/protocols/DataDeviceWlr.cpp | 12 +- src/protocols/DataDeviceWlr.hpp | 3 +- src/protocols/GammaControl.cpp | 15 +- src/protocols/InputMethodV2.cpp | 11 +- src/protocols/LinuxDMABUF.cpp | 37 ++--- src/protocols/LinuxDMABUF.hpp | 9 +- src/protocols/PrimarySelection.cpp | 12 +- src/protocols/PrimarySelection.hpp | 3 +- src/protocols/SecurityContext.cpp | 21 ++- src/protocols/SecurityContext.hpp | 19 ++- src/protocols/VirtualKeyboard.cpp | 10 +- src/protocols/VirtualKeyboard.hpp | 1 + src/protocols/core/DataDevice.cpp | 12 +- src/protocols/core/DataDevice.hpp | 3 +- src/protocols/core/Seat.cpp | 29 +--- src/protocols/core/Shm.cpp | 23 +-- src/protocols/core/Shm.hpp | 14 +- src/protocols/types/DataDevice.hpp | 9 +- src/render/OpenGL.cpp | 41 ++--- src/render/OpenGL.hpp | 13 +- src/render/Renderer.cpp | 20 +-- src/xwayland/Dnd.cpp | 4 +- src/xwayland/Dnd.hpp | 3 +- src/xwayland/Server.cpp | 173 +++++++------------- src/xwayland/Server.hpp | 27 +-- src/xwayland/XDataSource.cpp | 13 +- src/xwayland/XDataSource.hpp | 5 +- src/xwayland/XWM.cpp | 20 +-- src/xwayland/XWM.hpp | 27 +-- 50 files changed, 422 insertions(+), 526 deletions(-) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index c0a9c591..8d086bac 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -5,27 +5,24 @@ #include #include +using namespace Hyprutils::OS; + CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { - if (m_inotifyFd < 0) { + if (!m_inotifyFd.isValid()) { Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); return; } - const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); - if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor take F_GETFL, F_SETFL + const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); + if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) { Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); - close(m_inotifyFd); - m_inotifyFd = -1; + m_inotifyFd.reset(); return; } } -CConfigWatcher::~CConfigWatcher() { - if (m_inotifyFd >= 0) - close(m_inotifyFd); -} - -int CConfigWatcher::getInotifyFD() { +CFileDescriptor& CConfigWatcher::getInotifyFD() { return m_inotifyFd; } @@ -38,7 +35,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // cleanup old paths for (auto& watch : m_watches) { - inotify_rm_watch(m_inotifyFd, watch.wd); + inotify_rm_watch(m_inotifyFd.get(), watch.wd); } m_watches.clear(); @@ -46,7 +43,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), .file = path, }); } @@ -58,7 +55,7 @@ void CConfigWatcher::setOnChange(const std::function 0) { + while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); if (WD == m_watches.end()) { diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp index c36ecd17..97945689 100644 --- a/src/config/ConfigWatcher.hpp +++ b/src/config/ConfigWatcher.hpp @@ -3,20 +3,21 @@ #include #include #include +#include class CConfigWatcher { public: CConfigWatcher(); - ~CConfigWatcher(); + ~CConfigWatcher() = default; struct SConfigWatchEvent { std::string file; }; - int getInotifyFD(); - void setWatchList(const std::vector& paths); - void setOnChange(const std::function& fn); - void onInotifyEvent(); + Hyprutils::OS::CFileDescriptor& getInotifyFD(); + void setWatchList(const std::vector& paths); + void setOnChange(const std::function& fn); + void onInotifyEvent(); private: struct SInotifyWatch { @@ -26,7 +27,7 @@ class CConfigWatcher { std::function m_watchCallback; std::vector m_watches; - int m_inotifyFd = -1; + Hyprutils::OS::CFileDescriptor m_inotifyFd; }; -inline UP g_pConfigWatcher = makeUnique(); \ No newline at end of file +inline UP g_pConfigWatcher = makeUnique(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 359428b1..cd6451e2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -25,6 +25,7 @@ #include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include "../config/ConfigDataValues.hpp" @@ -1680,8 +1681,6 @@ CHyprCtl::CHyprCtl() { CHyprCtl::~CHyprCtl() { if (m_eventSource) wl_event_source_remove(m_eventSource); - if (m_iSocketFD >= 0) - close(m_iSocketFD); if (!m_socketPath.empty()) unlink(m_socketPath.c_str()); } @@ -1840,10 +1839,13 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; + if (!g_pHyprCtl->m_iSocketFD.isValid()) + return 0; + sockaddr_in clientAddress; socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); + const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); std::array readBuffer; @@ -1900,9 +1902,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { } void CHyprCtl::startHyprCtlSocket() { - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } @@ -1913,15 +1915,15 @@ void CHyprCtl::startHyprCtlSocket() { strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); return; } // 10 max queued. - listen(m_iSocketFD, 10); + listen(m_iSocketFD.get(), 10); Debug::log(LOG, "Hypr socket started at {}", m_socketPath); - m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); + m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index eed8265c..a95a5f93 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -4,6 +4,7 @@ #include "../helpers/MiscFunctions.hpp" #include "../desktop/Window.hpp" #include +#include // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); @@ -14,12 +15,12 @@ class CHyprCtl { CHyprCtl(); ~CHyprCtl(); - std::string makeDynamicCall(const std::string& input); - SP registerCommand(SHyprCtlCommand cmd); - void unregisterCommand(const SP& cmd); - std::string getReply(std::string); + std::string makeDynamicCall(const std::string& input); + SP registerCommand(SHyprCtlCommand cmd); + void unregisterCommand(const SP& cmd); + std::string getReply(std::string); - int m_iSocketFD = -1; + Hyprutils::OS::CFileDescriptor m_iSocketFD; struct { bool all = false; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 4623fe84..307d840b 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Hyprutils::OS; + #define LED_COUNT 3 constexpr static std::array MODNAMES = { @@ -41,9 +43,6 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymap) xkb_keymap_unref(xkbKeymap); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - if (xkbSymState) xkb_state_unref(xkbSymState); @@ -51,7 +50,7 @@ void IKeyboard::clearManuallyAllocd() { xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; - xkbKeymapFD = -1; + xkbKeymapFD.reset(); } void IKeyboard::setKeymap(const SStringRuleNames& rules) { @@ -147,31 +146,30 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::updateKeymapFD() { Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - xkbKeymapFD = -1; + if (xkbKeymapFD.isValid()) + xkbKeymapFD.reset(); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); xkbKeymapString = cKeymapStr; free(cKeymapStr); - int rw, ro; - if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + CFileDescriptor rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); else { - auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); - close(rw); + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); + rw.reset(); if (keymapFDDest == MAP_FAILED) { Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); - close(ro); + ro.reset(); } else { memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); munmap(keymapFDDest, xkbKeymapString.length() + 1); - xkbKeymapFD = ro; + xkbKeymapFD = std::move(ro); } } - Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD); + Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index dce2127a..aabf4cc2 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -6,6 +6,7 @@ #include #include +#include AQUAMARINE_FORWARD(IKeyboard); @@ -96,7 +97,7 @@ class IKeyboard : public IHID { std::string xkbFilePath = ""; std::string xkbKeymapString = ""; - int xkbKeymapFD = -1; + Hyprutils::OS::CFileDescriptor xkbKeymapFD; SStringRuleNames currentRules; int repeatRate = 0; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5ebb0842..f532617c 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -836,50 +836,48 @@ bool envEnabled(const std::string& env) { return std::string(ENV) == "1"; } -std::pair openExclusiveShm() { +std::pair openExclusiveShm() { // Only absolute paths can be shared across different shm_open() calls std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { - int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) - return {fd, name}; + CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)}; + if (fd.isValid()) + return {std::move(fd), name}; } - return {-1, ""}; + return {{}, ""}; } -int allocateSHMFile(size_t len) { +CFileDescriptor allocateSHMFile(size_t len) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) - return -1; + if (!fd.isValid()) + return {}; shm_unlink(name.c_str()); int ret; do { - ret = ftruncate(fd, len); + ret = ftruncate(fd.get(), len); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - return -1; + return {}; } - return fd; + return std::move(fd); } -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { +bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) { + if (!fd.isValid()) { return false; } // CLOEXEC is guaranteed to be set by shm_open - int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); - if (ro_fd < 0) { + CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)}; + if (!ro_fd.isValid()) { shm_unlink(name.c_str()); - close(fd); return false; } @@ -887,24 +885,20 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { // Make sure the file cannot be re-opened in read-write mode (e.g. via // "/proc/self/fd/" on Linux) - if (fchmod(fd, 0) != 0) { - close(fd); - close(ro_fd); + if (fchmod(fd.get(), 0) != 0) { return false; } int ret; do { - ret = ftruncate(fd, size); + ret = ftruncate(fd.get(), size); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - close(ro_fd); return false; } - *rw_fd_ptr = fd; - *ro_fd_ptr = ro_fd; + rw_fd_ptr = std::move(fd); + ro_fd_ptr = std::move(ro_fd); return true; } diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index d0824284..bd288638 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../SharedDefs.hpp" #include "../macros.hpp" @@ -35,8 +36,8 @@ double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); -int allocateSHMFile(size_t len); -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr); float stringToPercentage(const std::string& VALUE, const float REL); template diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 42acf485..fc3de3aa 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -32,6 +32,7 @@ #include using namespace Hyprutils::String; using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -1301,19 +1302,15 @@ bool CMonitor::attemptDirectScanout() { // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; - int explicitWaitFD = -1; + CFileDescriptor explicitWaitFD; if (DOEXPLICIT) { explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); - if (explicitWaitFD < 0) + if (!explicitWaitFD.isValid()) Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); } - DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + DOEXPLICIT = DOEXPLICIT && explicitWaitFD.isValid(); - auto cleanup = CScopeGuard([explicitWaitFD, this]() { - output->state->resetExplicitFences(); - if (explicitWaitFD >= 0) - close(explicitWaitFD); - }); + auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1323,8 +1320,8 @@ bool CMonitor::attemptDirectScanout() { output->state->resetExplicitFences(); if (DOEXPLICIT) { - Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); - output->state->setExplicitInFence(explicitWaitFD); + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD.get()); + output->state->setExplicitInFence(explicitWaitFD.get()); } bool ok = output->commit(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2b02c30a..c67bccc5 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -16,6 +16,7 @@ #include "DamageRing.hpp" #include #include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs : uint8_t { diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 16b5bd92..46b617bc 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -4,6 +4,7 @@ #include #include +using namespace Hyprutils::OS; SP CSyncTimeline::create(int drmFD_) { auto timeline = SP(new CSyncTimeline); @@ -85,10 +86,9 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin auto w = makeShared(); w->fn = waiter; w->timeline = self; + w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)}; - int eventFD = eventfd(0, EFD_CLOEXEC); - - if (eventFD < 0) { + if (!w->eventFd.isValid()) { Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); return false; } @@ -97,19 +97,17 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin .handle = handle, .flags = flags, .point = point, - .fd = eventFD, + .fd = w->eventFd.get(), }; if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); - close(eventFD); return false; } - w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get()); if (!w->source) { Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); - close(eventFD); return false; } @@ -126,32 +124,32 @@ void CSyncTimeline::removeWaiter(SWaiter* w) { std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); } -int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { +CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) { int sync = -1; uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); - return -1; + return {}; } if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } drmSyncobjDestroy(drmFD, syncHandle); - return sync; + return CFileDescriptor{sync}; } -bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) { uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { @@ -159,7 +157,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { return false; } - if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); return false; diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 88ad4921..ba65e004 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../memory/Memory.hpp" /* @@ -20,26 +21,27 @@ class CSyncTimeline { ~CSyncTimeline(); struct SWaiter { - std::function fn; - wl_event_source* source = nullptr; - WP timeline; + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + Hyprutils::OS::CFileDescriptor eventFd; }; // check if the timeline point has been signaled // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE // std::nullopt on fail - std::optional check(uint64_t point, uint32_t flags); + std::optional check(uint64_t point, uint32_t flags); - bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); - void removeWaiter(SWaiter*); - int exportAsSyncFileFD(uint64_t src); - bool importFromSyncFileFD(uint64_t dst, int fd); - bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); - void signal(uint64_t point); + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); - int drmFD = -1; - uint32_t handle = 0; - WP self; + int drmFD = -1; + uint32_t handle = 0; + WP self; private: CSyncTimeline() = default; diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index fc55b472..6231f0bc 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -9,9 +9,10 @@ #include #include #include +using namespace Hyprutils::OS; CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) { - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); return; } @@ -25,31 +26,27 @@ CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_ strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); return; } // 10 max queued. - if (listen(m_iSocketFD, 10) < 0) { + if (listen(m_iSocketFD.get(), 10) < 0) { Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); return; } - m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr); + m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, onClientEvent, nullptr); } CEventManager::~CEventManager() { for (const auto& client : m_vClients) { wl_event_source_remove(client.eventSource); - close(client.fd); } if (m_pEventSource != nullptr) wl_event_source_remove(m_pEventSource); - - if (m_iSocketFD >= 0) - close(m_iSocketFD); } int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { @@ -66,33 +63,31 @@ int CEventManager::onServerEvent(int fd, uint32_t mask) { wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); return 0; } - sockaddr_in clientAddress; - socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK); - if (ACCEPTEDCONNECTION < 0) { + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + CFileDescriptor ACCEPTEDCONNECTION{accept4(m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK)}; + if (!ACCEPTEDCONNECTION.isValid()) { if (errno != EAGAIN) { Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); } return 0; } - Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); + Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION.get()); // add to event loop so we can close it when we need to - auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr); + auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION.get(), 0, onServerEvent, nullptr); m_vClients.emplace_back(SClient{ - ACCEPTEDCONNECTION, + std::move(ACCEPTEDCONNECTION), {}, eventSource, }); @@ -113,7 +108,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { // send all queued events while (!CLIENTIT->events.empty()) { const auto& event = CLIENTIT->events.front(); - if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0) + if (write(CLIENTIT->fd.get(), event->c_str(), event->length()) < 0) break; CLIENTIT->events.erase(CLIENTIT->events.begin()); @@ -128,13 +123,12 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { } std::vector::iterator CEventManager::findClientByFD(int fd) { - return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; }); + return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); } std::vector::iterator CEventManager::removeClientByFD(int fd) { const auto CLIENTIT = findClientByFD(fd); wl_event_source_remove(CLIENTIT->eventSource); - close(fd); return m_vClients.erase(CLIENTIT); } @@ -157,11 +151,11 @@ void CEventManager::postEvent(const SHyprIPCEvent& event) { for (auto it = m_vClients.begin(); it != m_vClients.end();) { // try to send the event immediately if the queue is empty const auto QUEUESIZE = it->events.size(); - if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) { + if (QUEUESIZE > 0 || write(it->fd.get(), sharedEvent->c_str(), sharedEvent->length()) < 0) { if (QUEUESIZE >= MAX_QUEUED_EVENTS) { // too many events queued, remove the client - Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd); - it = removeClientByFD(it->fd); + Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd.get()); + it = removeClientByFD(it->fd.get()); continue; } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 6b506d33..c8335d20 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,6 @@ #pragma once #include - +#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" @@ -26,19 +26,19 @@ class CEventManager { int onClientEvent(int fd, uint32_t mask); struct SClient { - int fd = -1; - std::vector> events; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor fd; + std::vector> events; + wl_event_source* eventSource = nullptr; }; std::vector::iterator findClientByFD(int fd); std::vector::iterator removeClientByFD(int fd); private: - int m_iSocketFD = -1; - wl_event_source* m_pEventSource = nullptr; + Hyprutils::OS::CFileDescriptor m_iSocketFD; + wl_event_source* m_pEventSource = nullptr; - std::vector m_vClients; + std::vector m_vClients; }; inline UP g_pEventManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2cb77d21..247550ae 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -28,7 +28,9 @@ #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include @@ -853,19 +855,18 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. - unsigned int ttynum = 0; - int fd; - if ((fd = open("/dev/tty", O_RDONLY | O_NOCTTY)) >= 0) { + unsigned int ttynum = 0; + Hyprutils::OS::CFileDescriptor fd{open("/dev/tty", O_RDONLY | O_NOCTTY)}; + if (fd.isValid()) { #if defined(VT_GETSTATE) struct vt_stat st; - if (!ioctl(fd, VT_GETSTATE, &st)) + if (!ioctl(fd.get(), VT_GETSTATE, &st)) ttynum = st.v_active; #elif defined(VT_GETACTIVE) int vt; - if (!ioctl(fd, VT_GETACTIVE, &vt)) + if (!ioctl(fd.get(), VT_GETACTIVE, &vt)) ttynum = vt; #endif - close(fd); } if (ttynum == TTY) @@ -944,11 +945,11 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo Debug::log(LOG, "Unable to create pipe for fork"); } - pid_t child, grandchild; + CFileDescriptor pipeSock[2] = {CFileDescriptor{socket[0]}, CFileDescriptor{socket[1]}}; + + pid_t child, grandchild; child = fork(); if (child < 0) { - close(socket[0]); - close(socket[1]); Debug::log(LOG, "Fail to create the first fork"); return 0; } @@ -967,22 +968,16 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); - close(socket[0]); - close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); } - close(socket[0]); - write(socket[1], &grandchild, sizeof(grandchild)); - close(socket[1]); + write(pipeSock[1].get(), &grandchild, sizeof(grandchild)); // exit child _exit(0); } // run in parent - close(socket[1]); - read(socket[0], &grandchild, sizeof(grandchild)); - close(socket[0]); + read(pipeSock[0].get(), &grandchild, sizeof(grandchild)); // clear child and leave grandchild to init waitpid(child, nullptr, 0); if (grandchild < 0) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 4021c171..83bdf4a0 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -11,11 +11,12 @@ #include #include +using namespace Hyprutils::OS; #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { - m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + m_sTimers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)}; m_sWayland.loop = wlEventLoop; m_sWayland.display = display; } @@ -31,8 +32,6 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sIdle.eventSource); if (m_configWatcherInotifySource) wl_event_source_remove(m_configWatcherInotifySource); - if (m_sTimers.timerfd >= 0) - close(m_sTimers.timerfd); } static int timerWrite(int fd, uint32_t mask, void* data) { @@ -52,10 +51,10 @@ static int configWatcherWrite(int fd, uint32_t mask, void* data) { } void CEventLoopManager::enterLoop() { - m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd.get(), WL_EVENT_READABLE, timerWrite, nullptr); - if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) - m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); + if (const auto& FD = g_pConfigWatcher->getInotifyFD(); FD.isValid()) + m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD.get(), WL_EVENT_READABLE, configWatcherWrite, nullptr); syncPollFDs(); m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); @@ -120,7 +119,7 @@ void CEventLoopManager::nudgeTimers() { itimerspec ts = {.it_value = now}; - timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr); + timerfd_settime(m_sTimers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr); } void CEventLoopManager::doLater(const std::function& fn) { diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 95cc6109..ebeb2160 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -6,6 +6,7 @@ #include #include #include "helpers/signal/Signal.hpp" +#include #include "EventLoopTimer.hpp" @@ -54,7 +55,7 @@ class CEventLoopManager { struct { std::vector> timers; - int timerfd = -1; + Hyprutils::OS::CFileDescriptor timerfd; } m_sTimers; SIdleData m_sIdle; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 6fdbaf4b..e70f0441 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,6 +4,7 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +using namespace Hyprutils::OS; CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if UNLIKELY (!good()) @@ -185,15 +186,14 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc RESOURCE->parent = self; }); - int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); - if (fd < 0) { + CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()}; + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd in lease"); return; } - LOGM(LOG, "Sending DRMFD {} to new lease device", fd); - resource->sendDrmFd(fd); - close(fd); + LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get()); + resource->sendDrmFd(fd.get()); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { if (m) @@ -231,16 +231,15 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { } CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { - auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); - auto fd = drm->getNonMasterFD(); + CFileDescriptor fd{drm->getNonMasterFD()}; - if (fd < 0) { + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } - close(fd); success = true; name = drm->gpuName; } diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index ec1e73f2..c7849149 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "drm-lease-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include /* TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index ce598385..23dafbca 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if UNLIKELY (!good()) @@ -103,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; @@ -112,7 +113,7 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SPsetOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); - timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd.get()); if (!timeline) { resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); @@ -120,11 +121,6 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) - close(fd); -} - SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -171,7 +167,7 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SPsetImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), CFileDescriptor{fd}); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 42ecdb3e..8677576f 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -4,6 +4,7 @@ #include "WaylandProtocol.hpp" #include "linux-drm-syncobj-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CWLSurfaceResource; class CDRMSyncobjTimelineResource; @@ -32,14 +33,14 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, int fd_); - ~CDRMSyncobjTimelineResource(); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); bool good(); WP self; - int fd = -1; + Hyprutils::OS::CFileDescriptor fd; SP timeline; private: diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 71ee1c4a..3da5afd6 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -2,6 +2,7 @@ #include #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +using namespace Hyprutils::OS; CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -11,21 +12,20 @@ CWLRDataOffer::CWLRDataOffer(SP resource_, SPsetOnDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); resource->setReceive([this](CZwlrDataControlOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -77,15 +77,13 @@ std::vector CWLRDataSource::mimes() { return mimeTypes; } -void CWLRDataSource::send(const std::string& mime, uint32_t fd) { +void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLRDataSource::accepted(const std::string& mime) { diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 5eef163c..7f14b320 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "wlr-data-control-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CWLRDataControlManagerResource; class CWLRDataSource; @@ -38,7 +39,7 @@ class CWLRDataSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 43ba9d41..0a383e2e 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -4,6 +4,7 @@ #include "../helpers/Monitor.hpp" #include "../protocols/core/Output.hpp" #include "../render/Renderer.hpp" +using namespace Hyprutils::OS; CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if UNLIKELY (!resource_->resource()) @@ -46,34 +47,33 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + CFileDescriptor gammaFd{fd}; if UNLIKELY (!pMonitor) { LOGM(ERR, "setGamma for a dead monitor"); resource->sendFailed(); - close(fd); return; } LOGM(LOG, "setGamma for {}", pMonitor->szName); - int fdFlags = fcntl(fd, F_GETFL, 0); + // TODO: make CFileDescriptor getflags use F_GETFL + int fdFlags = fcntl(gammaFd.get(), F_GETFL, 0); if UNLIKELY (fdFlags < 0) { LOGM(ERR, "Failed to get fd flags"); resource->sendFailed(); - close(fd); return; } - if UNLIKELY (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor setflags use F_SETFL + if UNLIKELY (fcntl(gammaFd.get(), F_SETFL, fdFlags | O_NONBLOCK) < 0) { LOGM(ERR, "Failed to set fd flags"); resource->sendFailed(); - close(fd); return; } - ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); + ssize_t readBytes = pread(gammaFd.get(), gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { LOGM(ERR, "Failed to read bytes"); - close(fd); if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { gamma->error(ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch"); @@ -85,7 +85,6 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } gammaTableSet = true; - close(fd); // translate the table to AQ format std::vector red, green, blue; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 796cec06..33121ecd 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -33,25 +33,22 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); - if UNLIKELY (keymapFD < 0) { + auto keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); + if UNLIKELY (!keymapFD.isValid()) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD.get(), 0); if UNLIKELY (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); - close(keymapFD); return; } memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); - - close(keymapFD); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD.get(), keyboard->xkbKeymapString.length() + 1); sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index d3135da0..b7b91594 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,6 +14,8 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" +using namespace Hyprutils::OS; + static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -77,29 +79,21 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + CFileDescriptor fds[2]; + allocateSHMFilePair(tableSize, fds[0], fds[1]); - auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0].get(), 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); - close(fds[0]); - close(fds[1]); return; } - close(fds[0]); - std::copy(formatsVec.begin(), formatsVec.end(), arr); munmap(arr, tableSize); - tableFD = fds[1]; -} - -CDMABUFFormatTable::~CDMABUFFormatTable() { - close(tableFD); + tableFD = std::move(fds[1]); } CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { @@ -234,18 +228,18 @@ void CLinuxDMABUFParamsResource::create(uint32_t id) { } bool CLinuxDMABUFParamsResource::commence() { - if (PROTO::linuxDma->mainDeviceFD < 0) + if (!PROTO::linuxDma->mainDeviceFD.isValid()) return true; for (int i = 0; i < attrs->planes; i++) { uint32_t handle = 0; - if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD.get(), attrs->fds.at(i), &handle)) { LOGM(ERR, "Failed to import dmabuf fd"); return false; } - if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD.get(), handle)) { LOGM(ERR, "Failed to close dmabuf handle"); return false; } @@ -303,7 +297,7 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); auto& formatTable = PROTO::linuxDma->formatTable; - resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + resource->sendFormatTable(formatTable->tableFD.get(), formatTable->tableSize); sendDefaultFeedback(); } @@ -472,9 +466,9 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const if (device->available_nodes & (1 << DRM_NODE_RENDER)) { const char* name = device->nodes[DRM_NODE_RENDER]; - mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + mainDeviceFD = CFileDescriptor{open(name, O_RDWR | O_CLOEXEC)}; drmFreeDevice(&device); - if (mainDeviceFD < 0) { + if (!mainDeviceFD.isValid()) { LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; @@ -496,7 +490,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { auto newFormatTable = makeUnique(formatTable->rendererTranche, formatTable->monitorTranches); for (auto const& feedback : m_vFeedbacks) { - feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + feedback->resource->sendFormatTable(newFormatTable->tableFD.get(), newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { PHLMONITOR mon; auto HLSurface = CWLSurface::fromResource(feedback->surface); @@ -519,11 +513,6 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { formatTable = std::move(newFormatTable); } -CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { - if (mainDeviceFD >= 0) - close(mainDeviceFD); -} - void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 91cf3283..6c967878 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -9,6 +9,7 @@ #include "../helpers/Format.hpp" #include "../helpers/Monitor.hpp" #include +#include class CDMABuffer; class CWLSurfaceResource; @@ -48,9 +49,9 @@ struct SDMABUFTranche { class CDMABUFFormatTable { public: CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector> tranches); - ~CDMABUFFormatTable(); + ~CDMABUFFormatTable() = default; - int tableFD = -1; + Hyprutils::OS::CFileDescriptor tableFD; size_t tableSize = 0; SDMABUFTranche rendererTranche; std::vector> monitorTranches; @@ -107,7 +108,7 @@ class CLinuxDMABUFResource { class CLinuxDMABufV1Protocol : public IWaylandProtocol { public: CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); - ~CLinuxDMABufV1Protocol(); + ~CLinuxDMABufV1Protocol() = default; virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); void updateScanoutTranche(SP surface, PHLMONITOR pMonitor); @@ -128,7 +129,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { UP formatTable; dev_t mainDevice; - int mainDeviceFD = -1; + Hyprutils::OS::CFileDescriptor mainDeviceFD; friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 567bfdd2..620f262e 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" +using namespace Hyprutils::OS; CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -12,21 +13,20 @@ CPrimarySelectionOffer::CPrimarySelectionOffer(SP r resource->setOnDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); resource->setReceive([this](CZwpPrimarySelectionOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -78,15 +78,13 @@ std::vector CPrimarySelectionSource::mimes() { return mimeTypes; } -void CPrimarySelectionSource::send(const std::string& mime, uint32_t fd) { +void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CPrimarySelectionSource::accepted(const std::string& mime) { diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp index aeebe03c..0ecc962b 100644 --- a/src/protocols/PrimarySelection.hpp +++ b/src/protocols/PrimarySelection.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "primary-selection-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CPrimarySelectionOffer; class CPrimarySelectionSource; @@ -38,7 +39,7 @@ class CPrimarySelectionSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index e5b3cf2a..30fca260 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -1,6 +1,7 @@ #include "SecurityContext.hpp" #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; static int onListenFdEvent(int fd, uint32_t mask, void* data) { auto sc = (CSecurityContext*)data; @@ -14,8 +15,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD_) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); +SP CSecurityContextSandboxedClient::create(CFileDescriptor clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(std::move(clientFD_))); if (!p->client) return nullptr; return p; @@ -27,8 +28,8 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { - client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(CFileDescriptor clientFD_) : clientFD(std::move(clientFD_)) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD.get()); if (!client) return; @@ -41,7 +42,6 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.listener.link); wl_list_init(&destroyListener.listener.link); - close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { @@ -113,8 +113,8 @@ CSecurityContext::CSecurityContext(SP resource_, int liste LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); - listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); - closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD.get(), WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD.get(), 0, ::onCloseFdEvent, this); if (!listenSource || !closeSource) { r->noMemory(); @@ -144,16 +144,15 @@ void CSecurityContext::onListen(uint32_t mask) { if (!(mask & WL_EVENT_READABLE)) return; - int clientFD = accept(listenFD, nullptr, nullptr); - if UNLIKELY (clientFD < 0) { + CFileDescriptor clientFD{accept(listenFD.get(), nullptr, nullptr)}; + if UNLIKELY (!clientFD.isValid()) { LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); return; } - auto newClient = CSecurityContextSandboxedClient::create(clientFD); + auto newClient = CSecurityContextSandboxedClient::create(std::move(clientFD)); if UNLIKELY (!newClient) { LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); - close(clientFD); return; } diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index 2bec08d4..56d4f7b4 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -4,19 +4,20 @@ #include #include "WaylandProtocol.hpp" #include "security-context-v1.hpp" +#include class CSecurityContext { public: CSecurityContext(SP resource_, int listenFD_, int closeFD_); ~CSecurityContext(); - bool good(); + bool good(); - std::string sandboxEngine, appID, instanceID; - int listenFD = -1, closeFD = -1; + std::string sandboxEngine, appID, instanceID; + Hyprutils::OS::CFileDescriptor listenFD, closeFD; - void onListen(uint32_t mask); - void onClose(uint32_t mask); + void onListen(uint32_t mask); + void onClose(uint32_t mask); private: SP resource; @@ -44,7 +45,7 @@ struct SCSecurityContextSandboxedClientDestroyWrapper { class CSecurityContextSandboxedClient { public: - static SP create(int clientFD); + static SP create(Hyprutils::OS::CFileDescriptor clientFD); ~CSecurityContextSandboxedClient(); void onDestroy(); @@ -52,10 +53,10 @@ class CSecurityContextSandboxedClient { SCSecurityContextSandboxedClientDestroyWrapper destroyListener; private: - CSecurityContextSandboxedClient(int clientFD_); + CSecurityContextSandboxedClient(Hyprutils::OS::CFileDescriptor clientFD_); - wl_client* client = nullptr; - int clientFD = -1; + wl_client* client = nullptr; + Hyprutils::OS::CFileDescriptor clientFD; friend class CSecurityContextProtocol; friend class CSecurityContext; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 4fec57c0..00aca041 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,6 +1,7 @@ #include "VirtualKeyboard.hpp" #include #include "../devices/IKeyboard.hpp" +using namespace Hyprutils::OS; CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -51,20 +52,19 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { - auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + CFileDescriptor keymapFd{fd}; if UNLIKELY (!xkbContext) { LOGM(ERR, "xkbContext creation failed"); r->noMemory(); - close(fd); return; } - auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); + auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, keymapFd.get(), 0); if UNLIKELY (keymapData == MAP_FAILED) { LOGM(ERR, "keymapData alloc failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -75,7 +75,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP LOGM(ERR, "xkbKeymap creation failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -86,7 +85,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP xkb_keymap_unref(xkbKeymap); xkb_context_unref(xkbContext); - close(fd); }); name = "hl-virtual-keyboard"; diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 8157b276..0a13003b 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "virtual-keyboard-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CVirtualKeyboardV1Resource { public: diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index e17b5612..0931608a 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,6 +13,7 @@ #include "../../managers/HookSystemManager.hpp" #include "../../helpers/Monitor.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -39,15 +40,14 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } @@ -58,7 +58,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPaccepted(mime ? mime : ""); } - source->send(mime ? mime : "", fd); + source->send(mime ? mime : "", std::move(sendFd)); recvd = true; @@ -182,15 +182,13 @@ std::vector CWLDataSourceResource::mimes() { return mimeTypes; } -void CWLDataSourceResource::send(const std::string& mime, uint32_t fd) { +void CWLDataSourceResource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLDataSourceResource::cancelled() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index d8bc2b9c..dfea4a71 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -16,6 +16,7 @@ #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" #include "../types/DataDevice.hpp" +#include class CWLDataDeviceResource; class CWLDataDeviceManagerResource; @@ -63,7 +64,7 @@ class CWLDataSourceResource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index c6b2de05..1f07a15e 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -321,35 +321,18 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - std::string_view keymap; - int fd; - uint32_t size; - if (keyboard) { - keymap = keyboard->xkbKeymapString; - fd = keyboard->xkbKeymapFD; - size = keyboard->xkbKeymapString.length() + 1; - } else { - fd = open("/dev/null", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - LOGM(ERR, "Failed to open /dev/null"); - return; - } - size = 0; - } + std::string_view keymap = keyboard->xkbKeymapString; + Hyprutils::OS::CFileDescriptor& fd = keyboard->xkbKeymapFD; + uint32_t size = keyboard->xkbKeymapString.length() + 1; - if (keymap == lastKeymap) { - if (!keyboard) - close(fd); + if (keymap == lastKeymap) return; - } + lastKeymap = keymap; const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; - resource->sendKeymap(format, fd, size); - - if (!keyboard) - close(fd); + resource->sendKeymap(format, fd.get(), size); } void CWLKeyboardResource::sendEnter(SP surface) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 1649f82f..e0e62560 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,6 +7,7 @@ #include "../types/WLBuffer.hpp" #include "../../helpers/Format.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if UNLIKELY (!pool_->pool->data) @@ -51,7 +52,7 @@ bool CWLSHMBuffer::isSynchronous() { Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { Aquamarine::SSHMAttrs attrs; attrs.success = true; - attrs.fd = pool->fd; + attrs.fd = pool->fd.get(); attrs.format = NFormatUtils::shmToDRM(fmt); attrs.size = size; attrs.stride = stride; @@ -75,13 +76,12 @@ void CWLSHMBuffer::update(const CRegion& damage) { texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); } -CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) { +CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) { ; } CSHMPool::~CSHMPool() { munmap(data, size); - close(fd); } void CSHMPool::resize(size_t size_) { @@ -90,23 +90,23 @@ void CSHMPool::resize(size_t size_) { if (data) munmap(data, size); size = size_; - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); if UNLIKELY (data == MAP_FAILED) - LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd.get()); } -static int shmIsSizeValid(int fd, size_t size) { +static int shmIsSizeValid(CFileDescriptor& fd, size_t size) { struct stat st; - if UNLIKELY (fstat(fd, &st) == -1) { - LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); + if UNLIKELY (fstat(fd.get(), &st) == -1) { + LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd.get()); return 0; } return (size_t)st.st_size >= size; } -CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { +CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, CFileDescriptor fd_, size_t size_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -115,7 +115,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t return; } - pool = makeShared(fd_, size_); + pool = makeShared(std::move(fd_), size_); resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); @@ -176,7 +176,8 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { - const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); + CFileDescriptor poolFd{fd}; + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), std::move(poolFd), size)); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index d7e81367..fef821cb 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -7,6 +7,8 @@ - wl_buffer with shm */ +#include +#include #include #include #include "../WaylandProtocol.hpp" @@ -18,14 +20,14 @@ class CWLSHMPoolResource; class CSHMPool { public: - CSHMPool(int fd, size_t size); + CSHMPool(Hyprutils::OS::CFileDescriptor fd, size_t size); ~CSHMPool(); - int fd = 0; - size_t size = 0; - void* data = nullptr; + Hyprutils::OS::CFileDescriptor fd; + size_t size = 0; + void* data = nullptr; - void resize(size_t size); + void resize(size_t size); }; class CWLSHMBuffer : public IHLBuffer { @@ -57,7 +59,7 @@ class CWLSHMBuffer : public IHLBuffer { class CWLSHMPoolResource { public: - CWLSHMPoolResource(SP resource_, int fd, size_t size); + CWLSHMPoolResource(SP resource_, Hyprutils::OS::CFileDescriptor fd, size_t size); bool good(); diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 62f10de2..cbb4b271 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -7,6 +7,7 @@ #include #include "../../helpers/memory/Memory.hpp" #include "../../helpers/math/Math.hpp" +#include class CWLDataOfferResource; class CX11DataOffer; @@ -24,10 +25,10 @@ class IDataSource { IDataSource() = default; virtual ~IDataSource() = default; - virtual std::vector mimes() = 0; - virtual void send(const std::string& mime, uint32_t fd) = 0; - virtual void accepted(const std::string& mime) = 0; - virtual void cancelled() = 0; + virtual std::vector mimes() = 0; + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd) = 0; + virtual void accepted(const std::string& mime) = 0; + virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); virtual void sendDndFinished(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 78b53c9b..e4aadd63 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -19,6 +19,7 @@ #include #include #include +using namespace Hyprutils::OS; const std::vector ASSET_PATHS = { #ifdef DATAROOTDIR @@ -301,11 +302,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_iDRMFD(g_pCompositor->m_iDRMFD) { Debug::log(WARN, "EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm"); if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { success = true; - m_iGBMFD = openRenderNode(m_iDRMFD); - if (m_iGBMFD < 0) + m_iGBMFD = CFileDescriptor{openRenderNode(m_iDRMFD)}; + if (!m_iGBMFD.isValid()) RASSERT(false, "Couldn't open a gbm fd"); - m_pGbmDevice = gbm_create_device(m_iGBMFD); + m_pGbmDevice = gbm_create_device(m_iGBMFD.get()); if (!m_pGbmDevice) RASSERT(false, "Couldn't open a gbm device"); @@ -371,9 +372,6 @@ CHyprOpenGLImpl::~CHyprOpenGLImpl() { if (m_pGbmDevice) gbm_device_destroy(m_pGbmDevice); - - if (m_iGBMFD >= 0) - close(m_iGBMFD); } std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { @@ -2954,29 +2952,28 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } -SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { +SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { std::vector attribs; - int dupFd = -1; - if (fenceFD > 0) { - dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { + CFileDescriptor dupFd; + if (fenceFD.isValid()) { + dupFd = fenceFD.duplicate(); + if (!dupFd.isValid()) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; } // reserve number of elements to avoid reallocations attribs.reserve(3); attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); - attribs.push_back(dupFd); + attribs.push_back(dupFd.get()); attribs.push_back(EGL_NONE); } EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { Debug::log(ERR, "eglCreateSyncKHR failed"); - if (dupFd >= 0) - close(dupFd); return nullptr; - } + } else + dupFd.take(); // eglCreateSyncKHR only takes ownership on success // we need to flush otherwise we might not get a valid fd glFlush(); @@ -2989,19 +2986,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { auto eglsync = SP(new CEGLSync); eglsync->sync = sync; - eglsync->m_iFd = fd; + eglsync->m_iFd = CFileDescriptor{fd}; return eglsync; } bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { - int fd = timeline->exportAsSyncFileFD(point); - if (fd < 0) { + auto fd = timeline->exportAsSyncFileFD(point); + if (!fd.isValid()) { Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); return false; } - auto sync = g_pHyprOpenGL->createEGLSync(fd); - close(fd); + auto sync = g_pHyprOpenGL->createEGLSync(std::move(fd)); if (!sync) { Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); return false; @@ -3082,12 +3078,9 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); - - if (m_iFd >= 0) - close(m_iFd); } -int CEGLSync::fd() { +CFileDescriptor& CEGLSync::fd() { return m_iFd; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1ebb0162..d7abdf63 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "../debug/TracyDefines.hpp" @@ -146,15 +147,15 @@ class CEGLSync { public: ~CEGLSync(); - EGLSyncKHR sync = nullptr; + EGLSyncKHR sync = nullptr; - int fd(); - bool wait(); + Hyprutils::OS::CFileDescriptor& fd(); + bool wait(); private: CEGLSync() = default; - int m_iFd = -1; + Hyprutils::OS::CFileDescriptor m_iFd; friend class CHyprOpenGLImpl; }; @@ -228,14 +229,14 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); + SP createEGLSync(Hyprutils::OS::CFileDescriptor fenceFD); bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; + Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; EGLDisplay m_pEglDisplay = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 67d8b58b..42445728 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -36,6 +36,7 @@ #include using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; extern "C" { #include @@ -1462,10 +1463,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamar bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it - auto inFD = pMonitor->output->state->state().explicitInFence; + CFileDescriptor inFD{pMonitor->output->state->state().explicitInFence}; pMonitor->output->state->resetExplicitFences(); - if (inFD >= 0) - pMonitor->output->state->setExplicitInFence(inFD); + if (inFD.isValid()) + pMonitor->output->state->setExplicitInFence(inFD.get()); static auto PHDR = CConfigValue("experimental:hdr"); @@ -1515,7 +1516,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { bool ok = pMonitor->state.commit(); if (!ok) { - if (inFD >= 0) { + if (inFD.isValid()) { Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); pMonitor->output->state->resetExplicitFences(); ok = pMonitor->state.commit(); @@ -1534,11 +1535,8 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (!explicitOptions.explicitEnabled) return ok; - if (inFD >= 0) - close(inFD); - Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); @@ -2272,7 +2270,7 @@ void CHyprRenderer::endRender() { auto explicitOptions = getExplicitSyncSettings(); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) { Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; @@ -2285,12 +2283,12 @@ void CHyprRenderer::endRender() { } auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); - if (fd <= 0) { + if (!fd.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } - PMONITOR->output->state->setExplicitInFence(fd); + PMONITOR->output->state->setExplicitInFence(fd.take()); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index d4ae3780..16d166ce 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -7,6 +7,8 @@ #include "../managers/XWaylandManager.hpp" #include "../desktop/WLSurface.hpp" +using namespace Hyprutils::OS; + #ifndef NO_XWAYLAND static xcb_atom_t dndActionToAtom(uint32_t actions) { if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) @@ -172,7 +174,7 @@ std::vector CX11DataSource::mimes() { return mimeTypes; } -void CX11DataSource::send(const std::string& mime, uint32_t fd) { +void CX11DataSource::send(const std::string& mime, CFileDescriptor fd) { ; } diff --git a/src/xwayland/Dnd.hpp b/src/xwayland/Dnd.hpp index 8da60ddd..fb030796 100644 --- a/src/xwayland/Dnd.hpp +++ b/src/xwayland/Dnd.hpp @@ -2,6 +2,7 @@ #include "../protocols/types/DataDevice.hpp" #include +#include #define XDND_VERSION 5 @@ -35,7 +36,7 @@ class CX11DataSource : public IDataSource { ~CX11DataSource() = default; virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index d5dce333..99bcdf62 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -24,70 +24,41 @@ #include "../defines.hpp" #include "../Compositor.hpp" #include "../managers/CursorManager.hpp" +using namespace Hyprutils::OS; // Constants -constexpr int SOCKET_DIR_PERMISSIONS = 0755; -constexpr int SOCKET_BACKLOG = 1; -constexpr int MAX_SOCKET_RETRIES = 32; -constexpr int LOCK_FILE_MODE = 0444; +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 0444; -static bool setCloseOnExec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - if (cloexec) - flags = flags | FD_CLOEXEC; - else - flags = flags & ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - return true; -} - -static void cleanUpSocket(int fd, const char* path) { - close(fd); - if (path[0]) - unlink(path); -} - -static inline void closeSocketSafely(int& fd) { - if (fd >= 0) - close(fd); -} - -static int createSocket(struct sockaddr_un* addr, size_t path_size) { - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { +static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; + if (!fd.isValid()) { Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - return -1; + return {}; } - if (!setCloseOnExec(fd, true)) { - close(fd); - return -1; + if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) { + return {}; } if (addr->sun_path[0]) unlink(addr->sun_path); - if (bind(fd, (struct sockaddr*)addr, size) < 0) { + if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) { Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } - if (listen(fd, SOCKET_BACKLOG) < 0) { + if (listen(fd.get(), SOCKET_BACKLOG) < 0) { Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } return fd; @@ -141,7 +112,7 @@ static std::string getSocketPath(int display, bool isLinux) { return std::format("/tmp/.X11-unix/X{}_", display); } -static bool openSockets(std::array& sockets, int display) { +static bool openSockets(std::array& sockets, int display) { if (!ensureSocketDirExists()) return false; @@ -151,17 +122,16 @@ static bool openSockets(std::array& sockets, int display) { path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[0] = createSocket(&addr, path.length()); - if (sockets[0] < 0) + sockets[0] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[0].isValid()) return false; path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = createSocket(&addr, path.length()); - if (sockets[1] < 0) { - close(sockets[0]); - sockets[0] = -1; + sockets[1] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[1].isValid()) { + sockets[0].reset(); return false; } @@ -174,7 +144,8 @@ static void startServer(void* data) { } static int xwaylandReady(int fd, uint32_t mask, void* data) { - return g_pXWayland->pServer->ready(fd, mask); + CFileDescriptor xwlFd{fd}; + return g_pXWayland->pServer->ready(std::move(xwlFd), mask); } static bool safeRemove(const std::string& path) { @@ -186,38 +157,34 @@ static bool safeRemove(const std::string& path) { bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { - std::string lockPath = std::format("/tmp/.X{}-lock", i); + std::string lockPath = std::format("/tmp/.X{}-lock", i); - int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); - if (fd >= 0) { + CFileDescriptor fd{open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE)}; + if (fd.isValid()) { // we managed to open the lock if (!openSockets(xFDs, i)) { safeRemove(lockPath); - close(fd); continue; } const std::string pidStr = std::to_string(getpid()); - if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { safeRemove(lockPath); - close(fd); continue; } - close(fd); display = i; displayName = std::format(":{}", display); break; } - fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); + fd = CFileDescriptor{open(lockPath.c_str(), O_RDONLY | O_CLOEXEC)}; - if (fd < 0) + if (!fd.isValid()) continue; char pidstr[12] = {0}; - read(fd, pidstr, sizeof(pidstr) - 1); - close(fd); + read(fd.get(), pidstr, sizeof(pidstr) - 1); int32_t pid = 0; try { @@ -249,9 +216,6 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - closeSocketSafely(xFDs[0]); - closeSocketSafely(xFDs[1]); - std::string lockPath = std::format("/tmp/.X{}-lock", display); safeRemove(lockPath); @@ -277,21 +241,11 @@ void CXWaylandServer::die() { if (pipeSource) wl_event_source_remove(pipeSource); - if (pipeFd >= 0) - close(pipeFd); - - closeSocketSafely(waylandFDs[0]); - closeSocketSafely(waylandFDs[1]); - closeSocketSafely(xwmFDs[0]); - closeSocketSafely(xwmFDs[1]); - // possible crash. Better to leak a bit. //if (xwaylandClient) // wl_client_destroy(xwaylandClient); xwaylandClient = nullptr; - waylandFDs = {-1, -1}; - xwmFDs = {-1, -1}; } bool CXWaylandServer::create() { @@ -307,15 +261,17 @@ bool CXWaylandServer::create() { return true; } -void CXWaylandServer::runXWayland(int notifyFD) { - if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { +void CXWaylandServer::runXWayland(CFileDescriptor& notifyFD) { + if (!xFDs[0].setFlags(xFDs[0].getFlags() & ~FD_CLOEXEC) || !xFDs[1].setFlags(xFDs[1].getFlags() & ~FD_CLOEXEC) || + !waylandFDs[1].setFlags(waylandFDs[1].getFlags() & ~FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() & ~FD_CLOEXEC)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } - auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]); + auto cmd = + std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0].get(), xFDs[1].get(), notifyFD.get(), xwmFDs[1].get()); - auto waylandSocket = std::format("{}", waylandFDs[1]); + auto waylandSocket = std::format("{}", waylandFDs[1].get()); setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true); Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd); @@ -327,40 +283,46 @@ void CXWaylandServer::runXWayland(int notifyFD) { } bool CXWaylandServer::start() { - idleSource = nullptr; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) { + idleSource = nullptr; + int wlPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, wlPair) != 0) { Debug::log(ERR, "socketpair failed (1)"); die(); return false; } + waylandFDs[0] = CFileDescriptor{wlPair[0]}; + waylandFDs[1] = CFileDescriptor{wlPair[1]}; - if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { + if (!waylandFDs[0].setFlags(waylandFDs[0].getFlags() | FD_CLOEXEC) || !waylandFDs[1].setFlags(waylandFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) { + int xwmPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmPair) != 0) { Debug::log(ERR, "socketpair failed (2)"); die(); return false; } - if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { + xwmFDs[0] = CFileDescriptor{xwmPair[0]}; + xwmFDs[1] = CFileDescriptor{xwmPair[1]}; + + if (!xwmFDs[0].setFlags(xwmFDs[0].getFlags() | FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; } - xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]); + xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0].get()); if (!xwaylandClient) { Debug::log(ERR, "wl_client_create failed"); die(); return false; } - waylandFDs[0] = -1; + waylandFDs[0].take(); // does this leak? int notify[2] = {-1, -1}; if (pipe(notify) < 0) { @@ -369,22 +331,20 @@ bool CXWaylandServer::start() { return false; } - if (!setCloseOnExec(notify[0], true)) { + CFileDescriptor notifyFds[2] = {CFileDescriptor{notify[0]}, CFileDescriptor{notify[1]}}; + + if (!notifyFds[0].setFlags(notifyFds[0].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (3)"); - close(notify[0]); - close(notify[1]); die(); return false; } - pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); - pipeFd = notify[0]; + pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr); + pipeFd = std::move(notifyFds[0]); serverPID = fork(); if (serverPID < 0) { Debug::log(ERR, "fork failed"); - close(notify[0]); - close(notify[1]); die(); return false; } else if (serverPID == 0) { @@ -393,25 +353,19 @@ bool CXWaylandServer::start() { Debug::log(ERR, "second fork failed"); _exit(1); } else if (pid == 0) - runXWayland(notify[1]); + runXWayland(notifyFds[1]); _exit(0); } - close(notify[1]); - close(waylandFDs[1]); - closeSocketSafely(xwmFDs[1]); - waylandFDs[1] = -1; - xwmFDs[1] = -1; - return true; } -int CXWaylandServer::ready(int fd, uint32_t mask) { +int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) { if (mask & WL_EVENT_READABLE) { // xwayland writes twice char buf[64]; - ssize_t n = read(fd, buf, sizeof(buf)); + ssize_t n = read(fd.get(), buf, sizeof(buf)); if (n < 0 && errno != EINTR) { Debug::log(ERR, "Xwayland: read from displayFd failed"); mask = 0; @@ -436,7 +390,6 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { Debug::log(LOG, "XWayland is ready"); - close(fd); wl_event_source_remove(pipeSource); pipeSource = nullptr; diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp index 7a36a965..ccbcf6ea 100644 --- a/src/xwayland/Server.hpp +++ b/src/xwayland/Server.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../helpers/signal/Signal.hpp" struct wl_event_source; @@ -19,7 +20,7 @@ class CXWaylandServer { bool start(); // called on ready - int ready(int fd, uint32_t mask); + int ready(Hyprutils::OS::CFileDescriptor fd, uint32_t mask); void die(); @@ -30,20 +31,20 @@ class CXWaylandServer { wl_client* xwaylandClient = nullptr; private: - bool tryOpenSockets(); - void runXWayland(int notifyFD); + bool tryOpenSockets(); + void runXWayland(Hyprutils::OS::CFileDescriptor& notifyFD); - pid_t serverPID = 0; + pid_t serverPID = 0; - std::string displayName; - int display = -1; - std::array xFDs = {-1, -1}; - std::array xFDReadEvents = {nullptr, nullptr}; - wl_event_source* idleSource = nullptr; - wl_event_source* pipeSource = nullptr; - int pipeFd = -1; - std::array xwmFDs = {-1, -1}; - std::array waylandFDs = {-1, -1}; + std::string displayName; + int display = -1; + std::array xFDs; + std::array xFDReadEvents = {nullptr, nullptr}; + wl_event_source* idleSource = nullptr; + wl_event_source* pipeSource = nullptr; + Hyprutils::OS::CFileDescriptor pipeFd; + std::array xwmFDs; + std::array waylandFDs; friend class CXWM; }; diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 4b0c5a29..e6282dcb 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -5,6 +5,7 @@ #include "XDataSource.hpp" #include +using namespace Hyprutils::OS; CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, @@ -47,7 +48,7 @@ std::vector CXDataSource::mimes() { return mimeTypes; } -void CXDataSource::send(const std::string& mime, uint32_t fd) { +void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { xcb_atom_t mimeAtom = 0; if (mime == "text/plain") @@ -65,11 +66,10 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { if (!mimeAtom) { Debug::log(ERR, "[XDataSource] mime atom not found"); - close(fd); return; } - Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); + Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); selection.transfer = makeUnique(selection); selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); @@ -81,8 +81,9 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { xcb_flush(g_pXWayland->pWM->connection); - fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = fd; + //TODO: make CFileDescriptor setflags take SETFL aswell + fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); + selection.transfer->wlFD = std::move(fd); } void CXDataSource::accepted(const std::string& mime) { @@ -101,4 +102,4 @@ eDataSourceType CXDataSource::type() { return DATA_SOURCE_TYPE_X11; } -#endif \ No newline at end of file +#endif diff --git a/src/xwayland/XDataSource.hpp b/src/xwayland/XDataSource.hpp index c629aa2a..a61ffcc9 100644 --- a/src/xwayland/XDataSource.hpp +++ b/src/xwayland/XDataSource.hpp @@ -1,6 +1,7 @@ #pragma once #include "../protocols/types/DataDevice.hpp" +#include struct SXSelection; @@ -9,7 +10,7 @@ class CXDataSource : public IDataSource { CXDataSource(SXSelection&); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); @@ -19,4 +20,4 @@ class CXDataSource : public IDataSource { SXSelection& selection; std::vector mimeTypes; // these two have shared idx std::vector mimeAtoms; // -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 6673105e..81900c7b 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -17,6 +17,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" +using namespace Hyprutils::OS; #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -883,7 +884,7 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0].get()) { if (connection.hasError()) { Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); @@ -901,7 +902,7 @@ CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(connection)); screen = screen_iterator.data; - eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0], WL_EVENT_READABLE, ::onX11Event, nullptr); + eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0].get(), WL_EVENT_READABLE, ::onX11Event, nullptr); wl_event_source_check(eventSource); gatherResources(); @@ -1180,13 +1181,12 @@ void CXWM::getTransferData(SXSelection& sel) { if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - close(sel.transfer->wlFD); sel.transfer.reset(); return; } else { sel.onWrite(); if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1361,13 +1361,13 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { // the wayland client might not expect a non-blocking fd // fcntl(p[1], F_SETFL, O_NONBLOCK); - transfer->wlFD = p[0]; + transfer->wlFD = CFileDescriptor{p[0]}; Debug::log(LOG, "[xwm] sending wayland selection to xwayland with mime {}, target {}, fds {} {}", mime, e->target, p[0], p[1]); - selection->send(mime, p[1]); + selection->send(mime, CFileDescriptor{p[1]}); - transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD, WL_EVENT_READABLE, ::readDataSource, this); + transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); return true; } @@ -1376,10 +1376,9 @@ int SXSelection::onWrite() { char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; - ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - close(transfer->wlFD); transfer.reset(); return 0; } @@ -1389,7 +1388,6 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(transfer->wlFD); transfer.reset(); } @@ -1397,8 +1395,6 @@ int SXSelection::onWrite() { } SXTransfer::~SXTransfer() { - if (wlFD) - close(wlFD); if (eventSource) wl_event_source_remove(eventSource); if (incomingWindow) diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index dfaf33b9..73a02a86 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -10,6 +10,7 @@ #include #include #include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -18,25 +19,25 @@ struct SXSelection; struct SXTransfer { ~SXTransfer(); - SXSelection& selection; - bool out = true; + SXSelection& selection; + bool out = true; - bool incremental = false; - bool flushOnDelete = false; - bool propertySet = false; + bool incremental = false; + bool flushOnDelete = false; + bool propertySet = false; - int wlFD = -1; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor wlFD; + wl_event_source* eventSource = nullptr; - std::vector data; + std::vector data; - xcb_selection_request_event_t request; + xcb_selection_request_event_t request; - int propertyStart; - xcb_get_property_reply_t* propertyReply; - xcb_window_t incomingWindow; + int propertyStart; + xcb_get_property_reply_t* propertyReply; + xcb_window_t incomingWindow; - bool getIncomingSelectionProp(bool erase); + bool getIncomingSelectionProp(bool erase); }; struct SXSelection { From ef03f6911694413b1b06aba727ad9ab089a511f7 Mon Sep 17 00:00:00 2001 From: nyx Date: Thu, 30 Jan 2025 16:36:42 -0500 Subject: [PATCH 1157/2393] xwayland: handle window coords correctly (#9238) --- src/desktop/Window.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e59a8d4e..09037cbd 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1706,9 +1706,15 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional // TODO: this should be decoupled from setWindowSize IMO Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); - if (m_bIsX11) { - if (const auto XWAYLANDPOS = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); XWAYLANDPOS != Vector2D{}) - windowPos = XWAYLANDPOS; + if (m_bIsX11 && PMONITOR) { + windowPos -= PMONITOR->vecPosition; + + if (*PXWLFORCESCALEZERO) { + windowPos *= PMONITOR->scale; + size *= PMONITOR->scale; + } + + windowPos += PMONITOR->vecXWaylandPosition; } if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) @@ -1716,13 +1722,10 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional m_vReportedPosition = windowPos; m_vPendingReportedSize = size; + m_fX11SurfaceScaledBy = 1.0f; - m_fX11SurfaceScaledBy = 1.0f; - - if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) { - size *= PMONITOR->scale; + if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) m_fX11SurfaceScaledBy = PMONITOR->scale; - } if (m_bIsX11 && m_pXWaylandSurface) m_pXWaylandSurface->configure({windowPos, size}); From e6a9cfab9199788ee0dcefd8b1bda46f93e6a001 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 31 Jan 2025 06:23:32 -0600 Subject: [PATCH 1158/2393] monitor: preferred mode now tries first 3 modes if preferred fails before erroring (#9246) --- src/helpers/Monitor.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fc3de3aa..9aa6efce 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -435,7 +435,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { // accumulate requested modes in reverse order (cause inesrting at front is inefficient) std::vector> requestedModes; - std::string requestedStr = "preferred"; + std::string requestedStr = "unknown"; // use sortFunc, add best 3 to requestedModes in reverse, since we test in reverse auto addBest3Modes = [&](auto const& sortFunc) { @@ -446,13 +446,24 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend()); }; - // last fallback is preferred mode, btw this covers resolution == Vector2D() + // last fallback is always preferred mode if (!output->preferredMode()) Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", output->name); else requestedModes.push_back(output->preferredMode()); - if (RULE->resolution == Vector2D(-1, -1)) { + if (RULE->resolution == Vector2D()) { + requestedStr = "preferred"; + + // fallback to first 3 modes if preferred fails/doesn't exist + requestedModes = output->modes; + if (requestedModes.size() > 3) + requestedModes.erase(requestedModes.begin() + 3, requestedModes.end()); + std::ranges::reverse(requestedModes.begin(), requestedModes.end()); + + if (output->preferredMode()) + requestedModes.push_back(output->preferredMode()); + } else if (RULE->resolution == Vector2D(-1, -1)) { requestedStr = "highrr"; // sort prioritizing refresh rate 1st and resolution 2nd, then add best 3 From ea16b64ec169afcd21020dfb819a73c37428c7f2 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 07:26:08 -0500 Subject: [PATCH 1159/2393] xwayland: prevent invalid window configurations for X11 apps (#9253) * fix(xwayland): prevent invalid window configurations for X11 apps * refact(xwayland): remove unneeded line --- src/desktop/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 09037cbd..91c76e7c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1700,7 +1700,7 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional const auto PMONITOR = m_pMonitor.lock(); - size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); // calculate pos // TODO: this should be decoupled from setWindowSize IMO From 7d51dee103e22742d425d14faebb0273a64ac8c1 Mon Sep 17 00:00:00 2001 From: Aaron Tulino <13600347+aaronjamt@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:33:36 -0700 Subject: [PATCH 1160/2393] hyprctl: Extract IPC code to separate method (#9223) This makes it possible to use the same IPC code for more projects in the future --- hyprctl/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 4cc73bdf..ac88f1da 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -225,7 +225,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) { return 0; } -int requestHyprpaper(std::string arg) { +int requestIPC(std::string filename, std::string arg) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SERVERSOCKET < 0) { @@ -243,7 +243,7 @@ int requestHyprpaper(std::string arg) { const std::string USERID = std::to_string(getUID()); - std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock"; + std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/" + filename; strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); @@ -278,6 +278,10 @@ int requestHyprpaper(std::string arg) { return 0; } +int requestHyprpaper(std::string arg) { + return requestIPC(".hyprpaper.sock", arg); +} + void batchRequest(std::string arg, bool json) { std::string commands = arg.substr(arg.find_first_of(' ') + 1); From ac5668192ed56c50b5612c7670e397a2128eeba6 Mon Sep 17 00:00:00 2001 From: Brayden Zee Date: Fri, 31 Jan 2025 07:33:51 -0500 Subject: [PATCH 1161/2393] desktop: fix segfault when destroying a partially create layer surface (#9247) --- src/desktop/LayerSurface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index e2d0177b..78dae0a9 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -98,7 +98,8 @@ void CLayerSurface::onDestroy() { onUnmap(); } else { Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); - alpha->setValueAndWarp(0.f); + if (alpha) + alpha->setValueAndWarp(0.f); fadingOut = true; g_pCompositor->addToFadingOutSafe(self.lock()); } From 9c38287410b305503f921e411eb39686b23ccc42 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 31 Jan 2025 13:32:36 +0000 Subject: [PATCH 1162/2393] groupbar: various visual improvements added rounding, round at edges, and indicator height --- src/config/ConfigDescriptions.hpp | 32 ++++++- src/config/ConfigManager.cpp | 7 +- .../decorations/CHyprGroupBarDecoration.cpp | 91 +++++++++++++++---- src/render/pass/RectPassElement.cpp | 5 + src/render/pass/RectPassElement.hpp | 1 + src/render/pass/TexPassElement.cpp | 6 +- src/render/pass/TexPassElement.hpp | 1 + 7 files changed, 121 insertions(+), 22 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 483f1f1f..01ef392e 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -883,7 +883,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "group:groupbar:gradients", .description = "enables gradients", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, SConfigOptionDescription{ .value = "group:groupbar:height", @@ -891,6 +891,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{14, 1, 64}, }, + SConfigOptionDescription{ + .value = "group:groupbar:indicator_height", + .description = "height of the groupbar indicator", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 1, 64}, + }, SConfigOptionDescription{ .value = "group:groupbar:stacked", .description = "render the groupbar as a vertical stack", @@ -915,6 +921,30 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:groupbar:rounding", + .description = "how much to round the groupbar", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:gradient_rounding", + .description = "how much to round the groupbar gradient", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:round_only_edges", + .description = "if yes, will only round at the groupbar edges", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:groupbar_round_only_edges", + .description = "if yes, will only round at the groupbar gradient edges", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "group:groupbar:text_color", .description = "controls the group bar text color", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 86581b10..e36a2914 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -441,13 +441,18 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); - m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:groupbar:height", Hyprlang::INT{14}); + m_pConfig->addConfigValue("group:groupbar:indicator_height", Hyprlang::INT{3}); m_pConfig->addConfigValue("group:groupbar:priority", Hyprlang::INT{3}); m_pConfig->addConfigValue("group:groupbar:render_titles", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:scrolling", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:text_color", Hyprlang::INT{0xffffffff}); m_pConfig->addConfigValue("group:groupbar:stacked", Hyprlang::INT{0}); + m_pConfig->addConfigValue("group:groupbar:rounding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradient_rounding", Hyprlang::INT{2}); + m_pConfig->addConfigValue("group:groupbar:round_only_edges", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradient_round_only_edges", Hyprlang::INT{1}); m_pConfig->addConfigValue("debug:int", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:log_damage", Hyprlang::INT{0}); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 88501d74..1a64b024 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -15,7 +15,6 @@ static SP m_tGradientInactive = makeShared(); static SP m_tGradientLockedActive = makeShared(); static SP m_tGradientLockedInactive = makeShared(); -constexpr int BAR_INDICATOR_HEIGHT = 3; constexpr int BAR_PADDING_OUTER_VERT = 2; constexpr int BAR_PADDING_OUTER_HORZ = 2; constexpr int BAR_TEXT_PAD = 2; @@ -30,12 +29,13 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindo } SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { - static auto PHEIGHT = CConfigValue("group:groupbar:height"); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); - static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); - static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); - static auto PPRIORITY = CConfigValue("group:groupbar:priority"); - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PHEIGHT = CConfigValue("group:groupbar:height"); + static auto PINDICATORHEIGHT = CConfigValue("group:groupbar:indicator_height"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); + static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); + static auto PPRIORITY = CConfigValue("group:groupbar:priority"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); SDecorationPositioningInfo info; info.policy = DECORATION_POSITION_STICKY; @@ -45,10 +45,10 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { if (*PENABLED && m_pWindow->m_sWindowData.decorate.valueOrDefault()) { if (*PSTACKED) { - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT}, {0, 0}}; } else - info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; + info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; } else info.desiredExtents = {{0, 0}, {0, 0}}; return info; @@ -99,19 +99,24 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); - static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); - static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); - static auto PHEIGHT = CConfigValue("group:groupbar:height"); - static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); + static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); + static auto PHEIGHT = CConfigValue("group:groupbar:height"); + static auto PINDICATORHEIGHT = CConfigValue("group:groupbar:indicator_height"); + static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PROUNDING = CConfigValue("group:groupbar:rounding"); + static auto PGRADIENTROUNDING = CConfigValue("group:groupbar:gradient_rounding"); + static auto PGRADIENTROUNDINGONLYEDGES = CConfigValue("group:groupbar:gradient_round_only_edges"); + static auto PROUNDONLYEDGES = CConfigValue("group:groupbar:round_only_edges"); if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) return; const auto ASSIGNEDBOX = assignedBoxGlobal(); - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; m_fBarHeight = *PSTACKED ? ((ASSIGNEDBOX.h - 2 - BAR_PADDING_OUTER_VERT) - BAR_PADDING_OUTER_VERT * (barsToDraw)) / barsToDraw : ASSIGNEDBOX.h - BAR_PADDING_OUTER_VERT; @@ -126,8 +131,8 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i; CBox rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, - m_fBarWidth, BAR_INDICATOR_HEIGHT}; + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - *PINDICATORHEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, + m_fBarWidth, *PINDICATORHEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -152,6 +157,30 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { CRectPassElement::SRectData rectdata; rectdata.color = color; rectdata.box = rect; + if (*PROUNDING) { + if (*PROUNDONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + rectdata.round = *PROUNDING; + else if (i == 0) { + double first = rect.w - (*PROUNDING * 2); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PROUNDING * 2; + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else + rectdata.round = *PROUNDING; + } g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, @@ -166,6 +195,30 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { CTexPassElement::SRenderData data; data.tex = GRADIENTTEX; data.box = rect; + if (*PGRADIENTROUNDING) { + if (*PGRADIENTROUNDINGONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + data.round = *PGRADIENTROUNDING; + else if (i == 0) { + double first = rect.w - (*PGRADIENTROUNDING * 2); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = 0; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PGRADIENTROUNDING * 2; + data.round = 0; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else + rectdata.round = *PGRADIENTROUNDING; + } g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } } @@ -229,7 +282,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float texSize = tex->m_vSize; } -void renderGradientTo(SP tex, CGradientValueData* grad) { +static void renderGradientTo(SP tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) return; diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index fba06286..aa024577 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -9,10 +9,15 @@ void CRectPassElement::draw(const CRegion& damage) { if (data.box.w <= 0 || data.box.h <= 0) return; + if (!data.clipBox.empty()) + g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox; + if (data.color.a == 1.F || !data.blur) g_pHyprOpenGL->renderRectWithDamage(data.box, data.color, damage, data.round, data.roundingPower); else g_pHyprOpenGL->renderRectWithBlur(data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); + + g_pHyprOpenGL->m_RenderData.clipBox = {}; } bool CRectPassElement::needsLiveBlur() { diff --git a/src/render/pass/RectPassElement.hpp b/src/render/pass/RectPassElement.hpp index d27abdcc..f798dbf9 100644 --- a/src/render/pass/RectPassElement.hpp +++ b/src/render/pass/RectPassElement.hpp @@ -10,6 +10,7 @@ class CRectPassElement : public IPassElement { float roundingPower = 2.0f; bool blur = false, xray = false; float blurA = 1.F; + CBox clipBox; }; CRectPassElement(const SRectData& data); diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index c7eab292..8b577373 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -13,9 +13,13 @@ void CTexPassElement::draw(const CRegion& damage) { CScopeGuard x = {[]() { // - g_pHyprOpenGL->m_bEndFrame = false; + g_pHyprOpenGL->m_bEndFrame = false; + g_pHyprOpenGL->m_RenderData.clipBox = {}; }}; + if (!data.clipBox.empty()) + g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox; + if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection; g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index 036b89fe..6faa0872 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -19,6 +19,7 @@ class CTexPassElement : public IPassElement { SP syncTimeline; int64_t syncPoint = 0; std::optional replaceProjection; + CBox clipBox; }; CTexPassElement(const SRenderData& data); From 12b5034c99f28025e6c6be29c33bde9f4a24ac9f Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 31 Jan 2025 15:36:22 +0200 Subject: [PATCH 1163/2393] configWatcher: watch both symlinks and canonical paths (#9219) --- src/config/ConfigWatcher.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index 8d086bac..e5db1e86 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace Hyprutils::OS; @@ -43,9 +44,19 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY | IN_DONT_FOLLOW), .file = path, }); + + std::error_code ec, ec2; + const auto CANONICAL = std::filesystem::canonical(path, ec); + const auto IS_SYMLINK = std::filesystem::is_symlink(path, ec2); + if (!ec && !ec2 && IS_SYMLINK) { + m_watches.emplace_back(SInotifyWatch{ + .wd = inotify_add_watch(m_inotifyFd.get(), CANONICAL.c_str(), IN_MODIFY), + .file = path, + }); + } } } From a4b7d1c2d7538068ab4832a66f86801f5f75cc65 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 08:36:56 -0500 Subject: [PATCH 1164/2393] xwayland: correct pointer coordinate mismatch in X11 windows (#9259) refactor(xwayland): add back comments --- src/desktop/Window.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 91c76e7c..0f6bac99 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1697,8 +1697,7 @@ Vector2D CWindow::requestedMaxSize() { void CWindow::sendWindowSize(Vector2D size, bool force, std::optional overridePos) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - - const auto PMONITOR = m_pMonitor.lock(); + const auto PMONITOR = m_pMonitor.lock(); size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); @@ -1707,14 +1706,9 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); if (m_bIsX11 && PMONITOR) { - windowPos -= PMONITOR->vecPosition; - - if (*PXWLFORCESCALEZERO) { - windowPos *= PMONITOR->scale; + windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); + if (*PXWLFORCESCALEZERO) size *= PMONITOR->scale; - } - - windowPos += PMONITOR->vecXWaylandPosition; } if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) From ddf180fa304e71b1d6eaa9f2b250a907131b05d9 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 11:08:43 -0500 Subject: [PATCH 1165/2393] render: enforce framebuffer offloading and remove introspection toggle (#9217) --- src/config/ConfigDescriptions.hpp | 7 -- src/config/ConfigManager.cpp | 1 - src/render/OpenGL.cpp | 147 ++---------------------------- src/render/OpenGL.hpp | 3 - src/render/pass/Pass.cpp | 4 - src/render/pass/Pass.hpp | 1 - 6 files changed, 10 insertions(+), 153 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 01ef392e..2fa86817 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1294,13 +1294,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, - SConfigOptionDescription{ - .value = "opengl:force_introspection", - .description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - " - "nothing, 1 - force always on, 2 - force always on if nvidia", - .type = CONFIG_OPTION_INT, - .data = SConfigOptionDescription::SRangeData{2, 0, 2}, - }, /* * render: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e36a2914..8bb6d157 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -619,7 +619,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); - m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{1}); // TODO: remove this. I don't think it does us any good to disable intro. m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e4aadd63..75a5eadb 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -650,112 +650,6 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool return shader; } -bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { - // passes requiring introspection are the ones that need to render blur, - // or when we are rendering to a multigpu target - - static auto PBLUR = CConfigValue("decoration:blur:enabled"); - static auto PXRAY = CConfigValue("decoration:blur:xray"); - static auto POPTIM = CConfigValue("decoration:blur:new_optimizations"); - static auto PBLURSPECIAL = CConfigValue("decoration:blur:special"); - static auto PBLURPOPUPS = CConfigValue("decoration:blur:popups"); - - if (m_RenderData.mouseZoomFactor != 1.0 || g_pHyprRenderer->m_bCrashingInProgress) - return true; - - // mirrors should not be offloaded (as we then would basically copy the same data twice) - // yes, this breaks mirrors of mirrors - if (pMonitor->isMirror()) - return false; - - // monitors that are mirrored however must be offloaded because we cannot copy from output FBs - if (!pMonitor->mirrors.empty()) - return true; - - if (*PBLUR == 0) - return false; - - if (preBlurQueued()) - return true; - - if (!pMonitor->solitaryClient.expired()) - return false; - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; - if (ls->forceBlur && !XRAYMODE) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; - if (ls->forceBlur && !XRAYMODE) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - // these two block optimization - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - if (ls->forceBlur) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - if (ls->forceBlur) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - if (*PBLURSPECIAL) { - for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (!ws->m_bIsSpecialWorkspace || ws->m_pMonitor != pMonitor) - continue; - - if (ws->m_fAlpha->value() == 0) - continue; - - return true; - } - } - - if (*PXRAY) - return false; - - for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden()) - continue; - - if (!g_pHyprRenderer->shouldRenderWindow(w)) - continue; - - if (w->popupsCount() > 0 && *PBLURPOPUPS) - return true; - - if (!w->m_bIsFloating && *POPTIM && !w->onSpecialWorkspace()) - continue; - - if (w->m_sWindowData.noBlur.valueOrDefault() || w->m_sWindowData.xray.valueOrDefault()) - continue; - - if (w->opaque()) - continue; - - return true; - } - - return false; -} - void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; @@ -811,8 +705,6 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { m_RenderData.pMonitor = pMonitor; - static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); - #ifndef GLES2 const GLenum RESETSTATUS = glGetGraphicsResetStatus(); if (RESETSTATUS != GL_NO_ERROR) { @@ -871,30 +763,12 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb applyScreenShader(*PSHADER); } - const auto PRBO = g_pHyprRenderer->getCurrentRBO(); - const bool FBPROPERSIZE = !fb || fb->m_vSize == pMonitor->vecPixelSize; - const bool USERFORCEDINTROSPECTION = *PFORCEINTROSPECTION == 1 ? true : (*PFORCEINTROSPECTION == 2 ? g_pHyprRenderer->isNvidia() : false); // 0 - no, 1 - yes, 2 - nvidia only - - if (USERFORCEDINTROSPECTION || m_RenderData.forceIntrospection || !FBPROPERSIZE || m_sFinalScreenShader.program > 0 || - (PRBO && pMonitor->vecPixelSize != PRBO->getFB()->m_vSize) || passRequiresIntrospection(pMonitor)) { - // we have to offload - // bind the offload Hypr Framebuffer - m_RenderData.pCurrentMonData->offloadFB.bind(); - m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offloadFB; - m_bOffloadedFramebuffer = true; - } else { - // we can render to the rbo / fbo (fake) directly - const auto PFBO = fb ? fb : PRBO->getFB(); - m_RenderData.currentFB = PFBO; - if (PFBO->getStencilTex() != m_RenderData.pCurrentMonData->stencilTex) - PFBO->addStencil(m_RenderData.pCurrentMonData->stencilTex); - - PFBO->bind(); - m_bOffloadedFramebuffer = false; - } + m_RenderData.pCurrentMonData->offloadFB.bind(); + m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offloadFB; + m_bOffloadedFramebuffer = true; m_RenderData.mainFB = m_RenderData.currentFB; - m_RenderData.outFB = fb ? fb : PRBO->getFB(); + m_RenderData.outFB = fb ? fb : g_pHyprRenderer->getCurrentRBO()->getFB(); } void CHyprOpenGLImpl::end() { @@ -952,13 +826,12 @@ void CHyprOpenGLImpl::end() { // reset our data m_RenderData.pMonitor.reset(); - m_RenderData.mouseZoomFactor = 1.f; - m_RenderData.mouseZoomUseMouse = true; - m_RenderData.forceIntrospection = false; - m_RenderData.blockScreenShader = false; - m_RenderData.currentFB = nullptr; - m_RenderData.mainFB = nullptr; - m_RenderData.outFB = nullptr; + m_RenderData.mouseZoomFactor = 1.f; + m_RenderData.mouseZoomUseMouse = true; + m_RenderData.blockScreenShader = false; + m_RenderData.currentFB = nullptr; + m_RenderData.mainFB = nullptr; + m_RenderData.outFB = nullptr; // if we dropped to offMain, release it now. // if there is a plugin constantly using it, this might be a bit slow, diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index d7abdf63..7b7b7e6f 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -126,7 +126,6 @@ struct SCurrentRenderData { float mouseZoomFactor = 1.f; bool mouseZoomUseMouse = true; // true by default bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() bool blockScreenShader = false; bool simplePass = false; @@ -322,8 +321,6 @@ class CHyprOpenGLImpl { void preBlurForCurrentMonitor(); - bool passRequiresIntrospection(PHLMONITOR pMonitor); - friend class CHyprRenderer; friend class CTexPassElement; friend class CPreBlurElement; diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 81b918ac..5068cbbc 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -17,10 +17,6 @@ bool CRenderPass::single() const { return m_vPassElements.size() == 1; } -bool CRenderPass::needsIntrospection() const { - return true; -} - void CRenderPass::add(SP el) { m_vPassElements.emplace_back(makeShared(CRegion{}, el)); } diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp index a0810155..bbc55d2c 100644 --- a/src/render/pass/Pass.hpp +++ b/src/render/pass/Pass.hpp @@ -10,7 +10,6 @@ class CRenderPass { public: bool empty() const; bool single() const; - bool needsIntrospection() const; void add(SP elem); void clear(); From d11d0697155e0896c4ab76406e6d5dcf35abff05 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 1 Feb 2025 09:29:06 +0200 Subject: [PATCH 1166/2393] CI/Nix: remove deprecated magic-nix-cache-action --- .github/workflows/nix-build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index a98468ac..5b2e81cf 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -19,7 +19,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - uses: cachix/cachix-action@v15 with: From 5b43c106bd1cde9ac0b5626130890cde4de0b245 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 1 Feb 2025 14:44:20 +0000 Subject: [PATCH 1167/2393] animation: don't immediately disconnect active vars during tick (#9272) --- CMakeLists.txt | 2 +- src/managers/AnimationManager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a34d677c..9c286831 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.4.0) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 5be7aa33..29f669dc 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -43,7 +43,7 @@ CHyprAnimationManager::CHyprAnimationManager() { template static void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { if (warp || av.value() == av.goal()) { - av.warp(); + av.warp(true, false); return; } @@ -53,7 +53,7 @@ static void updateVariable(CAnimatedVariable& av, const float POINTY, b static void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { if (warp || av.value() == av.goal()) { - av.warp(); + av.warp(true, false); return; } From c6f672257bd2ae98f4fd7a6a273b2d1d3e944baa Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:08:30 +0000 Subject: [PATCH 1168/2393] desktop: move popup and subsurface ctors to factories makes sure m_pSelf is set before we do anything like possibly adding children fixes #9275 supersedes #9276 --- src/desktop/LayerSurface.cpp | 7 ++--- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 41 ++++++++++++++++++---------- src/desktop/Popup.hpp | 8 ++++-- src/desktop/Subsurface.cpp | 53 ++++++++++++++++++++++++------------ src/desktop/Subsurface.hpp | 10 ++++--- src/desktop/Window.cpp | 6 ++-- src/desktop/Window.hpp | 2 +- 8 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 78dae0a9..f4ffaedf 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -31,10 +31,9 @@ PHLLS CLayerSurface::create(SP resource) { pLS->szNamespace = resource->layerNamespace; - pLS->layer = resource->current.layer; - pLS->popupHead = makeUnique(pLS); - pLS->popupHead->m_pSelf = pLS->popupHead; - pLS->monitor = pMonitor; + pLS->layer = resource->current.layer; + pLS->popupHead = CPopup::create(pLS); + pLS->monitor = pMonitor; pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index ab259733..f2be7459 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -59,7 +59,7 @@ class CLayerSurface { CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; - UP popupHead; + SP popupHead; void onDestroy(); void onMap(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index dea94f55..20ff49d7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -12,23 +12,37 @@ #include "../render/OpenGL.hpp" #include -CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { - initAllSignals(); +SP CPopup::create(PHLWINDOW pOwner) { + auto popup = SP(new CPopup()); + popup->m_pWindowOwner = pOwner; + popup->m_pSelf = popup; + popup->initAllSignals(); + return popup; } -CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { - initAllSignals(); +SP CPopup::create(PHLLS pOwner) { + auto popup = SP(new CPopup()); + popup->m_pLayerOwner = pOwner; + popup->m_pSelf = popup; + popup->initAllSignals(); + return popup; } -CPopup::CPopup(SP popup, WP pOwner) : - m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(popup->surface->surface.lock(), this); +SP CPopup::create(SP resource, WP pOwner) { + auto popup = SP(new CPopup()); + popup->m_pResource = resource; + popup->m_pWindowOwner = pOwner->m_pWindowOwner; + popup->m_pLayerOwner = pOwner->m_pLayerOwner; + popup->m_pParent = pOwner; + popup->m_pSelf = popup; + popup->m_pWLSurface = CWLSurface::create(); + popup->m_pWLSurface->assign(resource->surface->surface.lock(), popup.get()); - m_vLastSize = popup->surface->current.geometry.size(); - reposition(); + popup->m_vLastSize = resource->surface->current.geometry.size(); + popup->reposition(); - initAllSignals(); + popup->initAllSignals(); + return popup; } CPopup::~CPopup() { @@ -59,7 +73,7 @@ void CPopup::initAllSignals() { } void CPopup::onNewPopup(SP popup) { - const auto& POPUP = m_vChildren.emplace_back(makeShared(popup, m_pSelf)); + const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf)); POPUP->m_pSelf = POPUP; Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } @@ -91,8 +105,7 @@ void CPopup::onMap() { g_pInputManager->simulateMouseMovement(); - m_pSubsurfaceHead = makeUnique(m_pSelf); - m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; + m_pSubsurfaceHead = CSubsurface::create(m_pSelf); //unconstrain(); sendScale(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 6051f7eb..a64af7eb 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -10,11 +10,11 @@ class CXDGPopupResource; class CPopup { public: // dummy head nodes - CPopup(PHLWINDOW pOwner); - CPopup(PHLLS pOwner); + static SP create(PHLWINDOW pOwner); + static SP create(PHLLS pOwner); // real nodes - CPopup(SP popup, WP pOwner); + static SP create(SP popup, WP pOwner); ~CPopup(); @@ -45,6 +45,8 @@ class CPopup { bool m_bMapped = false; private: + CPopup() = default; + // T1 owners, each popup has to have one of these PHLWINDOWREF m_pWindowOwner; PHLLSREF m_pLayerOwner; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 1d938f39..33ee3553 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -7,28 +7,45 @@ #include "../render/Renderer.hpp" #include "../managers/input/InputManager.hpp" -CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { - initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); +UP CSubsurface::create(PHLWINDOW pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pWindowParent = pOwner; + subsurface->m_pSelf = subsurface; + + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); + return subsurface; } -CSubsurface::CSubsurface(WP pOwner) : m_pPopupParent(pOwner) { - initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); +UP CSubsurface::create(WP pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pPopupParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); + return subsurface; } -CSubsurface::CSubsurface(SP pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(pSubsurface->surface.lock(), this); - initSignals(); - initExistingSubsurfaces(pSubsurface->surface.lock()); +UP CSubsurface::create(SP pSubsurface, PHLWINDOW pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pWindowParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->m_pWLSurface = CWLSurface::create(); + subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); + return subsurface; } -CSubsurface::CSubsurface(SP pSubsurface, WP pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(pSubsurface->surface.lock(), this); - initSignals(); - initExistingSubsurfaces(pSubsurface->surface.lock()); +UP CSubsurface::create(SP pSubsurface, WP pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pPopupParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->m_pWLSurface = CWLSurface::create(); + subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); + return subsurface; } void CSubsurface::initSignals() { @@ -131,9 +148,9 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { WP PSUBSURFACE; if (!m_pWindowParent.expired()) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pWindowParent.lock())); + PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pWindowParent.lock())); else if (m_pPopupParent) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pPopupParent)); + PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent)); PSUBSURFACE->m_pSelf = PSUBSURFACE; diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index 41958671..2983c7c1 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -10,12 +10,12 @@ class CWLSubsurfaceResource; class CSubsurface { public: // root dummy nodes - CSubsurface(PHLWINDOW pOwner); - CSubsurface(WP pOwner); + static UP create(PHLWINDOW pOwner); + static UP create(WP pOwner); // real nodes - CSubsurface(SP pSubsurface, PHLWINDOW pOwner); - CSubsurface(SP pSubsurface, WP pOwner); + static UP create(SP pSubsurface, PHLWINDOW pOwner); + static UP create(SP pSubsurface, WP pOwner); ~CSubsurface() = default; @@ -37,6 +37,8 @@ class CSubsurface { WP m_pSelf; private: + CSubsurface() = default; + struct { CHyprSignalListener destroySubsurface; CHyprSignalListener commitSubsurface; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 0f6bac99..6e580e49 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -571,10 +571,8 @@ void CWindow::onMap() { if (m_bIsX11) return; - m_pSubsurfaceHead = makeUnique(m_pSelf.lock()); - m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; - m_pPopupHead = makeUnique(m_pSelf.lock()); - m_pPopupHead->m_pSelf = m_pPopupHead; + m_pSubsurfaceHead = CSubsurface::create(m_pSelf.lock()); + m_pPopupHead = CPopup::create(m_pSelf.lock()); } void CWindow::onBorderAngleAnimEnd(WP pav) { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ce2f8eb2..3573d7ab 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -298,7 +298,7 @@ class CWindow { // desktop components UP m_pSubsurfaceHead; - UP m_pPopupHead; + SP m_pPopupHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; From 88adae73ba3b57490fdef1041f58fcc6a15a54c8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:31:31 +0000 Subject: [PATCH 1169/2393] pass: add input region debug --- src/render/pass/Pass.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 5068cbbc..60c1bc30 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -8,6 +8,7 @@ #include "../../managers/eventLoop/EventLoopManager.hpp" #include "../../render/Renderer.hpp" #include "../../Compositor.hpp" +#include "../../protocols/core/Compositor.hpp" bool CRenderPass::empty() const { return false; @@ -242,6 +243,22 @@ void CRenderPass::renderDebugData() { if (g_pCompositor->m_pLastWindow) renderHLSurface(debugData.lastWindowText, g_pCompositor->m_pLastWindow->m_pWLSurface->resource(), Colors::LIGHT_BLUE.modifyA(0.1F)); + if (g_pSeatManager->state.pointerFocus) { + if (g_pSeatManager->state.pointerFocus->current.input.intersect(CBox{{}, g_pSeatManager->state.pointerFocus->current.size}).getExtents().size() != + g_pSeatManager->state.pointerFocus->current.size) { + auto hlSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); + if (hlSurface) { + auto BOX = hlSurface->getSurfaceBoxGlobal(); + if (BOX) { + auto region = g_pSeatManager->state.pointerFocus->current.input.copy() + .scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale) + .translate(BOX->pos() - g_pHyprOpenGL->m_RenderData.pMonitor->vecPosition); + g_pHyprOpenGL->renderRectWithDamage(box, CHyprColor{0.8F, 0.8F, 0.2F, 0.4F}, region); + } + } + } + } + const auto DISCARDED_ELEMENTS = std::count_if(m_vPassElements.begin(), m_vPassElements.end(), [](const auto& e) { return e->discard; }); auto tex = g_pHyprOpenGL->renderText(std::format("occlusion layers: {}\npass elements: {} ({} discarded)\nviewport: {:X0}", occludedRegions.size(), m_vPassElements.size(), DISCARDED_ELEMENTS, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize), From e380b6ed66aceeae8fde84b4baed0d91550e9f4c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:49:10 +0000 Subject: [PATCH 1170/2393] popup: take xdg geometry into account in input calcs fixes #9023 --- src/desktop/Popup.cpp | 12 +++++++----- src/protocols/core/Compositor.cpp | 4 +--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 20ff49d7..e66cebcd 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -339,22 +339,24 @@ void CPopup::breadthfirst(std::function, void*)> fn, void* data) WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { std::vector> popups; - breadthfirst([](WP popup, void* data) { ((std::vector>*)data)->push_back(popup); }, &popups); + breadthfirst([&popups](WP popup, void* data) { popups.push_back(popup); }, &popups); for (auto const& p : popups | std::views::reverse) { if (!p->m_pResource || !p->m_bMapped) continue; if (!allowsInput) { - const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); + const Vector2D offset = + p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); const auto BOX = CBox{p->coordsGlobal() + offset, size}; if (BOX.containsPoint(globalCoords)) return p; } else { - const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const auto REGION = + const Vector2D offset = + p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 93683993..92c3c425 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -308,9 +308,7 @@ void CWLSurfaceResource::breadthfirst(std::function, std::pair, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput) { std::vector, Vector2D>> surfs; - breadthfirst([](SP surf, const Vector2D& offset, - void* data) { ((std::vector, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, - &surfs); + breadthfirst([&surfs](SP surf, const Vector2D& offset, void* data) { surfs.emplace_back(std::make_pair<>(surf, offset)); }, &surfs); for (auto const& [surf, pos] : surfs | std::views::reverse) { if (!allowsInput) { From 64fefa3749868e6170b6275963c6528456a7d9f2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 19:10:19 +0000 Subject: [PATCH 1171/2393] desktop: move popups to UPs and fix missing subsurface resource fixes #9283 --- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 15 ++++++++------- src/desktop/Popup.hpp | 8 ++++---- src/desktop/Subsurface.cpp | 2 ++ src/desktop/Window.hpp | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index f2be7459..ab259733 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -59,7 +59,7 @@ class CLayerSurface { CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; - SP popupHead; + UP popupHead; void onDestroy(); void onMap(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index e66cebcd..4accb58f 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -12,24 +12,24 @@ #include "../render/OpenGL.hpp" #include -SP CPopup::create(PHLWINDOW pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(PHLWINDOW pOwner) { + auto popup = UP(new CPopup()); popup->m_pWindowOwner = pOwner; popup->m_pSelf = popup; popup->initAllSignals(); return popup; } -SP CPopup::create(PHLLS pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(PHLLS pOwner) { + auto popup = UP(new CPopup()); popup->m_pLayerOwner = pOwner; popup->m_pSelf = popup; popup->initAllSignals(); return popup; } -SP CPopup::create(SP resource, WP pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(SP resource, WP pOwner) { + auto popup = UP(new CPopup()); popup->m_pResource = resource; popup->m_pWindowOwner = pOwner->m_pWindowOwner; popup->m_pLayerOwner = pOwner->m_pLayerOwner; @@ -282,7 +282,8 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { - auto cpy = m_vChildren; + std::vector> cpy; + std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); for (auto const& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index a64af7eb..0bca436c 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -10,11 +10,11 @@ class CXDGPopupResource; class CPopup { public: // dummy head nodes - static SP create(PHLWINDOW pOwner); - static SP create(PHLLS pOwner); + static UP create(PHLWINDOW pOwner); + static UP create(PHLLS pOwner); // real nodes - static SP create(SP popup, WP pOwner); + static UP create(SP popup, WP pOwner); ~CPopup(); @@ -64,7 +64,7 @@ class CPopup { bool m_bInert = false; // - std::vector> m_vChildren; + std::vector> m_vChildren; UP m_pSubsurfaceHead; struct { diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 33ee3553..db106a09 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -29,6 +29,7 @@ UP CSubsurface::create(WP pOwner) { UP CSubsurface::create(SP pSubsurface, PHLWINDOW pOwner) { auto subsurface = UP(new CSubsurface()); subsurface->m_pWindowParent = pOwner; + subsurface->m_pSubsurface = pSubsurface; subsurface->m_pSelf = subsurface; subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); @@ -40,6 +41,7 @@ UP CSubsurface::create(SP pSubsurface, PHLWI UP CSubsurface::create(SP pSubsurface, WP pOwner) { auto subsurface = UP(new CSubsurface()); subsurface->m_pPopupParent = pOwner; + subsurface->m_pSubsurface = pSubsurface; subsurface->m_pSelf = subsurface; subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 3573d7ab..ce2f8eb2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -298,7 +298,7 @@ class CWindow { // desktop components UP m_pSubsurfaceHead; - SP m_pPopupHead; + UP m_pPopupHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; From 97a24ec6f3abd2b2ce4c2e00627679a2713848dd Mon Sep 17 00:00:00 2001 From: micha4w Date: Sun, 2 Feb 2025 12:39:32 +0100 Subject: [PATCH 1172/2393] Nix: change meson buildtype from debugoptimized to debug --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index a4ddc63b..6a703713 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -155,7 +155,7 @@ in mesonBuildType = if debug - then "debugoptimized" + then "debug" else "release"; mesonFlags = flatten [ From 373108102c85f9568a8f28b7a85c5500634ca9a4 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 2 Feb 2025 09:31:04 -0800 Subject: [PATCH 1173/2393] protocols: implement hyprland-ctm-control rev 2 (#9267) * protocols: implement hyprland-ctm-control v2 * bump h-p and nix --- CMakeLists.txt | 2 +- flake.lock | 24 ++++++++++++------------ protocols/meson.build | 2 +- src/managers/ProtocolManager.cpp | 2 +- src/protocols/CTMControl.cpp | 22 +++++++++++++++++++++- src/protocols/CTMControl.hpp | 5 ++++- subprojects/hyprland-protocols | 2 +- 7 files changed, 41 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c286831..34e9a8ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) -pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.0) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2) if(hyprland_protocols_dep_FOUND) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") diff --git a/flake.lock b/flake.lock index dfdd8c5b..7637a2c7 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1738183445, - "narHash": "sha256-C1He3N1SA8D2u+TSlldbA9wiYwDvXI4GxX3zKaeD7qU=", + "lastModified": 1738456976, + "narHash": "sha256-cufyHbOMnSt9V4w4OVSzNcpJ+8DwzRZRJaca2Q89KVI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "48a000cf35dd10bfeb231152735aebbe875f4b74", + "rev": "257b2050790ab3b1eb389e0f8bdc400eb9510139", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1738018829, - "narHash": "sha256-5Ol5iahMlELx3lWuChyZsqqLk6sP6aqaJCJFw92OZGo=", + "lastModified": 1738437059, + "narHash": "sha256-J+8ecqaP3zD9GHeN8Y4hUapoELSoggp0IZI8laTFt/0=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "12cd7034e441a5ebfdef1a090c0788413b4a635b", + "rev": "5ac80e3686a4dfa55d2bd15c81a266b89594a295", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1737556638, - "narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=", + "lastModified": 1738422629, + "narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5", + "rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737885589, - "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", + "lastModified": 1738410390, + "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", + "rev": "3a228057f5b619feb3186e986dbe76278d707b6e", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index aa20940d..6ed1b11a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,7 +7,7 @@ wayland_protos = dependency( hyprland_protos = dependency( 'hyprland-protocols', - version: '>=0.6', + version: '>=0.6.2', fallback: 'hyprland-protocols', ) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index d3270fe2..62736ae5 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -167,7 +167,7 @@ CProtocolManager::CProtocolManager() { PROTO::xdgDialog = makeUnique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = makeUnique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); - PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); + PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); if (*PENABLEXXCM) { diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 5560271f..322f95e2 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -15,6 +15,9 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPsetSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4, wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) { + if (blocked) + return; + const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output); if UNLIKELY (!OUTPUTRESOURCE) @@ -41,6 +44,9 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPsetCommit([this](CHyprlandCtmControlManagerV1* r) { + if (blocked) + return; + LOGM(LOG, "Committing ctms to outputs"); for (auto& m : g_pCompositor->m_vMonitors) { @@ -54,7 +60,17 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPversion() >= 2) + resource->sendBlocked(); +} + CHyprlandCTMControlResource::~CHyprlandCTMControlResource() { + if (blocked) + return; + for (auto& m : g_pCompositor->m_vMonitors) { PROTO::ctm->setCTM(m, Mat3x3::identity()); } @@ -69,7 +85,6 @@ CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* ifa } void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); if UNLIKELY (!RESOURCE->good()) { @@ -78,6 +93,11 @@ void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uin return; } + if (m_pManager) + RESOURCE->block(); + else + m_pManager = RESOURCE; + LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get()); } diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index 2c168acd..eb54a3aa 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -16,11 +16,13 @@ class CHyprlandCTMControlResource { ~CHyprlandCTMControlResource(); bool good(); + void block(); private: SP resource; std::unordered_map ctms; + bool blocked = false; }; class CHyprlandCTMControlProtocol : public IWaylandProtocol { @@ -37,6 +39,7 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { // std::vector> m_vManagers; + WP m_pManager; // struct SCTMData { @@ -51,4 +54,4 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { namespace PROTO { inline UP ctm; -}; \ No newline at end of file +}; diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 4c75dd5c..755aef8d 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 +Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed From 70d94fec134c4b91916812901310e7765acf8405 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:34:26 +0300 Subject: [PATCH 1174/2393] refactor: clang-tidy in compositor (#9241) Co-authored-by: Alexandr Krylov --- src/Compositor.cpp | 90 ++++++++++++++------------------- src/Compositor.hpp | 5 +- src/macros.hpp | 3 +- src/managers/KeybindManager.cpp | 2 - 4 files changed, 40 insertions(+), 60 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 1daccbfd..6a241472 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,3 +1,4 @@ +#include #include #include "Compositor.hpp" @@ -21,14 +22,12 @@ #include #include #include -#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" #ifdef USES_SYSTEMD #include // for SdNotify #endif -#include "helpers/varlist/VarList.hpp" #include "helpers/fs/FsUtils.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" @@ -264,7 +263,6 @@ static bool filterGlobals(const wl_client* client, const wl_global* global, void // void CCompositor::initServer(std::string socketName, int socketFd) { - if (m_bOnlyConfigVerification) { g_pHookSystem = makeUnique(); g_pKeybindManager = makeUnique(); @@ -500,7 +498,7 @@ void CCompositor::cleanEnvironment() { "dbus-update-activation-environment 2>/dev/null && " #endif "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; - g_pKeybindManager->spawn(CMD); + CKeybindManager::spawn(CMD); } } @@ -738,7 +736,7 @@ void CCompositor::startCompositor() { "dbus-update-activation-environment 2>/dev/null && " #endif "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; - g_pKeybindManager->spawn(CMD); + CKeybindManager::spawn(CMD); } Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); @@ -839,12 +837,7 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { } bool CCompositor::monitorExists(PHLMONITOR pMonitor) { - for (auto const& m : m_vRealMonitors) { - if (m == pMonitor) - return true; - } - - return false; + return std::ranges::any_of(m_vRealMonitors, [&](const PHLMONITOR& m) { return m == pMonitor; }); } PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) { @@ -1175,8 +1168,8 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface pWindow->m_bIsUrgent = false; // Send an event - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", pWindow->m_szClass + "," + pWindow->m_szTitle}); - g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)pWindow.get())}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = pWindow->m_szClass + "," + pWindow->m_szTitle}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", (uintptr_t)pWindow.get())}); EMIT_HOOK_EVENT("activeWindow", pWindow); @@ -1217,8 +1210,8 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo if (!pSurface) { g_pSeatManager->setKeyboardFocus(nullptr); - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused - g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = ","}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = ""}); EMIT_HOOK_EVENT("keyboardFocus", (SP)nullptr); m_pLastFocus.reset(); return; @@ -1395,7 +1388,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { toMove.insert(toMove.begin(), pw); for (auto const& w : m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) { + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::ranges::find(toMove, w) == toMove.end()) { x11Stack(w, top, x11Stack); } } @@ -1454,7 +1447,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { for (auto const& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { - if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { + if (!lsl.empty() && std::ranges::find_if(lsl, [&](auto& other) { return other == ls; }) != lsl.end()) { std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); } } @@ -1477,7 +1470,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { } void CCompositor::addToFadingOutSafe(PHLLS pLS) { - const auto FOUND = std::find_if(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), [&](auto& other) { return other.lock() == pLS; }); + const auto FOUND = std::ranges::find_if(m_vSurfacesFadingOut, [&](auto& other) { return other.lock() == pLS; }); if (FOUND != m_vSurfacesFadingOut.end()) return; // if it's already added, don't add it. @@ -1490,7 +1483,7 @@ void CCompositor::removeFromFadingOutSafe(PHLLS ls) { } void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { - const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); + const auto FOUND = std::ranges::find_if(m_vWindowsFadingOut, [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); if (FOUND != m_vWindowsFadingOut.end()) return; // if it's already added, don't add it. @@ -1609,7 +1602,7 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks // auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double { - double dot = a.x * b.x + a.y * b.y; + double dot = (a.x * b.x) + (a.y * b.y); double ang = std::acos(dot / (a.size() * b.size())); return ang; }; @@ -1728,7 +1721,7 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight; - return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); + return VECNOTINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); } PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) { @@ -1902,7 +1895,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor - if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) + if (m_mMonitorIDMap.contains(name) && !std::ranges::any_of(m_vRealMonitors, [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) return m_mMonitorIDMap[name]; // otherwise, find minimum available ID that is not in the map @@ -1912,7 +1905,7 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { } MONITORID nextID = 0; - while (usedIDs.count(nextID) > 0) { + while (usedIDs.contains(nextID)) { nextID++; } m_mMonitorIDMap[name] = nextID; @@ -1920,7 +1913,6 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { } void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) { - const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace; @@ -1992,17 +1984,18 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING))); const auto PNEWWORKSPACE = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB : PWORKSPACEA; - g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PNEWWORKSPACE->m_szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspace", .data = PNEWWORKSPACE->m_szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspacev2", .data = std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)}); EMIT_HOOK_EVENT("workspace", PNEWWORKSPACE); } // event - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEA->m_szName + "," + pMonitorB->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); EMIT_HOOK_EVENT("moveWorkspace", (std::vector{PWORKSPACEA, pMonitorB})); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEB->m_szName + "," + pMonitorA->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); + EMIT_HOOK_EVENT("moveWorkspace", (std::vector{PWORKSPACEB, pMonitorA})); } @@ -2081,7 +2074,6 @@ PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) { } void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) { - if (!pWorkspace || !pMonitor) return; @@ -2188,8 +2180,8 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo updateSuspendedStates(); // event - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = pWorkspace->m_szName + "," + pMonitor->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); EMIT_HOOK_EVENT("moveWorkspace", (std::vector{pWorkspace, pMonitor})); } @@ -2200,12 +2192,8 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { for (auto const& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) continue; - - if (w->m_iID < lowestID) - lowestID = w->m_iID; - - if (w->m_iID > highestID) - highestID = w->m_iID; + lowestID = std::min(w->m_iID, lowestID); + highestID = std::max(w->m_iID, highestID); } return std::clamp(id, lowestID, highestID) != id; @@ -2281,7 +2269,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen()) setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); - const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE); + const bool CHANGEINTERNAL = !PWINDOW->m_bPinned && CURRENT_EFFECTIVE_MODE != EFFECTIVE_MODE; if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) { PWINDOW->m_bPinned = true; @@ -2308,7 +2296,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE; PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE; - g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "fullscreen", .data = std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); EMIT_HOOK_EVENT("fullscreen", PWINDOW); PWINDOW->updateDynamicRules(); @@ -2575,8 +2563,8 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con X = xIsPercent ? std::stof(x) * 0.01 * PMONITOR->vecSize.x : std::stoi(x); Y = yIsPercent ? std::stof(y) * 0.01 * PMONITOR->vecSize.y : std::stoi(y); } else { - X = xIsPercent ? std::stof(x) * 0.01 * relativeTo.x + relativeTo.x : std::stoi(x) + relativeTo.x; - Y = yIsPercent ? std::stof(y) * 0.01 * relativeTo.y + relativeTo.y : std::stoi(y) + relativeTo.y; + X = xIsPercent ? (std::stof(x) * 0.01 * relativeTo.x) + relativeTo.x : std::stoi(x) + relativeTo.x; + Y = yIsPercent ? (std::stof(y) * 0.01 * relativeTo.y) + relativeTo.y : std::stoi(y) + relativeTo.y; } return Vector2D(X, Y); @@ -2613,8 +2601,8 @@ void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) { const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_iID) : std::to_string(WORKSPACE_INVALID); const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_szName : "?"; - g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + WORKSPACE_NAME}); - g_pEventManager->postEvent(SHyprIPCEvent{"focusedmonv2", pMonitor->szName + "," + WORKSPACE_ID}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmon", .data = pMonitor->szName + "," + WORKSPACE_NAME}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmonv2", .data = pMonitor->szName + "," + WORKSPACE_ID}); EMIT_HOOK_EVENT("focusedMon", pMonitor); m_pLastMonitor = pMonitor->self; @@ -2804,14 +2792,10 @@ void CCompositor::arrangeMonitors() { // Finds the max and min values of explicitely placed monitors. for (auto const& m : arranged) { - if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight) - maxXOffsetRight = m->vecPosition.x + m->vecSize.x; - if (m->vecPosition.x < maxXOffsetLeft) - maxXOffsetLeft = m->vecPosition.x; - if (m->vecPosition.y + m->vecSize.y > maxYOffsetDown) - maxYOffsetDown = m->vecPosition.y + m->vecSize.y; - if (m->vecPosition.y < maxYOffsetUp) - maxYOffsetUp = m->vecPosition.y; + maxXOffsetRight = std::max(m->vecPosition.x + m->vecSize.x, maxXOffsetRight); + maxXOffsetLeft = std::min(m->vecPosition.x, maxXOffsetLeft); + maxYOffsetDown = std::max(m->vecPosition.y + m->vecSize.y, maxYOffsetDown); + maxYOffsetUp = std::min(m->vecPosition.y, maxYOffsetUp); } }; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index e55d7e1e..787ead08 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -1,15 +1,12 @@ #pragma once -#include #include -#include "defines.hpp" #include "managers/XWaylandManager.hpp" #include "managers/KeybindManager.hpp" #include "managers/SessionLockManager.hpp" #include "desktop/Window.hpp" #include "protocols/types/ColorManagement.hpp" -#include "helpers/memory/Memory.hpp" #include #include @@ -170,7 +167,7 @@ class CCompositor { uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; - rlimit m_sOriginalNofile = {0}; + rlimit m_sOriginalNofile = {}; }; inline UP g_pCompositor; diff --git a/src/macros.hpp b/src/macros.hpp index 0a3be8bc..a5176675 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -38,7 +38,8 @@ #define DYNLISTENER(name) CHyprWLListener hyprListener_##name #define DYNMULTILISTENER(name) wl_listener listen_##name -#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) +#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) +#define VECNOTINRECT(vec, x1, y1, x2, y2) ((vec).x < (x1) || (vec).x >= (x2) || (vec).y < (y1) || (vec).y >= (y2)) #define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < (delta)) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 247550ae..bc5d36c8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -12,8 +12,6 @@ #include "TokenManager.hpp" #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" -#include "helpers/varlist/VarList.hpp" -#include "../helpers/signal/Signal.hpp" #include "../managers/HookSystemManager.hpp" #include "../managers/input/InputManager.hpp" #include "../managers/LayoutManager.hpp" From 31431a92714ab7f53c25d2ececb26c5b7264b7e3 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sun, 2 Feb 2025 22:25:29 +0300 Subject: [PATCH 1175/2393] protocols: Support content-type-v1 proto (#9226) --- CMakeLists.txt | 9 ++ meson.build | 4 + protocols/meson.build | 1 + src/Compositor.cpp | 3 +- src/config/ConfigDescriptions.hpp | 13 +-- src/config/ConfigManager.cpp | 24 ++++- src/desktop/Window.cpp | 15 +++ src/desktop/Window.hpp | 159 ++++++++++++++-------------- src/desktop/WindowRule.cpp | 7 +- src/desktop/WindowRule.hpp | 2 + src/events/Windows.cpp | 9 +- src/helpers/Monitor.cpp | 5 +- src/macros.hpp | 1 + src/managers/ProtocolManager.cpp | 3 + src/protocols/ContentType.cpp | 95 +++++++++++++++++ src/protocols/ContentType.hpp | 59 +++++++++++ src/protocols/core/Compositor.hpp | 2 + src/protocols/types/ContentType.cpp | 37 +++++++ src/protocols/types/ContentType.hpp | 18 ++++ src/render/Renderer.cpp | 14 ++- 20 files changed, 386 insertions(+), 94 deletions(-) create mode 100644 src/protocols/ContentType.cpp create mode 100644 src/protocols/ContentType.hpp create mode 100644 src/protocols/types/ContentType.cpp create mode 100644 src/protocols/types/ContentType.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 34e9a8ed..a98f697d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,15 @@ pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) +string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) +list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR) +list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR) +list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH) + add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") +add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR}) +add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR}) +add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH}) add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") @@ -368,6 +376,7 @@ protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolnew("staging/security-context" "security-context-v1" false) +protocolnew("staging/content-type" "content-type-v1" false) protocolwayland() diff --git a/meson.build b/meson.build index ae6e3940..a367b166 100644 --- a/meson.build +++ b/meson.build @@ -36,7 +36,11 @@ hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprutils = dependency('hyprutils', version: '>= 0.2.3') +aquamarine_version_list = aquamarine.version().split('.') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_MINOR=@0@'.format(aquamarine_version_list.get(1))], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_PATCH=@0@'.format(aquamarine_version_list.get(2))], language: 'cpp') add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') diff --git a/protocols/meson.build b/protocols/meson.build index 6ed1b11a..7c57470b 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -70,6 +70,7 @@ protocols = [ wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', + wayland_protocol_dir / 'staging/content-type/content-type-v1.xml', ] wl_protocols = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6a241472..0aa0f13d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -72,6 +72,7 @@ using namespace Hyprutils::String; using namespace Aquamarine; +using enum NContentType::eContentType; static int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -2323,7 +2324,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // ignore if DS is disabled. - if (*PDIRECTSCANOUT) + if (*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && PWINDOW->getContentType() == CONTENT_TYPE_GAME)) g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 2fa86817..28cd29c4 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1314,9 +1314,9 @@ inline static const std::vector CONFIG_OPTIONS = { SConfigOptionDescription{ .value = "render:direct_scanout", .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " - "recommended to set this to false if the fullscreen application shows graphical glitches.", - .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + "recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2}, }, SConfigOptionDescription{ .value = "render:expand_undersized_textures", @@ -1362,9 +1362,10 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "cursor:no_break_fs_vrr", - .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)", - .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (may require no_hardware_cursors = true) " + "0 - off, 1 - on, 2 - auto (on with content type 'game')", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2}, }, SConfigOptionDescription{ .value = "cursor:min_refresh_rate", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8bb6d157..42a1a91c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -26,6 +26,7 @@ #include "../plugins/PluginSystem.hpp" #include "managers/HookSystemManager.hpp" +#include "protocols/types/ContentType.hpp" #include #include #include @@ -621,7 +622,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); - m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f}); @@ -1347,6 +1348,14 @@ std::vector> CConfigManager::getMatchingRules(PHLWINDOW pWindow, continue; } + if (!rule->szContentType.empty()) { + try { + const auto contentType = NContentType::fromString(rule->szContentType); + if (pWindow->getContentType() != contentType) + continue; + } catch (std::exception& e) { Debug::log(ERR, "Rule \"content:{}\" failed with: {}", rule->szContentType, e.what()); } + } + if (!rule->szWorkspace.empty()) { const auto PWORKSPACE = pWindow->m_pWorkspace; @@ -2361,6 +2370,7 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& const auto FOCUSPOS = VALUE.find("focus:"); const auto FULLSCREENSTATEPOS = VALUE.find("fullscreenstate:"); const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); + const auto CONTENTTYPEPOS = VALUE.find("content:"); // find workspacepos that isn't onworkspacepos size_t WORKSPACEPOS = std::string::npos; @@ -2373,8 +2383,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& currentPos = VALUE.find("workspace:", currentPos + 1); } - const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, - FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS}; + const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, + FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, CONTENTTYPEPOS}; if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; @@ -2411,6 +2421,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& min = WORKSPACEPOS; if (FOCUSPOS > pos && FOCUSPOS < min) min = FOCUSPOS; + if (CONTENTTYPEPOS > pos && CONTENTTYPEPOS < min) + min = CONTENTTYPEPOS; result = result.substr(0, min - pos); @@ -2469,6 +2481,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (ONWORKSPACEPOS != std::string::npos) rule->szOnWorkspace = extract(ONWORKSPACEPOS + 12); + if (CONTENTTYPEPOS != std::string::npos) + rule->szContentType = extract(CONTENTTYPEPOS + 8); + if (RULE == "unset") { std::erase_if(m_vWindowRules, [&](const auto& other) { if (!other->v2) @@ -2513,6 +2528,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (!rule->szOnWorkspace.empty() && rule->szOnWorkspace != other->szOnWorkspace) return false; + if (!rule->szContentType.empty() && rule->szContentType != other->szContentType) + return false; + return true; } }); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 6e580e49..6a523eec 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -15,6 +15,7 @@ #include "../managers/AnimationManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/ContentType.hpp" #include "../xwayland/XWayland.hpp" #include "../helpers/Color.hpp" #include "../events/Events.hpp" @@ -29,6 +30,7 @@ using namespace Hyprutils::String; using namespace Hyprutils::Animation; +using enum NContentType::eContentType; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -1724,3 +1726,16 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional else if (m_pXDGSurface && m_pXDGSurface->toplevel) m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor()); } + +NContentType::eContentType CWindow::getContentType() { + return m_pWLSurface->resource()->contentType.valid() ? m_pWLSurface->resource()->contentType->value : CONTENT_TYPE_NONE; +} + +void CWindow::setContentType(NContentType::eContentType contentType) { + if (!m_pWLSurface->resource()->contentType.valid()) + m_pWLSurface->resource()->contentType = PROTO::contentType->getContentType(m_pWLSurface->resource()); + // else disallow content type change if proto is used? + + Debug::log(INFO, "ContentType for window {}", (int)contentType); + m_pWLSurface->resource()->contentType->value = contentType; +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ce2f8eb2..b3c3d84f 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -19,6 +19,7 @@ #include "WLSurface.hpp" #include "Workspace.hpp" #include "WindowRule.hpp" +#include "protocols/types/ContentType.hpp" class CXDGSurfaceResource; class CXWaylandSurface; @@ -393,85 +394,87 @@ class CWindow { } // methods - CBox getFullWindowBoundingBox(); - SBoxExtents getFullWindowExtents(); - CBox getWindowBoxUnified(uint64_t props); - CBox getWindowIdealBoundingBoxIgnoreReserved(); - void addWindowDeco(UP deco); - void updateWindowDecos(); - void removeWindowDeco(IHyprWindowDecoration* deco); - void uncacheWindowDecos(); - bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); - pid_t getPID(); - IHyprWindowDecoration* getDecorationByType(eDecorationType); - void updateToplevel(); - void updateSurfaceScaleTransformDetails(bool force = false); - void moveToWorkspace(PHLWORKSPACE); - PHLWINDOW x11TransientFor(); - void onUnmap(); - void onMap(); - void setHidden(bool hidden); - bool isHidden(); - void applyDynamicRule(const SP& r); - void updateDynamicRules(); - SBoxExtents getFullWindowReservedArea(); - Vector2D middle(); - bool opaque(); - float rounding(); - float roundingPower(); - bool canBeTorn(); - void setSuspended(bool suspend); - bool visibleOnMonitor(PHLMONITOR pMonitor); - WORKSPACEID workspaceID(); - MONITORID monitorID(); - bool onSpecialWorkspace(); - void activate(bool force = false); - int surfacesCount(); - void clampWindowSize(const std::optional minSize, const std::optional maxSize); - bool isFullscreen(); - bool isEffectiveInternalFSMode(const eFullscreenMode); - int getRealBorderSize(); - float getScrollMouse(); - float getScrollTouchpad(); - void updateWindowData(); - void updateWindowData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(WP pav); - bool isInCurvedCorner(double x, double y); - bool hasPopupAt(const Vector2D& pos); - int popupsCount(); - void applyGroupRules(); - void createGroup(); - void destroyGroup(); - PHLWINDOW getGroupHead(); - PHLWINDOW getGroupTail(); - PHLWINDOW getGroupCurrent(); - PHLWINDOW getGroupPrevious(); - PHLWINDOW getGroupWindowByIndex(int); - int getGroupSize(); - bool canBeGroupedInto(PHLWINDOW pWindow); - void setGroupCurrent(PHLWINDOW pWindow); - void insertWindowToGroup(PHLWINDOW pWindow); - void updateGroupOutputs(); - void switchWithWindowInGroup(PHLWINDOW pWindow); - void setAnimationsToMove(); - void onWorkspaceAnimUpdate(); - void onFocusAnimUpdate(); - void onUpdateState(); - void onUpdateMeta(); - void onX11Configure(CBox box); - void onResourceChangeX11(); - std::string fetchTitle(); - std::string fetchClass(); - void warpCursor(bool force = false); - PHLWINDOW getSwallower(); - void unsetWindowData(eOverridePriority priority); - bool isX11OverrideRedirect(); - bool isModal(); - Vector2D requestedMinSize(); - Vector2D requestedMaxSize(); - void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + CBox getFullWindowBoundingBox(); + SBoxExtents getFullWindowExtents(); + CBox getWindowBoxUnified(uint64_t props); + CBox getWindowIdealBoundingBoxIgnoreReserved(); + void addWindowDeco(UP deco); + void updateWindowDecos(); + void removeWindowDeco(IHyprWindowDecoration* deco); + void uncacheWindowDecos(); + bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); + pid_t getPID(); + IHyprWindowDecoration* getDecorationByType(eDecorationType); + void updateToplevel(); + void updateSurfaceScaleTransformDetails(bool force = false); + void moveToWorkspace(PHLWORKSPACE); + PHLWINDOW x11TransientFor(); + void onUnmap(); + void onMap(); + void setHidden(bool hidden); + bool isHidden(); + void applyDynamicRule(const SP& r); + void updateDynamicRules(); + SBoxExtents getFullWindowReservedArea(); + Vector2D middle(); + bool opaque(); + float rounding(); + float roundingPower(); + bool canBeTorn(); + void setSuspended(bool suspend); + bool visibleOnMonitor(PHLMONITOR pMonitor); + WORKSPACEID workspaceID(); + MONITORID monitorID(); + bool onSpecialWorkspace(); + void activate(bool force = false); + int surfacesCount(); + void clampWindowSize(const std::optional minSize, const std::optional maxSize); + bool isFullscreen(); + bool isEffectiveInternalFSMode(const eFullscreenMode); + int getRealBorderSize(); + float getScrollMouse(); + float getScrollTouchpad(); + void updateWindowData(); + void updateWindowData(const struct SWorkspaceRule&); + void onBorderAngleAnimEnd(WP pav); + bool isInCurvedCorner(double x, double y); + bool hasPopupAt(const Vector2D& pos); + int popupsCount(); + void applyGroupRules(); + void createGroup(); + void destroyGroup(); + PHLWINDOW getGroupHead(); + PHLWINDOW getGroupTail(); + PHLWINDOW getGroupCurrent(); + PHLWINDOW getGroupPrevious(); + PHLWINDOW getGroupWindowByIndex(int); + int getGroupSize(); + bool canBeGroupedInto(PHLWINDOW pWindow); + void setGroupCurrent(PHLWINDOW pWindow); + void insertWindowToGroup(PHLWINDOW pWindow); + void updateGroupOutputs(); + void switchWithWindowInGroup(PHLWINDOW pWindow); + void setAnimationsToMove(); + void onWorkspaceAnimUpdate(); + void onFocusAnimUpdate(); + void onUpdateState(); + void onUpdateMeta(); + void onX11Configure(CBox box); + void onResourceChangeX11(); + std::string fetchTitle(); + std::string fetchClass(); + void warpCursor(bool force = false); + PHLWINDOW getSwallower(); + void unsetWindowData(eOverridePriority priority); + bool isX11OverrideRedirect(); + bool isModal(); + Vector2D requestedMinSize(); + Vector2D requestedMaxSize(); + void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + NContentType::eContentType getContentType(); + void setContentType(NContentType::eContentType contentType); - CBox getWindowMainSurfaceBox() const { + CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; } diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp index 306a25ce..fea2d43b 100644 --- a/src/desktop/WindowRule.cpp +++ b/src/desktop/WindowRule.cpp @@ -8,8 +8,9 @@ static const auto RULES = std::unordered_set{ "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto RULES_PREFIX = std::unordered_set{ - "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", - "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", + "animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", + "monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", + "size", "suppressevent", "tag", "workspace", "xray", }; CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) { @@ -74,6 +75,8 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool ruleType = RULE_WORKSPACE; else if (rule.starts_with("prop")) ruleType = RULE_PROP; + else if (rule.starts_with("content")) + ruleType = RULE_CONTENT; else { // check if this is a prop. const CVarList VARS(rule, 0, 's', true); diff --git a/src/desktop/WindowRule.hpp b/src/desktop/WindowRule.hpp index be9c2d9c..50e221f3 100644 --- a/src/desktop/WindowRule.hpp +++ b/src/desktop/WindowRule.hpp @@ -36,6 +36,7 @@ class CWindowRule { RULE_TAG, RULE_WORKSPACE, RULE_PROP, + RULE_CONTENT, }; eRuleType ruleType = RULE_INVALID; @@ -58,6 +59,7 @@ class CWindowRule { std::string szFullscreenState = ""; // empty means any std::string szOnWorkspace = ""; // empty means any std::string szWorkspace = ""; // empty means any + std::string szContentType = ""; // empty means any // precompiled regexes CRuleRegexContainer rTitle; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index f6ef9ced..8eaabd29 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -11,11 +11,11 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" +#include "protocols/types/ContentType.hpp" #include "../xwayland/XSurface.hpp" #include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" #include "../desktop/LayerSurface.hpp" -#include "../managers/input/InputManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../managers/AnimationManager.hpp" @@ -307,6 +307,13 @@ void Events::listener_mapWindow(void* owner, void* data) { } break; } + case CWindowRule::RULE_CONTENT: { + const CVarList VARS(r->szRule, 0, ' '); + try { + PWINDOW->setContentType(NContentType::fromString(VARS[1])); + } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); } + break; + } default: break; } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9aa6efce..3ea6d49b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -33,6 +33,7 @@ using namespace Hyprutils::String; using namespace Hyprutils::Utils; using namespace Hyprutils::OS; +using enum NContentType::eContentType; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -799,8 +800,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); // skip scheduling extra frames for fullsreen apps with vrr - bool shouldSkip = - *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; + const bool shouldSkip = activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN && + (*PNOBREAK == 1 || (*PNOBREAK == 2 && activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && output->state->state().adaptiveSync; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { diff --git a/src/macros.hpp b/src/macros.hpp index a5176675..d2cad6b7 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -111,6 +111,7 @@ } \ } +#define AQUAMARINE_VERSION_NUMBER (AQUAMARINE_VERSION_MAJOR * 10000 + AQUAMARINE_VERSION_MINOR * 100 + AQUAMARINE_VERSION_PATCH) #define AQUAMARINE_FORWARD(name) \ namespace Aquamarine { \ class name; \ diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 62736ae5..6cd3a608 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -58,10 +58,12 @@ #include "../protocols/core/Shm.hpp" #include "../protocols/ColorManagement.hpp" #include "../protocols/FrogColorManagement.hpp" +#include "../protocols/ContentType.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" +#include "content-type-v1.hpp" #include #include @@ -169,6 +171,7 @@ CProtocolManager::CProtocolManager() { PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); + PROTO::contentType = makeUnique(&wp_content_type_manager_v1_interface, 1, "ContentType"); if (*PENABLEXXCM) { PROTO::colorManagement = makeUnique(&xx_color_manager_v4_interface, 1, "ColorManagement"); diff --git a/src/protocols/ContentType.cpp b/src/protocols/ContentType.cpp new file mode 100644 index 00000000..0dd5481a --- /dev/null +++ b/src/protocols/ContentType.cpp @@ -0,0 +1,95 @@ +#include "ContentType.hpp" +#include "content-type-v1.hpp" +#include "protocols/types/ContentType.hpp" + +CContentTypeManager::CContentTypeManager(SP resource) : m_resource(resource) { + if UNLIKELY (!good()) + return; + + resource->setDestroy([](CWpContentTypeManagerV1* r) {}); + resource->setOnDestroy([this](CWpContentTypeManagerV1* r) { PROTO::contentType->destroyResource(this); }); + + resource->setGetSurfaceContentType([](CWpContentTypeManagerV1* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->colorManagement) { + r->error(WP_CONTENT_TYPE_MANAGER_V1_ERROR_ALREADY_CONSTRUCTED, "CT manager already exists"); + return; + } + + const auto RESOURCE = PROTO::contentType->m_vContentTypes.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + if UNLIKELY (!RESOURCE->good()) { + r->noMemory(); + PROTO::contentType->m_vContentTypes.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->contentType = RESOURCE; + }); +} + +bool CContentTypeManager::good() { + return m_resource->resource(); +} + +CContentType::CContentType(WP surface) { + destroy = surface->events.destroy.registerListener([this](std::any d) { PROTO::contentType->destroyResource(this); }); +} + +CContentType::CContentType(SP resource) : m_resource(resource) { + if UNLIKELY (!good()) + return; + + m_pClient = resource->client(); + + resource->setDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); }); + resource->setOnDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); }); + + resource->setSetContentType([this](CWpContentTypeV1* r, wpContentTypeV1Type type) { value = NContentType::fromWP(type); }); +} + +bool CContentType::good() { + return m_resource && m_resource->resource(); +} + +wl_client* CContentType::client() { + return m_pClient; +} + +CContentTypeProtocol::CContentTypeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CContentTypeProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if UNLIKELY (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +SP CContentTypeProtocol::getContentType(WP surface) { + if (surface->contentType.valid()) + return surface->contentType.lock(); + + return m_vContentTypes.emplace_back(makeShared(surface)); +} + +void CContentTypeProtocol::destroyResource(CContentTypeManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CContentTypeProtocol::destroyResource(CContentType* resource) { + std::erase_if(m_vContentTypes, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ContentType.hpp b/src/protocols/ContentType.hpp new file mode 100644 index 00000000..c0359bf1 --- /dev/null +++ b/src/protocols/ContentType.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "WaylandProtocol.hpp" +#include "core/Compositor.hpp" +#include "content-type-v1.hpp" +#include "protocols/types/ContentType.hpp" + +class CContentTypeManager { + public: + CContentTypeManager(SP resource); + + bool good(); + + private: + SP m_resource; +}; + +class CContentType { + public: + CContentType(SP resource); + CContentType(WP surface); + + bool good(); + wl_client* client(); + NContentType::eContentType value = NContentType::CONTENT_TYPE_NONE; + + WP self; + + private: + SP m_resource; + wl_client* m_pClient = nullptr; + + CHyprSignalListener destroy; + + friend class CContentTypeProtocol; +}; + +class CContentTypeProtocol : public IWaylandProtocol { + public: + CContentTypeProtocol(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); + + SP getContentType(WP surface); + + private: + void destroyResource(CContentTypeManager* resource); + void destroyResource(CContentType* resource); + + std::vector> m_vManagers; + std::vector> m_vContentTypes; + + friend class CContentTypeManager; + friend class CContentType; +}; + +namespace PROTO { + inline UP contentType; +}; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 20614813..aaaf9b1a 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -26,6 +26,7 @@ class CViewportResource; class CDRMSyncobjSurfaceResource; class CColorManagementSurface; class CFrogColorManagementSurface; +class CContentType; class CWLCallbackResource { public: @@ -123,6 +124,7 @@ class CWLSurfaceResource { WP viewportResource; WP syncobj; // may not be present WP colorManagement; + WP contentType; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/protocols/types/ContentType.cpp b/src/protocols/types/ContentType.cpp new file mode 100644 index 00000000..c0a3d30f --- /dev/null +++ b/src/protocols/types/ContentType.cpp @@ -0,0 +1,37 @@ +#include "ContentType.hpp" +#include +#include +#include + +namespace NContentType { + static std::unordered_map const table = { + {"none", CONTENT_TYPE_NONE}, {"photo", CONTENT_TYPE_PHOTO}, {"video", CONTENT_TYPE_VIDEO}, {"game", CONTENT_TYPE_GAME}}; + + eContentType fromString(const std::string name) { + auto it = table.find(name); + if (it != table.end()) + return it->second; + else + throw std::invalid_argument(std::format("Unknown content type {}", name)); + } + + eContentType fromWP(wpContentTypeV1Type contentType) { + switch (contentType) { + case WP_CONTENT_TYPE_V1_TYPE_NONE: return CONTENT_TYPE_NONE; + case WP_CONTENT_TYPE_V1_TYPE_PHOTO: return CONTENT_TYPE_PHOTO; + case WP_CONTENT_TYPE_V1_TYPE_VIDEO: return CONTENT_TYPE_VIDEO; + case WP_CONTENT_TYPE_V1_TYPE_GAME: return CONTENT_TYPE_GAME; + default: return CONTENT_TYPE_NONE; + } + } + + uint16_t toDRM(eContentType contentType) { + switch (contentType) { + case CONTENT_TYPE_NONE: return DRM_MODE_CONTENT_TYPE_GRAPHICS; + case CONTENT_TYPE_PHOTO: return DRM_MODE_CONTENT_TYPE_PHOTO; + case CONTENT_TYPE_VIDEO: return DRM_MODE_CONTENT_TYPE_CINEMA; + case CONTENT_TYPE_GAME: return DRM_MODE_CONTENT_TYPE_GAME; + default: return DRM_MODE_CONTENT_TYPE_NO_DATA; + } + } +} \ No newline at end of file diff --git a/src/protocols/types/ContentType.hpp b/src/protocols/types/ContentType.hpp new file mode 100644 index 00000000..66fcbca7 --- /dev/null +++ b/src/protocols/types/ContentType.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "content-type-v1.hpp" +#include + +namespace NContentType { + + enum eContentType : uint8_t { + CONTENT_TYPE_NONE = 0, + CONTENT_TYPE_PHOTO = 1, + CONTENT_TYPE_VIDEO = 2, + CONTENT_TYPE_GAME = 3, + }; + + eContentType fromString(const std::string name); + eContentType fromWP(wpContentTypeV1Type contentType); + uint16_t toDRM(eContentType contentType); +} \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 42445728..6d7b409c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -33,10 +33,14 @@ #include "pass/SurfacePassElement.hpp" #include "debug/Log.hpp" #include "protocols/ColorManagement.hpp" +#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2 +#include "protocols/types/ContentType.hpp" +#endif #include using namespace Hyprutils::Utils; using namespace Hyprutils::OS; +using enum NContentType::eContentType; extern "C" { #include @@ -1192,7 +1196,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if (*PDIRECTSCANOUT && !shouldTear) { + if ((*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { @@ -1509,6 +1513,14 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { } } +#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2 + if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { + const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); + pMonitor->output->state->setContentType(NContentType::toDRM(WINDOW->getContentType())); + } else + pMonitor->output->state->setContentType(NContentType::toDRM(CONTENT_TYPE_NONE)); +#endif + if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; pMonitor->output->state->setCTM(pMonitor->ctm); From 44004abc0189b9ba49444431e2a39d2df7e930bb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 2 Feb 2025 22:16:00 +0000 Subject: [PATCH 1176/2393] config: fix includes --- src/config/ConfigManager.cpp | 4 ++-- src/desktop/Window.hpp | 2 +- src/events/Windows.cpp | 2 +- src/protocols/ContentType.hpp | 2 +- subprojects/hyprland-protocols | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 42a1a91c..3f45ddfe 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -25,8 +25,8 @@ #include "../debug/HyprNotificationOverlay.hpp" #include "../plugins/PluginSystem.hpp" -#include "managers/HookSystemManager.hpp" -#include "protocols/types/ContentType.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../protocols/types/ContentType.hpp" #include #include #include diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index b3c3d84f..2d004855 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -19,7 +19,7 @@ #include "WLSurface.hpp" #include "Workspace.hpp" #include "WindowRule.hpp" -#include "protocols/types/ContentType.hpp" +#include "../protocols/types/ContentType.hpp" class CXDGSurfaceResource; class CXWaylandSurface; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 8eaabd29..a068ba07 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -11,7 +11,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" -#include "protocols/types/ContentType.hpp" +#include "../protocols/types/ContentType.hpp" #include "../xwayland/XSurface.hpp" #include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" diff --git a/src/protocols/ContentType.hpp b/src/protocols/ContentType.hpp index c0359bf1..4c0c445f 100644 --- a/src/protocols/ContentType.hpp +++ b/src/protocols/ContentType.hpp @@ -3,7 +3,7 @@ #include "WaylandProtocol.hpp" #include "core/Compositor.hpp" #include "content-type-v1.hpp" -#include "protocols/types/ContentType.hpp" +#include "types/ContentType.hpp" class CContentTypeManager { public: diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 755aef8d..4c75dd5c 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed +Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 From 708d16636047c6a311c4e44424cf7d2090219a47 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Mon, 3 Feb 2025 04:34:30 +0300 Subject: [PATCH 1177/2393] dispatchers: add cyclenext hist option (#9055) --- src/Compositor.cpp | 83 +++++++++++++++++++-------------- src/Compositor.hpp | 7 ++- src/managers/KeybindManager.cpp | 32 ++++++------- src/managers/KeybindManager.hpp | 2 +- 4 files changed, 67 insertions(+), 57 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0aa0f13d..95a57e03 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1058,7 +1058,7 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP out) { return nullptr; } -void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface) { +void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface, bool preserveFocusHistory) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); @@ -1178,12 +1178,13 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface g_pInputManager->recheckIdleInhibitorStatus(); - // move to front of the window history - const auto HISTORYPIVOT = std::find_if(m_vWindowFocusHistory.begin(), m_vWindowFocusHistory.end(), [&](const auto& other) { return other.lock() == pWindow; }); - if (HISTORYPIVOT == m_vWindowFocusHistory.end()) { - Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow); - } else { - std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); + if (!preserveFocusHistory) { + // move to front of the window history + const auto HISTORYPIVOT = std::ranges::find_if(m_vWindowFocusHistory, [&](const auto& other) { return other.lock() == pWindow; }); + if (HISTORYPIVOT == m_vWindowFocusHistory.end()) + Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow); + else + std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); } if (*PFOLLOWMOUSE == 0) @@ -1396,7 +1397,6 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { }; x11Stack(pWindow, top, x11Stack); - for (const auto& it : toMove) { moveToZ(it, top); } @@ -1647,37 +1647,52 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks return nullptr; } -PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { - auto it = std::ranges::find(m_vWindows, pWindow); - const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; - const auto IN_RIGHT = std::find_if(it, m_vWindows.end(), FINDER); - if (IN_RIGHT != m_vWindows.end()) - return *IN_RIGHT; - const auto IN_LEFT = std::find_if(m_vWindows.begin(), it, FINDER); - return *IN_LEFT; -} - -PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { - auto it = std::ranges::find(std::ranges::reverse_view(m_vWindows), pWindow); - const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; - const auto IN_LEFT = std::find_if(it, m_vWindows.rend(), FINDER); - if (IN_LEFT != m_vWindows.rend()) - return *IN_LEFT; - const auto IN_RIGHT = std::find_if(m_vWindows.rbegin(), it, FINDER); - return *IN_RIGHT; -} - -inline static bool isWorkspaceMatches(PHLWINDOW pWindow, const PHLWINDOW w, bool anyWorkspace) { +template +static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) { return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace; } -inline static bool isFloatingMatches(PHLWINDOW w, std::optional floating) { +template +static bool isFloatingMatches(WINDOWPTR w, std::optional floating) { return !floating.has_value() || w->m_bIsFloating == floating.value(); -}; +} -bool CCompositor::isWindowAvailableForCycle(PHLWINDOW pWindow, const PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace) { - return isFloatingMatches(w, floating) && w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && - (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()); +template +static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, bool focusableOnly, std::optional floating, bool anyWorkspace = false) { + return isFloatingMatches(w, floating) && + (w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())); +} + +template +static PHLWINDOW getWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function PRED) { + const auto IN_ONE_SIDE = std::find_if(cur, end, PRED); + if (IN_ONE_SIDE != end) + return *IN_ONE_SIDE; + const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED); + return *IN_OTHER_SIDE; +} + +template +static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function PRED) { + const auto IN_ONE_SIDE = std::find_if(cur, end, PRED); + if (IN_ONE_SIDE != end) + return IN_ONE_SIDE->lock(); + const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED); + return IN_OTHER_SIDE->lock(); +} + +PHLWINDOW CCompositor::getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly, std::optional floating, bool visible, bool next) { + const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; + // also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again + return next ? + getWeakWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindowFocusHistory), cur), m_vWindowFocusHistory.rend(), m_vWindowFocusHistory.rbegin(), FINDER) : + getWeakWindowPred(std::ranges::find(m_vWindowFocusHistory, cur), m_vWindowFocusHistory.end(), m_vWindowFocusHistory.begin(), FINDER); +} + +PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional floating, bool visible, bool prev) { + const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; + return prev ? getWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindows), cur), m_vWindows.rend(), m_vWindows.rbegin(), FINDER) : + getWindowPred(std::ranges::find(m_vWindows, cur), m_vWindows.end(), m_vWindows.begin(), FINDER); } WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 787ead08..a57095a3 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -83,7 +83,7 @@ class CCompositor { PHLMONITOR getMonitorFromCursor(); PHLMONITOR getMonitorFromVector(const Vector2D&); void removeWindowFromVectorSafe(PHLWINDOW); - void focusWindow(PHLWINDOW, SP pSurface = nullptr); + void focusWindow(PHLWINDOW, SP pSurface = nullptr, bool preserveFocusHistory = false); void focusSurface(SP, PHLWINDOW pWindowOwner = nullptr); bool monitorExists(PHLMONITOR); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); @@ -105,8 +105,8 @@ class CCompositor { void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); - PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); - PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); + PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional floating = std::nullopt, bool visible = false, bool prev = false); + PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional floating = std::nullopt, bool visible = false, bool next = false); WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); @@ -163,7 +163,6 @@ class CCompositor { void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); - bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace = false); uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index bc5d36c8..47cc4f67 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -367,7 +367,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) { return true; } -void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { +void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PNOWARPS = CConfigValue("cursor:no_warps"); @@ -386,7 +386,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE); - g_pCompositor->focusWindow(PWINDOWTOCHANGETO); + g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); @@ -396,7 +396,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { PWINDOWTOCHANGETO->m_vRealSize->warp(); } else { updateRelativeCursorCoords(); - g_pCompositor->focusWindow(PWINDOWTOCHANGETO); + g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); PWINDOWTOCHANGETO->warpCursor(); // Move mouse focus to the new window if required by current follow_mouse and warp modes @@ -1473,7 +1473,7 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) { } const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? - (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) : + g_pCompositor->getWindowCycle(PLASTWINDOW, true, {}, false, arg != 'd' && arg != 'b' && arg != 'r') : g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); // Prioritize focus change within groups if the window is a part of it. @@ -2221,11 +2221,13 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) { floatStatus = true; const auto VISIBLE = args.contains("visible") || args.contains("v"); - const auto& w = (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) ? - g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE) : - g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE); + const auto PREV = args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"); + const auto NEXT = args.contains("next") || args.contains("n"); // prev is default in classic alt+tab + const auto HIST = args.contains("hist") || args.contains("h"); + const auto& w = HIST ? g_pCompositor->getWindowCycleHist(g_pCompositor->m_pLastWindow, true, floatStatus, VISIBLE, NEXT) : + g_pCompositor->getWindowCycle(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE, PREV); - switchToWindow(w); + switchToWindow(w, HIST); return {}; } @@ -2620,18 +2622,12 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) { g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() : nullptr; - if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true); - else - toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true); + const bool NEED_PREV = arg == "last" || arg == "l" || arg == "prev" || arg == "p"; + toSwap = g_pCompositor->getWindowCycle(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true, std::nullopt, false, NEED_PREV); // sometimes we may come back to ourselves. - if (toSwap == PLASTWINDOW) { - if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true); - else - toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); - } + if (toSwap == PLASTWINDOW) + toSwap = g_pCompositor->getWindowCycle(PLASTWINDOW, true, std::nullopt, false, NEED_PREV); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 1848ca78..cea3e3cf 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -148,7 +148,7 @@ class CKeybindManager { static bool tryMoveFocusToMonitor(PHLMONITOR monitor); static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); - static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); + static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory = false); static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace); static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); From 1da0b2c02e99d3bd35f4d1a6f9a55dc403715913 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 19:45:26 +0000 Subject: [PATCH 1178/2393] subprojects: update h-p fixes #9309 --- subprojects/hyprland-protocols | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 4c75dd5c..755aef8d 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 +Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed From 70cfc7cc9c4ecadbb9dd9a75f096fc70177a8ca5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 19:53:14 +0000 Subject: [PATCH 1179/2393] cmonitor: guard old workspace --- src/helpers/Monitor.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 3ea6d49b..e4843211 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1019,15 +1019,17 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo if (pWorkspace == activeWorkspace) return; - const auto POLDWORKSPACE = activeWorkspace; - POLDWORKSPACE->m_bVisible = false; - pWorkspace->m_bVisible = true; + const auto POLDWORKSPACE = activeWorkspace; + if (POLDWORKSPACE) + POLDWORKSPACE->m_bVisible = false; + pWorkspace->m_bVisible = true; activeWorkspace = pWorkspace; if (!internal) { - const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID; - POLDWORKSPACE->startAnim(false, ANIMTOLEFT); + const auto ANIMTOLEFT = POLDWORKSPACE && pWorkspace->m_iID > POLDWORKSPACE->m_iID; + if (POLDWORKSPACE) + POLDWORKSPACE->startAnim(false, ANIMTOLEFT); pWorkspace->startAnim(true, ANIMTOLEFT); // move pinned windows From 5e7292434a9189d0550187f8a6fb687848194a41 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 22:36:10 +0000 Subject: [PATCH 1180/2393] compositor: guard null ws in updating fade --- src/Compositor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 95a57e03..22cb70fb 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2217,6 +2217,9 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { + if (!pWorkspace) + return; + const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; for (auto const& w : g_pCompositor->m_vWindows) { From 3b99e906df8b439d65e740301940e57efc057012 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 4 Feb 2025 10:18:08 +0000 Subject: [PATCH 1181/2393] compositor: don't iterate over unmapped ls-es in vectorToLS fixes #9312 --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 22cb70fb..a8cbae3a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1245,7 +1245,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) + if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) continue; auto SURFACEAT = ls->popupHead->at(pos, true); @@ -1263,7 +1263,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& ls : *layerSurfaces | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) + if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) continue; auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); From 84c9baecc6b73f6321b2739061e3c232710f73bf Mon Sep 17 00:00:00 2001 From: Tom Benham <38216488+tomben13@users.noreply.github.com> Date: Wed, 5 Feb 2025 10:56:41 +0100 Subject: [PATCH 1182/2393] keybinds: Added `toggleswallow` dispatcher (#5548) * Added `toggleswallow` dispatcher * clang-format * Removed brackets for 1-line if --- src/desktop/Window.cpp | 6 ++++-- src/desktop/Window.hpp | 3 ++- src/events/Windows.cpp | 13 +++++++++---- src/managers/KeybindManager.cpp | 22 ++++++++++++++++++++++ src/managers/KeybindManager.hpp | 1 + 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 6a523eec..c71fe652 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -452,8 +452,10 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } if (const auto SWALLOWED = m_pSwallowed.lock()) { - SWALLOWED->moveToWorkspace(pWorkspace); - SWALLOWED->m_pMonitor = m_pMonitor; + if (SWALLOWED->m_bCurrentlySwallowed) { + SWALLOWED->moveToWorkspace(pWorkspace); + SWALLOWED->m_pMonitor = m_pMonitor; + } } // update xwayland coords diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 2d004855..8444a113 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -355,7 +355,8 @@ class CWindow { // swallowing PHLWINDOWREF m_pSwallowed; - bool m_bGroupSwallowed = false; + bool m_bCurrentlySwallowed = false; + bool m_bGroupSwallowed = false; // focus stuff bool m_bStayFocused = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a068ba07..d96bb332 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -392,6 +392,8 @@ void Events::listener_mapWindow(void* owner, void* data) { // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. const auto SWALLOWER = PWINDOW->getSwallower(); PWINDOW->m_pSwallowed = SWALLOWER; + if (PWINDOW->m_pSwallowed) + PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true; if (PWINDOW->m_bIsFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); @@ -731,12 +733,15 @@ void Events::listener_unmapWindow(void* owner, void* data) { // swallowing if (valid(PWINDOW->m_pSwallowed)) { - PWINDOW->m_pSwallowed->setHidden(false); + if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) { + PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false; + PWINDOW->m_pSwallowed->setHidden(false); - if (PWINDOW->m_sGroupData.pNextWindow.lock()) - PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. + if (PWINDOW->m_sGroupData.pNextWindow.lock()) + PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. - g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); + } PWINDOW->m_pSwallowed->m_bGroupSwallowed = false; PWINDOW->m_pSwallowed.reset(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 47cc4f67..2d6b2cb8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -113,6 +113,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["tagwindow"] = tagWindow; + m_mDispatchers["toggleswallow"] = toggleSwallow; m_mDispatchers["submap"] = setSubmap; m_mDispatchers["pass"] = pass; m_mDispatchers["sendshortcut"] = sendshortcut; @@ -2306,6 +2307,27 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) { return {}; } +SDispatchResult CKeybindManager::toggleSwallow(std::string args) { + PHLWINDOWREF pWindow = g_pCompositor->m_pLastWindow; + + if (!valid(pWindow) || !valid(pWindow->m_pSwallowed)) + return {}; + + if (pWindow->m_pSwallowed->m_bCurrentlySwallowed) { + // Unswallow + pWindow->m_pSwallowed->m_bCurrentlySwallowed = false; + pWindow->m_pSwallowed->setHidden(false); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow->m_pSwallowed.lock()); + } else { + // Reswallow + pWindow->m_pSwallowed->m_bCurrentlySwallowed = true; + pWindow->m_pSwallowed->setHidden(true); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow->m_pSwallowed.lock()); + } + + return {}; +} + SDispatchResult CKeybindManager::setSubmap(std::string submap) { if (submap == "reset" || submap == "") { m_szCurrentSelectedSubmap = ""; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index cea3e3cf..712fd58d 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -199,6 +199,7 @@ class CKeybindManager { static SDispatchResult circleNext(std::string); static SDispatchResult focusWindow(std::string); static SDispatchResult tagWindow(std::string); + static SDispatchResult toggleSwallow(std::string); static SDispatchResult setSubmap(std::string); static SDispatchResult pass(std::string); static SDispatchResult sendshortcut(std::string); From 873bff390e56fb379754221d9652d0c3b850eaad Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 5 Feb 2025 09:53:09 -0500 Subject: [PATCH 1183/2393] renderer: fix missing null checks to prevent crashes (#9332) --- src/render/Renderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6d7b409c..0fcda827 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1196,7 +1196,9 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if ((*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && !shouldTear) { + if ((*PDIRECTSCANOUT == 1 || + (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow() && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && + !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { From 64591c85aa212fe06fab90ea2deaccbec529c0c0 Mon Sep 17 00:00:00 2001 From: raf Date: Wed, 5 Feb 2025 14:55:33 +0000 Subject: [PATCH 1184/2393] nix: add hydraJobs output for aggregating Hyprland build jobs --- flake.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flake.nix b/flake.nix index c1c580ae..801d96ec 100644 --- a/flake.nix +++ b/flake.nix @@ -157,5 +157,11 @@ nixosModules.default = import ./nix/module.nix inputs; homeManagerModules.default = import ./nix/hm-module.nix self; + + # Hydra build jobs + # Recent versions of Hydra can aggregate jobsets from 'hydraJobs' intead of a release.nix + # or similar. Remember to filter large or incompatible attributes here. More eval jobs can + # be added by merging, e.g., self.packages // self.devShells. + hydraJobs = self.packages; }; } From 8a6778f0a087cdfc4bc1d3751b0be2c2bf3322aa Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 5 Feb 2025 15:41:54 +0000 Subject: [PATCH 1185/2393] scripts: don't overwrite generated version if we're not in a git repo --- scripts/generateVersion.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/generateVersion.sh b/scripts/generateVersion.sh index fdcc4712..e88cef3f 100755 --- a/scripts/generateVersion.sh +++ b/scripts/generateVersion.sh @@ -1,4 +1,13 @@ #!/bin/sh + +# if the git directory doesn't exist, don't gather data to avoid overwriting, unless +# the version file is missing altogether (otherwise compiling will fail) +if [[ ! -d ./.git ]]; then + if [[ -f ./src/version.h ]]; then + exit 0 + fi +fi + cp -fr ./src/version.h.in ./src/version.h HASH=${HASH-$(git rev-parse HEAD)} From 868b2b544abb61764089b0e4e9b0fd153a9db26f Mon Sep 17 00:00:00 2001 From: nyx Date: Thu, 6 Feb 2025 06:16:47 -0500 Subject: [PATCH 1186/2393] window: fix missing surface null checks to prevent crashes (#9350) --- src/desktop/Window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index c71fe652..b5126b67 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1730,7 +1730,10 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional } NContentType::eContentType CWindow::getContentType() { - return m_pWLSurface->resource()->contentType.valid() ? m_pWLSurface->resource()->contentType->value : CONTENT_TYPE_NONE; + if (!m_pWLSurface || !m_pWLSurface->resource() || !m_pWLSurface->resource()->contentType.valid()) + return CONTENT_TYPE_NONE; + + return m_pWLSurface->resource()->contentType->value; } void CWindow::setContentType(NContentType::eContentType contentType) { From f1e32cd122ad64ba7119ee7fe65f7c1074a65b91 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 6 Feb 2025 12:18:04 +0100 Subject: [PATCH 1187/2393] core: avoid .at() and use [] operator (#9347) avoid .at() where it makes sense and use [] operator in loops. --- src/desktop/Window.cpp | 8 ++++---- src/devices/IKeyboard.cpp | 20 ++++++++++---------- src/layout/MasterLayout.cpp | 2 +- src/managers/PointerManager.cpp | 2 +- src/managers/XCursorManager.cpp | 2 +- src/render/OpenGL.cpp | 8 ++++---- src/xwayland/XDataSource.cpp | 4 ++-- src/xwayland/XWM.cpp | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b5126b67..8f6d2cb5 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1626,17 +1626,17 @@ PHLWINDOW CWindow::getSwallower() { if (!(*PSWALLOWREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); }); - if (candidates.size() <= 0) + if (candidates.size() == 0) return nullptr; if (!(*PSWALLOWEXREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); }); - if (candidates.size() <= 0) + if (candidates.size() == 0) return nullptr; if (candidates.size() == 1) - return candidates.at(0); + return candidates[0]; // walk up the focus history and find the last focused for (auto const& w : g_pCompositor->m_vWindowFocusHistory) { @@ -1648,7 +1648,7 @@ PHLWINDOW CWindow::getSwallower() { } // if none are found (??) then just return the first one - return candidates.at(0); + return candidates[0]; } void CWindow::unsetWindowData(eOverridePriority priority) { diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 307d840b..89891ebd 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -126,14 +126,14 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { updateModifiers(0, 0, modifiersState.locked, modifiersState.group); } - for (size_t i = 0; i < LEDNAMES.size(); ++i) { - ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i)); - Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i)); + for (size_t i = 0; i < std::min(LEDNAMES.size(), ledIndexes.size()); ++i) { + ledIndexes[i] = xkb_map_led_get_index(xkbKeymap, LEDNAMES[i]); + Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], ledIndexes[i]); } - for (size_t i = 0; i < MODNAMES.size(); ++i) { - modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i)); - Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i)); + for (size_t i = 0; i < std::min(MODNAMES.size(), modIndexes.size()); ++i) { + modIndexes[i] = xkb_map_mod_get_index(xkbKeymap, MODNAMES[i]); + Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], modIndexes[i]); } updateKeymapFD(); @@ -289,8 +289,8 @@ std::optional IKeyboard::getLEDs() { return {}; uint32_t leds = 0; - for (uint32_t i = 0; i < LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i))) + for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, ledIndexes.size()); ++i) { + if (xkb_state_led_index_is_active(xkbState, ledIndexes[i])) leds |= (1 << i); } @@ -323,10 +323,10 @@ uint32_t IKeyboard::getModifiers() { uint32_t modMask = modifiersState.depressed | modifiersState.latched; uint32_t mods = 0; for (size_t i = 0; i < modIndexes.size(); ++i) { - if (modIndexes.at(i) == XKB_MOD_INVALID) + if (modIndexes[i] == XKB_MOD_INVALID) continue; - if (!(modMask & (1 << modIndexes.at(i)))) + if (!(modMask & (1 << modIndexes[i]))) continue; mods |= (1 << i); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 4773147f..dc301bfa 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -1357,7 +1357,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi int nextOrPrev = 0; for (size_t i = 0; i < cycle.size(); ++i) { - if (PWORKSPACEDATA->orientation == cycle.at(i)) { + if (PWORKSPACEDATA->orientation == cycle[i]) { nextOrPrev = i + direction; break; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 48ef5e16..1c8e9976 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -475,7 +475,7 @@ SP CPointerManager::renderHWCursorBuffer(SP> CXCursorManager::loadStandardCursors(std::string cons // load the default xcursor shapes that exist in the theme for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { - std::string shape{XCURSOR_STANDARD_NAMES.at(i)}; + std::string shape{XCURSOR_STANDARD_NAMES[i]}; auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size); if (!xImages) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 75a5eadb..3b641c36 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -402,14 +402,14 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo result.reserve(mods.size()); bool linearIsExternal = false; - for (size_t i = 0; i < mods.size(); ++i) { - if (external.at(i)) { - if (mods.at(i) == DRM_FORMAT_MOD_LINEAR) + for (size_t i = 0; i < std::min(mods.size(), external.size()); ++i) { + if (external[i]) { + if (mods[i] == DRM_FORMAT_MOD_LINEAR) linearIsExternal = true; continue; } - result.push_back(mods.at(i)); + result.push_back(mods[i]); } // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index e6282dcb..9384db69 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -57,8 +57,8 @@ void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { mimeAtom = HYPRATOMS["UTF8_STRING"]; else { for (size_t i = 0; i < mimeTypes.size(); ++i) { - if (mimeTypes.at(i) == mime) { - mimeAtom = mimeAtoms.at(i); + if (mimeTypes[i] == mime) { + mimeAtom = mimeAtoms[i]; break; } } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 81900c7b..68552dd6 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1051,13 +1051,13 @@ void CXWM::readWindowData(SP surf) { }; for (size_t i = 0; i < interestingProps.size(); i++) { - xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, surf->xID, interestingProps.at(i), XCB_ATOM_ANY, 0, 2048); + xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, surf->xID, interestingProps[i], XCB_ATOM_ANY, 0, 2048); xcb_get_property_reply_t* reply = xcb_get_property_reply(connection, cookie, nullptr); if (!reply) { Debug::log(ERR, "[xwm] Failed to get window property"); continue; } - readProp(surf, interestingProps.at(i), reply); + readProp(surf, interestingProps[i], reply); free(reply); } } From ff9e059de6dd30c813270ff5a74053339cc94765 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 6 Feb 2025 11:21:04 +0000 Subject: [PATCH 1188/2393] window: move size reporting to animation begin callback (#9298) * window: fix resizes with an update callback * window: fixup sendWindowSize Remove the size argument from sendWindowSize, since it is now a member of the Window class and we don't want any mismatches between m_vRealSize and what we report. Remove sendWindowSize from mapWindow, since we shouldn't need it. * window: sendWindowSize on animation begin * window: move most calls to sendWindowSize to the animation begin callback * window: remove sendWindowSize in unmanaged if not fullscreen --- src/Compositor.cpp | 2 +- src/desktop/Window.cpp | 26 +++++++++++-------- src/desktop/Window.hpp | 2 +- src/desktop/Workspace.cpp | 2 +- src/events/Windows.cpp | 9 +------ src/layout/DwindleLayout.cpp | 4 --- src/layout/IHyprLayout.cpp | 18 +++++-------- src/layout/MasterLayout.cpp | 4 --- src/managers/KeybindManager.cpp | 1 - src/managers/XWaylandManager.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 3 --- 11 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a8cbae3a..e460bbca 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2330,7 +2330,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS updateFullscreenFadeOnWorkspace(PWORKSPACE); - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(true); PWORKSPACE->forceReportSizesToWindows(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 8f6d2cb5..b0d7b58c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -458,9 +458,6 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } } - // update xwayland coords - sendWindowSize(m_vRealSize->goal()); - if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); @@ -563,6 +560,15 @@ void CWindow::onMap() { *m_fBorderAngleAnimationProgress = 1.f; } + m_vRealSize->setCallbackOnBegin( + [this](auto) { + if (!m_bIsMapped || isX11OverrideRedirect()) + return; + + sendWindowSize(); + }, + false); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); @@ -1315,7 +1321,6 @@ void CWindow::clampWindowSize(const std::optional minSize, const std:: *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; *m_vRealSize = NEWSIZE; - sendWindowSize(NEWSIZE); } bool CWindow::isFullscreen() { @@ -1539,7 +1544,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { - sendWindowSize(m_vRealSize->goal(), true); + sendWindowSize(true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); return; @@ -1566,8 +1571,6 @@ void CWindow::onX11Configure(CBox box) { m_vPosition = m_vRealPosition->goal(); m_vSize = m_vRealSize->goal(); - sendWindowSize(box.size(), true); - m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); @@ -1697,15 +1700,16 @@ Vector2D CWindow::requestedMaxSize() { return maxSize; } -void CWindow::sendWindowSize(Vector2D size, bool force, std::optional overridePos) { +void CWindow::sendWindowSize(bool force) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); const auto PMONITOR = m_pMonitor.lock(); - size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(), + m_vRealSize->goal(), force); - // calculate pos // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); + Vector2D windowPos = m_vRealPosition->goal(); + Vector2D size = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); if (m_bIsX11 && PMONITOR) { windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 8444a113..9a4a36c2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -471,7 +471,7 @@ class CWindow { bool isModal(); Vector2D requestedMinSize(); Vector2D requestedMaxSize(); - void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 8dbf30b7..7f8e7fc9 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -624,7 +624,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - w->sendWindowSize(w->m_vRealSize->goal(), true); + w->sendWindowSize(true); } } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index d96bb332..399894f9 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -688,13 +688,6 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; - - // Fix some X11 popups being invisible / having incorrect size on open. - // What the ACTUAL FUCK is going on?????? I HATE X11 - if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) { - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true, PWINDOW->m_vRealPosition->goal() - Vector2D{1, 1}); - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); - } } void Events::listener_unmapWindow(void* owner, void* data) { @@ -964,7 +957,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(true); g_pHyprRenderer->damageWindow(PWINDOW); return; } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 8aaafaa3..ecd7abea 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -198,16 +198,12 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess *PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealPosition = wb.pos(); - - PWINDOW->sendWindowSize(wb.size()); } if (force) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 9a0ba6ee..e84ffb21 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -176,11 +176,9 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vRealSize->warp(); } - if (!pWindow->isX11OverrideRedirect()) { - pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); - + if (!pWindow->isX11OverrideRedirect()) g_pCompositor->changeWindowZOrder(pWindow, true); - } else { + else { pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal(); pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; } @@ -362,9 +360,6 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; DRAGGINGWINDOW->m_bDraggingTiled = false; - if (pWindow->m_bIsFloating) - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); // match the size of the window - static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW); @@ -606,10 +601,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (*PANIMATEMOUSE) *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); - else + else { DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->sendWindowSize(); + } - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { @@ -679,9 +675,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { } else { DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size()); DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->sendWindowSize(); } - - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); } @@ -787,7 +782,6 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); pWindow->updateToplevel(); - pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); g_pHyprRenderer->damageWindow(pWindow); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index dc301bfa..a429843f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -678,16 +678,12 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } if (m_bForceWarps && !*PANIMATE) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2d6b2cb8..8daa6838 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1908,7 +1908,6 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { if (PWORKSPACE->m_bDefaultFloating) { w->m_vRealPosition->setValueAndWarp(SAVEDPOS); w->m_vRealSize->setValueAndWarp(SAVEDSIZE); - w->sendWindowSize(SAVEDSIZE); *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index a5506329..63b14962 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - pWindow->sendWindowSize(pWindow->m_vRealSize->value(), true); // update xwayland output pos + pWindow->sendWindowSize(true); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 1a64b024..32422e14 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -456,9 +456,6 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window - if (pWindowInsertAfter->m_bIsFloating) - pDraggedWindow->sendWindowSize(pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window - pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); if (WINDOWINDEX == -1) From 30b49c75bf04ceffc9fb1652a4d02e4eebacc24c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 6 Feb 2025 12:13:35 +0000 Subject: [PATCH 1189/2393] popup: improve ::at() behavior --- src/desktop/Popup.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 4accb58f..82767ead 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -347,18 +347,19 @@ WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { continue; if (!allowsInput) { - const Vector2D offset = - p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; - const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); + const bool HASSURFACE = p->m_pResource && p->m_pResource->surface; - const auto BOX = CBox{p->coordsGlobal() + offset, size}; + Vector2D offset = HASSURFACE ? p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + Vector2D size = HASSURFACE ? p->m_pResource->surface->current.geometry.size() : p->size(); + + if (size == Vector2D{}) + size = p->size(); + + const auto BOX = CBox{p->coordsGlobal() + offset, size}; if (BOX.containsPoint(globalCoords)) return p; } else { - const Vector2D offset = - p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; - const auto REGION = - CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); + const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal()); if (REGION.containsPoint(globalCoords)) return p; } From acbcf0cf115d55ef80a75ded3223a9e098f77541 Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:42:20 +0100 Subject: [PATCH 1190/2393] toplevelexport: fix transformed origin for shm buffers (#9343) * toplevelexport: fix transformed origin for shm buffers * toplevelexport: fix style nits --- src/protocols/ToplevelExport.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 8b835b50..a9009aa4 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -11,6 +11,7 @@ #include "../render/Renderer.hpp" #include +#include CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -289,7 +290,29 @@ bool CToplevelExportFrame::copyShm(timespec* now) { glPixelStorei(GL_PACK_ALIGNMENT, 1); auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; - glReadPixels(0, 0, box.width, box.height, glFormat, PFORMAT->glType, pixelData); + + auto origin = Vector2D(0, 0); + switch (PMONITOR->transform) { + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + case WL_OUTPUT_TRANSFORM_90: { + origin.y = PMONITOR->vecPixelSize.y - box.height; + break; + } + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + case WL_OUTPUT_TRANSFORM_180: { + origin.x = PMONITOR->vecPixelSize.x - box.width; + origin.y = PMONITOR->vecPixelSize.y - box.height; + break; + } + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_270: { + origin.x = PMONITOR->vecPixelSize.x - box.width; + break; + } + default: break; + } + + glReadPixels(origin.x, origin.y, box.width, box.height, glFormat, PFORMAT->glType, pixelData); if (overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); From 54441e0c4e51dd182f78876c014446d5d0359ba8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 6 Feb 2025 17:45:25 +0000 Subject: [PATCH 1191/2393] renderer: fix fade out on silent moves to special --- src/render/Renderer.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0fcda827..6f0bbe44 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -379,7 +379,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (w->m_bIsFloating) continue; // floating are in the second pass - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; // render active window after all others of this pass @@ -390,11 +393,14 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo // render the bad boy renderWindow(w.lock(), pMonitor, time, true, RENDER_PASS_MAIN); + w.reset(); } if (lastWindow) renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); + lastWindow.reset(); + // Non-floating popup for (auto& w : windows) { if (!w) @@ -403,7 +409,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (w->m_bIsFloating) continue; // floating are in the second pass - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; // render the bad boy @@ -419,7 +428,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (!w->m_bIsFloating || w->m_bPinned) continue; - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; if (pWorkspace->m_bIsSpecialWorkspace && w->m_pMonitor != pWorkspace->m_pMonitor) From a724332eb82c33308a8cb6127172f128e3afe14c Mon Sep 17 00:00:00 2001 From: Paul Cross <3613973+kreejzak@users.noreply.github.com> Date: Sat, 8 Feb 2025 01:45:13 +0100 Subject: [PATCH 1192/2393] desktop: add ability to target pinned windows in workspace rules (#9344) * desktop: add ability to target pinned windows in workspace rules * desktop: add ability to target pinned windows in workspace rules * fix formating --- src/desktop/Workspace.cpp | 21 +++++++++++++++++---- src/desktop/Workspace.hpp | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 7f8e7fc9..f2c22195 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -261,6 +261,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { // n - named: n[true] or n[s:string] or n[e:string] // m - monitor: m[monitor_selector] // w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and + // flag p to count only pinned windows, e.g. w[p1-2], w[pg4] // flag g to count groups instead of windows, e.g. w[t1-2], w[fg4] // flag v will count only visible windows // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states @@ -370,6 +371,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { prop = prop.substr(2, prop.length() - 3); int wantsOnlyTiled = -1; + int wantsOnlyPinned = false; bool wantsCountGroup = false; bool wantsCountVisible = false; @@ -381,6 +383,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { } else if (flag == 'f' && wantsOnlyTiled == -1) { wantsOnlyTiled = 0; flagCount++; + } else if (flag == 'p' && !wantsOnlyPinned) { + wantsOnlyPinned = true; + flagCount++; } else if (flag == 'g' && !wantsCountGroup) { wantsCountGroup = true; flagCount++; @@ -411,9 +416,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { int count; if (wantsCountGroup) count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (count != from) @@ -444,10 +451,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { WORKSPACEID count; if (wantsCountGroup) - count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = + getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (std::clamp(count, from, to) != count) @@ -535,13 +544,15 @@ bool CWorkspace::isVisibleNotCovered() { return PMONITOR->activeWorkspace->m_iID == m_iID; } -int CWorkspace::getWindows(std::optional onlyTiled, std::optional onlyVisible) { +int CWorkspace::getWindows(std::optional onlyTiled, std::optional onlyPinned, std::optional onlyVisible) { int no = 0; for (auto const& w : g_pCompositor->m_vWindows) { if (w->workspaceID() != m_iID || !w->m_bIsMapped) continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) continue; + if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) + continue; if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) continue; no++; @@ -550,7 +561,7 @@ int CWorkspace::getWindows(std::optional onlyTiled, std::optional on return no; } -int CWorkspace::getGroups(std::optional onlyTiled, std::optional onlyVisible) { +int CWorkspace::getGroups(std::optional onlyTiled, std::optional onlyPinned, std::optional onlyVisible) { int no = 0; for (auto const& w : g_pCompositor->m_vWindows) { if (w->workspaceID() != m_iID || !w->m_bIsMapped) @@ -559,6 +570,8 @@ int CWorkspace::getGroups(std::optional onlyTiled, std::optional onl continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) continue; + if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) + continue; if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) continue; no++; diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index e9859d4f..12dbe328 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -72,8 +72,8 @@ class CWorkspace { SWorkspaceIDName getPrevWorkspaceIDName() const; void updateWindowDecos(); void updateWindowData(); - int getWindows(std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroups(std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getWindows(std::optional onlyTiled = {}, std::optional onlyPinned = {}, std::optional onlyVisible = {}); + int getGroups(std::optional onlyTiled = {}, std::optional onlyPinned = {}, std::optional onlyVisible = {}); bool hasUrgentWindow(); PHLWINDOW getFirstWindow(); PHLWINDOW getTopLeftWindow(); From f7fcbe32c9f66bcfc86853a5cda95edcf481f573 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sat, 8 Feb 2025 01:46:26 +0100 Subject: [PATCH 1193/2393] renderer: various fixes towards improving gpu calls robustness (#9188) ensure framebuffer textures are detached and deleted, avoid leaving framebuffers bound when not needed * render: avoid calling glDeleteProgram on no program its safe to do so but it adds a bunch of unnecessery lines in apitrace when tracing. if guard it and return early. * opengl: ensure texture and buffers are unbound ensure bound buffers are unbound after use, also detach textures from framebuffer before deleting it otherwise it will become dangling and essentially leak. --- src/protocols/Screencopy.cpp | 6 ++++ src/protocols/ToplevelExport.cpp | 6 ++++ src/render/Framebuffer.cpp | 56 +++++++++++++++++--------------- src/render/Framebuffer.hpp | 3 +- src/render/OpenGL.hpp | 2 -- src/render/Renderbuffer.cpp | 8 ++--- src/render/Shader.cpp | 5 ++- 7 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index e086cc76..aae5caf1 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -289,6 +289,12 @@ bool CScreencopyFrame::copyShm() { g_pHyprOpenGL->m_RenderData.pMonitor.reset(); +#ifndef GLES2 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +#else + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif + LOGM(TRACE, "Copied frame via shm"); return true; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index a9009aa4..fb0bd9c7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -319,6 +319,12 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pPointerManager->damageCursor(PMONITOR->self.lock()); } + outFB.unbind(); + +#ifndef GLES2 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +#endif + return true; } diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 93f8fe7f..6905eb36 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -12,29 +12,26 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { uint32_t glFormat = NFormatUtils::drmFormatToGL(drmFormat); uint32_t glType = NFormatUtils::glFormatToType(glFormat); - if (!m_cTex) + if (!m_cTex) { m_cTex = makeShared(); - - if (!m_iFbAllocated) { - firstAlloc = true; - glGenFramebuffers(1, &m_iFb); - m_iFbAllocated = true; - } - - if (m_cTex->m_iTexID == 0) { - firstAlloc = true; m_cTex->allocate(); glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + firstAlloc = true; + } + + if (!m_iFbAllocated) { + glGenFramebuffers(1, &m_iFb); + m_iFbAllocated = true; + firstAlloc = true; } if (firstAlloc || m_vSize != Vector2D(w, h)) { glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, nullptr); - glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0); @@ -43,9 +40,6 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { if (m_pStencilTex) { glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); - - glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0); } #endif @@ -57,8 +51,7 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } glBindTexture(GL_TEXTURE_2D, 0); - if (g_pHyprOpenGL) - glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); + glBindFramebuffer(GL_FRAMEBUFFER, 0); m_vSize = Vector2D(w, h); @@ -80,7 +73,7 @@ void CFramebuffer::addStencil(SP tex) { RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); + glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } @@ -90,25 +83,36 @@ void CFramebuffer::bind() { #else glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); #endif + if (g_pHyprOpenGL) glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); else glViewport(0, 0, m_vSize.x, m_vSize.y); } +void CFramebuffer::unbind() { +#ifndef GLES2 + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#else + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + void CFramebuffer::release() { - if (!m_iFbAllocated && !m_cTex) - return; + if (m_iFbAllocated) { + glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - Debug::log(TRACE, "fb {} released", m_iFb); - - if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); + m_iFbAllocated = false; + m_iFb = 0; + } - m_cTex.reset(); - m_iFbAllocated = false; - m_vSize = Vector2D(); - m_iFb = 0; + if (m_cTex) + m_cTex.reset(); + + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 84dfeef1..092e548e 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -11,6 +11,7 @@ class CFramebuffer { bool alloc(int w, int h, uint32_t format = GL_RGBA); void addStencil(SP tex); void bind(); + void unbind(); void release(); void reset(); bool isAllocated(); @@ -28,4 +29,4 @@ class CFramebuffer { SP m_pStencilTex; friend class CRenderbuffer; -}; \ No newline at end of file +}; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 7b7b7e6f..cf1d2549 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -233,8 +233,6 @@ class CHyprOpenGLImpl { SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; - Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 887f31a9..1ea9f785 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -46,7 +46,7 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : return; } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + m_sFramebuffer.unbind(); listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); }); @@ -68,11 +68,7 @@ void CRenderbuffer::bindFB() { void CRenderbuffer::unbind() { glBindRenderbuffer(GL_RENDERBUFFER, 0); -#ifndef GLES2 - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#else - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif + m_sFramebuffer.unbind(); } CFramebuffer* CRenderbuffer::getFB() { diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index b494d79d..984d8ce3 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -17,7 +17,10 @@ CShader::~CShader() { } void CShader::destroy() { + if (program == 0) + return; + glDeleteProgram(program); program = 0; -} \ No newline at end of file +} From feb8ad48f0153a15b96356f280dbd04849db0e04 Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 8 Feb 2025 09:05:44 -0500 Subject: [PATCH 1194/2393] groups: deactivate unfocused windows in groups (#9354) --- src/Compositor.cpp | 3 +++ src/desktop/Window.cpp | 16 ++++++++++++++++ src/desktop/Window.hpp | 1 + 3 files changed, 20 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e460bbca..aebb0ac1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1189,6 +1189,9 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface if (*PFOLLOWMOUSE == 0) g_pInputManager->sendMotionEventsToFocused(); + + if (pWindow->m_sGroupData.pNextWindow) + pWindow->deactivateGroupMembers(); } void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindowOwner) { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b0d7b58c..7c0cb741 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1748,3 +1748,19 @@ void CWindow::setContentType(NContentType::eContentType contentType) { Debug::log(INFO, "ContentType for window {}", (int)contentType); m_pWLSurface->resource()->contentType->value = contentType; } + +void CWindow::deactivateGroupMembers() { + auto curr = getGroupHead(); + while (curr) { + if (curr != m_pSelf.lock()) { + if (curr->m_bIsX11) + curr->m_pXWaylandSurface->activate(false); + else if (curr->m_pXDGSurface && curr->m_pXDGSurface->toplevel) + curr->m_pXDGSurface->toplevel->setActive(false); + } + + curr = curr->m_sGroupData.pNextWindow.lock(); + if (curr == getGroupHead()) + break; + } +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 9a4a36c2..171a15f4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -474,6 +474,7 @@ class CWindow { void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); + void deactivateGroupMembers(); CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; From 8e10ddb592977ef2e1836e75b0e5550ba8fb56f0 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:00:55 +0500 Subject: [PATCH 1195/2393] datadevice: fix wrong param (#9370) Reason: look at the setReceive parameters and also at the next line(tries to narrow) --- src/protocols/core/DataDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 0931608a..25117265 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -39,7 +39,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + resource->setReceive([this](CWlDataOffer* r, const char* mime, int fd) { CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); From 56f6f61596a547cdcdfb7aa7c3550e380b487ee3 Mon Sep 17 00:00:00 2001 From: clamydo <13063485+clamydo@users.noreply.github.com> Date: Sun, 9 Feb 2025 15:30:30 +0100 Subject: [PATCH 1196/2393] tablet: take `active_area_size` into account when sending tip event (#9325) * fixes #9322, take `active_area_size` into account when sending tip event * check if `relative_input` is set As suggested by @y47s5s68tq870r7tc1xpp755pabopg * refactoring active area in own function to keep it DRY * coding style * making transformation static --------- Co-authored-by: clamydo --- src/managers/input/Tablets.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 0952a7d4..e1a2f2aa 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -88,6 +88,20 @@ static void refocusTablet(SP tab, SP tool, bool motion = f PROTO::tablet->motion(tool, local); } +static Vector2D transformToActiveRegion(const Vector2D pos, const CBox activeArea) { + auto newPos = pos; + + //Calculate transformations if active area is set + if (!activeArea.empty()) { + if (!std::isnan(pos.x)) + newPos.x = (pos.x - activeArea.x) / (activeArea.w - activeArea.x); + if (!std::isnan(pos.y)) + newPos.y = (pos.y - activeArea.y) / (activeArea.h - activeArea.y); + } + + return newPos; +} + void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { const auto PTAB = e.tablet; const auto PTOOL = ensureTabletToolPresent(e.tool); @@ -113,16 +127,9 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { if (PTAB->relativeInput) g_pPointerManager->move(delta); - else { - //Calculate transformations if active area is set - if (!PTAB->activeArea.empty()) { - if (!std::isnan(x)) - x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); - if (!std::isnan(y)) - y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); - } - g_pPointerManager->warpAbsolute({x, y}, PTAB); - } + else + g_pPointerManager->warpAbsolute(transformToActiveRegion({x, y}, PTAB->activeArea), PTAB); + break; } } @@ -160,7 +167,12 @@ void CInputManager::onTabletTip(CTablet::STipEvent e) { const auto PTAB = e.tablet; const auto PTOOL = ensureTabletToolPresent(e.tool); const auto POS = e.tip; - g_pPointerManager->warpAbsolute(POS, PTAB); + + if (PTAB->relativeInput) + g_pPointerManager->move({0, 0}); + else + g_pPointerManager->warpAbsolute(transformToActiveRegion(POS, PTAB->activeArea), PTAB); + refocusTablet(PTAB, PTOOL, true); if (e.in) From 1f97643e830d513cafc2057860bbefa5cc01a0ee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:38:20 +0000 Subject: [PATCH 1197/2393] core: add mallopt to modify trim threshold --- src/Compositor.cpp | 14 ++++++++++++++ src/Compositor.hpp | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index aebb0ac1..88a2530b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -69,6 +69,8 @@ #include #include #include +#include +#include using namespace Hyprutils::String; using namespace Aquamarine; @@ -162,10 +164,22 @@ void CCompositor::restoreNofile() { Debug::log(ERR, "Failed restoring NOFILE limits"); } +void CCompositor::setMallocThreshold() { +#ifdef M_TRIM_THRESHOLD + // The default is 128 pages, + // which is very large and can lead to a lot of memory used for no reason + // because trimming hasn't happened + static const int PAGESIZE = sysconf(_SC_PAGESIZE); + mallopt(M_TRIM_THRESHOLD, 6 * PAGESIZE); +#endif +} + CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) { if (onlyConfig) return; + setMallocThreshold(); + m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a57095a3..893ffadd 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -52,8 +52,6 @@ class CCompositor { void startCompositor(); void stopCompositor(); void cleanup(); - void createLockFile(); - void removeLockFile(); void bumpNofile(); void restoreNofile(); @@ -163,6 +161,9 @@ class CCompositor { void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); + void createLockFile(); + void removeLockFile(); + void setMallocThreshold(); uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; From 3a43e7bb9a787755639838d7cb005a9d33f8c6f2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:50:54 +0000 Subject: [PATCH 1198/2393] config: default movefocus_cycles_fullscreen to false less confusing --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 28cd29c4..8d1b73c4 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1234,7 +1234,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "binds:movefocus_cycles_fullscreen", .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, SConfigOptionDescription{ .value = "binds:movefocus_cycles_groupfirst", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3f45ddfe..f87a5e6b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -594,7 +594,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("binds:workspace_center_on", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:focus_preferred_method", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0}); - m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); + m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:movefocus_cycles_groupfirst", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:window_direction_monitor_fallback", Hyprlang::INT{1}); From f261fb6fe028a1427cfd672eee6e7d5705cd696f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:58:09 +0000 Subject: [PATCH 1199/2393] groupbar: fix groupbar missing when indicator_height is <= 0 ref #9291 #9372 --- .../decorations/CHyprGroupBarDecoration.cpp | 188 +++++++++--------- 1 file changed, 95 insertions(+), 93 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 32422e14..4e430bef 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -99,7 +99,11 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + + if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) + return; + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); static auto PHEIGHT = CConfigValue("group:groupbar:height"); @@ -110,14 +114,19 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { static auto PGRADIENTROUNDING = CConfigValue("group:groupbar:gradient_rounding"); static auto PGRADIENTROUNDINGONLYEDGES = CConfigValue("group:groupbar:gradient_round_only_edges"); static auto PROUNDONLYEDGES = CConfigValue("group:groupbar:round_only_edges"); + static auto PGROUPCOLACTIVE = CConfigValue("group:groupbar:col.active"); + static auto PGROUPCOLINACTIVE = CConfigValue("group:groupbar:col.inactive"); + static auto PGROUPCOLACTIVELOCKED = CConfigValue("group:groupbar:col.locked_active"); + static auto PGROUPCOLINACTIVELOCKED = CConfigValue("group:groupbar:col.locked_inactive"); + auto* const GROUPCOLACTIVE = (CGradientValueData*)(PGROUPCOLACTIVE.ptr())->getData(); + auto* const GROUPCOLINACTIVE = (CGradientValueData*)(PGROUPCOLINACTIVE.ptr())->getData(); + auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); + auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) - return; + const auto ASSIGNEDBOX = assignedBoxGlobal(); - const auto ASSIGNEDBOX = assignedBoxGlobal(); - - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); - m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; m_fBarHeight = *PSTACKED ? ((ASSIGNEDBOX.h - 2 - BAR_PADDING_OUTER_VERT) - BAR_PADDING_OUTER_VERT * (barsToDraw)) / barsToDraw : ASSIGNEDBOX.h - BAR_PADDING_OUTER_VERT; const auto DESIREDHEIGHT = *PSTACKED ? (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT : BAR_PADDING_OUTER_VERT * 2L + ONEBARHEIGHT; @@ -134,116 +143,109 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - *PINDICATORHEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, *PINDICATORHEIGHT}; - if (rect.width <= 0 || rect.height <= 0) - break; - rect.scale(pMonitor->scale); - static auto PGROUPCOLACTIVE = CConfigValue("group:groupbar:col.active"); - static auto PGROUPCOLINACTIVE = CConfigValue("group:groupbar:col.inactive"); - static auto PGROUPCOLACTIVELOCKED = CConfigValue("group:groupbar:col.locked_active"); - static auto PGROUPCOLINACTIVELOCKED = CConfigValue("group:groupbar:col.locked_inactive"); - auto* const GROUPCOLACTIVE = (CGradientValueData*)(PGROUPCOLACTIVE.ptr())->getData(); - auto* const GROUPCOLINACTIVE = (CGradientValueData*)(PGROUPCOLINACTIVE.ptr())->getData(); - auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); - auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked || g_pKeybindManager->m_bGroupsLocked; const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; CHyprColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; color.a *= a; - CRectPassElement::SRectData rectdata; - rectdata.color = color; - rectdata.box = rect; - if (*PROUNDING) { - if (*PROUNDONLYEDGES) { - static constexpr double PADDING = 20; - if (i == 0 && barsToDraw == 1) + if (!rect.empty()) { + CRectPassElement::SRectData rectdata; + rectdata.color = color; + rectdata.box = rect; + if (*PROUNDING) { + if (*PROUNDONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + rectdata.round = *PROUNDING; + else if (i == 0) { + double first = rect.w - (*PROUNDING * 2); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PROUNDING * 2; + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else rectdata.round = *PROUNDING; - else if (i == 0) { - double first = rect.w - (*PROUNDING * 2); - rectdata.round = *PROUNDING; - rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); - rectdata.round = 0; - rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } else if (i == barsToDraw - 1) { - double first = *PROUNDING * 2; - rectdata.round = 0; - rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); - rectdata.round = *PROUNDING; - rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } - } else - rectdata.round = *PROUNDING; + } + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); } - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}; rect.scale(pMonitor->scale); - if (*PGRADIENTS) { - const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX->m_iTexID) { - CTexPassElement::SRenderData data; - data.tex = GRADIENTTEX; - data.box = rect; - if (*PGRADIENTROUNDING) { - if (*PGRADIENTROUNDINGONLYEDGES) { - static constexpr double PADDING = 20; + if (!rect.empty()) { + if (*PGRADIENTS) { + const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + if (GRADIENTTEX->m_iTexID) { + CTexPassElement::SRenderData data; + data.tex = GRADIENTTEX; + data.box = rect; + if (*PGRADIENTROUNDING) { + if (*PGRADIENTROUNDINGONLYEDGES) { + static constexpr double PADDING = 20; - if (i == 0 && barsToDraw == 1) + if (i == 0 && barsToDraw == 1) + data.round = *PGRADIENTROUNDING; + else if (i == 0) { + double first = rect.w - (*PGRADIENTROUNDING * 2); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = 0; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PGRADIENTROUNDING * 2; + data.round = 0; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else data.round = *PGRADIENTROUNDING; - else if (i == 0) { - double first = rect.w - (*PGRADIENTROUNDING * 2); - data.round = *PGRADIENTROUNDING; - data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - data.round = 0; - data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } else if (i == barsToDraw - 1) { - double first = *PGRADIENTROUNDING * 2; - data.round = 0; - data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - data.round = *PGRADIENTROUNDING; - data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } - } else - rectdata.round = *PGRADIENTROUNDING; + } + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } + } + + if (*PRENDERTITLES) { + CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); + + if (!pTitleTex) + pTitleTex = + m_sTitleTexs.titleTexs + .emplace_back(makeUnique(m_dwGroupMembers[WINDOWINDEX].lock(), + Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) + .get(); + rect.y += std::ceil((rect.height - pTitleTex->texSize.y) / 2.0); + rect.height = pTitleTex->texSize.y; + rect.width = pTitleTex->texSize.x; + rect.x += std::round(((m_fBarWidth * pMonitor->scale) / 2.0) - (pTitleTex->texSize.x / 2.0)); + rect.round(); + + CTexPassElement::SRenderData data; + data.tex = pTitleTex->tex; + data.box = rect; g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } } - if (*PRENDERTITLES) { - CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); - - if (!pTitleTex) - pTitleTex = - m_sTitleTexs.titleTexs - .emplace_back(makeUnique(m_dwGroupMembers[WINDOWINDEX].lock(), - Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) - .get(); - rect.y += std::ceil((rect.height - pTitleTex->texSize.y) / 2.0); - rect.height = pTitleTex->texSize.y; - rect.width = pTitleTex->texSize.x; - rect.x += std::round((m_fBarWidth * pMonitor->scale) / 2.0 - (pTitleTex->texSize.x / 2.0)); - rect.round(); - - CTexPassElement::SRenderData data; - data.tex = pTitleTex->tex; - data.box = rect; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - } - if (*PSTACKED) yoff += ONEBARHEIGHT; else From e1179b665b307e46a57367493a85ac80f34f2ce4 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 10 Feb 2025 20:11:35 +0200 Subject: [PATCH 1200/2393] flake.lock: update --- flake.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/flake.lock b/flake.lock index 7637a2c7..38f48983 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1738456976, - "narHash": "sha256-cufyHbOMnSt9V4w4OVSzNcpJ+8DwzRZRJaca2Q89KVI=", + "lastModified": 1739103745, + "narHash": "sha256-c53dcRaw0F4Os9WD05HwIRs9kTDZw4Mxe1XK4edEALo=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "257b2050790ab3b1eb389e0f8bdc400eb9510139", + "rev": "a3dda0d10ce9aa1d1dfb7a6c139ea8c2872c74bd", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1738178255, - "narHash": "sha256-+D6Nu2ewXbMTFzx/Q4jDOo+LAOUPr0cxQJg5k33daIE=", + "lastModified": 1738664950, + "narHash": "sha256-xIeGNM+iivwVHkv9tHwOqoUP5dDrtees34bbFKKMZYs=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "dcadd3398abe146d60c67e0d9ee6e27b301cae82", + "rev": "7c6d165e1eb9045a996551eb9f121b6d1b30adc3", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1738437059, - "narHash": "sha256-J+8ecqaP3zD9GHeN8Y4hUapoELSoggp0IZI8laTFt/0=", + "lastModified": 1739049071, + "narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "5ac80e3686a4dfa55d2bd15c81a266b89594a295", + "rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73", "type": "github" }, "original": { @@ -189,11 +189,11 @@ ] }, "locked": { - "lastModified": 1737981711, - "narHash": "sha256-lh6cL5D8nPplB3WovCQjLUZ7k7MViiBrMlpkfm4R7/c=", + "lastModified": 1739048983, + "narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "96bf0677fa9cd13508294e3d4559dfbbc8beff73", + "rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8", "type": "github" }, "original": { @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1737634606, - "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", + "lastModified": 1739048914, + "narHash": "sha256-vd5rJBTmp2w7SDgfv23Zcd84ktI5eDA7e5UBzx+pKrU=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "f41271d35cc0f370d300413d756c2677f386af9d", + "rev": "a7334904d591f38757c46fbe2ab68651877d9099", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1737978343, - "narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=", + "lastModified": 1739048933, + "narHash": "sha256-ck6MaoYvISBQKqZR+HcxXnx0wOhyCauxfVMaV5zhJxQ=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab", + "rev": "e4e018a2ca6f5a9c33511973454199e1c7c85499", "type": "github" }, "original": { @@ -261,11 +261,11 @@ ] }, "locked": { - "lastModified": 1735493474, - "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", + "lastModified": 1739049028, + "narHash": "sha256-RleJp7LYbr6s+M1xgbmhtBs+fYa3ZdIiF7+QalJ4D1g=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", + "rev": "04146df74a8d5ec0b579657307be01f1e241125f", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1738410390, - "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", + "lastModified": 1739020877, + "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3a228057f5b619feb3186e986dbe76278d707b6e", + "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", "type": "github" }, "original": { From f2d43e5f2180adb81b3b7b51a7d0f39dace70b05 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 10 Feb 2025 20:17:29 +0200 Subject: [PATCH 1201/2393] nix/overlays: add wayland-protocols overlay --- nix/overlays.nix | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/nix/overlays.nix b/nix/overlays.nix index b632d0b4..c5dd1bee 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -28,6 +28,7 @@ in { inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default + self.overlays.wayland-protocols-bump self.overlays.udis86 # Hyprland packages themselves @@ -89,4 +90,17 @@ in { patches = []; }); }; + + # Temporary bump until https://nixpk.gs/pr-tracker.html?pr=367753 is merged. + # Expect to build the universe. + wayland-protocols-bump = final: prev: { + wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: { + version = "1.40"; + + src = prev.fetchurl { + url = "https://gitlab.freedesktop.org/wayland/${super.pname}/-/releases/${self.version}/downloads/${super.pname}-${self.version}.tar.xz"; + hash = "sha256-shcReTJHwsQnY5FDkt+p/LnjcoyktKoRCtuNkV/ABok="; + }; + }); + }; } From f83fe9986b34c53c67b113a015d54fe8c084e9bd Mon Sep 17 00:00:00 2001 From: "J. J. Ramsey" Date: Tue, 11 Feb 2025 09:58:43 -0500 Subject: [PATCH 1202/2393] protocols: add version 2 of ext-idle-notify-v1 protocol (#8959) Signed-off-by: James Ramsey Co-authored-by: James Ramsey --- protocols/meson.build | 2 +- src/managers/ProtocolManager.cpp | 2 +- src/protocols/IdleNotify.cpp | 26 ++++++++++++++++++-------- src/protocols/IdleNotify.hpp | 9 ++++++--- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index 7c57470b..f0a6a7e6 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,6 +1,6 @@ wayland_protos = dependency( 'wayland-protocols', - version: '>=1.32', + version: '>=1.40', fallback: 'wayland-protocols', default_options: ['tests=false'], ) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6cd3a608..6474d661 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -147,7 +147,7 @@ CProtocolManager::CProtocolManager() { PROTO::constraints = makeUnique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = makeUnique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::activation = makeUnique(&xdg_activation_v1_interface, 1, "XDGActivation"); - PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); + PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 2, "IdleNotify"); PROTO::lockNotify = makeUnique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); PROTO::sessionLock = makeUnique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = makeUnique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index bc5aabb1..14a5f3e1 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -10,7 +10,8 @@ static int onTimer(SP self, void* data) { return 0; } -CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_) : resource(resource_), timeoutMs(timeoutMs_) { +CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_, bool obeyInhibitors_) : + resource(resource_), timeoutMs(timeoutMs_), obeyInhibitors(obeyInhibitors_) { if UNLIKELY (!resource_->resource()) return; @@ -35,7 +36,7 @@ bool CExtIdleNotification::good() { } void CExtIdleNotification::updateTimer() { - if (PROTO::idle->isInhibited) + if (PROTO::idle->isInhibited && obeyInhibitors) timer->updateTimeout(std::nullopt); else timer->updateTimeout(std::chrono::milliseconds(timeoutMs)); @@ -54,6 +55,10 @@ void CExtIdleNotification::onActivity() { updateTimer(); } +bool CExtIdleNotification::inhibitorsAreObeyed() const { + return obeyInhibitors; +} + CIdleNotifyProtocol::CIdleNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -63,7 +68,10 @@ void CIdleNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ve RESOURCE->setOnDestroy([this](CExtIdleNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CExtIdleNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetIdleNotification([this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat); }); + RESOURCE->setGetIdleNotification( + [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, true); }); + RESOURCE->setGetInputIdleNotification( + [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, false); }); } void CIdleNotifyProtocol::onManagerResourceDestroy(wl_resource* res) { @@ -74,9 +82,10 @@ void CIdleNotifyProtocol::destroyNotification(CExtIdleNotification* notif) { std::erase_if(m_vNotifications, [&](const auto& other) { return other.get() == notif; }); } -void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { - const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout)).get(); +void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat, bool obeyInhibitors) { + const auto CLIENT = pMgr->client(); + const auto RESOURCE = + m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout, obeyInhibitors)).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); @@ -94,6 +103,7 @@ void CIdleNotifyProtocol::onActivity() { void CIdleNotifyProtocol::setInhibit(bool inhibited) { isInhibited = inhibited; for (auto const& n : m_vNotifications) { - n->onActivity(); + if (n->inhibitorsAreObeyed()) + n->onActivity(); } -} \ No newline at end of file +} diff --git a/src/protocols/IdleNotify.hpp b/src/protocols/IdleNotify.hpp index e3dcdc98..efc3accc 100644 --- a/src/protocols/IdleNotify.hpp +++ b/src/protocols/IdleNotify.hpp @@ -9,19 +9,22 @@ class CEventLoopTimer; class CExtIdleNotification { public: - CExtIdleNotification(SP resource_, uint32_t timeoutMs); + CExtIdleNotification(SP resource_, uint32_t timeoutMs, bool obeyInhibitors); ~CExtIdleNotification(); bool good(); void onTimerFired(); void onActivity(); + bool inhibitorsAreObeyed() const; + private: SP resource; uint32_t timeoutMs = 0; SP timer; - bool idled = false; + bool idled = false; + bool obeyInhibitors = false; void updateTimer(); }; @@ -38,7 +41,7 @@ class CIdleNotifyProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyNotification(CExtIdleNotification* notif); - void onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat); + void onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat, bool obeyInhibitors); bool isInhibited = false; From 68bb3e7f0a1d528a8b2da1f92d2005889587561d Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 12 Feb 2025 08:54:42 -0500 Subject: [PATCH 1203/2393] env: move XDG_SESSION_TYPE to before backend init (#9390) --- src/Compositor.cpp | 1 - src/main.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 88a2530b..6d9e8d7e 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -386,7 +386,6 @@ void CCompositor::initServer(std::string socketName, int socketFd) { } setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); - setenv("XDG_SESSION_TYPE", "wayland", 1); if (!getenv("XDG_CURRENT_DESKTOP")) { setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); m_bDesktopEnvSet = true; diff --git a/src/main.cpp b/src/main.cpp index 464ed978..397d7463 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ int main(int argc, char** argv) { setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("XDG_BACKEND", "wayland", 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); setenv("MOZ_ENABLE_WAYLAND", "1", 1); From 17894051634716ab80c6502abdbb90ae2bc68f25 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:06:36 +0000 Subject: [PATCH 1204/2393] session-lock: send locked when in unsafe state (#9399) --- src/managers/SessionLockManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 996860a1..40611199 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -89,6 +89,13 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pCompositor->focusSurface(nullptr); g_pSeatManager->setGrab(nullptr); + + // Normally the locked event is sent after each output rendered a lock screen frame. + // When there are no outputs, send it right away. + if (g_pCompositor->m_bUnsafeState) { + m_pSessionLock->lock->sendLocked(); + m_pSessionLock->m_hasSentLocked = true; + } } bool CSessionLockManager::isSessionLocked() { @@ -131,8 +138,7 @@ void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) { if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked) return; m_pSessionLock->m_lockedMonitors.emplace(id); - const auto MONITORS = g_pCompositor->m_vMonitors; - const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); + const bool LOCKED = std::ranges::all_of(g_pCompositor->m_vMonitors, [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); if (LOCKED && m_pSessionLock->lock->good()) { m_pSessionLock->lock->sendLocked(); m_pSessionLock->m_hasSentLocked = true; From 208f94fe12a30474d6805262524da3da492a0990 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:08:03 +0000 Subject: [PATCH 1205/2393] animations: sync inactive/active border angles when using borderangle animations (#9401) --- src/render/decorations/CHyprBorderDecoration.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 5f2fdbda..0df3acde 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -63,6 +63,11 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (m_pWindow->m_fBorderAngleAnimationProgress->enabled()) { grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress->value() * M_PI * 2; grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); + + // When borderangle is animated, it is counterintuitive to fade between inactive/active gradient angles. + // Instead we sync the angles to avoid fading between them and additionally rotating the border angle. + if (ANIMATED) + m_pWindow->m_cRealBorderColorPrevious.m_fAngle = grad.m_fAngle; } int borderSize = m_pWindow->getRealBorderSize(); From 5d2b00829484684b619a8c0de6b1d2b1d18d31a9 Mon Sep 17 00:00:00 2001 From: Anthony Ruhier Date: Thu, 13 Feb 2025 12:09:25 +0100 Subject: [PATCH 1206/2393] renderer: disable explicit if aquamarine output doesn't support it (#9396) (#9398) The explicit settings ignore the aquamarine output.supportsExplicit attribute, which creates glitches on drivers not supporting explicit sync (example: freedreno). If the output has been set as not supporting explicit, disable the explicit settings. --- src/helpers/Monitor.cpp | 2 +- src/render/Renderer.cpp | 14 +++++++++++--- src/render/Renderer.hpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e4843211..fead5db9 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1312,7 +1312,7 @@ bool CMonitor::attemptDirectScanout() { return false; } - auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(); + auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output); // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6f0bbe44..531ceb33 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1557,7 +1557,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { } } - auto explicitOptions = getExplicitSyncSettings(); + auto explicitOptions = getExplicitSyncSettings(pMonitor->output); if (!explicitOptions.explicitEnabled) return ok; @@ -2293,7 +2293,7 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - auto explicitOptions = getExplicitSyncSettings(); + auto explicitOptions = getExplicitSyncSettings(PMONITOR->output); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { auto sync = g_pHyprOpenGL->createEGLSync({}); @@ -2336,7 +2336,7 @@ bool CHyprRenderer::isNvidia() { return m_bNvidia; } -SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { +SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings(SP output) { static auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static auto PENABLEEXPLICITKMS = CConfigValue("render:explicit_sync_kms"); @@ -2344,6 +2344,14 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { settings.explicitEnabled = *PENABLEEXPLICIT; settings.explicitKMSEnabled = *PENABLEEXPLICITKMS; + if (!output->supportsExplicit) { + Debug::log(LOG, "Renderer: the aquamarine output does not support explicit, explicit settings are disabled."); + settings.explicitEnabled = false; + settings.explicitKMSEnabled = false; + + return settings; + } + if (*PENABLEEXPLICIT == 2 /* auto */) settings.explicitEnabled = true; if (*PENABLEEXPLICITKMS == 2 /* auto */) { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index e64d41c1..731ed926 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -75,7 +75,7 @@ class CHyprRenderer { bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); - SExplicitSyncSettings getExplicitSyncSettings(); + SExplicitSyncSettings getExplicitSyncSettings(SP output); void addWindowToRenderUnfocused(PHLWINDOW window); void makeWindowSnapshot(PHLWINDOW); void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); From 40adb3dfb4b6f8cf0c5093f095954e3ef162a8eb Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:37:59 +0000 Subject: [PATCH 1207/2393] config: actually set initial beziers (#9400) --- src/config/ConfigManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f87a5e6b..43abcb1f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -885,9 +885,9 @@ void CConfigManager::setDefaultAnimationVars() { m_AnimationTree.createNode("specialWorkspaceOut", "specialWorkspace"); // init the root nodes - m_AnimationTree.setConfigForNode("global", 1, 8.f, "", "default"); - m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "", "linear"); - m_AnimationTree.setConfigForNode("borderangle", 0, 0.f, "", "default"); + m_AnimationTree.setConfigForNode("global", 1, 8.f, "default"); + m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "linear"); + m_AnimationTree.setConfigForNode("borderangle", 0, 1, "default"); } std::optional CConfigManager::resetHLConfig() { From df3fba157279de53c582344b59699a21ac5d62b5 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:31:03 +0500 Subject: [PATCH 1208/2393] internal: remove unused variable (#9402) --- src/helpers/MiscFunctions.cpp | 91 ----------------------------------- 1 file changed, 91 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index f532617c..9e398fd9 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -49,97 +49,6 @@ using namespace Hyprutils::OS; #endif #endif -static const float transforms[][9] = { - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - 1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - -1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - 1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - -1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, -}; - std::string absolutePath(const std::string& rawpath, const std::string& currentPath) { auto value = rawpath; From fb36815b0146d7b494cd648be0dfaa67a14d164a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Feb 2025 22:51:36 +0000 Subject: [PATCH 1209/2393] renderer: remove spammy log --- src/render/Renderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 531ceb33..b61f1c3e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2345,7 +2345,6 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings(SPsupportsExplicit) { - Debug::log(LOG, "Renderer: the aquamarine output does not support explicit, explicit settings are disabled."); settings.explicitEnabled = false; settings.explicitKMSEnabled = false; From 1309b59f2cb5179a4c59c111c35c7feede535eb6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Feb 2025 00:18:43 +0000 Subject: [PATCH 1210/2393] monitor: report a scheduled frame when tearing on cursor move --- src/helpers/Monitor.cpp | 18 ++++++++++++++++++ src/helpers/Monitor.hpp | 1 + src/managers/PointerManager.cpp | 10 +++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fead5db9..24db3ea4 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1441,6 +1441,24 @@ void CMonitor::onMonitorFrame() { g_pHyprRenderer->renderMonitor(self.lock()); } +void CMonitor::onCursorMovedOnMonitor() { + if (!tearingState.activelyTearing || !solitaryClient || !g_pHyprRenderer->shouldRenderCursor()) + return; + + // submit a frame immediately. This will only update the cursor pos. + // output->state->setBuffer(output->state->state().buffer); + // output->state->addDamage(CRegion{}); + // output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE); + // if (!output->commit()) + // Debug::log(ERR, "onCursorMovedOnMonitor: tearing and wanted to update cursor, failed."); + + // FIXME: try to do the above. We currently can't just render because drm is a fucking bitch + // and throws a "nO pRoP cAn Be ChAnGeD dUrInG AsYnC fLiP" on crtc_x + // this will throw too but fix it if we use sw cursors + + tearingState.frameScheduledWhileBusy = true; +} + CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) { ; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index c67bccc5..690b8c4a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -186,6 +186,7 @@ class CMonitor { void scheduleDone(); bool attemptDirectScanout(); void setCTM(const Mat3x3& ctm); + void onCursorMovedOnMonitor(); void debugLastPresentation(const std::string& message); void onMonitorFrame(); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 1c8e9976..24f2b35d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -17,6 +17,9 @@ #include #include #include +#include + +using namespace Hyprutils::Utils; CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { @@ -310,7 +313,12 @@ void CPointerManager::onCursorMoved() { recalc = true; } - if (state->hardwareFailed || !state->entered) + if (!state->entered) + continue; + + CScopeGuard x([m] { m->onCursorMovedOnMonitor(); }); + + if (state->hardwareFailed) continue; const auto CURSORPOS = getCursorPosForMonitor(m); From 2f967037aa00c4aecce62222e5e21c1790148eb0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Feb 2025 00:21:50 +0000 Subject: [PATCH 1211/2393] config: set no_hw_cursors to auto by default and disable on tearing when tearing, updates to the overlay plane may be ignored by the kernel. To avoid the cursor being a slideshow, disable hw cursors --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 5 +++-- src/config/ConfigManager.hpp | 2 +- src/managers/PointerManager.cpp | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 8d1b73c4..23635760 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1356,7 +1356,7 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "cursor:no_hardware_cursors", - .description = "disables hardware cursors", + .description = "disables hardware cursors. Auto = disable when tearing", .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, }, diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 43abcb1f..00dba200 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -621,7 +621,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); - m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); @@ -2798,12 +2798,13 @@ const std::vector& CConfigManager::getAllDescriptions( return CONFIG_OPTIONS; } -bool CConfigManager::shouldUseSoftwareCursors() { +bool CConfigManager::shouldUseSoftwareCursors(PHLMONITOR pMonitor) { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); switch (*PNOHW) { case 0: return false; case 1: return true; + case 2: return pMonitor->tearingState.activelyTearing; default: break; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index f0696882..b914a3a3 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -189,7 +189,7 @@ class CConfigManager { void ensureMonitorStatus(); void ensureVRR(PHLMONITOR pMonitor = nullptr); - bool shouldUseSoftwareCursors(); + bool shouldUseSoftwareCursors(PHLMONITOR pMonitor); void updateWatcher(); std::string parseKeyword(const std::string&, const std::string&); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 24f2b35d..048719b8 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -274,7 +274,7 @@ void CPointerManager::updateCursorBackend() { continue; } - if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors() || !attemptHardwareCursor(state)) { + if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors(m) || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->hardwareFailed = true; @@ -737,7 +737,8 @@ void CPointerManager::damageIfSoftware() { if (mw->monitor.expired() || !mw->monitor->output) continue; - if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { + if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors(mw->monitor.lock())) && + b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { g_pHyprRenderer->damageBox(b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } From 3eb6cb1875bd2f0850d19b1ad1b554c61b06bcec Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sat, 15 Feb 2025 14:48:52 +0100 Subject: [PATCH 1212/2393] syncobj: ensure we only add waiters on succesful checks (#9412) timeline check only returns nullopt on ETIME_ERR , meaning the if check later on returns true if drmSyncobjTimelineWait returns anything else like EINVAL/EPERM/EACCESS etc, so actually check the returned .value() of the std::optional. also move the fd to rvalue references. --- src/protocols/DRMSyncobj.cpp | 4 ++-- src/protocols/DRMSyncobj.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 23dafbca..38aab305 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -75,7 +75,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); @@ -104,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor&& fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 8677576f..9895dff1 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -33,7 +33,7 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor&& fd_); ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); From 7a6fde8414ae200759ac41569f189ac5e1ba0fbb Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 15 Feb 2025 08:51:17 -0500 Subject: [PATCH 1213/2393] internal: redirect exec'd app output to /dev/null (#9411) --- src/managers/KeybindManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8daa6838..4bfd1454 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -967,6 +967,14 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); + + int devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); + if (devnull != -1) { + dup2(devnull, STDOUT_FILENO); + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); From 410da2e46fc44d93196cd902a070391a416cff01 Mon Sep 17 00:00:00 2001 From: Roberto Previdi Date: Sat, 15 Feb 2025 15:01:52 +0100 Subject: [PATCH 1214/2393] workspaces: update persistence on workspace rename (#9368) --- src/Compositor.cpp | 51 ++++++++++++++++++++++++++------------- src/Compositor.hpp | 2 +- src/debug/HyprCtl.cpp | 14 ++++++----- src/desktop/Workspace.cpp | 6 +++++ 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6d9e8d7e..5389844f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3043,34 +3043,53 @@ bool CCompositor::shouldChangePreferredImageDescription() { return false; } -void CCompositor::ensurePersistentWorkspacesPresent(const std::vector& rules) { +void CCompositor::ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace) { + for (const auto& rule : rules) { if (!rule.isPersistent) continue; + PHLWORKSPACE PWORKSPACE = nullptr; + if (pWorkspace) { + if (pWorkspace->matchesStaticSelector(rule.workspaceString)) + PWORKSPACE = pWorkspace; + else + continue; + } + const auto PMONITOR = getMonitorFromString(rule.monitor); + if (!PWORKSPACE) { + WORKSPACEID id = rule.workspaceId; + std::string wsname = rule.workspaceName; + + if (id == WORKSPACE_INVALID) { + const auto R = getWorkspaceIDNameFromString(rule.workspaceString); + id = R.id; + wsname = R.name; + } + + if (id == WORKSPACE_INVALID) { + Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); + continue; + } + PWORKSPACE = getWorkspaceByID(id); + if (!PWORKSPACE) + createNewWorkspace(id, PMONITOR ? PMONITOR : m_pLastMonitor.lock(), wsname, false); + } + + if (PWORKSPACE) + PWORKSPACE->m_bPersistent = true; + if (!PMONITOR) { Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve monitor for {}, skipping", rule.monitor); continue; } - WORKSPACEID id = rule.workspaceId; - std::string wsname = rule.workspaceName; - if (id == WORKSPACE_INVALID) { - const auto R = getWorkspaceIDNameFromString(rule.workspaceString); - id = R.id; - wsname = R.name; - } - - if (id == WORKSPACE_INVALID) { - Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); - continue; - } - - if (const auto PWORKSPACE = getWorkspaceByID(id); PWORKSPACE) { + if (PWORKSPACE) { if (PWORKSPACE->m_pMonitor == PMONITOR) { Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} already on {}", rule.workspaceString, PMONITOR->szName); + continue; } @@ -3078,8 +3097,6 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector pSurface, wl_output_transform transform); void updateSuspendedStates(); void onNewMonitor(SP output); - void ensurePersistentWorkspacesPresent(const std::vector& rules); + void ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace = nullptr); SImageDescription getPreferredImageDescription(); bool shouldChangePreferredImageDescription(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cd6451e2..a155474d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -319,15 +319,17 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form "windows": {}, "hasfullscreen": {}, "lastwindow": "0x{:x}", - "lastwindowtitle": "{}" + "lastwindowtitle": "{}", + "ispersistent": {} }})#", w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), - escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), - (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); + escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), w->m_bHasFullscreenWindow ? "true" : "false", + (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false"); } else { - return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, - w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, - (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : ""); + return std::format( + "workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n", + w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, + (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent); } } diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index f2c22195..322c4e33 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -648,6 +648,12 @@ void CWorkspace::rename(const std::string& name) { Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name); m_szName = name; + const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock()); + m_bPersistent = WORKSPACERULE.isPersistent; + + if (WORKSPACERULE.isPersistent) + g_pCompositor->ensurePersistentWorkspacesPresent(std::vector{WORKSPACERULE}, m_pSelf.lock()); + g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName}); } From 9228116c9aa682477aae1a52d2d7d023bb075352 Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 15 Feb 2025 14:03:37 -0500 Subject: [PATCH 1215/2393] xwayland: fix a possible clipboard race condition (#9394) --- src/xwayland/XDataSource.cpp | 15 ++++--- src/xwayland/XWM.cpp | 85 ++++++++++++++++++++++++++++-------- src/xwayland/XWM.hpp | 2 +- 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 9384db69..003f6c9f 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -71,19 +71,20 @@ void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); - selection.transfer = makeUnique(selection); - selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); - const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; - xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, selection.transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK); + auto transfer = makeUnique(selection); + transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); + const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK); - xcb_convert_selection(g_pXWayland->pWM->connection, selection.transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME); + xcb_convert_selection(g_pXWayland->pWM->connection, transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME); xcb_flush(g_pXWayland->pWM->connection); //TODO: make CFileDescriptor setflags take SETFL aswell fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = std::move(fd); + transfer->wlFD = std::move(fd); + selection.transfers.emplace_back(std::move(transfer)); } void CXDataSource::accepted(const std::string& mime) { diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 68552dd6..f2a9b794 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -571,9 +571,10 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { SXSelection* sel = getSelection(e->selection); if (e->property == XCB_ATOM_NONE) { - if (sel->transfer) { + auto it = std::ranges::find_if(sel->transfers, [](const auto& t) { return !t->propertyReply; }); + if (it != sel->transfers.end()) { Debug::log(TRACE, "[xwm] converting selection failed"); - sel->transfer.reset(); + sel->transfers.erase(it); } } else if (e->target == HYPRATOMS["TARGETS"] && sel == &clipboard) { if (!focusedSurface) { @@ -582,7 +583,7 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { } setClipboardToWayland(*sel); - } else if (sel->transfer) + } else if (!sel->transfers.empty()) getTransferData(*sel); } @@ -1177,17 +1178,50 @@ static int writeDataSource(int fd, uint32_t mask, void* data) { void CXWM::getTransferData(SXSelection& sel) { Debug::log(LOG, "[xwm] getTransferData"); - sel.transfer->getIncomingSelectionProp(true); - - if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { - Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - sel.transfer.reset(); + auto it = std::ranges::find_if(sel.transfers, [](const auto& t) { return !t->propertyReply; }); + if (it == sel.transfers.end()) { + Debug::log(ERR, "[xwm] No pending transfer found"); return; - } else { - sel.onWrite(); - if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } + + auto& transfer = *it; + if (!transfer || !transfer->incomingWindow) { + Debug::log(ERR, "[xwm] Invalid transfer state"); + sel.transfers.erase(it); + return; + } + + if (!transfer->getIncomingSelectionProp(true)) { + Debug::log(ERR, "[xwm] Failed to get property data"); + sel.transfers.erase(it); + return; + } + + if (!transfer->propertyReply) { + Debug::log(ERR, "[xwm] No property reply"); + sel.transfers.erase(it); + return; + } + + if (transfer->propertyReply->type == HYPRATOMS["INCR"]) { + Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); + sel.transfers.erase(it); + return; + } + + const size_t pos = std::distance(sel.transfers.begin(), it); + sel.onWrite(); + + if (pos >= sel.transfers.size()) + return; + + auto newIt = sel.transfers.begin() + pos; + if (newIt == sel.transfers.end() || !(*newIt)) + return; + + auto& updatedTransfer = *newIt; + if (updatedTransfer->eventSource && updatedTransfer->wlFD.get() != -1) + updatedTransfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, updatedTransfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } void CXWM::setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot) { @@ -1290,16 +1324,21 @@ void SXSelection::onKeyboardFocus() { } int SXSelection::onRead(int fd, uint32_t mask) { - // TODO: support INCR + auto it = std::ranges::find_if(transfers, [fd](const auto& t) { return t->wlFD.get() == fd; }); + if (it == transfers.end()) { + Debug::log(ERR, "[xwm] No transfer found for fd {}", fd); + return 0; + } - size_t pre = transfer->data.size(); + auto& transfer = *it; + size_t pre = transfer->data.size(); transfer->data.resize(INCR_CHUNK_SIZE + pre); auto len = read(fd, transfer->data.data() + pre, INCR_CHUNK_SIZE - 1); if (len < 0) { Debug::log(ERR, "[xwm] readDataSource died"); g_pXWayland->pWM->selectionSendNotify(&transfer->request, false); - transfer.reset(); + transfers.erase(it); return 0; } @@ -1311,7 +1350,7 @@ int SXSelection::onRead(int fd, uint32_t mask) { transfer->data.size(), transfer->data.data()); xcb_flush(g_pXWayland->pWM->connection); g_pXWayland->pWM->selectionSendNotify(&transfer->request, true); - transfer.reset(); + transfers.erase(it); } else Debug::log(LOG, "[xwm] Received {} bytes, waiting...", len); @@ -1346,7 +1385,7 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { mime = *MIMES.begin(); } - transfer = makeUnique(*this); + auto transfer = makeUnique(*this); transfer->request = *e; int p[2]; @@ -1368,18 +1407,26 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { selection->send(mime, CFileDescriptor{p[1]}); transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); + transfers.emplace_back(std::move(transfer)); return true; } int SXSelection::onWrite() { + auto it = std::ranges::find_if(transfers, [](const auto& t) { return t->propertyReply; }); + if (it == transfers.end()) { + Debug::log(ERR, "[xwm] No transfer with property data found"); + return 0; + } + + auto& transfer = *it; char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - transfer.reset(); + transfers.erase(it); return 0; } @@ -1388,7 +1435,7 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - transfer.reset(); + transfers.erase(it); } return 1; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 73a02a86..f6dcee54 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -58,7 +58,7 @@ struct SXSelection { CHyprSignalListener keyboardFocusChange; } listeners; - UP transfer; + std::vector> transfers; }; class CXCBConnection { From 94a30889a78fa7c7f87fe8134c18357855824c35 Mon Sep 17 00:00:00 2001 From: andrewandreii <63286820+andrewandreii@users.noreply.github.com> Date: Sat, 15 Feb 2025 21:04:02 +0200 Subject: [PATCH 1216/2393] keybinds: fix some errors not returning a failure (#9416) --- src/managers/KeybindManager.cpp | 65 ++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4bfd1454..4e63e6dc 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1723,7 +1723,7 @@ SDispatchResult CKeybindManager::changeGroupActive(std::string args) { // index starts from '1'; '0' means last window const int INDEX = std::stoi(args); if (INDEX > PWINDOW->getGroupSize()) - return {}; + return {.success = false, .error = "Index too big, there aren't that many windows in this group"}; if (INDEX == 0) PWINDOW->setGroupCurrent(PWINDOW->getGroupTail()); else @@ -1986,7 +1986,7 @@ SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!args.contains(' ')) - return {}; + return {.success = false, .error = "Invalid arguments, expected: workspace monitor"}; std::string workspace = args.substr(0, args.find_first_of(' ')); std::string monitor = args.substr(args.find_first_of(' ') + 1); @@ -2129,13 +2129,16 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { SDispatchResult CKeybindManager::resizeActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Window is fullscreen"}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) - return {}; + return {.success = false, .error = "Invalid size provided"}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal()); @@ -2148,8 +2151,11 @@ SDispatchResult CKeybindManager::resizeActive(std::string args) { SDispatchResult CKeybindManager::moveActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Window is fullscreen"}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal()); @@ -2171,7 +2177,7 @@ SDispatchResult CKeybindManager::moveWindow(std::string args) { } if (PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window is fullscreen"}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal()); @@ -2193,12 +2199,12 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) { } if (PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window is fullscreen"}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) - return {}; + return {.success = false, .error = "Invalid size provided"}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW); @@ -2244,7 +2250,7 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) - return {}; + return {.success = false, .error = "No such window found"}; Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); @@ -2304,7 +2310,7 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) { else if (vars.size() == 2) PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); else - return {}; + return {.success = false, .error = "Invalid number of arguments, expected 1 or 2 arguments"}; if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { PWINDOW->updateDynamicRules(); @@ -2674,7 +2680,10 @@ SDispatchResult CKeybindManager::swapActiveWorkspaces(std::string args) { const auto PMON1 = g_pCompositor->getMonitorFromString(MON1); const auto PMON2 = g_pCompositor->getMonitorFromString(MON2); - if (!PMON1 || !PMON2 || PMON1 == PMON2) + if (!PMON1 || !PMON2) + return {.success = false, .error = "No such monitor found"}; + + if (PMON1 == PMON2) return {}; g_pCompositor->swapActiveWorkspaces(PMON1, PMON2); @@ -2697,7 +2706,7 @@ SDispatchResult CKeybindManager::pinActive(std::string args) { } if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window does not qualify to be pinned"}; PWINDOW->m_bPinned = !PWINDOW->m_bPinned; @@ -2825,8 +2834,11 @@ SDispatchResult CKeybindManager::lockGroups(std::string args) { SDispatchResult CKeybindManager::lockActiveGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Not a group"}; const auto PHEAD = PWINDOW->getGroupHead(); @@ -2947,7 +2959,7 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return {}; + return {.success = false, .error = "Groups locked"}; PHLWINDOW PWINDOW = nullptr; @@ -2956,8 +2968,11 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { else PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Window not in a group"}; moveWindowOutOfGroup(PWINDOW); @@ -2975,7 +2990,10 @@ SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) { } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || PWINDOW->isFullscreen()) + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (PWINDOW->isFullscreen()) return {}; if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { @@ -3064,8 +3082,11 @@ SDispatchResult CKeybindManager::moveGroupWindow(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PLASTWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Window not in a group"}; if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); From 897ee276dc0a8a6b11a8102b225a9e969faac0bf Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sun, 16 Feb 2025 00:20:42 +0000 Subject: [PATCH 1217/2393] xwayland: configure on a configure request and cleanup geometry conversion (#9375) * xwayland: configure the window on a configure request * xwayland: move coordinate conversion handling to their own functions * xwayland: rename configure to configureRequest --- src/desktop/Window.cpp | 120 ++++++++++++++++++++++++-------------- src/desktop/Window.hpp | 9 ++- src/xwayland/XSurface.hpp | 4 +- src/xwayland/XWM.cpp | 9 +-- src/xwayland/XWM.hpp | 2 +- 5 files changed, 91 insertions(+), 53 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7c0cb741..7b7f954d 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -95,15 +95,15 @@ CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { CWindow::CWindow(SP surface) : m_pXWaylandSurface(surface) { m_pWLSurface = CWLSurface::create(); - listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); - listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); - listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); - listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); - listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast(d)); }); - listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); - listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); - listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); - listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); }); + listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); + listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); + listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); + listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); + listeners.configureRequest = m_pXWaylandSurface->events.configureRequest.registerListener([this](std::any d) { onX11ConfigureRequest(std::any_cast(d)); }); + listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); + listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); + listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); + listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); }); if (m_pXWaylandSurface->overrideRedirect) listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); }); @@ -1530,14 +1530,14 @@ void CWindow::onResourceChangeX11() { Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get()); } -void CWindow::onX11Configure(CBox box) { +void CWindow::onX11ConfigureRequest(CBox box) { if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) { m_pXWaylandSurface->configure(box); m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); - if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) - m_fX11SurfaceScaledBy = PMONITOR->scale; + m_vReportedPosition = box.pos(); + updateX11SurfaceScale(); return; } @@ -1555,25 +1555,20 @@ void CWindow::onX11Configure(CBox box) { else setHidden(true); - const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos()); - - m_vRealPosition->setValueAndWarp(LOGICALPOS); - m_vRealSize->setValueAndWarp(box.size()); - - static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (*PXWLFORCESCALEZERO) { - if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { - m_vRealSize->setValueAndWarp(m_vRealSize->goal() / PMONITOR->scale); - m_fX11SurfaceScaledBy = PMONITOR->scale; - } - } + m_vRealPosition->setValueAndWarp(xwaylandPositionToReal(box.pos())); + m_vRealSize->setValueAndWarp(xwaylandSizeToReal(box.size())); m_vPosition = m_vRealPosition->goal(); m_vSize = m_vRealSize->goal(); - m_vPendingReportedSize = box.size(); - m_vReportedSize = box.size(); + if (m_vPendingReportedSize != box.size() || m_vReportedPosition != box.pos()) { + m_pXWaylandSurface->configure(box); + m_vReportedSize = box.size(); + m_vPendingReportedSize = box.size(); + m_vReportedPosition = box.pos(); + } + updateX11SurfaceScale(); updateWindowDecos(); if (!m_pWorkspace || !m_pWorkspace->isVisible()) @@ -1700,37 +1695,74 @@ Vector2D CWindow::requestedMaxSize() { return maxSize; } -void CWindow::sendWindowSize(bool force) { +Vector2D CWindow::realToReportSize() { + if (!m_bIsX11) + return m_vRealSize->goal().clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - const auto PMONITOR = m_pMonitor.lock(); + + const auto REPORTSIZE = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto PMONITOR = m_pMonitor.lock(); + + if (*PXWLFORCESCALEZERO && PMONITOR) + return REPORTSIZE * PMONITOR->scale; + + return REPORTSIZE; +} + +Vector2D CWindow::realToReportPosition() { + if (!m_bIsX11) + return m_vRealPosition->goal(); + + return g_pXWaylandManager->waylandToXWaylandCoords(m_vRealPosition->goal()); +} + +Vector2D CWindow::xwaylandSizeToReal(Vector2D size) { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + const auto PMONITOR = m_pMonitor.lock(); + const auto SIZE = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto SCALE = *PXWLFORCESCALEZERO ? PMONITOR->scale : 1.0f; + + return SIZE / SCALE; +} + +Vector2D CWindow::xwaylandPositionToReal(Vector2D pos) { + return g_pXWaylandManager->xwaylandToWaylandCoords(pos); +} + +void CWindow::updateX11SurfaceScale() { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + m_fX11SurfaceScaledBy = 1.0f; + if (m_bIsX11 && *PXWLFORCESCALEZERO) { + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) + m_fX11SurfaceScaledBy = PMONITOR->scale; + } +} + +void CWindow::sendWindowSize(bool force) { + const auto PMONITOR = m_pMonitor.lock(); Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(), m_vRealSize->goal(), force); // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = m_vRealPosition->goal(); - Vector2D size = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto REPORTPOS = realToReportPosition(); - if (m_bIsX11 && PMONITOR) { - windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); - if (*PXWLFORCESCALEZERO) - size *= PMONITOR->scale; - } + const auto REPORTSIZE = realToReportSize(); - if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) + if (!force && m_vPendingReportedSize == REPORTSIZE && (m_vReportedPosition == REPORTPOS || !m_bIsX11)) return; - m_vReportedPosition = windowPos; - m_vPendingReportedSize = size; - m_fX11SurfaceScaledBy = 1.0f; - - if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) - m_fX11SurfaceScaledBy = PMONITOR->scale; + m_vReportedPosition = REPORTPOS; + m_vPendingReportedSize = REPORTSIZE; + updateX11SurfaceScale(); if (m_bIsX11 && m_pXWaylandSurface) - m_pXWaylandSurface->configure({windowPos, size}); + m_pXWaylandSurface->configure({REPORTPOS, REPORTSIZE}); else if (m_pXDGSurface && m_pXDGSurface->toplevel) - m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor()); + m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(REPORTSIZE), REPORTPOS.floor()); } NContentType::eContentType CWindow::getContentType() { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 171a15f4..bc32bab4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -460,7 +460,7 @@ class CWindow { void onFocusAnimUpdate(); void onUpdateState(); void onUpdateMeta(); - void onX11Configure(CBox box); + void onX11ConfigureRequest(CBox box); void onResourceChangeX11(); std::string fetchTitle(); std::string fetchClass(); @@ -471,6 +471,11 @@ class CWindow { bool isModal(); Vector2D requestedMinSize(); Vector2D requestedMaxSize(); + Vector2D realToReportSize(); + Vector2D realToReportPosition(); + Vector2D xwaylandSizeToReal(Vector2D size); + Vector2D xwaylandPositionToReal(Vector2D size); + void updateX11SurfaceScale(); void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); @@ -497,7 +502,7 @@ class CWindow { CHyprSignalListener commit; CHyprSignalListener destroy; CHyprSignalListener activate; - CHyprSignalListener configure; + CHyprSignalListener configureRequest; CHyprSignalListener setGeometry; CHyprSignalListener updateState; CHyprSignalListener updateMetadata; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 7584354e..55e96078 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -50,7 +50,7 @@ class CXWaylandSurface { CSignal resourceChange; // associated / dissociated CSignal setGeometry; - CSignal configure; // CBox + CSignal configureRequest; // CBox CSignal map; CSignal unmap; @@ -116,4 +116,4 @@ class CXWaylandSurface { } listeners; friend class CXWM; -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index f2a9b794..a4e3289b 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -59,7 +59,7 @@ void CXWM::handleDestroy(xcb_destroy_notify_event_t* e) { std::erase_if(surfaces, [XSURF](const auto& other) { return XSURF == other; }); } -void CXWM::handleConfigure(xcb_configure_request_event_t* e) { +void CXWM::handleConfigureRequest(xcb_configure_request_event_t* e) { const auto XSURF = windowForXID(e->window); if (!XSURF) @@ -70,8 +70,9 @@ void CXWM::handleConfigure(xcb_configure_request_event_t* e) { if (!(MASK & GEOMETRY)) return; - XSURF->events.configure.emit(CBox{MASK & XCB_CONFIG_WINDOW_X ? e->x : XSURF->geometry.x, MASK & XCB_CONFIG_WINDOW_Y ? e->y : XSURF->geometry.y, - MASK & XCB_CONFIG_WINDOW_WIDTH ? e->width : XSURF->geometry.width, MASK & XCB_CONFIG_WINDOW_HEIGHT ? e->height : XSURF->geometry.height}); + XSURF->events.configureRequest.emit(CBox{MASK & XCB_CONFIG_WINDOW_X ? e->x : XSURF->geometry.x, MASK & XCB_CONFIG_WINDOW_Y ? e->y : XSURF->geometry.y, + MASK & XCB_CONFIG_WINDOW_WIDTH ? e->width : XSURF->geometry.width, + MASK & XCB_CONFIG_WINDOW_HEIGHT ? e->height : XSURF->geometry.height}); } void CXWM::handleConfigureNotify(xcb_configure_notify_event_t* e) { @@ -758,7 +759,7 @@ int CXWM::onEvent(int fd, uint32_t mask) { switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { case XCB_CREATE_NOTIFY: handleCreate((xcb_create_notify_event_t*)event); break; case XCB_DESTROY_NOTIFY: handleDestroy((xcb_destroy_notify_event_t*)event); break; - case XCB_CONFIGURE_REQUEST: handleConfigure((xcb_configure_request_event_t*)event); break; + case XCB_CONFIGURE_REQUEST: handleConfigureRequest((xcb_configure_request_event_t*)event); break; case XCB_CONFIGURE_NOTIFY: handleConfigureNotify((xcb_configure_notify_event_t*)event); break; case XCB_MAP_REQUEST: handleMapRequest((xcb_map_request_event_t*)event); break; case XCB_MAP_NOTIFY: handleMapNotify((xcb_map_notify_event_t*)event); break; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index f6dcee54..4326c77b 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -148,7 +148,7 @@ class CXWM { // event handlers void handleCreate(xcb_create_notify_event_t* e); void handleDestroy(xcb_destroy_notify_event_t* e); - void handleConfigure(xcb_configure_request_event_t* e); + void handleConfigureRequest(xcb_configure_request_event_t* e); void handleConfigureNotify(xcb_configure_notify_event_t* e); void handleMapRequest(xcb_map_request_event_t* e); void handleMapNotify(xcb_map_notify_event_t* e); From e2a9271150f9f1a2cba825f6f21bb130effc6b11 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Feb 2025 20:53:49 +0000 Subject: [PATCH 1218/2393] animations: add the gnomed animation style for windows --- src/managers/AnimationManager.cpp | 23 +++++++++++++++++++++-- src/managers/AnimationManager.hpp | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 29f669dc..18dae2a4 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -357,6 +357,21 @@ void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, *pWindow->m_vRealPosition = posOffset; } +void CHyprAnimationManager::animationGnomed(PHLWINDOW pWindow, bool close) { + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); + + if (close) { + *pWindow->m_vRealPosition = GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}; + *pWindow->m_vRealSize = Vector2D{GOALSIZE.x, 0.F}; + } else { + pWindow->m_vRealPosition->setValueAndWarp(GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}); + pWindow->m_vRealSize->setValueAndWarp(Vector2D{GOALSIZE.x, 0.F}); + *pWindow->m_vRealPosition = GOALPOS; + *pWindow->m_vRealSize = GOALSIZE; + } +} + void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (!close) { pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); @@ -387,7 +402,9 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos if (STYLE.starts_with("slide")) { CVarList animList2(STYLE, 0, 's'); animationSlide(pWindow, animList2[1], close); - } else { + } else if (STYLE == "gnomed" || STYLE == "gnome") + animationGnomed(pWindow, close); + else { // anim popin, fallback float minPerc = 0.f; @@ -405,6 +422,8 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos } else { if (animList[0] == "slide") animationSlide(pWindow, animList[1], close); + else if (animList[0] == "gnomed" || animList[0] == "gnome") + animationGnomed(pWindow, close); else { // anim popin, fallback @@ -425,7 +444,7 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { - if (style.starts_with("slide")) + if (style.starts_with("slide") || style == "gnome" || style == "gnomed") return ""; else if (style.starts_with("popin")) { // try parsing diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 067fa676..833087d7 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -59,6 +59,7 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { // Anim stuff void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); void animationSlide(PHLWINDOW, std::string force = "", bool close = false); + void animationGnomed(PHLWINDOW, bool close = false); }; inline UP g_pAnimationManager; From 59c615c321c45302491de3b1c003844c86aefca7 Mon Sep 17 00:00:00 2001 From: andrewandreii <63286820+andrewandreii@users.noreply.github.com> Date: Mon, 17 Feb 2025 04:03:27 +0200 Subject: [PATCH 1219/2393] input: add follow_mouse_threshold (#9392) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/managers/input/InputManager.cpp | 29 ++++++++++++++++++----------- src/managers/input/InputManager.hpp | 1 + 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 23635760..1283050d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -501,6 +501,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1, 0, 3}, }, + SConfigOptionDescription{ + .value = "input:follow_mouse_threshold", + .description = "The smallest distance in logical pixels the mouse needs to travel for the window under it to get focused. Works only with follow_mouse = 1.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{}, + }, SConfigOptionDescription{ .value = "input:focus_on_close", .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 00dba200..dc56d73f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -539,6 +539,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("animations:first_launch_animation", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1}); + m_pConfig->addConfigValue("input:follow_mouse_threshold", Hyprlang::FLOAT{0}); m_pConfig->addConfigValue("input:focus_on_close", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0}); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3d8c6de8..1d16f915 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -161,17 +161,23 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) return; - static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); - static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); - static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); - static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); - static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); - static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); - static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); - static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); + static auto PFOLLOWMOUSETHRESHOLD = CConfigValue("input:follow_mouse_threshold"); + static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); + static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); + static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); + static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); + static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); + static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; + if (FOLLOWMOUSE == 1 && m_tmrLastCursorMovement.getSeconds() < 0.5) + m_fMousePosDelta += MOUSECOORDSFLOORED.distance(m_vLastCursorPosFloored); + else + m_fMousePosDelta = 0; + m_pFoundSurfaceToFocus.reset(); m_pFoundLSToFocus.reset(); m_pFoundWindowToFocus.reset(); @@ -513,9 +519,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { // TODO: this looks wrong. When over a popup, it constantly is switching. // Temp fix until that's figured out. Otherwise spams windowrule lookups and other shit. - if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow) - g_pCompositor->focusWindow(pFoundWindow, foundSurface); - else + if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow) { + if (m_fMousePosDelta > *PFOLLOWMOUSETHRESHOLD || refocus) + g_pCompositor->focusWindow(pFoundWindow, foundSurface); + } else g_pCompositor->focusSurface(foundSurface, pFoundWindow); } } diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 3afb1b88..7774a6db 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -255,6 +255,7 @@ class CInputManager { // used for warping back after non-mouse input Vector2D m_vLastMousePos = {}; + double m_fMousePosDelta = 0; bool m_bLastInputMouse = true; // for holding focus on buttons held From d01f9943e1d401b09fc53be3c161279ab4f2c5ba Mon Sep 17 00:00:00 2001 From: nyx Date: Mon, 17 Feb 2025 13:02:32 -0500 Subject: [PATCH 1220/2393] subsurfaces: dont try to access popup surfaces when handling subsurface updates (#9421) --- src/desktop/Popup.cpp | 7 +++++++ src/desktop/Popup.hpp | 1 + src/desktop/Subsurface.cpp | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 82767ead..912069e7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -282,6 +282,9 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { + if (m_bInert || !m_pWLSurface) + return; + std::vector> cpy; std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); for (auto const& c : cpy) { @@ -367,3 +370,7 @@ WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { return {}; } + +bool CPopup::inert() const { + return m_bInert; +} diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 0bca436c..f6ca65da 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -34,6 +34,7 @@ class CPopup { void recheckTree(); bool visible(); + bool inert() const; // will also loop over this node void breadthfirst(std::function, void*)> fn, void* data); diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index db106a09..9846764c 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -107,7 +107,7 @@ void CSubsurface::onCommit() { g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); - if (m_pPopupParent) + if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) m_pPopupParent->recheckTree(); if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this m_pWindowParent->m_pPopupHead->recheckTree(); @@ -124,7 +124,7 @@ void CSubsurface::onCommit() { // g_pHyprRenderer->damageBox(box); CBox box; - if (m_pPopupParent) + if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{}); else if (m_pWindowParent) box = m_pWindowParent->getWindowMainSurfaceBox(); From e59623d1d564089543cddb496fbed30fbd6ab247 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 00:33:27 +0000 Subject: [PATCH 1221/2393] hyprctl: don't return empty str if there are no global shortcuts fixes #6043 --- src/debug/HyprCtl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a155474d..174eb932 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -811,8 +811,11 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri std::string ret = ""; const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto const& sh : SHORTCUTS) + for (auto const& sh : SHORTCUTS) { ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); + } + if (ret.empty()) + ret = "none"; } else { ret += "["; for (auto const& sh : SHORTCUTS) { From 3352317ca827dfb2dfd222274dfaf5941c78c086 Mon Sep 17 00:00:00 2001 From: nyx Date: Tue, 18 Feb 2025 09:18:22 -0500 Subject: [PATCH 1222/2393] scripts/generateVersion.sh: convert to posix (#9433) --- scripts/generateVersion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generateVersion.sh b/scripts/generateVersion.sh index e88cef3f..9313815d 100755 --- a/scripts/generateVersion.sh +++ b/scripts/generateVersion.sh @@ -2,8 +2,8 @@ # if the git directory doesn't exist, don't gather data to avoid overwriting, unless # the version file is missing altogether (otherwise compiling will fail) -if [[ ! -d ./.git ]]; then - if [[ -f ./src/version.h ]]; then +if [ ! -d ./.git ]; then + if [ -f ./src/version.h ]; then exit 0 fi fi From fb8eaba83f2d114fb346730e789a559ccc366887 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:10:40 +0000 Subject: [PATCH 1223/2393] core: add an ANR dialog for xdg-shell, we can ping the wm_base, and thus render an ANR dialog if an app dies for XWayland, there probably is a similar method, but I don't know about it and don't care. --- CMakeLists.txt | 2 +- src/Compositor.cpp | 5 + src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 10 ++ src/desktop/Window.hpp | 4 + src/managers/ANRManager.cpp | 173 +++++++++++++++++++++++++++++++++++ src/managers/ANRManager.hpp | 46 ++++++++++ src/protocols/XDGShell.cpp | 10 ++ src/protocols/XDGShell.hpp | 5 + src/render/OpenGL.cpp | 16 +++- src/render/Renderer.cpp | 6 ++ 11 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 src/managers/ANRManager.cpp create mode 100644 src/managers/ANRManager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a98f697d..22bc7498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5389844f..a35e4216 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -13,6 +13,7 @@ #include "managers/SeatManager.hpp" #include "managers/VersionKeeperManager.hpp" #include "managers/DonationNagManager.hpp" +#include "managers/ANRManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -592,6 +593,7 @@ void CCompositor::cleanup() { g_pEventLoopManager.reset(); g_pVersionKeeperMgr.reset(); g_pDonationNagManager.reset(); + g_pANRManager.reset(); g_pConfigWatcher.reset(); if (m_pAqBackend) @@ -694,6 +696,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the DonationNag!"); g_pDonationNagManager = makeUnique(); + Debug::log(LOG, "Creating the ANRManager!"); + g_pANRManager = makeUnique(); + Debug::log(LOG, "Starting XWayland"); g_pXWayland = makeUnique(g_pCompositor->m_bWantsXwayland); } break; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index dc56d73f..9b547ffb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -430,6 +430,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_hyprland_qtutils_check", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:lockdead_screen_delay", Hyprlang::INT{1000}); + m_pConfig->addConfigValue("misc:enable_anr_dialog", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7b7f954d..7c0693bf 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -13,6 +13,7 @@ #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" #include "../managers/AnimationManager.hpp" +#include "../managers/ANRManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ContentType.hpp" @@ -48,6 +49,7 @@ PHLWINDOW CWindow::create(SP surface) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(makeUnique(pWindow)); pWindow->addWindowDeco(makeUnique(pWindow)); @@ -71,6 +73,7 @@ PHLWINDOW CWindow::create(SP resource) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(makeUnique(pWindow)); pWindow->addWindowDeco(makeUnique(pWindow)); @@ -1796,3 +1799,10 @@ void CWindow::deactivateGroupMembers() { break; } } + +bool CWindow::isNotResponding() { + if (!m_pXDGSurface) + return false; + + return g_pANRManager->isNotResponding(m_pXDGSurface->owner.lock()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index bc32bab4..50b61050 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -388,6 +388,9 @@ class CWindow { // window tags CTagKeeper m_tags; + // ANR + PHLANIMVAR m_notRespondingTint; + // For the list lookup bool operator==(const CWindow& rhs) const { return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && @@ -480,6 +483,7 @@ class CWindow { NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); void deactivateGroupMembers(); + bool isNotResponding(); CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; diff --git a/src/managers/ANRManager.cpp b/src/managers/ANRManager.cpp new file mode 100644 index 00000000..e2b276ee --- /dev/null +++ b/src/managers/ANRManager.cpp @@ -0,0 +1,173 @@ +#include "ANRManager.hpp" +#include "../helpers/fs/FsUtils.hpp" +#include "../debug/Log.hpp" +#include "../macros.hpp" +#include "HookSystemManager.hpp" +#include "../Compositor.hpp" +#include "../protocols/XDGShell.hpp" +#include "./eventLoop/EventLoopManager.hpp" +#include "../config/ConfigValue.hpp" + +using namespace Hyprutils::OS; + +static constexpr auto TIMER_TIMEOUT = std::chrono::milliseconds(1500); + +CANRManager::CANRManager() { + if (!NFsUtils::executableExistsInPath("hyprland-dialog")) { + Debug::log(ERR, "hyprland-dialog missing from PATH, cannot start ANRManager"); + return; + } + + m_timer = makeShared(TIMER_TIMEOUT, [this](SP self, void* data) { onTick(); }, this); + g_pEventLoopManager->addTimer(m_timer); + + m_active = true; + + static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { + auto window = std::any_cast(data); + + if (window->m_bIsX11) + return; + + for (const auto& w : g_pCompositor->m_vWindows) { + if (w->m_bIsX11 || w == window || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner == window->m_pXDGSurface->owner) + return; + } + + m_data[window->m_pXDGSurface->owner] = makeShared(); + }); + + m_timer->updateTimeout(TIMER_TIMEOUT); +} + +void CANRManager::onTick() { + std::erase_if(m_data, [](const auto& e) { return e.first.expired(); }); + + static auto PENABLEANR = CConfigValue("misc:enable_anr_dialog"); + + if (!*PENABLEANR) { + m_timer->updateTimeout(TIMER_TIMEOUT * 10); + return; + } + + for (auto& [wmBase, data] : m_data) { + PHLWINDOW firstWindow; + int count = 0; + for (const auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner != wmBase) + continue; + + count++; + if (!firstWindow) + firstWindow = w; + } + + if (count == 0) + continue; + + if (data->missedResponses > 0) { + if (!data->isThreadRunning() && !data->dialogThreadSaidWait) { + pid_t pid = 0; + wl_client_get_credentials(wmBase->client(), &pid, nullptr, nullptr); + data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, pid); + + for (const auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner != wmBase) + continue; + + *w->m_notRespondingTint = 0.2F; + } + } + } else if (data->isThreadRunning()) + data->killDialog(); + + if (data->missedResponses == 0) + data->dialogThreadSaidWait = false; + + data->missedResponses++; + + wmBase->ping(); + } + + m_timer->updateTimeout(TIMER_TIMEOUT); +} + +void CANRManager::onResponse(SP wmBase) { + if (!m_data.contains(wmBase)) + return; + + auto& data = m_data.at(wmBase); + data->missedResponses = 0; + if (data->isThreadRunning()) + data->killDialog(); +} + +void CANRManager::SANRData::runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID) { + if (!dialogThreadExited) + killDialog(); + + // dangerous: might lock if the above failed!! + if (dialogThread.joinable()) + dialogThread.join(); + + dialogThreadExited = false; + dialogThreadSaidWait = false; + dialogThread = std::thread([title, appName, appClass, dialogWmPID, this]() { + SP proc = + makeShared("hyprland-dialog", + std::vector{"--title", title, "--text", + std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName, appClass), + "--buttons", "terminate;wait"}); + + dialogProc = proc; + proc->runSync(); + + dialogThreadExited = true; + + if (proc->stdOut().empty()) + return; + + if (proc->stdOut().starts_with("terminate")) + kill(dialogWmPID, SIGKILL); + if (proc->stdOut().starts_with("wait")) + dialogThreadSaidWait = true; + }); +} + +bool CANRManager::SANRData::isThreadRunning() { + if (dialogThread.native_handle() == 0) + return false; + if (dialogThreadExited) + return false; + return pthread_kill(dialogThread.native_handle(), 0) != ESRCH; +} + +void CANRManager::SANRData::killDialog() const { + if (!dialogProc) + return; + + kill(dialogProc->pid(), SIGKILL); +} + +CANRManager::SANRData::~SANRData() { + if (dialogThread.joinable()) { + killDialog(); + // dangerous: might lock if the above failed!! + dialogThread.join(); + } +} + +bool CANRManager::isNotResponding(SP wmBase) { + if (!m_data.contains(wmBase)) + return false; + return m_data[wmBase]->missedResponses > 1; +} diff --git a/src/managers/ANRManager.hpp b/src/managers/ANRManager.hpp new file mode 100644 index 00000000..7d67e872 --- /dev/null +++ b/src/managers/ANRManager.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "../helpers/memory/Memory.hpp" +#include "../desktop/DesktopTypes.hpp" +#include +#include +#include +#include +#include "./eventLoop/EventLoopTimer.hpp" +#include "../helpers/signal/Signal.hpp" +#include +#include + +class CXDGWMBase; + +class CANRManager { + public: + CANRManager(); + + void onResponse(SP wmBase); + bool isNotResponding(SP wmBase); + + private: + bool m_active = false; + SP m_timer; + + void onTick(); + + struct SANRData { + ~SANRData(); + + int missedResponses = 0; + std::thread dialogThread; + SP dialogProc; + std::atomic dialogThreadExited = false; + std::atomic dialogThreadSaidWait = false; + + void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID); + bool isThreadRunning(); + void killDialog() const; + }; + + std::map, SP> m_data; +}; + +inline UP g_pANRManager; \ No newline at end of file diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index f5d1a8fa..9424a9d6 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/ANRManager.hpp" #include "../helpers/Monitor.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" @@ -740,6 +741,11 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { LOGM(LOG, "New xdg_surface at {:x}", (uintptr_t)RESOURCE.get()); }); + + resource->setPong([this](CXdgWmBase* r, uint32_t serial) { + g_pANRManager->onResponse(self.lock()); + events.pong.emit(); + }); } bool CXDGWMBase::good() { @@ -750,6 +756,10 @@ wl_client* CXDGWMBase::client() { return pClient; } +void CXDGWMBase::ping() { + resource->sendPing(1337); +} + CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { grab = makeShared(); grab->keyboard = true; diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 4c2b8100..b46e0236 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -241,12 +241,17 @@ class CXDGWMBase { bool good(); wl_client* client(); + void ping(); std::vector> positioners; std::vector> surfaces; WP self; + struct { + CSignal pong; + } events; + private: SP resource; wl_client* pClient = nullptr; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 3b641c36..1a296b65 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1396,12 +1396,18 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB glUniform1f(shader->roundingPower, roundingPower); if (allowDim && m_RenderData.currentWindow) { - glUniform1i(shader->applyTint, 1); - const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); - glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); - } else { + if (m_RenderData.currentWindow->m_notRespondingTint->value() > 0) { + const auto DIM = m_RenderData.currentWindow->m_notRespondingTint->value(); + glUniform1i(shader->applyTint, 1); + glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); + } else if (m_RenderData.currentWindow->m_fDimPercent->value() > 0) { + glUniform1i(shader->applyTint, 1); + const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); + glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); + } else + glUniform1i(shader->applyTint, 0); + } else glUniform1i(shader->applyTint, 0); - } } const float verts[] = { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b61f1c3e..f01a0d12 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -473,6 +473,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe if (ignorePosition) { renderdata.pos.x = pMonitor->vecPosition.x; renderdata.pos.y = pMonitor->vecPosition.y; + } else { + const bool ANR = pWindow->isNotResponding(); + if (ANR && pWindow->m_notRespondingTint->goal() != 0.2F) + *pWindow->m_notRespondingTint = 0.2F; + else if (!ANR && pWindow->m_notRespondingTint->goal() != 0.F) + *pWindow->m_notRespondingTint = 0.F; } if (standalone) From 3c1a2e9fcae6575e1f17627047c93d6e9fcc8634 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:18:34 +0000 Subject: [PATCH 1224/2393] config/descriptions: add enable_anr_dialog --- src/config/ConfigDescriptions.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 1283050d..4e591fa8 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1187,6 +1187,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1000, 0, 5000}, }, + SConfigOptionDescription{ + .value = "misc:enable_anr_dialog", + .description = "whether to enable the ANR (app not responding) dialog when your apps hang", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * binds: From 0137a5f6cdd24d5a10f813572791f1e641221a5b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:20:00 +0000 Subject: [PATCH 1225/2393] anr: capitalize options --- src/managers/ANRManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/managers/ANRManager.cpp b/src/managers/ANRManager.cpp index e2b276ee..af1cb93a 100644 --- a/src/managers/ANRManager.cpp +++ b/src/managers/ANRManager.cpp @@ -126,7 +126,7 @@ void CANRManager::SANRData::runDialog(const std::string& title, const std::strin makeShared("hyprland-dialog", std::vector{"--title", title, "--text", std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName, appClass), - "--buttons", "terminate;wait"}); + "--buttons", "Terminate;Wait"}); dialogProc = proc; proc->runSync(); @@ -136,9 +136,9 @@ void CANRManager::SANRData::runDialog(const std::string& title, const std::strin if (proc->stdOut().empty()) return; - if (proc->stdOut().starts_with("terminate")) + if (proc->stdOut().starts_with("Terminate")) kill(dialogWmPID, SIGKILL); - if (proc->stdOut().starts_with("wait")) + if (proc->stdOut().starts_with("Wait")) dialogThreadSaidWait = true; }); } From 6d25ef09cd6a33bcd589bd0f1e88e86fcff2dc67 Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 19 Feb 2025 10:29:39 -0500 Subject: [PATCH 1226/2393] xwayland: add INCR support for clipboard transfers (#9434) add INCR protocol support for large transfers fix write handling for partial transfers fix an issue where wayland windows could die from a paste from an xwayland window --- src/xwayland/XWM.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index a4e3289b..0899261a 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -589,9 +589,18 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { } bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { - // Debug::log(LOG, "[xwm] Selection property notify for {} target {}", e->atom, e->window); + if (e->state != XCB_PROPERTY_DELETE) + return false; - // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); + auto it = std::ranges::find_if(clipboard.transfers, [e](const auto& t) { return t->incomingWindow == e->window; }); + if (it != clipboard.transfers.end()) { + if (!(*it)->getIncomingSelectionProp(true)) { + clipboard.transfers.erase(it); + return false; + } + getTransferData(clipboard); + return true; + } return false; } @@ -1205,8 +1214,10 @@ void CXWM::getTransferData(SXSelection& sel) { } if (transfer->propertyReply->type == HYPRATOMS["INCR"]) { - Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - sel.transfers.erase(it); + transfer->incremental = true; + transfer->propertyStart = 0; + free(transfer->propertyReply); + transfer->propertyReply = nullptr; return; } @@ -1426,6 +1437,8 @@ int SXSelection::onWrite() { ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { + if (errno == EAGAIN) + return 1; Debug::log(ERR, "[xwm] write died in transfer get"); transfers.erase(it); return 0; @@ -1436,7 +1449,13 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - transfers.erase(it); + if (!transfer->incremental) { + transfers.erase(it); + } else { + free(transfer->propertyReply); + transfer->propertyReply = nullptr; + transfer->propertyStart = 0; + } } return 1; From fa246cb6ed5f486aad27c11dd46b3a26768a15d1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 20 Feb 2025 14:56:17 +0200 Subject: [PATCH 1227/2393] flake.lock: update hyprutils and aquamarine --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 38f48983..76eee761 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1739103745, - "narHash": "sha256-c53dcRaw0F4Os9WD05HwIRs9kTDZw4Mxe1XK4edEALo=", + "lastModified": 1739298463, + "narHash": "sha256-oAFv9jKwwA7d7384d2LeywDSgwhvb3ZnrwbfoWPhXsI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "a3dda0d10ce9aa1d1dfb7a6c139ea8c2872c74bd", + "rev": "f239e5aadd6d23c48e085c2de3397e2058e54d16", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1739048933, - "narHash": "sha256-ck6MaoYvISBQKqZR+HcxXnx0wOhyCauxfVMaV5zhJxQ=", + "lastModified": 1739891528, + "narHash": "sha256-h8HOCZ/rw2Buzku+GKF77VXxrGjCSOQkLhptiEKMYg0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "e4e018a2ca6f5a9c33511973454199e1c7c85499", + "rev": "61a5382f4b1ab578064d470b1b3d3f0df396b8ba", "type": "github" }, "original": { From 2cfa5d2408cd3e213aa0c87076ce9ada0dc08e20 Mon Sep 17 00:00:00 2001 From: Aaron Tulino <13600347+aaronjamt@users.noreply.github.com> Date: Fri, 21 Feb 2025 07:20:11 -0700 Subject: [PATCH 1228/2393] hyprctl: Add IPC support for Hyprsunset (#9315) * Add IPC support for Hyprsunset * clang-format * Add documentation --- hyprctl/Strings.hpp | 11 +++++++++++ hyprctl/main.cpp | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index f77626a5..c70ca737 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -22,6 +22,7 @@ commands: getoption
({})", binaryName, binaryPath)); } else if (pid >= 0) { if (type == PERMISSION_TYPE_PLUGIN) { const auto LOOKUP = binaryNameForPid(pid); - description = std::format("An application {} is {}:
{}", LOOKUP.value_or("Unknown"), permissionToHumanString(type), binaryPath); + description = std::format(std::runtime_format(permissionToHumanString(type)), LOOKUP.value_or("Unknown"), binaryPath); } else { const auto LOOKUP = binaryNameForPid(pid); - description = std::format("An application {} ({}) is {}.", LOOKUP.value_or("Unknown"), binaryPath, permissionToHumanString(type)); + description = std::format(std::runtime_format(permissionToHumanString(type)), LOOKUP.value_or("Unknown"), binaryPath); } } else - description = std::format("An application is {}:
{}", permissionToHumanString(type), binaryPath); - - description += "

Do you want to allow this?"; + description = std::format(std::runtime_format(permissionToHumanString(type)), binaryPath); std::vector options; diff --git a/src/managers/permissions/DynamicPermissionManager.hpp b/src/managers/permissions/DynamicPermissionManager.hpp index f8cfe3ad..a61f256e 100644 --- a/src/managers/permissions/DynamicPermissionManager.hpp +++ b/src/managers/permissions/DynamicPermissionManager.hpp @@ -17,6 +17,7 @@ enum eDynamicPermissionType : uint8_t { PERMISSION_TYPE_UNKNOWN = 0, PERMISSION_TYPE_SCREENCOPY, PERMISSION_TYPE_PLUGIN, + PERMISSION_TYPE_KEYBOARD, }; enum eDynamicPermissionRuleSource : uint8_t { From d9c8a378118d954932eb9906b07150ccd9a3a434 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 18 May 2025 19:34:14 +0200 Subject: [PATCH 1520/2393] input: always allow focus to permission popups --- src/Compositor.cpp | 31 ++++++++++++++----- src/desktop/Window.cpp | 4 +++ src/desktop/Window.hpp | 2 ++ src/helpers/AsyncDialogBox.cpp | 19 +++++++++--- src/helpers/AsyncDialogBox.hpp | 6 +++- src/managers/input/InputManager.cpp | 9 ++++-- .../permissions/DynamicPermissionManager.cpp | 3 +- 7 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 973cb26b..c6593923 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -870,10 +870,14 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper static auto PBORDERGRABEXTEND = CConfigValue("general:extend_border_grab_area"); static auto PSPECIALFALLTHRU = CConfigValue("input:special_fallthrough"); const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; + const bool ONLY_PRIORITY = properties & FOCUS_PRIORITY; // pinned windows on top of floating regardless if (properties & ALLOW_FLOATING) { for (auto const& w : m_windows | std::views::reverse) { + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + if (w->m_isFloating && w->m_isMapped && !w->isHidden() && !w->m_X11ShouldntFocus && w->m_pinned && !w->m_windowData.noFocus.valueOrDefault() && w != pIgnoreWindow) { const auto BB = w->getWindowBoxUnified(properties); CBox box = BB.copy().expand(!w->isX11OverrideRedirect() ? BORDER_GRAB_AREA : 0); @@ -898,6 +902,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper if (!w->m_workspace) continue; + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + const auto PWINDOWMONITOR = w->m_monitor.lock(); // to avoid focusing windows behind special workspaces from other monitors @@ -950,7 +957,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper const WORKSPACEID WSPID = special ? PMONITOR->activeSpecialWorkspaceID() : PMONITOR->activeWorkspaceID(); const auto PWORKSPACE = getWorkspaceByID(WSPID); - if (PWORKSPACE->m_hasFullscreenWindow && !(properties & SKIP_FULLSCREEN_PRIORITY)) + if (PWORKSPACE->m_hasFullscreenWindow && !(properties & SKIP_FULLSCREEN_PRIORITY) && !ONLY_PRIORITY) return PWORKSPACE->getFullscreenWindow(); auto found = floating(false); @@ -959,6 +966,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper // for windows, we need to check their extensions too, first. for (auto const& w : m_windows) { + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + if (special != w->onSpecialWorkspace()) continue; @@ -973,6 +983,9 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper } for (auto const& w : m_windows) { + if (ONLY_PRIORITY && !w->priorityFocus()) + continue; + if (special != w->onSpecialWorkspace()) continue; @@ -1083,14 +1096,16 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); - if (g_pSessionLockManager->isSessionLocked()) { - Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock"); - return; - } + if (!pWindow || !pWindow->priorityFocus()) { + if (g_pSessionLockManager->isSessionLocked()) { + Debug::log(LOG, "Refusing a keyboard focus to a window because of a sessionlock"); + return; + } - if (!g_pInputManager->m_exclusiveLSes.empty()) { - Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls"); - return; + if (!g_pInputManager->m_exclusiveLSes.empty()) { + Debug::log(LOG, "Refusing a keyboard focus to a window because of an exclusive ls"); + return; + } } if (pWindow && pWindow->m_isX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_xwaylandSurface->wantsFocus()) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7ef54da0..9f69e364 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1836,3 +1836,7 @@ PHLWINDOW CWindow::parent() { return m_xdgSurface->m_toplevel->m_parent->m_window.lock(); } + +bool CWindow::priorityFocus() { + return !m_isX11 && CAsyncDialogBox::isPriorityDialogBox(getPID()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 47d28db2..0d06b69c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -51,6 +51,7 @@ enum eGetWindowProperties : uint8_t { ALLOW_FLOATING = 1 << 4, USE_PROP_TILED = 1 << 5, SKIP_FULLSCREEN_PRIORITY = 1 << 6, + FOCUS_PRIORITY = 1 << 7, }; enum eSuppressEvents : uint8_t { @@ -408,6 +409,7 @@ class CWindow { std::optional xdgTag(); std::optional xdgDescription(); PHLWINDOW parent(); + bool priorityFocus(); CBox getWindowMainSurfaceBox() const { return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y}; diff --git a/src/helpers/AsyncDialogBox.cpp b/src/helpers/AsyncDialogBox.cpp index 42dac469..697d61ba 100644 --- a/src/helpers/AsyncDialogBox.cpp +++ b/src/helpers/AsyncDialogBox.cpp @@ -7,7 +7,7 @@ using namespace Hyprutils::OS; -static std::vector asyncDialogBoxes; +static std::vector>> asyncDialogBoxes; // SP CAsyncDialogBox::create(const std::string& title, const std::string& description, std::vector buttons) { @@ -24,7 +24,18 @@ SP CAsyncDialogBox::create(const std::string& title, const std: } bool CAsyncDialogBox::isAsyncDialogBox(pid_t pid) { - return std::ranges::contains(asyncDialogBoxes, pid); + return std::ranges::find_if(asyncDialogBoxes, [pid](const auto& e) { return e.first == pid; }) != asyncDialogBoxes.end(); +} + +bool CAsyncDialogBox::isPriorityDialogBox(pid_t pid) { + for (const auto& [p, db] : asyncDialogBoxes) { + if (p != pid) + continue; + + return db && db->m_priority; + } + + return false; } CAsyncDialogBox::CAsyncDialogBox(const std::string& title, const std::string& description, std::vector buttons) : @@ -68,7 +79,7 @@ void CAsyncDialogBox::onWrite(int fd, uint32_t mask) { Debug::log(LOG, "CAsyncDialogBox: dialog {:x} hung up, closed."); m_promiseResolver->resolve(m_stdout); - std::erase(asyncDialogBoxes, m_dialogPid); + std::erase_if(asyncDialogBoxes, [this](const auto& e) { return e.first == m_dialogPid; }); wl_event_source_remove(m_readEventSource); m_selfReference.reset(); @@ -112,7 +123,7 @@ SP> CAsyncDialogBox::open() { } m_dialogPid = proc.pid(); - asyncDialogBoxes.emplace_back(m_dialogPid); + asyncDialogBoxes.emplace_back(std::make_pair<>(m_dialogPid, m_selfWeakReference)); // close the write fd, only the dialog owns it now close(outPipe[1]); diff --git a/src/helpers/AsyncDialogBox.hpp b/src/helpers/AsyncDialogBox.hpp index 4018a857..0ee0144e 100644 --- a/src/helpers/AsyncDialogBox.hpp +++ b/src/helpers/AsyncDialogBox.hpp @@ -16,6 +16,7 @@ class CAsyncDialogBox { public: static SP create(const std::string& title, const std::string& description, std::vector buttons); static bool isAsyncDialogBox(pid_t pid); + static bool isPriorityDialogBox(pid_t pid); CAsyncDialogBox(const CAsyncDialogBox&) = delete; CAsyncDialogBox(CAsyncDialogBox&&) = delete; @@ -26,7 +27,10 @@ class CAsyncDialogBox { void kill(); bool isRunning() const; - void onWrite(int fd, uint32_t mask); + // focus priority, only permission popups + bool m_priority = false; + + void onWrite(int fd, uint32_t mask); private: CAsyncDialogBox(const std::string& title, const std::string& description, std::vector buttons); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index f9f36cf2..2d50dbcf 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -250,7 +250,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (PMONITOR != g_pCompositor->m_lastMonitor && (*PMOUSEFOCUSMON || refocus) && m_forcedFocus.expired()) g_pCompositor->setActiveMonitor(PMONITOR); - if (g_pSessionLockManager->isSessionLocked()) { + // check for windows that have focus priority like our permission popups + pFoundWindow = g_pCompositor->vectorToWindowUnified(mouseCoords, FOCUS_PRIORITY); + if (pFoundWindow) + foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); + + if (!foundSurface && g_pSessionLockManager->isSessionLocked()) { // set keyboard focus on session lock surface regardless of layers const auto PSESSIONLOCKSURFACE = g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->m_id); @@ -288,7 +293,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (!forcedFocus) forcedFocus = g_pCompositor->getForceFocus(); - if (forcedFocus) { + if (forcedFocus && !foundSurface) { pFoundWindow = forcedFocus; surfacePos = pFoundWindow->m_realPosition->value(); foundSurface = pFoundWindow->m_wlSurface->resource(); diff --git a/src/managers/permissions/DynamicPermissionManager.cpp b/src/managers/permissions/DynamicPermissionManager.cpp index dd1fd4cf..c015adfe 100644 --- a/src/managers/permissions/DynamicPermissionManager.cpp +++ b/src/managers/permissions/DynamicPermissionManager.cpp @@ -296,7 +296,8 @@ void CDynamicPermissionManager::askForPermission(wl_client* client, const std::s } else options = {"Deny", "Allow"}; - rule->m_dialogBox = CAsyncDialogBox::create("Permission request", description, options); + rule->m_dialogBox = CAsyncDialogBox::create("Permission request", description, options); + rule->m_dialogBox->m_priority = true; if (!rule->m_dialogBox) { Debug::log(ERR, "CDynamicPermissionManager::askForPermission: hyprland-qtutils likely missing, cannot ask! Disabling permission control..."); From eb3b38d40baca5c05ddbc1507b3d3f02a0ccb164 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 19 May 2025 01:27:30 +0200 Subject: [PATCH 1521/2393] eventLoop: fixup event source callbacks --- src/managers/eventLoop/EventLoopManager.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 338b75e3..6233a2d0 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -70,16 +70,20 @@ static int handleWaiterFD(int fd, uint32_t mask, void* data) { void CEventLoopManager::onFdReadable(SReadableWaiter* waiter) { auto it = std::ranges::find_if(m_readableWaiters, [waiter](const UP& w) { return waiter == w.get() && w->fd == waiter->fd && w->source == waiter->source; }); - if (waiter->source) { - wl_event_source_remove(waiter->source); - waiter->source = nullptr; + // ??? + if (it == m_readableWaiters.end()) + return; + + UP taken = std::move(*it); + m_readableWaiters.erase(it); + + if (taken->source) { + wl_event_source_remove(taken->source); + taken->source = nullptr; } - if (waiter->fn) - waiter->fn(); - - if (it != m_readableWaiters.end()) - m_readableWaiters.erase(it); + if (taken->fn) + taken->fn(); } void CEventLoopManager::enterLoop() { From b90910c0dcc6db9d7529d02190b0a19f69cb46e3 Mon Sep 17 00:00:00 2001 From: zacoons <73414084+zacoons@users.noreply.github.com> Date: Thu, 22 May 2025 01:41:40 +1000 Subject: [PATCH 1522/2393] renderer: add wrapping options to renderTexture method (#10497) --- src/render/OpenGL.cpp | 11 ++++++----- src/render/OpenGL.hpp | 5 +++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 20862a7a..855da879 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1409,10 +1409,11 @@ void CHyprOpenGLImpl::renderRectWithDamage(const CBox& box, const CHyprColor& co scissor(nullptr); } -void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV) { +void CHyprOpenGLImpl::renderTexture(SP tex, const CBox& box, float alpha, int round, float roundingPower, bool discardActive, bool allowCustomUV, GLenum wrapX, + GLenum wrapY) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, box, alpha, m_renderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true); + renderTextureInternalWithDamage(tex, box, alpha, m_renderData.damage, round, roundingPower, discardActive, false, allowCustomUV, true, wrapX, wrapY); scissor(nullptr); } @@ -1477,7 +1478,7 @@ void CHyprOpenGLImpl::passCMUniforms(const SShader& shader, const SImageDescript } void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CBox& box, float alpha, const CRegion& damage, int round, float roundingPower, bool discardActive, - bool noAA, bool allowCustomUV, bool allowDim) { + bool noAA, bool allowCustomUV, bool allowDim, GLenum wrapX, GLenum wrapY) { RASSERT(m_renderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex->m_texID > 0), "Attempted to draw nullptr texture!"); @@ -1541,8 +1542,8 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB glActiveTexture(GL_TEXTURE0); glBindTexture(tex->m_target, tex->m_texID); - glTexParameteri(tex->m_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(tex->m_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->m_target, GL_TEXTURE_WRAP_S, wrapX); + glTexParameteri(tex->m_target, GL_TEXTURE_WRAP_T, wrapY); if (m_renderData.useNearestNeighbor) { glTexParameteri(tex->m_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 09aff9da..fade4a9d 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -183,7 +183,8 @@ class CHyprOpenGLImpl { void renderRect(const CBox&, const CHyprColor&, int round = 0, float roundingPower = 2.0f); void renderRectWithBlur(const CBox&, const CHyprColor&, int round = 0, float roundingPower = 2.0f, float blurA = 1.f, bool xray = false); void renderRectWithDamage(const CBox&, const CHyprColor&, const CRegion& damage, int round = 0, float roundingPower = 2.0f); - void renderTexture(SP, const CBox&, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); + void renderTexture(SP, const CBox&, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false, + GLenum wrapX = GL_CLAMP_TO_EDGE, GLenum wrapY = GL_CLAMP_TO_EDGE); void renderTextureWithDamage(SP, const CBox&, const CRegion& damage, float a, int round = 0, float roundingPower = 2.0f, bool discardActive = false, bool allowCustomUV = false); void renderTextureWithBlur(SP, const CBox&, float a, SP pSurface, int round = 0, float roundingPower = 2.0f, bool blockBlurOptimization = false, @@ -344,7 +345,7 @@ class CHyprOpenGLImpl { bool modifySDR = false); void passCMUniforms(const SShader&, const NColorManagement::SImageDescription& imageDescription); void renderTextureInternalWithDamage(SP, const CBox& box, float a, const CRegion& damage, int round = 0, float roundingPower = 2.0f, bool discardOpaque = false, - bool noAA = false, bool allowCustomUV = false, bool allowDim = false); + bool noAA = false, bool allowCustomUV = false, bool allowDim = false, GLenum wrapX = GL_CLAMP_TO_EDGE, GLenum wrapY = GL_CLAMP_TO_EDGE); void renderTexturePrimitive(SP tex, const CBox& box); void renderSplash(cairo_t* const, cairo_surface_t* const, double offset, const Vector2D& size); From 185c96849ef59da3e101116662d942dea16b468a Mon Sep 17 00:00:00 2001 From: darkwater Date: Wed, 21 May 2025 23:44:21 +0200 Subject: [PATCH 1523/2393] input: unhide cursor on tablet events after touch events (#10484) --- src/managers/input/Tablets.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 5b9ca378..b0fe7c64 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -134,6 +134,7 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { } } + m_lastInputTouch = false; simulateMouseMovement(); refocusTablet(PTAB, PTOOL, true); m_lastCursorMovement.reset(); From 4f161da3d6a3eb16cffd8c7706e2b916c82c93a7 Mon Sep 17 00:00:00 2001 From: nezu <29180158+dumbasPL@users.noreply.github.com> Date: Thu, 22 May 2025 13:54:02 +0200 Subject: [PATCH 1524/2393] hyprpm: ignore pins when adding a package with a git rev (#10502) ref #10436 --- hyprpm/src/core/PluginManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 76f20110..90eba579 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -256,7 +256,7 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& progress.printMessageAbove(message); } - if (!pManifest->m_repository.commitPins.empty()) { + if (rev.empty() && !pManifest->m_repository.commitPins.empty()) { // check commit pins progress.printMessageAbove(infoString("Manifest has {} pins, checking", pManifest->m_repository.commitPins.size())); From bd4733a0ff2b89fd3f22dc6ec9ff00e070753662 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 22 May 2025 18:02:18 +0300 Subject: [PATCH 1525/2393] flake.lock: update nix/overlays: remove wayland-protocols overlay. PR landed in master a while ago --- flake.lock | 24 ++++++++++++------------ nix/overlays.nix | 13 ------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/flake.lock b/flake.lock index 1be8e6d4..de57aab4 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1745357003, - "narHash": "sha256-jYwzQkv1r7HN/4qrAuKp+NR4YYNp2xDrOX5O9YVqkWo=", + "lastModified": 1747864449, + "narHash": "sha256-PIjVAWghZhr3L0EFM2UObhX84UQxIACbON0IC0zzSKA=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "a19cf76ee1a15c1c12083fa372747ce46387289f", + "rev": "389372c5f4dc1ac0e7645ed29a35fd6d71672ef5", "type": "github" }, "original": { @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1746655412, - "narHash": "sha256-kVQ0bHVtX6baYxRWWIh4u3LNJZb9Zcm2xBeDPOGz5BY=", + "lastModified": 1747484975, + "narHash": "sha256-+LAQ81HBwG0lwshHlWe0kfWg4KcChIPpnwtnwqmnoEU=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "557241780c179cf7ef224df392f8e67dab6cef83", + "rev": "163c83b3db48a17c113729c220a60b94596c9291", "type": "github" }, "original": { @@ -261,11 +261,11 @@ ] }, "locked": { - "lastModified": 1739870480, - "narHash": "sha256-SiDN5BGxa/1hAsqhgJsS03C3t2QrLgBT8u+ENJ0Qzwc=", + "lastModified": 1747584298, + "narHash": "sha256-PH9qZqWLHvSBQiUnA0NzAyQA3tu2no2z8kz0ZeHWj4w=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "206367a08dc5ac4ba7ad31bdca391d098082e64b", + "rev": "e511882b9c2e1d7a75d45d8fddd2160daeafcbc3", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1747327360, - "narHash": "sha256-LSmTbiq/nqZR9B2t4MRnWG7cb0KVNU70dB7RT4+wYK4=", + "lastModified": 1747744144, + "narHash": "sha256-W7lqHp0qZiENCDwUZ5EX/lNhxjMdNapFnbErcbnP11Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e06158e58f3adee28b139e9c2bcfcc41f8625b46", + "rev": "2795c506fe8fb7b03c36ccb51f75b6df0ab2553f", "type": "github" }, "original": { diff --git a/nix/overlays.nix b/nix/overlays.nix index 687a49d4..6085bf80 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -29,7 +29,6 @@ in { inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default self.overlays.udis86 - self.overlays.wayland-protocols # Hyprland packages themselves (final: _prev: let @@ -96,16 +95,4 @@ in { patches = []; }); }; - - # TODO: remove when https://github.com/NixOS/nixpkgs/pull/397497 lands in master - wayland-protocols = final: prev: { - wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: { - version = "1.43"; - - src = final.fetchurl { - url = "https://gitlab.freedesktop.org/wayland/${self.pname}/-/releases/${self.version}/downloads/${self.pname}-${self.version}.tar.xz"; - hash = "sha256-ujw0Jd0nxXtSkek9upe+EkeWAeALyrJNJkcZSMtkNlM="; - }; - }); - }; } From 81cd526f923f4a9074bbfef59b4c7e9f3350c349 Mon Sep 17 00:00:00 2001 From: Virt <41426325+VirtCode@users.noreply.github.com> Date: Fri, 23 May 2025 23:41:35 +0200 Subject: [PATCH 1526/2393] cursor: fix screencopy cursor pos and duplicate shape with sw cursors (#10519) * cursor: account for hotspot with overridePos * cursor: don't draw cursor on screencopy if using sw anyways --- src/managers/PointerManager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 7bd66c5d..f42fd686 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -603,10 +603,17 @@ void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time:: return; } + // don't render cursor if forced but we are already using sw cursors for the monitor + // otherwise we draw the cursor again for screencopy when using sw cursors + if (forceRender && (state->hardwareFailed || state->softwareLocks != 0)) + return; + auto box = state->box.copy(); if (overridePos.has_value()) { box.x = overridePos->x; box.y = overridePos->y; + + box.translate(-m_currentCursorImage.hotspot); } if (box.intersection(CBox{{}, {pMonitor->m_size}}).empty()) From 55076edaac38865562d647e22b42566822264218 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 24 May 2025 20:39:36 +0200 Subject: [PATCH 1527/2393] versionkeeper: don't pop up on initial launch --- src/managers/VersionKeeperManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/managers/VersionKeeperManager.cpp b/src/managers/VersionKeeperManager.cpp index ef9c274d..93f820f4 100644 --- a/src/managers/VersionKeeperManager.cpp +++ b/src/managers/VersionKeeperManager.cpp @@ -31,6 +31,7 @@ CVersionKeeperManager::CVersionKeeperManager() { if (!LASTVER) { NFsUtils::writeToFile(*DATAROOT + "/" + VERSION_FILE_NAME, "0.0.0"); LASTVER = "0.0.0"; + return; } if (!isVersionOlderThanRunning(*LASTVER)) { From 28c9122adbb9cba2ba19ad723eb0f36c19b21f2d Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sat, 24 May 2025 18:41:03 +0000 Subject: [PATCH 1528/2393] [gha] Nix: update inputs --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index de57aab4..22f246d5 100644 --- a/flake.lock +++ b/flake.lock @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1747744144, - "narHash": "sha256-W7lqHp0qZiENCDwUZ5EX/lNhxjMdNapFnbErcbnP11Q=", + "lastModified": 1748026106, + "narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2795c506fe8fb7b03c36ccb51f75b6df0ab2553f", + "rev": "063f43f2dbdef86376cc29ad646c45c46e93234c", "type": "github" }, "original": { From cc0792c1dce250311a19e92bad204eefae072592 Mon Sep 17 00:00:00 2001 From: Vladimir-csp <4061903+Vladimir-csp@users.noreply.github.com> Date: Sat, 24 May 2025 17:26:10 +0300 Subject: [PATCH 1529/2393] hyprland-uwsm.desktop: Add TryExec This should hide this entry when uwsm is missing (at least in DMs that handle TryExec) --- systemd/hyprland-uwsm.desktop | 1 + 1 file changed, 1 insertion(+) diff --git a/systemd/hyprland-uwsm.desktop b/systemd/hyprland-uwsm.desktop index e00f4aa2..3f37532d 100644 --- a/systemd/hyprland-uwsm.desktop +++ b/systemd/hyprland-uwsm.desktop @@ -2,5 +2,6 @@ Name=Hyprland (uwsm-managed) Comment=An intelligent dynamic tiling Wayland compositor Exec=uwsm start -- hyprland.desktop +TryExec=uwsm DesktopNames=Hyprland Type=Application From a58ab20e8bc27a50d55e924b13047db6bbf9dc4a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 25 May 2025 18:45:23 +0200 Subject: [PATCH 1530/2393] debug/pass: show live/precompile blur in debug --- src/render/pass/Pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index fc743865..5877d9a9 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -273,8 +273,8 @@ void CRenderPass::renderDebugData() { auto yn = [](const bool val) -> const char* { return val ? "yes" : "no"; }; auto tick = [](const bool val) -> const char* { return val ? "✔" : "✖"; }; for (const auto& el : m_passElements | std::views::reverse) { - passStructure += std::format("{} {} (bb: {} op: {})\n", tick(!el->discard), el->element->passName(), yn(el->element->boundingBox().has_value()), - yn(!el->element->opaqueRegion().empty())); + passStructure += std::format("{} {} (bb: {} op: {}, pb: {}, lb: {})\n", tick(!el->discard), el->element->passName(), yn(el->element->boundingBox().has_value()), + yn(!el->element->opaqueRegion().empty()), yn(el->element->needsPrecomputeBlur()), yn(el->element->needsLiveBlur())); } if (!passStructure.empty()) From 2347050285920925db8bc844e3232bc932eef21e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 25 May 2025 18:48:32 +0200 Subject: [PATCH 1531/2393] pass/surface: make sure popup blurs are marked for require live blur fixes #10535 --- src/render/pass/SurfacePassElement.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/render/pass/SurfacePassElement.cpp b/src/render/pass/SurfacePassElement.cpp index d161f909..2163566a 100644 --- a/src/render/pass/SurfacePassElement.cpp +++ b/src/render/pass/SurfacePassElement.cpp @@ -195,6 +195,9 @@ bool CSurfacePassElement::needsLiveBlur() { if (!m_data.pLS && !m_data.pWindow) return BLUR; + if (m_data.popup) + return BLUR; + const bool NEWOPTIM = g_pHyprOpenGL->shouldUseNewBlurOptimizations(m_data.pLS, m_data.pWindow); return BLUR && !NEWOPTIM; @@ -209,6 +212,9 @@ bool CSurfacePassElement::needsPrecomputeBlur() { if (!m_data.pLS && !m_data.pWindow) return BLUR; + if (m_data.popup) + return false; + const bool NEWOPTIM = g_pHyprOpenGL->shouldUseNewBlurOptimizations(m_data.pLS, m_data.pWindow); return BLUR && NEWOPTIM; From 292a7456af9465a57a7fe3ee36d113ae661a9ff3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 26 May 2025 16:53:35 +0200 Subject: [PATCH 1532/2393] eventLoop: fixup headers --- src/managers/eventLoop/EventLoopManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index a3c755a7..977d2b01 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -5,7 +5,7 @@ #include #include #include -#include "helpers/signal/Signal.hpp" +#include "../../helpers/signal/Signal.hpp" #include #include "EventLoopTimer.hpp" From 4c4c9bb324b9e17bddb72c4614b451775521ee24 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 27 May 2025 01:15:11 +0800 Subject: [PATCH 1533/2393] dwindle: add better automatic window drag and drop direction detection (#9704) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 26 +++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 8fc6b04b..19c1f74c 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1757,6 +1757,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"}, }, + SConfigOptionDescription{ + .value = "dwindle:precise_move", + .description = "if enabled, bindm movewindow will drop the window more precisely depending on where your mouse is.", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * master: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f5f0bed3..99b4cf85 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -592,6 +592,7 @@ CConfigManager::CConfigManager() { registerConfigVar("dwindle:split_bias", Hyprlang::INT{0}); registerConfigVar("dwindle:smart_split", Hyprlang::INT{0}); registerConfigVar("dwindle:smart_resizing", Hyprlang::INT{1}); + registerConfigVar("dwindle:precise_move", Hyprlang::INT{0}); registerConfigVar("master:special_scale_factor", {1.f}); registerConfigVar("master:mfact", {0.55f}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 8d32e44e..93b09c87 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -362,9 +362,33 @@ void IHyprLayout::onEndDragWindow() { } if (DRAGGINGWINDOW->m_draggingTiled) { + static auto PPRECISEMOUSE = CConfigValue("dwindle:precise_mouse_move"); DRAGGINGWINDOW->m_isFloating = false; g_pInputManager->refocus(); - changeWindowFloatingMode(DRAGGINGWINDOW); + + if (*PPRECISEMOUSE) { + eDirection direction = DIRECTION_DEFAULT; + + const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); + const PHLWINDOW pReferenceWindow = g_pCompositor->vectorToWindowUnified(MOUSECOORDS, RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING, DRAGGINGWINDOW); + + if (pReferenceWindow && pReferenceWindow != DRAGGINGWINDOW) { + const Vector2D draggedCenter = DRAGGINGWINDOW->m_realPosition->goal() + DRAGGINGWINDOW->m_realSize->goal() / 2.f; + const Vector2D referenceCenter = pReferenceWindow->m_realPosition->goal() + pReferenceWindow->m_realSize->goal() / 2.f; + const float xDiff = draggedCenter.x - referenceCenter.x; + const float yDiff = draggedCenter.y - referenceCenter.y; + + if (fabs(xDiff) > fabs(yDiff)) + direction = xDiff < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; + else + direction = yDiff < 0 ? DIRECTION_UP : DIRECTION_DOWN; + } + + onWindowRemovedTiling(DRAGGINGWINDOW); + onWindowCreatedTiling(DRAGGINGWINDOW, direction); + } else + changeWindowFloatingMode(DRAGGINGWINDOW); + DRAGGINGWINDOW->m_lastFloatingSize = m_draggingWindowOriginalFloatSize; } From c2805aad92978577a4d89b14f1c4f51e50247547 Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Mon, 26 May 2025 18:25:58 +0100 Subject: [PATCH 1534/2393] config: add maxwidth monitor resolution mode (#10528) Signed-off-by: Nikolaos Karaolidis --- src/config/ConfigManager.cpp | 2 ++ src/helpers/Monitor.cpp | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 99b4cf85..a8d70bb6 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2014,6 +2014,8 @@ std::optional CConfigManager::handleMonitor(const std::string& comm newrule.resolution = Vector2D(-1, -1); } else if (ARGS[1].starts_with("highres")) { newrule.resolution = Vector2D(-1, -2); + } else if (ARGS[1].starts_with("maxwidth")) { + newrule.resolution = Vector2D(-1, -3); } else if (parseModeLine(ARGS[1], newrule.drmMode)) { newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay); newrule.refreshRate = float(newrule.drmMode.vrefresh) / 1000; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 4dc0942d..72a221f5 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -515,7 +515,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { } else if (RULE->resolution == Vector2D(-1, -2)) { requestedStr = "highres"; - // sort prioritizing resultion 1st and refresh rate 2nd, then add best 3 + // sort prioritizing resolution 1st and refresh rate 2nd, then add best 3 addBest3Modes([](auto const& a, auto const& b) { if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) return true; @@ -524,6 +524,17 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { return true; return false; }); + } else if (RULE->resolution == Vector2D(-1, -3)) { + requestedStr = "maxwidth"; + + // sort prioritizing widest resolution 1st and refresh rate 2nd, then add best 3 + addBest3Modes([](auto const& a, auto const& b) { + if (a->pixelSize.x > b->pixelSize.x) + return true; + if (a->pixelSize.x == b->pixelSize.x && std::round(a->refreshRate) > std::round(b->refreshRate)) + return true; + return false; + }); } else if (RULE->resolution != Vector2D()) { // user requested mode requestedStr = std::format("{:X0}@{:.2f}Hz", RULE->resolution, RULE->refreshRate); From be6ee6e55f08387a9e2fbf712c061fb238a70319 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 26 May 2025 23:33:25 +0200 Subject: [PATCH 1535/2393] cmake: disable gprof by default --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4267a59d..61893803 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,7 +153,7 @@ endif() add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) -set(USE_GPROF ON) +set(USE_GPROF OFF) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) message(STATUS "Setting debug flags") From a62ccb169aa05ef40c6c215c0638e843740920f3 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 27 May 2025 15:33:17 +0800 Subject: [PATCH 1536/2393] config: fix crash on misnamed variable (#10549) --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 19c1f74c..f59bd1a9 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1758,7 +1758,7 @@ inline static const std::vector CONFIG_OPTIONS = { .data = SConfigOptionDescription::SChoiceData{0, "positional,current,opening"}, }, SConfigOptionDescription{ - .value = "dwindle:precise_move", + .value = "dwindle:precise_mouse_move", .description = "if enabled, bindm movewindow will drop the window more precisely depending on where your mouse is.", .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a8d70bb6..a4f09d65 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -592,7 +592,7 @@ CConfigManager::CConfigManager() { registerConfigVar("dwindle:split_bias", Hyprlang::INT{0}); registerConfigVar("dwindle:smart_split", Hyprlang::INT{0}); registerConfigVar("dwindle:smart_resizing", Hyprlang::INT{1}); - registerConfigVar("dwindle:precise_move", Hyprlang::INT{0}); + registerConfigVar("dwindle:precise_mouse_move", Hyprlang::INT{0}); registerConfigVar("master:special_scale_factor", {1.f}); registerConfigVar("master:mfact", {0.55f}); From ddb9f8394df01eaa575955e7f0eee99065441e4b Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 27 May 2025 22:50:00 +0800 Subject: [PATCH 1537/2393] config: fix inconsistant hint of default value (#10556) similar to https://github.com/hyprwm/hyprland-wiki/pull/1093 --- src/config/ConfigDescriptions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index f59bd1a9..5e18233d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1761,7 +1761,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "dwindle:precise_mouse_move", .description = "if enabled, bindm movewindow will drop the window more precisely depending on where your mouse is.", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, /* From 90d0b8ecae9540c21ce418ef781cf0fc2afc4dff Mon Sep 17 00:00:00 2001 From: Nikolaos Karaolidis Date: Tue, 27 May 2025 15:51:59 +0100 Subject: [PATCH 1538/2393] core: add auto-center arrangements (#10527) Signed-off-by: Nikolaos Karaolidis --- src/Compositor.cpp | 24 ++++++++++++++++++++++++ src/config/ConfigManager.cpp | 12 +++++++++++- src/helpers/Monitor.hpp | 6 +++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index c6593923..b4d3aaea 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2890,6 +2890,30 @@ void CCompositor::arrangeMonitors() { case eAutoDirs::DIR_AUTO_LEFT: newPosition.x = maxXOffsetLeft - m->m_size.x; break; case eAutoDirs::DIR_AUTO_RIGHT: case eAutoDirs::DIR_AUTO_NONE: newPosition.x = maxXOffsetRight; break; + case eAutoDirs::DIR_AUTO_CENTER_UP: { + int width = maxXOffsetRight - maxXOffsetLeft; + newPosition.y = maxYOffsetUp - m->m_size.y; + newPosition.x = maxXOffsetLeft + (width - m->m_size.x) / 2; + break; + } + case eAutoDirs::DIR_AUTO_CENTER_DOWN: { + int width = maxXOffsetRight - maxXOffsetLeft; + newPosition.y = maxYOffsetDown; + newPosition.x = maxXOffsetLeft + (width - m->m_size.x) / 2; + break; + } + case eAutoDirs::DIR_AUTO_CENTER_LEFT: { + int height = maxYOffsetDown - maxYOffsetUp; + newPosition.x = maxXOffsetLeft - m->m_size.x; + newPosition.y = maxYOffsetUp + (height - m->m_size.y) / 2; + break; + } + case eAutoDirs::DIR_AUTO_CENTER_RIGHT: { + int height = maxYOffsetDown - maxYOffsetUp; + newPosition.x = maxXOffsetRight; + newPosition.y = maxYOffsetUp + (height - m->m_size.y) / 2; + break; + } default: UNREACHABLE(); } Debug::log(LOG, "arrangeMonitors: {} auto {:j}", m->m_name, m->m_position); diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a4f09d65..a79afb35 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2049,10 +2049,20 @@ std::optional CConfigManager::handleMonitor(const std::string& comm newrule.autoDir = eAutoDirs::DIR_AUTO_UP; else if (ARGS[2] == "auto-down") newrule.autoDir = eAutoDirs::DIR_AUTO_DOWN; + else if (ARGS[2] == "auto-center-right") + newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_RIGHT; + else if (ARGS[2] == "auto-center-left") + newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_LEFT; + else if (ARGS[2] == "auto-center-up") + newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_UP; + else if (ARGS[2] == "auto-center-down") + newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_DOWN; else { Debug::log(WARN, "Invalid auto direction. Valid options are 'auto'," - "'auto-up', 'auto-down', 'auto-left', and 'auto-right'."); + "'auto-up', 'auto-down', 'auto-left', 'auto-right'," + "'auto-center-up', 'auto-center-down'," + "'auto-center-left', and 'auto-center-right'."); error += "invalid auto direction "; } } else { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 31777b0c..019a5547 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -25,7 +25,11 @@ enum eAutoDirs : uint8_t { DIR_AUTO_UP, DIR_AUTO_DOWN, DIR_AUTO_LEFT, - DIR_AUTO_RIGHT + DIR_AUTO_RIGHT, + DIR_AUTO_CENTER_UP, + DIR_AUTO_CENTER_DOWN, + DIR_AUTO_CENTER_LEFT, + DIR_AUTO_CENTER_RIGHT }; enum eCMType : uint8_t { From 24915a3a9b0bb8c4dc8b5a365cc0bc3a03ee36f0 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Tue, 27 May 2025 20:10:22 +0500 Subject: [PATCH 1539/2393] windowrules: Add noscreenshare (#10482) --- src/desktop/Window.hpp | 2 ++ src/protocols/Screencopy.cpp | 54 ++++++++++++++++++++++++++++++++ src/protocols/ToplevelExport.cpp | 17 +++++----- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 0d06b69c..3f73c468 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -104,6 +104,7 @@ struct SWindowData { CWindowOverridableVar xray = false; CWindowOverridableVar renderUnfocused = false; CWindowOverridableVar noFollowMouse = false; + CWindowOverridableVar noScreenShare = false; CWindowOverridableVar borderSize = {std::string("general:border_size"), Hyprlang::INT(0), std::nullopt}; CWindowOverridableVar rounding = {std::string("decoration:rounding"), Hyprlang::INT(0), std::nullopt}; @@ -489,6 +490,7 @@ namespace NWindowProperties { {"immediate", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.tearing; }}, {"xray", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.xray; }}, {"nofollowmouse", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noFollowMouse; }}, + {"noscreenshare", [](const PHLWINDOW& pWindow) { return &pWindow->m_windowData.noScreenShare; }}, }; const std::unordered_map*(const PHLWINDOW&)>> intWindowProperties = { diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 5fa7c84e..8002776a 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -13,6 +13,7 @@ #include "types/Buffer.hpp" #include "../helpers/Format.hpp" #include "../helpers/time/Time.hpp" +#include "XDGShell.hpp" #include #include @@ -200,6 +201,59 @@ void CScreencopyFrame::renderMon() { g_pHyprOpenGL->renderTexture(TEXTURE, monbox, 1); g_pHyprOpenGL->setRenderModifEnabled(true); g_pHyprOpenGL->setMonitorTransformEnabled(false); + + for (auto const& w : g_pCompositor->m_windows) { + if (!w->m_windowData.noScreenShare.valueOrDefault()) + continue; + + if (!g_pHyprRenderer->shouldRenderWindow(w)) + continue; + + const auto PWORKSPACE = w->m_workspace; + + if UNLIKELY (!PWORKSPACE) + continue; + + const auto REALPOS = w->m_realPosition->value() + (w->m_pinned ? Vector2D{} : PWORKSPACE->m_renderOffset->value()); + const auto noScreenShareBox = CBox{REALPOS.x, REALPOS.y, std::max(w->m_realSize->value().x, 5.0), std::max(w->m_realSize->value().y, 5.0)} + .scale(m_monitor->m_scale) + .translate({-m_monitor->m_position.x, -m_monitor->m_position.y}) + .translate({-m_box.x, -m_box.y}); + + const auto dontRound = w->isEffectiveInternalFSMode(FSMODE_FULLSCREEN) || w->m_windowData.noRounding.valueOrDefault(); + const auto rounding = dontRound ? 0 : w->rounding() * m_monitor->m_scale; + const auto roundingPower = dontRound ? 2.0f : w->roundingPower(); + + g_pHyprOpenGL->renderRect(noScreenShareBox, {0, 0, 0, 255}, rounding, roundingPower); + + if (w->m_isX11 || !w->m_popupHead) + continue; + + const auto geom = w->m_xdgSurface->m_current.geometry; + const Vector2D popupBaseOffset = REALPOS - Vector2D{geom.pos().x, geom.pos().y}; + + w->m_popupHead->breadthfirst( + [&](WP popup, void*) { + if (!popup->m_wlSurface || !popup->m_wlSurface->resource() || !popup->m_mapped) + return; + + const auto popRel = popup->coordsRelativeToParent(); + popup->m_wlSurface->resource()->breadthfirst( + [&](SP surf, const Vector2D& localOff, void*) { + const auto size = surf->m_current.size; + const auto surfBox = CBox{popupBaseOffset.x + popRel.x + localOff.x, popupBaseOffset.y + popRel.y + localOff.y, size.x, size.y} + .scale(m_monitor->m_scale) + .translate({-m_monitor->m_position.x, -m_monitor->m_position.y}) + .translate({-m_box.x, -m_box.y}); + + if LIKELY (surfBox.w > 0 && surfBox.h > 0) + g_pHyprOpenGL->renderRect(surfBox, {0, 0, 0, 255}); + }, + nullptr); + }, + nullptr); + } + if (m_overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(m_monitor.lock(), Time::steadyNow(), fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_monitor->m_position - m_box.pos(), true); diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index e50f1fce..4d0ee0f8 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -257,10 +257,11 @@ bool CToplevelExportFrame::copyShm(const Time::steady_tp& now) { // render client at 0,0 if (PERM == PERMISSION_RULE_ALLOW_MODE_ALLOW) { - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); - g_pHyprRenderer->m_bBlockSurfaceFeedback = false; - + if (!m_window->m_windowData.noScreenShare.valueOrDefault()) { + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + } if (overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->m_self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_window->m_realPosition->value()); } else if (PERM == PERMISSION_RULE_ALLOW_MODE_DENY) { @@ -338,9 +339,11 @@ bool CToplevelExportFrame::copyDmabuf(const Time::steady_tp& now) { g_pHyprOpenGL->clear(CHyprColor(0, 0, 0, 1.0)); if (PERM == PERMISSION_RULE_ALLOW_MODE_ALLOW) { - g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); - g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + if (!m_window->m_windowData.noScreenShare.valueOrDefault()) { + g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(m_window); // block the feedback to avoid spamming the surface if it's visible + g_pHyprRenderer->renderWindow(m_window, PMONITOR, now, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->m_bBlockSurfaceFeedback = false; + } if (overlayCursor) g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->m_self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - m_window->m_realPosition->value()); From 9b327ddfd1ad4cfef7a04a178e9f0aed16e95e0a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 27 May 2025 21:26:47 +0200 Subject: [PATCH 1540/2393] monitor: mark 0, 0 presentation timestamps as invalid fixes #10562 --- src/helpers/Monitor.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 72a221f5..d7536a39 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -74,11 +74,16 @@ void CMonitor::onConnect(bool noRule) { auto E = std::any_cast(d); timespec* ts = E.when; - if (!ts) { - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - PROTO::presentation->onPresented(m_self.lock(), Time::fromTimespec(&now), E.refresh, E.seq, E.flags); - } else + + if (ts && ts->tv_sec <= 2) { + // drop this timestamp, it's not valid. Likely drm is cringe. We can't push it further because + // a) it's wrong, b) our translations aren't 100% accurate and risk underflows + ts = nullptr; + } + + if (!ts) + PROTO::presentation->onPresented(m_self.lock(), Time::steadyNow(), E.refresh, E.seq, E.flags); + else PROTO::presentation->onPresented(m_self.lock(), Time::fromTimespec(E.when), E.refresh, E.seq, E.flags); }); From 5cc6cb49458634bd277ada22dfffe6f189cd7d34 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 28 May 2025 15:18:30 +0200 Subject: [PATCH 1541/2393] groupbar: force recalc on visibility changes fixes #10566 --- .../decorations/CHyprGroupBarDecoration.cpp | 17 ++++++++++++----- .../decorations/CHyprGroupBarDecoration.hpp | 3 +++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 84060e0d..65d7d7ff 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -29,7 +29,6 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { static auto PHEIGHT = CConfigValue("group:groupbar:height"); static auto PINDICATORGAP = CConfigValue("group:groupbar:indicator_gap"); static auto PINDICATORHEIGHT = CConfigValue("group:groupbar:indicator_height"); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); static auto PPRIORITY = CConfigValue("group:groupbar:priority"); @@ -43,7 +42,7 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { info.priority = *PPRIORITY; info.reserved = true; - if (*PENABLED && m_window->m_windowData.decorate.valueOrDefault()) { + if (visible()) { if (*PSTACKED) { const auto ONEBARHEIGHT = *POUTERGAP + *PINDICATORHEIGHT + *PINDICATORGAP + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + (*PKEEPUPPERGAP * *POUTERGAP)}, {0, 0}}; @@ -96,11 +95,14 @@ void CHyprGroupBarDecoration::damageEntire() { void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw - int barsToDraw = m_dwGroupMembers.size(); + int barsToDraw = m_dwGroupMembers.size(); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); + const bool VISIBLE = visible(); - if (!*PENABLED || !m_window->m_windowData.decorate.valueOrDefault()) + if (VISIBLE != m_bLastVisibilityStatus) + g_pDecorationPositioner->repositionDeco(this); + + if (!VISIBLE) return; static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); @@ -583,3 +585,8 @@ CBox CHyprGroupBarDecoration::assignedBoxGlobal() { return box.round(); } + +bool CHyprGroupBarDecoration::visible() { + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + return *PENABLED && m_window->m_windowData.decorate.valueOrDefault(); +} diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index feb304f2..5e1abc5a 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -56,10 +56,13 @@ class CHyprGroupBarDecoration : public IHyprWindowDecoration { float m_barWidth; float m_barHeight; + bool m_bLastVisibilityStatus = true; + CTitleTex* textureFromTitle(const std::string&); void invalidateTextures(); CBox assignedBoxGlobal(); + bool visible(); bool onBeginWindowDragOnDeco(const Vector2D&); bool onEndWindowDragOnDeco(const Vector2D&, PHLWINDOW); From 9bf1b491440eac6f9c0d6853013ad5666c12d1d9 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Wed, 28 May 2025 21:20:03 +0800 Subject: [PATCH 1542/2393] snap: add option to respect gaps (#10524) --- src/config/ConfigDescriptions.hpp | 6 ++++ src/config/ConfigManager.cpp | 1 + src/layout/IHyprLayout.cpp | 48 +++++++++++++++++++------------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 5e18233d..a77cf757 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -128,6 +128,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "general:snap:respect_gaps", + .description = "if true, snapping will respect gaps between windows", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * decoration: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index a79afb35..acbc0262 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -456,6 +456,7 @@ CConfigManager::CConfigManager() { registerConfigVar("general:snap:window_gap", Hyprlang::INT{10}); registerConfigVar("general:snap:monitor_gap", Hyprlang::INT{10}); registerConfigVar("general:snap:border_overlap", Hyprlang::INT{0}); + registerConfigVar("general:snap:respect_gaps", Hyprlang::INT{0}); registerConfigVar("general:col.active_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffffff"}); registerConfigVar("general:col.inactive_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xff444444"}); registerConfigVar("general:col.nogroup_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffaaff"}); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 93b09c87..1fe3a936 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -417,6 +417,7 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); static auto SNAPMONITORGAP = CConfigValue("general:snap:monitor_gap"); static auto SNAPBORDEROVERLAP = CConfigValue("general:snap:border_overlap"); + static auto SNAPRESPECTGAPS = CConfigValue("general:snap:respect_gaps"); const SnapFn SNAP = (MODE == MBIND_MOVE) ? snapMove : snapResize; int snaps = 0; @@ -444,9 +445,15 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA const int OTHERBORDERSIZE = other->getRealBorderSize(); const double BORDERSIZE = OVERLAP ? std::max(DRAGGINGBORDERSIZE, OTHERBORDERSIZE) : (DRAGGINGBORDERSIZE + OTHERBORDERSIZE); - const CBox SURF = other->getWindowMainSurfaceBox(); - const SRange SURFBX = {SURF.x - BORDERSIZE, SURF.x + SURF.w + BORDERSIZE}; - const SRange SURFBY = {SURF.y - BORDERSIZE, SURF.y + SURF.h + BORDERSIZE}; + const CBox SURF = other->getWindowMainSurfaceBox(); + double gapOffset = 0; + if (*SNAPRESPECTGAPS) { + static auto PGAPSINDATA = CConfigValue("general:gaps_in"); + auto* PGAPSINPTR = (CCssGapData*)(PGAPSINDATA.ptr())->getData(); + gapOffset = std::max({PGAPSINPTR->m_left, PGAPSINPTR->m_right, PGAPSINPTR->m_top, PGAPSINPTR->m_bottom}); + } + const SRange SURFBX = {SURF.x - BORDERSIZE - gapOffset, SURF.x + SURF.w + BORDERSIZE + gapOffset}; + const SRange SURFBY = {SURF.y - BORDERSIZE - gapOffset, SURF.y + SURF.h + BORDERSIZE + gapOffset}; // only snap windows if their ranges overlap in the opposite axis if (sourceY.start <= SURFBY.end && SURFBY.start <= sourceY.end) { @@ -497,32 +504,37 @@ static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRA const double GAPSIZE = *SNAPMONITORGAP; const double BORDERDIFF = OVERLAP ? DRAGGINGBORDERSIZE : 0; const auto MON = DRAGGINGWINDOW->m_monitor.lock(); - - SRange monX = {MON->m_position.x + MON->m_reservedTopLeft.x + DRAGGINGBORDERSIZE, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - DRAGGINGBORDERSIZE}; - SRange monY = {MON->m_position.y + MON->m_reservedTopLeft.y + DRAGGINGBORDERSIZE, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - DRAGGINGBORDERSIZE}; + double gapOffset = 0; + if (*SNAPRESPECTGAPS) { + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* PGAPSOUTPTR = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData(); + gapOffset = std::max({PGAPSOUTPTR->m_left, PGAPSOUTPTR->m_right, PGAPSOUTPTR->m_top, PGAPSOUTPTR->m_bottom}); + } if (CORNER & (CORNER_TOPLEFT | CORNER_BOTTOMLEFT) && - ((MON->m_reservedTopLeft.x > 0 && canSnap(sourceX.start, monX.start, GAPSIZE)) || - canSnap(sourceX.start, (monX.start -= MON->m_reservedTopLeft.x + BORDERDIFF), GAPSIZE))) { - SNAP(sourceX.start, sourceX.end, monX.start); + ((MON->m_reservedTopLeft.x > 0 && canSnap(sourceX.start, MON->m_position.x + MON->m_reservedTopLeft.x + DRAGGINGBORDERSIZE + gapOffset, GAPSIZE)) || + canSnap(sourceX.start, MON->m_position.x + MON->m_reservedTopLeft.x - BORDERDIFF + gapOffset, GAPSIZE))) { + SNAP(sourceX.start, sourceX.end, MON->m_position.x + MON->m_reservedTopLeft.x + DRAGGINGBORDERSIZE + gapOffset); snaps |= SNAP_LEFT; } if (CORNER & (CORNER_TOPRIGHT | CORNER_BOTTOMRIGHT) && - ((MON->m_reservedBottomRight.x > 0 && canSnap(sourceX.end, monX.end, GAPSIZE)) || - canSnap(sourceX.end, (monX.end += MON->m_reservedBottomRight.x + BORDERDIFF), GAPSIZE))) { - SNAP(sourceX.end, sourceX.start, monX.end); + ((MON->m_reservedBottomRight.x > 0 && + canSnap(sourceX.end, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - DRAGGINGBORDERSIZE - gapOffset, GAPSIZE)) || + canSnap(sourceX.end, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x + BORDERDIFF - gapOffset, GAPSIZE))) { + SNAP(sourceX.end, sourceX.start, MON->m_position.x + MON->m_size.x - MON->m_reservedBottomRight.x - DRAGGINGBORDERSIZE - gapOffset); snaps |= SNAP_RIGHT; } if (CORNER & (CORNER_TOPLEFT | CORNER_TOPRIGHT) && - ((MON->m_reservedTopLeft.y > 0 && canSnap(sourceY.start, monY.start, GAPSIZE)) || - canSnap(sourceY.start, (monY.start -= MON->m_reservedTopLeft.y + BORDERDIFF), GAPSIZE))) { - SNAP(sourceY.start, sourceY.end, monY.start); + ((MON->m_reservedTopLeft.y > 0 && canSnap(sourceY.start, MON->m_position.y + MON->m_reservedTopLeft.y + DRAGGINGBORDERSIZE + gapOffset, GAPSIZE)) || + canSnap(sourceY.start, MON->m_position.y + MON->m_reservedTopLeft.y - BORDERDIFF + gapOffset, GAPSIZE))) { + SNAP(sourceY.start, sourceY.end, MON->m_position.y + MON->m_reservedTopLeft.y + DRAGGINGBORDERSIZE + gapOffset); snaps |= SNAP_UP; } if (CORNER & (CORNER_BOTTOMLEFT | CORNER_BOTTOMRIGHT) && - ((MON->m_reservedBottomRight.y > 0 && canSnap(sourceY.end, monY.end, GAPSIZE)) || - canSnap(sourceY.end, (monY.end += MON->m_reservedBottomRight.y + BORDERDIFF), GAPSIZE))) { - SNAP(sourceY.end, sourceY.start, monY.end); + ((MON->m_reservedBottomRight.y > 0 && + canSnap(sourceY.end, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - DRAGGINGBORDERSIZE - gapOffset, GAPSIZE)) || + canSnap(sourceY.end, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y + BORDERDIFF - gapOffset, GAPSIZE))) { + SNAP(sourceY.end, sourceY.start, MON->m_position.y + MON->m_size.y - MON->m_reservedBottomRight.y - DRAGGINGBORDERSIZE - gapOffset); snaps |= SNAP_DOWN; } } From 9190443d951c21ab24201d033accf90b4d172f46 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Fri, 30 May 2025 18:25:59 +0500 Subject: [PATCH 1543/2393] refactor: use std::ranges whenever possible (#10584) --- src/Compositor.cpp | 4 ++-- src/config/ConfigDataValues.hpp | 2 +- src/config/ConfigManager.cpp | 12 +++++----- src/debug/HyprCtl.cpp | 11 ++++----- src/debug/HyprNotificationOverlay.cpp | 2 +- src/desktop/Window.cpp | 3 ++- src/devices/IKeyboard.cpp | 2 +- src/events/Windows.cpp | 2 +- src/helpers/MiscFunctions.cpp | 8 +++---- src/helpers/Monitor.cpp | 12 ++++++---- src/hyprerror/HyprError.cpp | 2 +- src/layout/MasterLayout.cpp | 23 +++++++++---------- src/managers/AnimationManager.cpp | 2 +- src/managers/CursorManager.cpp | 2 +- src/managers/EventManager.cpp | 2 +- src/managers/HookSystemManager.cpp | 2 +- src/managers/KeybindManager.cpp | 13 ++++------- src/managers/LayoutManager.cpp | 4 ++-- src/managers/PointerManager.cpp | 2 +- src/managers/SeatManager.cpp | 2 +- src/managers/XCursorManager.cpp | 8 +++---- src/managers/input/InputManager.cpp | 12 +++++----- src/protocols/AlphaModifier.cpp | 2 +- src/protocols/ColorManagement.cpp | 4 ++-- src/protocols/DRMLease.cpp | 6 ++--- src/protocols/DataDeviceWlr.cpp | 6 ++--- src/protocols/FocusGrab.cpp | 4 ++-- src/protocols/ForeignToplevel.cpp | 2 +- src/protocols/ForeignToplevelWlr.cpp | 2 +- src/protocols/HyprlandSurface.cpp | 2 +- src/protocols/LayerShell.cpp | 2 +- src/protocols/LinuxDMABUF.cpp | 16 ++++++------- src/protocols/PointerConstraints.cpp | 2 +- src/protocols/PrimarySelection.cpp | 6 ++--- src/protocols/SecurityContext.cpp | 2 +- src/protocols/VirtualKeyboard.cpp | 2 +- src/protocols/XDGActivation.cpp | 5 ++-- src/protocols/XDGShell.cpp | 8 +++---- src/protocols/XXColorManagement.cpp | 4 ++-- src/protocols/core/Compositor.cpp | 4 ++-- src/protocols/core/DataDevice.cpp | 6 ++--- src/protocols/core/Seat.cpp | 4 ++-- src/protocols/core/Shm.cpp | 2 +- src/protocols/core/Subcompositor.cpp | 14 +++++------ src/render/OpenGL.cpp | 8 +++---- src/render/Renderer.cpp | 10 ++++---- .../decorations/DecorationPositioner.cpp | 16 ++++++------- src/render/pass/Pass.cpp | 2 +- src/xwayland/XSurface.cpp | 2 +- src/xwayland/XWM.cpp | 8 +++---- 50 files changed, 137 insertions(+), 146 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b4d3aaea..8d53f3d8 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1724,13 +1724,13 @@ static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, c PHLWINDOW CCompositor::getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly, std::optional floating, bool visible, bool next) { const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; // also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again - return next ? getWeakWindowPred(std::ranges::find(std::ranges::reverse_view(m_windowFocusHistory), cur), m_windowFocusHistory.rend(), m_windowFocusHistory.rbegin(), FINDER) : + return next ? getWeakWindowPred(std::ranges::find(m_windowFocusHistory | std::views::reverse, cur), m_windowFocusHistory.rend(), m_windowFocusHistory.rbegin(), FINDER) : getWeakWindowPred(std::ranges::find(m_windowFocusHistory, cur), m_windowFocusHistory.end(), m_windowFocusHistory.begin(), FINDER); } PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional floating, bool visible, bool prev) { const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; - return prev ? getWindowPred(std::ranges::find(std::ranges::reverse_view(m_windows), cur), m_windows.rend(), m_windows.rbegin(), FINDER) : + return prev ? getWindowPred(std::ranges::find(m_windows | std::views::reverse, cur), m_windows.rend(), m_windows.rbegin(), FINDER) : getWindowPred(std::ranges::find(m_windows, cur), m_windows.end(), m_windows.begin(), FINDER); } diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 2fad9277..d17e7672 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -158,7 +158,7 @@ class CFontWeightConfigValueData : public ICustomConfigValueData { void parseWeight(const std::string& strWeight) { auto lcWeight{strWeight}; - transform(strWeight.begin(), strWeight.end(), lcWeight.begin(), ::tolower); + std::ranges::transform(strWeight, lcWeight.begin(), ::tolower); // values taken from Pango weight enums const auto WEIGHTS = std::map{ diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index acbc0262..3ab53a3c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1651,7 +1651,7 @@ Hyprlang::CConfigValue* CConfigManager::getHyprlangConfigValuePtr(const std::str bool CConfigManager::deviceConfigExists(const std::string& dev) { auto copy = dev; - std::replace(copy.begin(), copy.end(), ' ', '-'); + std::ranges::replace(copy, ' ', '-'); return m_config->specialCategoryExistsForKey("device", copy.c_str()); } @@ -1902,7 +1902,7 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { auto args = CVarList(modeline, 0, 's'); auto keyword = args[0]; - std::transform(keyword.begin(), keyword.end(), keyword.begin(), ::tolower); + std::ranges::transform(keyword, keyword.begin(), ::tolower); if (keyword != "modeline") return false; @@ -1938,7 +1938,7 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { for (; argno < static_cast(args.size()); argno++) { auto key = args[argno]; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); + std::ranges::transform(key, key.begin(), ::tolower); auto it = flagsmap.find(key); @@ -2375,7 +2375,7 @@ std::optional CConfigManager::handleBind(const std::string& command HANDLER = "mouse"; // to lower - std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower); + std::ranges::transform(HANDLER, HANDLER.begin(), ::tolower); const auto DISPATCHER = g_pKeybindManager->m_dispatchers.find(HANDLER); @@ -2798,7 +2798,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin wsRule.workspaceId = id; wsRule.workspaceName = name; - const auto IT = std::find_if(m_workspaceRules.begin(), m_workspaceRules.end(), [&](const auto& other) { return other.workspaceString == wsRule.workspaceString; }); + const auto IT = std::ranges::find_if(m_workspaceRules, [&](const auto& other) { return other.workspaceString == wsRule.workspaceString; }); if (IT == m_workspaceRules.end()) m_workspaceRules.emplace_back(wsRule); @@ -2896,7 +2896,7 @@ std::optional CConfigManager::handleEnv(const std::string& command, } std::optional CConfigManager::handlePlugin(const std::string& command, const std::string& path) { - if (std::find(m_declaredPlugins.begin(), m_declaredPlugins.end(), path) != m_declaredPlugins.end()) + if (std::ranges::find(m_declaredPlugins, path) != m_declaredPlugins.end()) return "plugin '" + path + "' declared twice"; m_declaredPlugins.push_back(path); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index adfbab1e..c8cc5c59 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -216,10 +216,10 @@ static std::string getTagsData(PHLWINDOW w, eHyprCtlOutputFormat format) { const auto tags = w->m_tags.getTags(); if (format == eHyprCtlOutputFormat::FORMAT_JSON) - return std::accumulate(tags.begin(), tags.end(), std::string(), - [](const std::string& a, const std::string& b) { return a.empty() ? std::format("\"{}\"", b) : std::format("{}, \"{}\"", a, b); }); + return std::ranges::fold_left(tags, std::string(), + [](const std::string& a, const std::string& b) { return a.empty() ? std::format("\"{}\"", b) : std::format("{}, \"{}\"", a, b); }); else - return std::accumulate(tags.begin(), tags.end(), std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; }); + return std::ranges::fold_left(tags, std::string(), [](const std::string& a, const std::string& b) { return a.empty() ? b : a + ", " + b; }); } static std::string getGroupedData(PHLWINDOW w, eHyprCtlOutputFormat format) { @@ -921,7 +921,7 @@ static std::string bindsRequest(eHyprCtlOutputFormat format, std::string request std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { auto commitMsg = trim(GIT_COMMIT_MESSAGE); - std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); + std::ranges::replace(commitMsg, '#', ' '); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { std::string result = std::format("Hyprland {} built from branch {} at commit {} {} ({}).\n" @@ -1296,8 +1296,7 @@ static std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::stri } return result.empty() ? "ok" : result; } else { - auto k = std::find_if(g_pInputManager->m_keyboards.begin(), g_pInputManager->m_keyboards.end(), - [&](const auto& other) { return other->m_hlName == g_pInputManager->deviceNameToInternalString(KB); }); + auto k = std::ranges::find_if(g_pInputManager->m_keyboards, [&](const auto& other) { return other->m_hlName == g_pInputManager->deviceNameToInternalString(KB); }); if (k == g_pInputManager->m_keyboards.end()) return "device not found"; diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index 4e17e797..bfa5c4e4 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -13,7 +13,7 @@ static inline auto iconBackendFromLayout(PangoLayout* layout) { // preference: Nerd > FontAwesome > text auto eIconBackendChecks = std::array{ICONS_BACKEND_NF, ICONS_BACKEND_FA}; for (auto iconID : eIconBackendChecks) { - auto iconsText = std::accumulate(ICONS_ARRAY[iconID].begin(), ICONS_ARRAY[iconID].end(), std::string()); + auto iconsText = std::ranges::fold_left(ICONS_ARRAY[iconID], std::string(), std::plus<>()); pango_layout_set_text(layout, iconsText.c_str(), -1); if (pango_layout_get_unknown_glyphs_count(layout) == 0) return iconID; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 9f69e364..cc3c9390 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -1507,7 +1508,7 @@ std::string CWindow::fetchClass() { } void CWindow::onAck(uint32_t serial) { - const auto SERIAL = std::ranges::find_if(m_pendingSizeAcks.rbegin(), m_pendingSizeAcks.rend(), [serial](const auto& e) { return e.first == serial; }); + const auto SERIAL = std::ranges::find_if(m_pendingSizeAcks | std::views::reverse, [serial](const auto& e) { return e.first == serial; }); if (SERIAL == m_pendingSizeAcks.rend()) return; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 597724a6..89ad8c16 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -379,7 +379,7 @@ bool IKeyboard::updateModifiersState() { void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) { - const auto contains = std::find(m_pressedXKB.begin(), m_pressedXKB.end(), xkbKey) != m_pressedXKB.end(); + const auto contains = std::ranges::find(m_pressedXKB, xkbKey) != m_pressedXKB.end(); if (contains && pressed) return; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 4bf54ca8..b019adff 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -742,7 +742,7 @@ void Events::listener_unmapWindow(void* owner, void* data) { EMIT_HOOK_EVENT("closeWindow", PWINDOW); if (PWINDOW->m_isFloating && !PWINDOW->m_isX11 && - std::any_of(PWINDOW->m_matchedRules.begin(), PWINDOW->m_matchedRules.end(), [](const auto& r) { return r->m_ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) { + std::ranges::any_of(PWINDOW->m_matchedRules, [](const auto& r) { return r->m_ruleType == CWindowRule::RULE_PERSISTENTSIZE; })) { Debug::log(LOG, "storing floating size {}x{} for window {}::{} on close", PWINDOW->m_realSize->value().x, PWINDOW->m_realSize->value().y, PWINDOW->m_class, PWINDOW->m_title); g_pConfigManager->storeFloatingSize(PWINDOW, PWINDOW->m_realSize->value()); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index ed67618e..ddd16144 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -243,7 +243,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { namedWSes.push_back(ws->m_id); } - std::sort(namedWSes.begin(), namedWSes.end()); + std::ranges::sort(namedWSes); if (absolute) { // 1-index @@ -388,7 +388,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { validWSes.push_back(ws->m_id); } - std::sort(validWSes.begin(), validWSes.end()); + std::ranges::sort(validWSes); ssize_t currentItem = -1; @@ -623,7 +623,7 @@ std::expected configStringToInt(const std::string& VALUE) const auto VALUEWITHOUTFUNC = trim(VALUE.substr(5, VALUE.length() - 6)); // try doing it the comma way first - if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 3) { + if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 3) { // cool std::string rolling = VALUEWITHOUTFUNC; auto r = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); @@ -657,7 +657,7 @@ std::expected configStringToInt(const std::string& VALUE) const auto VALUEWITHOUTFUNC = trim(VALUE.substr(4, VALUE.length() - 5)); // try doing it the comma way first - if (std::count(VALUEWITHOUTFUNC.begin(), VALUEWITHOUTFUNC.end(), ',') == 2) { + if (std::ranges::count(VALUEWITHOUTFUNC, ',') == 2) { // cool std::string rolling = VALUEWITHOUTFUNC; auto r = configStringToInt(trim(rolling.substr(0, rolling.find(',')))); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index d7536a39..5afd0123 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include using namespace Hyprutils::String; using namespace Hyprutils::Utils; @@ -189,7 +191,7 @@ void CMonitor::onConnect(bool noRule) { RASSERT(thisWrapper->get(), "CMonitor::onConnect: Had no wrapper???"); - if (std::find_if(g_pCompositor->m_monitors.begin(), g_pCompositor->m_monitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_monitors.end()) + if (std::ranges::find_if(g_pCompositor->m_monitors, [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_monitors.end()) g_pCompositor->m_monitors.push_back(*thisWrapper); m_enabled = true; @@ -320,7 +322,7 @@ void CMonitor::onDisconnect(bool destroy) { // remove mirror if (m_mirrorOf) { - m_mirrorOf->m_mirrors.erase(std::find_if(m_mirrorOf->m_mirrors.begin(), m_mirrorOf->m_mirrors.end(), [&](const auto& other) { return other == m_self; })); + m_mirrorOf->m_mirrors.erase(std::ranges::find_if(m_mirrorOf->m_mirrors, [&](const auto& other) { return other == m_self; })); // unlock software for mirrored monitor g_pPointerManager->unlockSoftwareForMonitor(m_mirrorOf.lock()); @@ -486,7 +488,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { std::ranges::sort(sortedModes, sortFunc); if (sortedModes.size() > 3) sortedModes.erase(sortedModes.begin() + 3, sortedModes.end()); - requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend()); + requestedModes.insert_range(requestedModes.end(), sortedModes | std::views::reverse); }; // last fallback is always preferred mode @@ -1019,7 +1021,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { // disable mirroring if (m_mirrorOf) { - m_mirrorOf->m_mirrors.erase(std::find_if(m_mirrorOf->m_mirrors.begin(), m_mirrorOf->m_mirrors.end(), [&](const auto& other) { return other == m_self; })); + m_mirrorOf->m_mirrors.erase(std::ranges::find_if(m_mirrorOf->m_mirrors, [&](const auto& other) { return other == m_self; })); // unlock software for mirrored monitor g_pPointerManager->unlockSoftwareForMonitor(m_mirrorOf.lock()); @@ -1046,7 +1048,7 @@ void CMonitor::setMirror(const std::string& mirrorOf) { RASSERT(thisWrapper->get(), "CMonitor::setMirror: Had no wrapper???"); - if (std::find_if(g_pCompositor->m_monitors.begin(), g_pCompositor->m_monitors.end(), [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_monitors.end()) { + if (std::ranges::find_if(g_pCompositor->m_monitors, [&](auto& other) { return other.get() == this; }) == g_pCompositor->m_monitors.end()) { g_pCompositor->m_monitors.push_back(*thisWrapper); } diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 614fdd2e..22744c93 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -63,7 +63,7 @@ void CHyprError::createQueued() { cairo_paint(CAIRO); cairo_restore(CAIRO); - const auto LINECOUNT = Hyprlang::INT{1} + std::count(m_queued.begin(), m_queued.end(), '\n'); + const auto LINECOUNT = Hyprlang::INT{1} + std::ranges::count(m_queued, '\n'); static auto LINELIMIT = CConfigValue("debug:error_limit"); static auto BAR_POSITION = CConfigValue("debug:error_position"); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 065dcdc2..cb1313a8 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -94,7 +94,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire if (*PNEWONACTIVE != "none" && !BNEWISMASTER) { const auto pLastNode = getNodeFromWindow(g_pCompositor->m_lastWindow.lock()); if (pLastNode && !(pLastNode->isMaster && (getMastersOnWorkspace(pWindow->workspaceID()) == 1 || *PNEWSTATUS == "slave"))) { - auto it = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), *pLastNode); + auto it = std::ranges::find(m_masterNodesData, *pLastNode); if (!BNEWBEFOREACTIVE) ++it; return &(*m_masterNodesData.emplace(it)); @@ -117,7 +117,7 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire const auto MOUSECOORDS = g_pInputManager->getMouseCoordsInternal(); static auto PDROPATCURSOR = CConfigValue("master:drop_at_cursor"); eOrientation orientation = getDynamicOrientation(pWindow->m_workspace); - const auto NODEIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), *PNODE); + const auto NODEIT = std::ranges::find(m_masterNodesData, *PNODE); bool forceDropAsMaster = false; // if dragging window to move, drop it at the cursor position instead of bottom/top of stack @@ -804,8 +804,8 @@ void CHyprMasterLayout::resizeActiveWindow(const Vector2D& pixResize, eRectCorne if (!*PSMARTRESIZING) { PNODE->percSize = std::clamp(PNODE->percSize + RESIZEDELTA / SIZE, 0.05, 1.95); } else { - const auto NODEIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), *PNODE); - const auto REVNODEIT = std::find(m_masterNodesData.rbegin(), m_masterNodesData.rend(), *PNODE); + const auto NODEIT = std::ranges::find(m_masterNodesData, *PNODE); + const auto REVNODEIT = std::ranges::find(m_masterNodesData | std::views::reverse, *PNODE); const float totalSize = isStackVertical ? WSSIZE.y : WSSIZE.x; const float minSize = totalSize / nodesInSameColumn * 0.2; @@ -1026,16 +1026,15 @@ PHLWINDOW CHyprMasterLayout::getNextWindow(PHLWINDOW pWindow, bool next, bool lo auto nodes = m_masterNodesData; if (!next) - std::reverse(nodes.begin(), nodes.end()); + std::ranges::reverse(nodes); - const auto NODEIT = std::find(nodes.begin(), nodes.end(), *PNODE); + const auto NODEIT = std::ranges::find(nodes, *PNODE); const bool ISMASTER = PNODE->isMaster; auto CANDIDATE = std::find_if(NODEIT, nodes.end(), [&](const auto& other) { return other != *PNODE && ISMASTER == other.isMaster && other.workspaceID == PNODE->workspaceID; }); if (CANDIDATE == nodes.end()) - CANDIDATE = - std::find_if(nodes.begin(), nodes.end(), [&](const auto& other) { return other != *PNODE && ISMASTER != other.isMaster && other.workspaceID == PNODE->workspaceID; }); + CANDIDATE = std::ranges::find_if(nodes, [&](const auto& other) { return other != *PNODE && ISMASTER != other.isMaster && other.workspaceID == PNODE->workspaceID; }); if (CANDIDATE != nodes.end() && !loop) { if (CANDIDATE->isMaster && next) @@ -1308,12 +1307,12 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!OLDMASTER) return 0; - const auto OLDMASTERIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), *OLDMASTER); + const auto OLDMASTERIT = std::ranges::find(m_masterNodesData, *OLDMASTER); for (auto& nd : m_masterNodesData) { if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) { nd.isMaster = true; - const auto NEWMASTERIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), nd); + const auto NEWMASTERIT = std::ranges::find(m_masterNodesData, nd); m_masterNodesData.splice(OLDMASTERIT, m_masterNodesData, NEWMASTERIT); switchToWindow(nd.pWindow.lock()); OLDMASTER->isMaster = false; @@ -1334,12 +1333,12 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri if (!OLDMASTER) return 0; - const auto OLDMASTERIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), *OLDMASTER); + const auto OLDMASTERIT = std::ranges::find(m_masterNodesData, *OLDMASTER); for (auto& nd : m_masterNodesData | std::views::reverse) { if (nd.workspaceID == PNODE->workspaceID && !nd.isMaster) { nd.isMaster = true; - const auto NEWMASTERIT = std::find(m_masterNodesData.begin(), m_masterNodesData.end(), nd); + const auto NEWMASTERIT = std::ranges::find(m_masterNodesData, nd); m_masterNodesData.splice(OLDMASTERIT, m_masterNodesData, NEWMASTERIT); switchToWindow(nd.pWindow.lock()); OLDMASTER->isMaster = false; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index d12b91a5..f935d3dc 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -384,7 +384,7 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos } std::string ANIMSTYLE = pWindow->m_realPosition->getStyle(); - transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower); + std::ranges::transform(ANIMSTYLE, ANIMSTYLE.begin(), ::tolower); CVarList animList(ANIMSTYLE, 0, 's'); diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 77ea5a28..9211fc20 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -186,7 +186,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { if (m_currentCursorShapeData.images.size() < 1) { // try with '_' first (old hc, etc) std::string newName = name; - std::replace(newName.begin(), newName.end(), '-', '_'); + std::ranges::replace(newName, '-', '_'); m_currentCursorShapeData = m_hyprcursor->getShape(newName.c_str(), m_currentStyleInfo); } diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index 651bf436..e0d8704b 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -123,7 +123,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { } std::vector::iterator CEventManager::findClientByFD(int fd) { - return std::find_if(m_clients.begin(), m_clients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); + return std::ranges::find_if(m_clients, [fd](const auto& client) { return client.fd.get() == fd; }); } std::vector::iterator CEventManager::removeClientByFD(int fd) { diff --git a/src/managers/HookSystemManager.cpp b/src/managers/HookSystemManager.cpp index 67e6e732..2f1f3a27 100644 --- a/src/managers/HookSystemManager.cpp +++ b/src/managers/HookSystemManager.cpp @@ -46,7 +46,7 @@ void CHookSystemManager::emit(std::vector* const callbacks, SCal m_currentEventPlugin = true; - if (std::find(faultyHandles.begin(), faultyHandles.end(), cb.handle) != faultyHandles.end()) + if (std::ranges::find(faultyHandles, cb.handle) != faultyHandles.end()) continue; try { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index c4c6d4ab..58951281 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -225,7 +225,7 @@ void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { uint32_t CKeybindManager::stringToModMask(std::string mods) { uint32_t modMask = 0; - std::transform(mods.begin(), mods.end(), mods.begin(), ::toupper); + std::ranges::transform(mods, mods.begin(), ::toupper); if (mods.contains("SHIFT")) modMask |= HL_MODIFIER_SHIFT; if (mods.contains("CAPS")) @@ -624,10 +624,8 @@ eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set k std::set boundKeysNotPressed; std::set pressedKeysNotBound; - std::set_difference(keybindKeysyms.begin(), keybindKeysyms.end(), pressedKeysyms.begin(), pressedKeysyms.end(), - std::inserter(boundKeysNotPressed, boundKeysNotPressed.begin())); - std::set_difference(pressedKeysyms.begin(), pressedKeysyms.end(), keybindKeysyms.begin(), keybindKeysyms.end(), - std::inserter(pressedKeysNotBound, pressedKeysNotBound.begin())); + std::ranges::set_difference(keybindKeysyms, pressedKeysyms, std::inserter(boundKeysNotPressed, boundKeysNotPressed.begin())); + std::ranges::set_difference(pressedKeysyms, keybindKeysyms, std::inserter(pressedKeysNotBound, pressedKeysNotBound.begin())); if (boundKeysNotPressed.empty() && pressedKeysNotBound.empty()) return MK_FULL_MATCH; @@ -670,8 +668,7 @@ SDispatchResult CKeybindManager::handleKeybinds(const uint32_t modmask, const SP for (auto& k : m_keybinds) { const bool SPECIALDISPATCHER = k->handler == "global" || k->handler == "pass" || k->handler == "sendshortcut" || k->handler == "mouse"; - const bool SPECIALTRIGGERED = - std::find_if(m_pressedSpecialBinds.begin(), m_pressedSpecialBinds.end(), [&](const auto& other) { return other == k; }) != m_pressedSpecialBinds.end(); + const bool SPECIALTRIGGERED = std::ranges::find_if(m_pressedSpecialBinds, [&](const auto& other) { return other == k; }) != m_pressedSpecialBinds.end(); const bool IGNORECONDITIONS = SPECIALDISPATCHER && !pressed && SPECIALTRIGGERED; // ignore mods. Pass, global dispatchers should be released immediately once the key is released. @@ -1106,7 +1103,7 @@ SDispatchResult CKeybindManager::signalWindow(std::string args) { return {.success = false, .error = "signalWindow: no window"}; } - if (!std::all_of(SIGNAL.begin(), SIGNAL.end(), ::isdigit)) + if (!std::ranges::all_of(SIGNAL, ::isdigit)) return {.success = false, .error = "signalWindow: signal has to be int"}; try { diff --git a/src/managers/LayoutManager.cpp b/src/managers/LayoutManager.cpp index a929b42e..08bbcf44 100644 --- a/src/managers/LayoutManager.cpp +++ b/src/managers/LayoutManager.cpp @@ -26,7 +26,7 @@ void CLayoutManager::switchToLayout(std::string layout) { } bool CLayoutManager::addLayout(const std::string& name, IHyprLayout* layout) { - if (std::find_if(m_layouts.begin(), m_layouts.end(), [&](const auto& other) { return other.first == name || other.second == layout; }) != m_layouts.end()) + if (std::ranges::find_if(m_layouts, [&](const auto& other) { return other.first == name || other.second == layout; }) != m_layouts.end()) return false; m_layouts.emplace_back(std::make_pair<>(name, layout)); @@ -37,7 +37,7 @@ bool CLayoutManager::addLayout(const std::string& name, IHyprLayout* layout) { } bool CLayoutManager::removeLayout(IHyprLayout* layout) { - const auto IT = std::find_if(m_layouts.begin(), m_layouts.end(), [&](const auto& other) { return other.second == layout; }); + const auto IT = std::ranges::find_if(m_layouts, [&](const auto& other) { return other.second == layout; }); if (IT == m_layouts.end() || IT->first == "dwindle" || IT->first == "master") return false; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index f42fd686..a82be1b0 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -94,7 +94,7 @@ bool CPointerManager::hasCursor() { } SP CPointerManager::stateFor(PHLMONITOR mon) { - auto it = std::find_if(m_monitorStates.begin(), m_monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; }); + auto it = std::ranges::find_if(m_monitorStates, [mon](const auto& other) { return other->monitor == mon; }); if (it == m_monitorStates.end()) return m_monitorStates.emplace_back(makeShared(mon)); return *it; diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 419e8bf4..a7660854 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -653,7 +653,7 @@ void CSeatManager::resendEnterEvents() { } bool CSeatGrab::accepts(SP surf) { - return std::find(m_surfs.begin(), m_surfs.end(), surf) != m_surfs.end(); + return std::ranges::find(m_surfs, surf) != m_surfs.end(); } void CSeatGrab::add(SP surf) { diff --git a/src/managers/XCursorManager.cpp b/src/managers/XCursorManager.cpp index 79bb7a5d..9bbf531b 100644 --- a/src/managers/XCursorManager.cpp +++ b/src/managers/XCursorManager.cpp @@ -127,8 +127,8 @@ void CXCursorManager::loadTheme(std::string const& name, int size, float scale) for (auto const& p : paths) { try { auto dirCursors = loadAllFromDir(p, m_lastLoadSize); - std::copy_if(dirCursors.begin(), dirCursors.end(), std::back_inserter(m_cursors), - [this](auto const& p) { return std::none_of(m_cursors.begin(), m_cursors.end(), [&p](auto const& dp) { return dp->shape == p->shape; }); }); + std::ranges::copy_if(dirCursors, std::back_inserter(m_cursors), + [this](auto const& p) { return std::ranges::none_of(m_cursors, [&p](auto const& dp) { return dp->shape == p->shape; }); }); } catch (std::exception& e) { Debug::log(ERR, "XCursor path {} can't be loaded: threw error {}", p, e.what()); } } } @@ -144,14 +144,14 @@ void CXCursorManager::loadTheme(std::string const& name, int size, float scale) if (legacyName.empty()) continue; - auto it = std::find_if(m_cursors.begin(), m_cursors.end(), [&legacyName](auto const& c) { return c->shape == legacyName; }); + auto it = std::ranges::find_if(m_cursors, [&legacyName](auto const& c) { return c->shape == legacyName; }); if (it == m_cursors.end()) { Debug::log(LOG, "XCursor failed to find a legacy shape with name {}, skipping", legacyName); continue; } - if (std::any_of(m_cursors.begin(), m_cursors.end(), [&shape](auto const& dp) { return dp->shape == shape; })) { + if (std::ranges::any_of(m_cursors, [&shape](auto const& dp) { return dp->shape == shape; })) { Debug::log(LOG, "XCursor already has a shape {} loaded, skipping", shape); continue; } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 2d50dbcf..cc0485d8 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -619,7 +619,7 @@ void CInputManager::onMouseButton(IPointer::SButtonEvent e) { if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) { m_currentlyHeldButtons.push_back(e.button); } else { - if (std::find_if(m_currentlyHeldButtons.begin(), m_currentlyHeldButtons.end(), [&](const auto& other) { return other == e.button; }) == m_currentlyHeldButtons.end()) + if (std::ranges::find_if(m_currentlyHeldButtons, [&](const auto& other) { return other == e.button; }) == m_currentlyHeldButtons.end()) return; std::erase_if(m_currentlyHeldButtons, [&](const auto& other) { return other == e.button; }); } @@ -1552,7 +1552,7 @@ void CInputManager::unconstrainMouse() { } bool CInputManager::isConstrained() { - return std::any_of(m_constraints.begin(), m_constraints.end(), [](auto const& c) { + return std::ranges::any_of(m_constraints, [](auto const& c) { const auto constraint = c.lock(); return constraint && constraint->isActive() && constraint->owner()->resource() == g_pCompositor->m_lastFocus; }); @@ -1773,9 +1773,9 @@ void CInputManager::unsetCursorImage() { } std::string CInputManager::deviceNameToInternalString(std::string in) { - std::replace(in.begin(), in.end(), ' ', '-'); - std::replace(in.begin(), in.end(), '\n', '-'); - std::transform(in.begin(), in.end(), in.begin(), ::tolower); + std::ranges::replace(in, ' ', '-'); + std::ranges::replace(in, '\n', '-'); + std::ranges::transform(in, in.begin(), ::tolower); return in; } @@ -1786,7 +1786,7 @@ std::string CInputManager::getNameForNewDevice(std::string internalName) { auto makeNewName = [&]() { return (proposedNewName.empty() ? "unknown-device" : proposedNewName) + (dupeno == 0 ? "" : ("-" + std::to_string(dupeno))); }; - while (std::find_if(m_hids.begin(), m_hids.end(), [&](const auto& other) { return other->m_hlName == makeNewName(); }) != m_hids.end()) + while (std::ranges::find_if(m_hids, [&](const auto& other) { return other->m_hlName == makeNewName(); }) != m_hids.end()) dupeno++; return makeNewName(); diff --git a/src/protocols/AlphaModifier.cpp b/src/protocols/AlphaModifier.cpp index e2408397..ad4bc107 100644 --- a/src/protocols/AlphaModifier.cpp +++ b/src/protocols/AlphaModifier.cpp @@ -81,7 +81,7 @@ void CAlphaModifierProtocol::destroyAlphaModifier(CAlphaModifier* modifier) { void CAlphaModifierProtocol::getSurface(CWpAlphaModifierV1* manager, uint32_t id, SP surface) { CAlphaModifier* alphaModifier = nullptr; - auto iter = std::find_if(m_alphaModifiers.begin(), m_alphaModifiers.end(), [&](const auto& entry) { return entry.second->m_surface == surface; }); + auto iter = std::ranges::find_if(m_alphaModifiers, [&](const auto& entry) { return entry.second->m_surface == surface; }); if (iter != m_alphaModifiers.end()) { if (iter->second->m_resource) { diff --git a/src/protocols/ColorManagement.cpp b/src/protocols/ColorManagement.cpp index 5ace1f7e..50bded7f 100644 --- a/src/protocols/ColorManagement.cpp +++ b/src/protocols/ColorManagement.cpp @@ -281,8 +281,8 @@ CColorManagementSurface::CColorManagementSurface(SP return; } - const auto imageDescription = std::find_if(PROTO::colorManagement->m_imageDescriptions.begin(), PROTO::colorManagement->m_imageDescriptions.end(), - [&](const auto& other) { return other->resource()->resource() == image_description; }); + const auto imageDescription = + std::ranges::find_if(PROTO::colorManagement->m_imageDescriptions, [&](const auto& other) { return other->resource()->resource() == image_description; }); if (imageDescription == PROTO::colorManagement->m_imageDescriptions.end()) { r->error(WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION, "Image description not found"); return; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index c4b5a84a..622c907c 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -96,7 +96,7 @@ CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP reso auto CONNECTOR = CDRMLeaseConnectorResource::fromResource(conn); - if (std::find(m_requested.begin(), m_requested.end(), CONNECTOR) != m_requested.end()) { + if (std::ranges::find(m_requested, CONNECTOR) != m_requested.end()) { m_resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Connector already requested"); return; } @@ -208,7 +208,7 @@ bool CDRMLeaseDeviceResource::good() { } void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { - if (std::find_if(m_connectorsSent.begin(), m_connectorsSent.end(), [monitor](const auto& e) { return e && !e->m_dead && e->m_monitor == monitor; }) != m_connectorsSent.end()) + if (std::ranges::find_if(m_connectorsSent, [monitor](const auto& e) { return e && !e->m_dead && e->m_monitor == monitor; }) != m_connectorsSent.end()) return; auto RESOURCE = makeShared(makeShared(m_resource->client(), m_resource->version(), 0), monitor); @@ -294,7 +294,7 @@ void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { void CDRMLeaseProtocol::offer(PHLMONITOR monitor) { std::erase_if(m_primaryDevice->m_offeredOutputs, [](const auto& e) { return e.expired(); }); - if (std::find(m_primaryDevice->m_offeredOutputs.begin(), m_primaryDevice->m_offeredOutputs.end(), monitor) != m_primaryDevice->m_offeredOutputs.end()) + if (std::ranges::find(m_primaryDevice->m_offeredOutputs, monitor) != m_primaryDevice->m_offeredOutputs.end()) return; if (monitor->m_output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 2e9c032b..e169f666 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -78,7 +78,7 @@ std::vector CWLRDataSource::mimes() { } void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) { + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); return; } @@ -87,7 +87,7 @@ void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { } void CWLRDataSource::accepted(const std::string& mime) { - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAccepted with non-existent mime"); // wlr has no accepted @@ -315,7 +315,7 @@ void CDataDeviceWLRProtocol::setSelection(SP source, bool primary) } SP CDataDeviceWLRProtocol::dataDeviceForClient(wl_client* c) { - auto it = std::find_if(m_devices.begin(), m_devices.end(), [c](const auto& e) { return e->client() == c; }); + auto it = std::ranges::find_if(m_devices, [c](const auto& e) { return e->client() == c; }); if (it == m_devices.end()) return nullptr; return *it; diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index 9f054953..41396459 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -36,7 +36,7 @@ bool CFocusGrab::good() { } bool CFocusGrab::isSurfaceComitted(SP surface) { - auto iter = std::find_if(m_surfaces.begin(), m_surfaces.end(), [surface](const auto& o) { return o.first == surface; }); + auto iter = std::ranges::find_if(m_surfaces, [surface](const auto& o) { return o.first == surface; }); if (iter == m_surfaces.end()) return false; @@ -70,7 +70,7 @@ void CFocusGrab::finish(bool sendCleared) { } void CFocusGrab::addSurface(SP surface) { - auto iter = std::find_if(m_surfaces.begin(), m_surfaces.end(), [surface](const auto& e) { return e.first == surface; }); + auto iter = std::ranges::find_if(m_surfaces, [surface](const auto& e) { return e.first == surface; }); if (iter == m_surfaces.end()) m_surfaces.emplace(surface, makeUnique(this, surface)); } diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index e48f0722..ec5943af 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -69,7 +69,7 @@ void CForeignToplevelList::onMap(PHLWINDOW pWindow) { SP CForeignToplevelList::handleForWindow(PHLWINDOW pWindow) { std::erase_if(m_handles, [](const auto& wp) { return wp.expired(); }); - const auto IT = std::find_if(m_handles.begin(), m_handles.end(), [pWindow](const auto& h) { return h->window() == pWindow; }); + const auto IT = std::ranges::find_if(m_handles, [pWindow](const auto& h) { return h->window() == pWindow; }); return IT == m_handles.end() ? SP{} : IT->lock(); } diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index dccf83b6..600412cb 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -247,7 +247,7 @@ void CForeignToplevelWlrManager::onMap(PHLWINDOW pWindow) { SP CForeignToplevelWlrManager::handleForWindow(PHLWINDOW pWindow) { std::erase_if(m_handles, [](const auto& wp) { return wp.expired(); }); - const auto IT = std::find_if(m_handles.begin(), m_handles.end(), [pWindow](const auto& h) { return h->window() == pWindow; }); + const auto IT = std::ranges::find_if(m_handles, [pWindow](const auto& h) { return h->window() == pWindow; }); return IT == m_handles.end() ? SP{} : IT->lock(); } diff --git a/src/protocols/HyprlandSurface.cpp b/src/protocols/HyprlandSurface.cpp index 9c66fba4..2e386027 100644 --- a/src/protocols/HyprlandSurface.cpp +++ b/src/protocols/HyprlandSurface.cpp @@ -109,7 +109,7 @@ void CHyprlandSurfaceProtocol::destroySurface(CHyprlandSurface* surface) { void CHyprlandSurfaceProtocol::getSurface(CHyprlandSurfaceManagerV1* manager, uint32_t id, SP surface) { CHyprlandSurface* hyprlandSurface = nullptr; - auto iter = std::find_if(m_surfaces.begin(), m_surfaces.end(), [&](const auto& entry) { return entry.second->m_surface == surface; }); + auto iter = std::ranges::find_if(m_surfaces, [&](const auto& entry) { return entry.second->m_surface == surface; }); if (iter != m_surfaces.end()) { if (iter->second->m_resource) { diff --git a/src/protocols/LayerShell.cpp b/src/protocols/LayerShell.cpp index 4cb37ff4..bb5480b6 100644 --- a/src/protocols/LayerShell.cpp +++ b/src/protocols/LayerShell.cpp @@ -130,7 +130,7 @@ CLayerShellResource::CLayerShellResource(SP resource_, SPsetAckConfigure([this](CZwlrLayerSurfaceV1* r, uint32_t serial) { - auto serialFound = std::find_if(m_serials.begin(), m_serials.end(), [serial](const auto& e) { return e.first == serial; }); + auto serialFound = std::ranges::find_if(m_serials, [serial](const auto& e) { return e.first == serial; }); if (serialFound == m_serials.end()) { r->error(ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE, "Serial invalid in ack_configure"); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index ee64415b..a0fe571a 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -46,8 +46,7 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec }); } else { // if it wasn't inserted then find its index in vec - auto it = - std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + auto it = std::ranges::find_if(formatsVec, [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); m_rendererTranche.indicies.push_back(it - formatsVec.begin()); } } @@ -69,8 +68,7 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec .modifier = mod, }); } else { - auto it = std::find_if(formatsVec.begin(), formatsVec.end(), - [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + auto it = std::ranges::find_if(formatsVec, [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); tranche.indicies.push_back(it - formatsVec.begin()); } } @@ -89,7 +87,7 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec return; } - std::copy(formatsVec.begin(), formatsVec.end(), arr); + std::ranges::copy(formatsVec, arr); munmap(arr, m_tableSize); @@ -169,7 +167,7 @@ CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(SPsize = {w, h}; m_attrs->format = fmt; - m_attrs->planes = 4 - std::count(m_attrs->fds.begin(), m_attrs->fds.end(), -1); + m_attrs->planes = 4 - std::ranges::count(m_attrs->fds, -1); create(0); }); @@ -188,7 +186,7 @@ CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(SPsize = {w, h}; m_attrs->format = fmt; - m_attrs->planes = 4 - std::count(m_attrs->fds.begin(), m_attrs->fds.end(), -1); + m_attrs->planes = 4 - std::ranges::count(m_attrs->fds, -1); create(id); }); @@ -564,8 +562,8 @@ void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface return; } - const auto& monitorTranchePair = std::find_if(m_formatTable->m_monitorTranches.begin(), m_formatTable->m_monitorTranches.end(), - [pMonitor](std::pair pair) { return pair.first == pMonitor; }); + const auto& monitorTranchePair = + std::ranges::find_if(m_formatTable->m_monitorTranches, [pMonitor](std::pair pair) { return pair.first == pMonitor; }); if (monitorTranchePair == m_formatTable->m_monitorTranches.end()) { LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); diff --git a/src/protocols/PointerConstraints.cpp b/src/protocols/PointerConstraints.cpp index 425a983d..ea917932 100644 --- a/src/protocols/PointerConstraints.cpp +++ b/src/protocols/PointerConstraints.cpp @@ -229,7 +229,7 @@ void CPointerConstraintsProtocol::onNewConstraint(SP constra const auto OWNER = constraint->owner(); - const auto DUPES = std::count_if(m_constraints.begin(), m_constraints.end(), [OWNER](const auto& c) { return c->owner() == OWNER; }); + const auto DUPES = std::ranges::count_if(m_constraints, [OWNER](const auto& c) { return c->owner() == OWNER; }); if UNLIKELY (DUPES > 1) { LOGM(ERR, "Constraint for surface duped"); diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 3c263647..14df7af5 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -79,7 +79,7 @@ std::vector CPrimarySelectionSource::mimes() { } void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) { - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) { + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); return; } @@ -88,7 +88,7 @@ void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) } void CPrimarySelectionSource::accepted(const std::string& mime) { - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAccepted with non-existent mime"); // primary sel has no accepted @@ -327,7 +327,7 @@ void CPrimarySelectionProtocol::onPointerFocus() { } SP CPrimarySelectionProtocol::dataDeviceForClient(wl_client* c) { - auto it = std::find_if(m_devices.begin(), m_devices.end(), [c](const auto& e) { return e->client() == c; }); + auto it = std::ranges::find_if(m_devices, [c](const auto& e) { return e->client() == c; }); if (it == m_devices.end()) return nullptr; return *it; diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index ae3f41b1..acabe0a1 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -214,5 +214,5 @@ void CSecurityContextProtocol::destroyContext(CSecurityContext* context) { } bool CSecurityContextProtocol::isClientSandboxed(const wl_client* client) { - return std::find_if(m_sandboxedClients.begin(), m_sandboxedClients.end(), [client](const auto& e) { return e->m_client == client; }) != m_sandboxedClients.end(); + return std::ranges::find_if(m_sandboxedClients, [client](const auto& e) { return e->m_client == client; }) != m_sandboxedClients.end(); } diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 48ed7eeb..7512f9bd 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -31,7 +31,7 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP .state = (wl_keyboard_key_state)state, }); - const bool CONTAINS = std::find(m_pressed.begin(), m_pressed.end(), key) != m_pressed.end(); + const bool CONTAINS = std::ranges::find(m_pressed, key) != m_pressed.end(); if (state && !CONTAINS) m_pressed.emplace_back(key); else if (!state && CONTAINS) diff --git a/src/protocols/XDGActivation.cpp b/src/protocols/XDGActivation.cpp index bae3acc3..f25ffca8 100644 --- a/src/protocols/XDGActivation.cpp +++ b/src/protocols/XDGActivation.cpp @@ -33,8 +33,7 @@ CXDGActivationToken::CXDGActivationToken(SP resource_) : PROTO::activation->m_sentTokens.push_back({m_token, m_resource->client()}); - auto count = std::count_if(PROTO::activation->m_sentTokens.begin(), PROTO::activation->m_sentTokens.end(), - [this](const auto& other) { return other.client == m_resource->client(); }); + auto count = std::ranges::count_if(PROTO::activation->m_sentTokens, [this](const auto& other) { return other.client == m_resource->client(); }); if UNLIKELY (count > 10) { // remove first token. Too many, dear app. @@ -68,7 +67,7 @@ void CXDGActivationProtocol::bindManager(wl_client* client, void* data, uint32_t RESOURCE->setDestroy([this](CXdgActivationV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); RESOURCE->setGetActivationToken([this](CXdgActivationV1* pMgr, uint32_t id) { this->onGetToken(pMgr, id); }); RESOURCE->setActivate([this](CXdgActivationV1* pMgr, const char* token, wl_resource* surface) { - auto TOKEN = std::find_if(m_sentTokens.begin(), m_sentTokens.end(), [token](const auto& t) { return t.token == token; }); + auto TOKEN = std::ranges::find_if(m_sentTokens, [token](const auto& t) { return t.token == token; }); if UNLIKELY (TOKEN == m_sentTokens.end()) { LOGM(WARN, "activate event for non-existent token {}??", token); diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index d3d5c18e..5351e267 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -258,7 +258,7 @@ uint32_t CXDGToplevelResource::setSize(const Vector2D& size) { } uint32_t CXDGToplevelResource::setMaximized(bool maximized) { - bool set = std::find(m_pendingApply.states.begin(), m_pendingApply.states.end(), XDG_TOPLEVEL_STATE_MAXIMIZED) != m_pendingApply.states.end(); + bool set = std::ranges::find(m_pendingApply.states, XDG_TOPLEVEL_STATE_MAXIMIZED) != m_pendingApply.states.end(); if (maximized == set) return m_owner->m_scheduledSerial; @@ -272,7 +272,7 @@ uint32_t CXDGToplevelResource::setMaximized(bool maximized) { } uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) { - bool set = std::find(m_pendingApply.states.begin(), m_pendingApply.states.end(), XDG_TOPLEVEL_STATE_FULLSCREEN) != m_pendingApply.states.end(); + bool set = std::ranges::find(m_pendingApply.states, XDG_TOPLEVEL_STATE_FULLSCREEN) != m_pendingApply.states.end(); if (fullscreen == set) return m_owner->m_scheduledSerial; @@ -286,7 +286,7 @@ uint32_t CXDGToplevelResource::setFullscreen(bool fullscreen) { } uint32_t CXDGToplevelResource::setActive(bool active) { - bool set = std::find(m_pendingApply.states.begin(), m_pendingApply.states.end(), XDG_TOPLEVEL_STATE_ACTIVATED) != m_pendingApply.states.end(); + bool set = std::ranges::find(m_pendingApply.states, XDG_TOPLEVEL_STATE_ACTIVATED) != m_pendingApply.states.end(); if (active == set) return m_owner->m_scheduledSerial; @@ -303,7 +303,7 @@ uint32_t CXDGToplevelResource::setSuspeneded(bool sus) { if (m_resource->version() < 6) return m_owner->scheduleConfigure(); // SUSPENDED is since 6 - bool set = std::find(m_pendingApply.states.begin(), m_pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != m_pendingApply.states.end(); + bool set = std::ranges::find(m_pendingApply.states, XDG_TOPLEVEL_STATE_SUSPENDED) != m_pendingApply.states.end(); if (sus == set) return m_owner->m_scheduledSerial; diff --git a/src/protocols/XXColorManagement.cpp b/src/protocols/XXColorManagement.cpp index 5a345f40..23b033a0 100644 --- a/src/protocols/XXColorManagement.cpp +++ b/src/protocols/XXColorManagement.cpp @@ -237,8 +237,8 @@ CXXColorManagementSurface::CXXColorManagementSurface(SPm_imageDescriptions.begin(), PROTO::xxColorManagement->m_imageDescriptions.end(), - [&](const auto& other) { return other->resource()->resource() == image_description; }); + const auto imageDescription = + std::ranges::find_if(PROTO::xxColorManagement->m_imageDescriptions, [&](const auto& other) { return other->resource()->resource() == image_description; }); if (imageDescription == PROTO::xxColorManagement->m_imageDescriptions.end()) { r->error(XX_COLOR_MANAGEMENT_SURFACE_V4_ERROR_IMAGE_DESCRIPTION, "Image description not found"); return; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 07bad77b..d1efe2e8 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -268,7 +268,7 @@ wl_client* CWLSurfaceResource::client() { } void CWLSurfaceResource::enter(PHLMONITOR monitor) { - if (std::find(m_enteredOutputs.begin(), m_enteredOutputs.end(), monitor) != m_enteredOutputs.end()) + if (std::ranges::find(m_enteredOutputs, monitor) != m_enteredOutputs.end()) return; if UNLIKELY (!PROTO::outputs.contains(monitor->m_name)) { @@ -295,7 +295,7 @@ void CWLSurfaceResource::enter(PHLMONITOR monitor) { } void CWLSurfaceResource::leave(PHLMONITOR monitor) { - if UNLIKELY (std::find(m_enteredOutputs.begin(), m_enteredOutputs.end(), monitor) == m_enteredOutputs.end()) + if UNLIKELY (std::ranges::find(m_enteredOutputs, monitor) == m_enteredOutputs.end()) return; auto output = PROTO::outputs.at(monitor->m_name)->outputResourceFrom(m_client); diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index ad580ed1..ec075e8b 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -171,7 +171,7 @@ void CWLDataSourceResource::accepted(const std::string& mime) { return; } - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) { + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAccepted with non-existent mime"); return; } @@ -184,7 +184,7 @@ std::vector CWLDataSourceResource::mimes() { } void CWLDataSourceResource::send(const std::string& mime, CFileDescriptor fd) { - if (std::find(m_mimeTypes.begin(), m_mimeTypes.end(), mime) == m_mimeTypes.end()) { + if (std::ranges::find(m_mimeTypes, mime) == m_mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); return; } @@ -424,7 +424,7 @@ SP CWLDataDeviceProtocol::dataDeviceForClient(wl_client* c) { return g_pXWayland->m_wm->getDataDevice(); #endif - auto it = std::find_if(m_devices.begin(), m_devices.end(), [c](const auto& e) { return e->client() == c; }); + auto it = std::ranges::find_if(m_devices, [c](const auto& e) { return e->client() == c; }); if (it == m_devices.end()) return nullptr; return *it; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index bc224043..c341f95a 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -204,10 +204,10 @@ void CWLPointerResource::sendButton(uint32_t timeMs, uint32_t button, wl_pointer if (!(PROTO::seat->m_currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_POINTER)) return; - if (state == WL_POINTER_BUTTON_STATE_RELEASED && std::find(m_pressedButtons.begin(), m_pressedButtons.end(), button) == m_pressedButtons.end()) { + if (state == WL_POINTER_BUTTON_STATE_RELEASED && std::ranges::find(m_pressedButtons, button) == m_pressedButtons.end()) { LOGM(ERR, "sendButton release on a non-pressed button"); return; - } else if (state == WL_POINTER_BUTTON_STATE_PRESSED && std::find(m_pressedButtons.begin(), m_pressedButtons.end(), button) != m_pressedButtons.end()) { + } else if (state == WL_POINTER_BUTTON_STATE_PRESSED && std::ranges::find(m_pressedButtons, button) != m_pressedButtons.end()) { LOGM(ERR, "sendButton press on a non-pressed button"); return; } diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 228884b9..8d610fe0 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -137,7 +137,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, CFileDescriptor return; } - if UNLIKELY (std::find(PROTO::shm->m_shmFormats.begin(), PROTO::shm->m_shmFormats.end(), fmt) == PROTO::shm->m_shmFormats.end()) { + if UNLIKELY (std::ranges::find(PROTO::shm->m_shmFormats, fmt) == PROTO::shm->m_shmFormats.end()) { r->error(WL_SHM_ERROR_INVALID_FORMAT, "Format invalid"); return; } diff --git a/src/protocols/core/Subcompositor.cpp b/src/protocols/core/Subcompositor.cpp index 4111b5dc..85a0edc4 100644 --- a/src/protocols/core/Subcompositor.cpp +++ b/src/protocols/core/Subcompositor.cpp @@ -30,7 +30,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPm_subsurfaces, [this](const auto& e) { return e == m_self || !e; }); - auto it = std::find(m_parent->m_subsurfaces.begin(), m_parent->m_subsurfaces.end(), SURF); + auto it = std::ranges::find(m_parent->m_subsurfaces, SURF); if (it == m_parent->m_subsurfaces.end()) { LOGM(ERR, "Invalid surface reference in placeAbove, likely parent"); @@ -43,7 +43,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPm_subsurfaces.emplace_back(m_self); } - std::sort(m_parent->m_subsurfaces.begin(), m_parent->m_subsurfaces.end(), [](const auto& a, const auto& b) { return a->m_zIndex < b->m_zIndex; }); + std::ranges::sort(m_parent->m_subsurfaces, [](const auto& a, const auto& b) { return a->m_zIndex < b->m_zIndex; }); }); m_resource->setPlaceBelow([this](CWlSubsurface* r, wl_resource* surf) { @@ -61,7 +61,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPm_subsurfaces, [this](const auto& e) { return e == m_self || !e; }); - auto it = std::find(m_parent->m_subsurfaces.begin(), m_parent->m_subsurfaces.end(), SURF); + auto it = std::ranges::find(m_parent->m_subsurfaces, SURF); if (it == m_parent->m_subsurfaces.end()) { LOGM(ERR, "Invalid surface reference in placeBelow, likely parent"); @@ -74,7 +74,7 @@ CWLSubsurfaceResource::CWLSubsurfaceResource(SP resource_, SPm_subsurfaces.emplace_back(m_self); } - std::sort(m_parent->m_subsurfaces.begin(), m_parent->m_subsurfaces.end(), [](const auto& a, const auto& b) { return a->m_zIndex < b->m_zIndex; }); + std::ranges::sort(m_parent->m_subsurfaces, [](const auto& a, const auto& b) { return a->m_zIndex < b->m_zIndex; }); }); m_listeners.commitSurface = m_surface->m_events.commit.registerListener([this](std::any d) { @@ -116,8 +116,7 @@ Vector2D CWLSubsurfaceResource::posRelativeToParent() { // surfaces we've visited and if we hit a surface we've visited we bail out. std::vector> surfacesVisited; - while (surf->m_role->role() == SURFACE_ROLE_SUBSURFACE && - std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + while (surf->m_role->role() == SURFACE_ROLE_SUBSURFACE && std::ranges::find_if(surfacesVisited, [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { surfacesVisited.emplace_back(surf); auto subsurface = ((CSubsurfaceRole*)m_parent->m_role.get())->m_subsurface.lock(); pos += subsurface->m_position; @@ -134,8 +133,7 @@ SP CWLSubsurfaceResource::t1Parent() { SP surf = m_parent.lock(); std::vector> surfacesVisited; - while (surf->m_role->role() == SURFACE_ROLE_SUBSURFACE && - std::find_if(surfacesVisited.begin(), surfacesVisited.end(), [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { + while (surf->m_role->role() == SURFACE_ROLE_SUBSURFACE && std::ranges::find_if(surfacesVisited, [surf](const auto& other) { return surf == other; }) == surfacesVisited.end()) { surfacesVisited.emplace_back(surf); auto subsurface = ((CSubsurfaceRole*)m_parent->m_role.get())->m_subsurface.lock(); surf = subsurface->m_parent.lock(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 855da879..89d769b3 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -255,7 +255,7 @@ EGLDeviceEXT CHyprOpenGLImpl::eglDeviceFromDRMFD(int drmFD) { CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmFD) { const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); - Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS); + Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::ranges::count(EGLEXTENSIONS, ' '), EGLEXTENSIONS); m_exts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference"); @@ -331,7 +331,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_drmFD(g_pCompositor->m_drmFD) { Debug::log(LOG, "Using: {}", (char*)glGetString(GL_VERSION)); Debug::log(LOG, "Vendor: {}", (char*)glGetString(GL_VENDOR)); Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER)); - Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_extensions.begin(), m_extensions.end(), ' '), m_extensions); + Debug::log(LOG, "Supported extensions: ({}) {}", std::ranges::count(m_extensions, ' '), m_extensions); m_exts.EXT_read_format_bgra = m_extensions.contains("GL_EXT_read_format_bgra"); @@ -415,7 +415,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo } // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) - if (!linearIsExternal && std::find(mods.begin(), mods.end(), DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) + if (!linearIsExternal && std::ranges::find(mods, DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) mods.push_back(DRM_FORMAT_MOD_LINEAR); return result; @@ -490,7 +490,7 @@ void CHyprOpenGLImpl::initDRMFormats() { free(fmtName); mods.clear(); - std::sort(modifierData.begin(), modifierData.end(), [](const auto& a, const auto& b) { + std::ranges::sort(modifierData, [](const auto& a, const auto& b) { if (a.first == 0) return false; if (a.second.contains("DCC")) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 982e2ed8..28f078aa 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -59,7 +59,7 @@ CHyprRenderer::CHyprRenderer() { if (!DRMV) continue; std::string name = std::string{DRMV->name, DRMV->name_len}; - std::transform(name.begin(), name.end(), name.begin(), tolower); + std::ranges::transform(name, name.begin(), tolower); if (name.contains("nvidia")) m_nvidia = true; @@ -76,7 +76,7 @@ CHyprRenderer::CHyprRenderer() { if (DRMV) { std::string name = std::string{DRMV->name, DRMV->name_len}; - std::transform(name.begin(), name.end(), name.begin(), tolower); + std::ranges::transform(name, name.begin(), tolower); if (name.contains("nvidia")) m_nvidia = true; @@ -1794,7 +1794,7 @@ void CHyprRenderer::arrangeLayersForMonitor(const MONITORID& monitor) { } for (auto& la : PMONITOR->m_layerSurfaceLayers) { - std::stable_sort(la.begin(), la.end(), [](const PHLLSREF& a, const PHLLSREF& b) { return a->m_order > b->m_order; }); + std::ranges::stable_sort(la, [](const PHLLSREF& a, const PHLLSREF& b) { return a->m_order > b->m_order; }); } for (auto const& la : PMONITOR->m_layerSurfaceLayers) @@ -2171,7 +2171,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(PHLMONITOR pMonitor) { } SP CHyprRenderer::getOrCreateRenderbuffer(SP buffer, uint32_t fmt) { - auto it = std::find_if(m_renderbuffers.begin(), m_renderbuffers.end(), [&](const auto& other) { return other->m_hlBuffer == buffer; }); + auto it = std::ranges::find_if(m_renderbuffers, [&](const auto& other) { return other->m_hlBuffer == buffer; }); if (it != m_renderbuffers.end()) return *it; @@ -2364,7 +2364,7 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings(SP("misc:render_unfocused_fps"); - if (std::find(m_renderUnfocused.begin(), m_renderUnfocused.end(), window) != m_renderUnfocused.end()) + if (std::ranges::find(m_renderUnfocused, window) != m_renderUnfocused.end()) return; m_renderUnfocused.emplace_back(window); diff --git a/src/render/decorations/DecorationPositioner.cpp b/src/render/decorations/DecorationPositioner.cpp index 82f2e5a8..178f3b9b 100644 --- a/src/render/decorations/DecorationPositioner.cpp +++ b/src/render/decorations/DecorationPositioner.cpp @@ -59,7 +59,7 @@ Vector2D CDecorationPositioner::getEdgeDefinedPoint(uint32_t edges, PHLWINDOW pW void CDecorationPositioner::uncacheDecoration(IHyprWindowDecoration* deco) { std::erase_if(m_windowPositioningDatas, [&](const auto& data) { return !data->pWindow.lock() || data->pDecoration == deco; }); - const auto WIT = std::find_if(m_windowDatas.begin(), m_windowDatas.end(), [&](const auto& other) { return other.first.lock() == deco->m_window.lock(); }); + const auto WIT = std::ranges::find_if(m_windowDatas, [&](const auto& other) { return other.first.lock() == deco->m_window.lock(); }); if (WIT == m_windowDatas.end()) return; @@ -72,7 +72,7 @@ void CDecorationPositioner::repositionDeco(IHyprWindowDecoration* deco) { } CDecorationPositioner::SWindowPositioningData* CDecorationPositioner::getDataFor(IHyprWindowDecoration* pDecoration, PHLWINDOW pWindow) { - auto it = std::find_if(m_windowPositioningDatas.begin(), m_windowPositioningDatas.end(), [&](const auto& el) { return el->pDecoration == pDecoration; }); + auto it = std::ranges::find_if(m_windowPositioningDatas, [&](const auto& el) { return el->pDecoration == pDecoration; }); if (it != m_windowPositioningDatas.end()) return it->get(); @@ -89,15 +89,14 @@ void CDecorationPositioner::sanitizeDatas() { std::erase_if(m_windowPositioningDatas, [](const auto& other) { if (!validMapped(other->pWindow)) return true; - if (std::find_if(other->pWindow->m_windowDecorations.begin(), other->pWindow->m_windowDecorations.end(), [&](const auto& el) { return el.get() == other->pDecoration; }) == - other->pWindow->m_windowDecorations.end()) + if (std::ranges::find_if(other->pWindow->m_windowDecorations, [&](const auto& el) { return el.get() == other->pDecoration; }) == other->pWindow->m_windowDecorations.end()) return true; return false; }); } void CDecorationPositioner::forceRecalcFor(PHLWINDOW pWindow) { - const auto WIT = std::find_if(m_windowDatas.begin(), m_windowDatas.end(), [&](const auto& other) { return other.first.lock() == pWindow; }); + const auto WIT = std::ranges::find_if(m_windowDatas, [&](const auto& other) { return other.first.lock() == pWindow; }); if (WIT == m_windowDatas.end()) return; @@ -110,7 +109,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { if (!validMapped(pWindow)) return; - const auto WIT = std::find_if(m_windowDatas.begin(), m_windowDatas.end(), [&](const auto& other) { return other.first.lock() == pWindow; }); + const auto WIT = std::ranges::find_if(m_windowDatas, [&](const auto& other) { return other.first.lock() == pWindow; }); if (WIT == m_windowDatas.end()) return; @@ -128,8 +127,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { } if (WINDOWDATA->lastWindowSize == pWindow->m_realSize->value() /* position not changed */ - && std::all_of(m_windowPositioningDatas.begin(), m_windowPositioningDatas.end(), - [pWindow](const auto& data) { return pWindow != data->pWindow.lock() || !data->needsReposition; }) + && std::ranges::all_of(m_windowPositioningDatas, [pWindow](const auto& data) { return pWindow != data->pWindow.lock() || !data->needsReposition; }) /* all window datas are either not for this window or don't need a reposition */ && !WINDOWDATA->needsRecalc /* window doesn't need recalc */ ) @@ -143,7 +141,7 @@ void CDecorationPositioner::onWindowUpdate(PHLWINDOW pWindow) { WINDOWDATA->needsRecalc = false; const bool EPHEMERAL = pWindow->m_realSize->isBeingAnimated(); - std::sort(datas.begin(), datas.end(), [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; }); + std::ranges::sort(datas, [](const auto& a, const auto& b) { return a->positioningInfo.priority > b->positioningInfo.priority; }); CBox wb = pWindow->getWindowMainSurfaceBox(); diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 5877d9a9..32296ad7 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -259,7 +259,7 @@ void CRenderPass::renderDebugData() { } } - const auto DISCARDED_ELEMENTS = std::count_if(m_passElements.begin(), m_passElements.end(), [](const auto& e) { return e->discard; }); + const auto DISCARDED_ELEMENTS = std::ranges::count_if(m_passElements, [](const auto& e) { return e->discard; }); auto tex = g_pHyprOpenGL->renderText(std::format("occlusion layers: {}\npass elements: {} ({} discarded)\nviewport: {:X0}", m_occludedRegions.size(), m_passElements.size(), DISCARDED_ELEMENTS, g_pHyprOpenGL->m_renderData.pMonitor->m_pixelSize), Colors::WHITE, 12); diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 949649ae..71e710b3 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -214,7 +214,7 @@ void CXWaylandSurface::restackToTop() { xcb_configure_window(g_pXWayland->m_wm->m_connection, m_xID, XCB_CONFIG_WINDOW_STACK_MODE, values); auto& stack = g_pXWayland->m_wm->m_mappedSurfacesStacking; - auto it = std::find(stack.begin(), stack.end(), m_self); + auto it = std::ranges::find(stack, m_self); if (it != stack.end()) std::rotate(it, it + 1, stack.end()); diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 8e4f9a87..76ae1d88 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -164,7 +164,7 @@ static bool lookupParentExists(SP XSURF, SP XSURF = XSURF->m_parent.lock(); - if (std::find(visited.begin(), visited.end(), XSURF) != visited.end()) + if (std::ranges::find(visited, XSURF) != visited.end()) return false; } @@ -202,7 +202,7 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ size_t len = xcb_get_property_value_length(reply); char* string = (char*)xcb_get_property_value(reply); XSURF->m_state.appid = std::string{string, len}; - if (std::count(XSURF->m_state.appid.begin(), XSURF->m_state.appid.end(), '\000') == 2) + if (std::ranges::count(XSURF->m_state.appid, '\000') == 2) XSURF->m_state.appid = XSURF->m_state.appid.substr(XSURF->m_state.appid.find_first_of('\000') + 1); // fuck you X if (!XSURF->m_state.appid.empty()) XSURF->m_state.appid.pop_back(); @@ -1109,7 +1109,7 @@ void CXWM::associate(SP surf, SP wlSurf) { if (surf->m_surface) return; - auto existing = std::find_if(m_surfaces.begin(), m_surfaces.end(), [wlSurf](const auto& e) { return e->m_surface == wlSurf; }); + auto existing = std::ranges::find_if(m_surfaces, [wlSurf](const auto& e) { return e->m_surface == wlSurf; }); if (existing != m_surfaces.end()) { Debug::log(WARN, "[xwm] associate() called but surface is already associated to {:x}, ignoring...", (uintptr_t)surf.get()); @@ -1420,7 +1420,7 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { if (MIMES.empty()) return false; - if (std::find(MIMES.begin(), MIMES.end(), mime) == MIMES.end()) { + if (std::ranges::find(MIMES, mime) == MIMES.end()) { Debug::log(ERR, "[xwm] X Client asked for an invalid MIME, sending the first advertised. THIS SHIT MAY BREAK!"); mime = *MIMES.begin(); } From af2fdb5d58f5d3017aafd78a8ddafb40f710e34b Mon Sep 17 00:00:00 2001 From: mitsuru Date: Fri, 30 May 2025 22:40:12 +0100 Subject: [PATCH 1544/2393] nix: use gcc15 resolves Nix build/CI failures introduced in 9190443 bumps flake.lock as gcc15Stdenv wasn't available at the pinned version of nixpkgs --- flake.lock | 6 +++--- nix/overlays.nix | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 22f246d5..01b437e6 100644 --- a/flake.lock +++ b/flake.lock @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748026106, - "narHash": "sha256-6m1Y3/4pVw1RWTsrkAK2VMYSzG4MMIj7sqUy7o8th1o=", + "lastModified": 1748460289, + "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "063f43f2dbdef86376cc29ad646c45c46e93234c", + "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", "type": "github" }, "original": { diff --git a/nix/overlays.nix b/nix/overlays.nix index 6085bf80..ee020eaa 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -35,7 +35,7 @@ in { date = mkDate (self.lastModifiedDate or "19700101"); in { hyprland = final.callPackage ./default.nix { - stdenv = final.gcc14Stdenv; + stdenv = final.gcc15Stdenv; version = "${version}+date=${date}_${self.shortRev or "dirty"}"; commit = self.rev or ""; revCount = self.sourceInfo.revCount or ""; From 4078e1d17c0fb1439ee5a0ba1e539f06a8f47aab Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Sat, 31 May 2025 18:02:02 +0500 Subject: [PATCH 1545/2393] refactor: replace all `typedef` with `using` (#10594) --- src/SharedDefs.hpp | 8 ++++---- src/desktop/DesktopTypes.hpp | 16 ++++++++-------- src/helpers/Format.hpp | 6 +++--- src/layout/IHyprLayout.cpp | 2 +- src/managers/HookSystemManager.hpp | 4 ++-- src/managers/XWaylandManager.hpp | 2 +- src/plugins/PluginAPI.hpp | 10 +++++----- src/protocols/types/ColorManagement.hpp | 2 +- src/xwayland/XSurface.hpp | 12 ++++++------ 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/SharedDefs.hpp b/src/SharedDefs.hpp index a46a2429..b8094997 100644 --- a/src/SharedDefs.hpp +++ b/src/SharedDefs.hpp @@ -58,8 +58,8 @@ struct SDispatchResult { std::string error; }; -typedef int64_t WINDOWID; -typedef int64_t MONITORID; -typedef int64_t WORKSPACEID; +using WINDOWID = int64_t; +using MONITORID = int64_t; +using WORKSPACEID = int64_t; -typedef std::function HOOK_CALLBACK_FN; +using HOOK_CALLBACK_FN = std::function; diff --git a/src/desktop/DesktopTypes.hpp b/src/desktop/DesktopTypes.hpp index 080f13d3..f724c7b9 100644 --- a/src/desktop/DesktopTypes.hpp +++ b/src/desktop/DesktopTypes.hpp @@ -6,21 +6,21 @@ class CLayerSurface; class CMonitor; /* Shared pointer to a workspace */ -typedef SP PHLWORKSPACE; +using PHLWORKSPACE = SP; /* Weak pointer to a workspace */ -typedef WP PHLWORKSPACEREF; +using PHLWORKSPACEREF = WP; /* Shared pointer to a window */ -typedef SP PHLWINDOW; +using PHLWINDOW = SP; /* Weak pointer to a window */ -typedef WP PHLWINDOWREF; +using PHLWINDOWREF = WP; /* Shared pointer to a layer surface */ -typedef SP PHLLS; +using PHLLS = SP; /* Weak pointer to a layer surface */ -typedef WP PHLLSREF; +using PHLLSREF = WP; /* Shared pointer to a monitor */ -typedef SP PHLMONITOR; +using PHLMONITOR = SP; /* Weak pointer to a monitor */ -typedef WP PHLMONITORREF; +using PHLMONITORREF = WP; diff --git a/src/helpers/Format.hpp b/src/helpers/Format.hpp index b1353dc7..fe68f763 100644 --- a/src/helpers/Format.hpp +++ b/src/helpers/Format.hpp @@ -5,8 +5,8 @@ #include "math/Math.hpp" #include -typedef uint32_t DRMFormat; -typedef uint32_t SHMFormat; +using DRMFormat = uint32_t; +using SHMFormat = uint32_t; struct SPixelFormat { DRMFormat drmFormat = 0; /* DRM_FORMAT_INVALID */ @@ -20,7 +20,7 @@ struct SPixelFormat { Vector2D blockSize; }; -typedef Aquamarine::SDRMFormat SDRMFormat; +using SDRMFormat = Aquamarine::SDRMFormat; namespace NFormatUtils { SHMFormat drmToShm(DRMFormat drm); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 1fe3a936..fbde7344 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -411,7 +411,7 @@ static void snapResize(double& start, double& end, const double P) { start = P; } -typedef std::function SnapFn; +using SnapFn = std::function; static void performSnap(Vector2D& sourcePos, Vector2D& sourceSize, PHLWINDOW DRAGGINGWINDOW, const eMouseBindMode MODE, const int CORNER, const Vector2D& BEGINSIZE) { static auto SNAPWINDOWGAP = CConfigValue("general:snap:window_gap"); diff --git a/src/managers/HookSystemManager.hpp b/src/managers/HookSystemManager.hpp index 69d54a60..647e9670 100644 --- a/src/managers/HookSystemManager.hpp +++ b/src/managers/HookSystemManager.hpp @@ -11,9 +11,9 @@ #define HANDLE void* -// global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally. +// global type alias for hooked functions. Passes itself as a ptr when called, and `data` additionally. -typedef std::function HOOK_CALLBACK_FN; +using HOOK_CALLBACK_FN = std::function; struct SCallbackFNPtr { WP fn; diff --git a/src/managers/XWaylandManager.hpp b/src/managers/XWaylandManager.hpp index e4f1e17a..59eee4c5 100644 --- a/src/managers/XWaylandManager.hpp +++ b/src/managers/XWaylandManager.hpp @@ -4,7 +4,7 @@ #include class CWindow; // because clangd -typedef SP PHLWINDOW; +using PHLWINDOW = SP; class CWLSurfaceResource; class CHyprXWaylandManager { diff --git a/src/plugins/PluginAPI.hpp b/src/plugins/PluginAPI.hpp index 0f333294..00a1e8b2 100644 --- a/src/plugins/PluginAPI.hpp +++ b/src/plugins/PluginAPI.hpp @@ -31,12 +31,12 @@ Feel like the API is missing something you'd like to use in your plugin? Open an #include #include -typedef struct { +using PLUGIN_DESCRIPTION_INFO = struct { std::string name; std::string description; std::string author; std::string version; -} PLUGIN_DESCRIPTION_INFO; +}; struct SFunctionMatch { void* address = nullptr; @@ -83,7 +83,7 @@ class CWindow; This function should not be modified, see the example plugin. */ -typedef REQUIRED std::string (*PPLUGIN_API_VERSION_FUNC)(); +using PPLUGIN_API_VERSION_FUNC = REQUIRED std::string (*)(); #define PLUGIN_API_VERSION pluginAPIVersion #define PLUGIN_API_VERSION_FUNC_STR "pluginAPIVersion" @@ -93,7 +93,7 @@ typedef REQUIRED std::string (*PPLUGIN_API_VERSION_FUNC)(); Keep in mind this is executed synchronously, and as such any blocking calls to hyprland might hang. (e.g. system("hyprctl ...")) */ -typedef REQUIRED PLUGIN_DESCRIPTION_INFO (*PPLUGIN_INIT_FUNC)(HANDLE); +using PPLUGIN_INIT_FUNC = REQUIRED PLUGIN_DESCRIPTION_INFO (*)(HANDLE); #define PLUGIN_INIT pluginInit #define PLUGIN_INIT_FUNC_STR "pluginInit" @@ -103,7 +103,7 @@ typedef REQUIRED PLUGIN_DESCRIPTION_INFO (*PPLUGIN_INIT_FUNC)(HANDLE); Hooks are unloaded after exit. */ -typedef OPTIONAL void (*PPLUGIN_EXIT_FUNC)(); +using PPLUGIN_EXIT_FUNC = OPTIONAL void (*)(); #define PLUGIN_EXIT pluginExit #define PLUGIN_EXIT_FUNC_STR "pluginExit" diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp index 48d8dd31..2dd1c075 100644 --- a/src/protocols/types/ColorManagement.hpp +++ b/src/protocols/types/ColorManagement.hpp @@ -54,7 +54,7 @@ namespace NColorManagement { return (eTransferFunction)tf; } - typedef Hyprgraphics::SPCPRimaries SPCPRimaries; + using SPCPRimaries = Hyprgraphics::SPCPRimaries; namespace NColorPrimaries { static const auto DEFAULT_PRIMARIES = SPCPRimaries{}; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index dc43acbb..ec71aad3 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -9,9 +9,9 @@ class CWLSurfaceResource; class CXWaylandSurfaceResource; #ifdef NO_XWAYLAND -typedef uint32_t xcb_pixmap_t; -typedef uint32_t xcb_window_t; -typedef struct { +using xcb_pixmap_t = uint32_t; +using xcb_window_t = uint32_t; +using xcb_icccm_wm_hints_t = struct { int32_t flags; uint32_t input; int32_t initial_state; @@ -20,8 +20,8 @@ typedef struct { int32_t icon_x, icon_y; xcb_pixmap_t icon_mask; xcb_window_t window_group; -} xcb_icccm_wm_hints_t; -typedef struct { +}; +using xcb_size_hints_t = struct { uint32_t flags; int32_t x, y; int32_t width, height; @@ -32,7 +32,7 @@ typedef struct { int32_t max_aspect_num, max_aspect_den; int32_t base_width, base_height; uint32_t win_gravity; -} xcb_size_hints_t; +}; #else #include #endif From 69c2b2926e128f1fd09080aed43944987a42026f Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Sat, 31 May 2025 23:49:50 +0500 Subject: [PATCH 1546/2393] internal: refactor to use empty() (#10599) --- src/config/ConfigManager.cpp | 22 +++++++++---------- src/debug/HyprCtl.cpp | 8 +++---- src/debug/HyprDebugOverlay.cpp | 8 +++---- src/debug/HyprNotificationOverlay.cpp | 4 ++-- src/desktop/Window.cpp | 4 ++-- src/events/Windows.cpp | 4 ++-- src/helpers/MiscFunctions.cpp | 2 +- src/helpers/Monitor.cpp | 2 +- src/hyprerror/HyprError.cpp | 4 ++-- src/layout/MasterLayout.cpp | 2 +- src/managers/AnimationManager.cpp | 4 ++-- src/managers/CursorManager.cpp | 8 +++---- src/managers/KeybindManager.cpp | 10 ++++----- src/managers/ProtocolManager.cpp | 2 +- src/managers/SeatManager.cpp | 2 +- src/managers/input/InputManager.cpp | 10 ++++----- src/plugins/HookSystem.cpp | 2 +- src/render/OpenGL.cpp | 12 +++++----- src/render/Renderer.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 2 +- 20 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3ab53a3c..f7fed52f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -100,7 +100,7 @@ static Hyprlang::CParseResult configHandleGradientSet(const char* VALUE, void** } } - if (DATA->m_colors.size() == 0) { + if (DATA->m_colors.empty()) { Debug::log(WARN, "Error parsing gradient {}", V); if (parseError.empty()) parseError = "Error parsing gradient " + V + ": No colors?"; @@ -2093,7 +2093,7 @@ std::optional CConfigManager::handleMonitor(const std::string& comm int argno = 4; - while (ARGS[argno] != "") { + while (!ARGS[argno].empty()) { if (ARGS[argno] == "mirror") { newrule.mirrorOf = ARGS[argno + 1]; argno++; @@ -2185,23 +2185,23 @@ std::optional CConfigManager::handleBezier(const std::string& comma std::string bezierName = ARGS[0]; - if (ARGS[1] == "") + if (ARGS[1].empty()) return "too few arguments"; float p1x = std::stof(ARGS[1]); - if (ARGS[2] == "") + if (ARGS[2].empty()) return "too few arguments"; float p1y = std::stof(ARGS[2]); - if (ARGS[3] == "") + if (ARGS[3].empty()) return "too few arguments"; float p2x = std::stof(ARGS[3]); - if (ARGS[4] == "") + if (ARGS[4].empty()) return "too few arguments"; float p2y = std::stof(ARGS[4]); - if (ARGS[5] != "") + if (!ARGS[5].empty()) return "too many arguments"; g_pAnimationManager->addBezierWithName(bezierName, Vector2D(p1x, p1y), Vector2D(p2x, p2y)); @@ -2256,10 +2256,10 @@ std::optional CConfigManager::handleAnimation(const std::string& co return "no such bezier"; } - if (ARGS[4] != "") { + if (!ARGS[4].empty()) { auto ERR = g_pAnimationManager->styleValidInConfigVar(ANIMNAME, ARGS[4]); - if (ERR != "") + if (!ERR.empty()) return ERR; } @@ -2384,12 +2384,12 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid dispatcher, requested \"" + HANDLER + "\" does not exist"; } - if (MOD == 0 && MODSTR != "") { + if (MOD == 0 && !MODSTR.empty()) { Debug::log(ERR, "Invalid mod: {}", MODSTR); return "Invalid mod, requested mod \"" + MODSTR + "\" is not a valid mod."; } - if ((KEY != "") || multiKey) { + if ((!KEY.empty()) || multiKey) { SParsedKey parsedKey = parseKey(KEY); if (parsedKey.catchAll && m_currentSubmap.empty()) { diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index c8cc5c59..77f54c2b 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -516,7 +516,7 @@ static std::string layersRequest(eHyprCtlOutputFormat format, std::string reques trimTrailingComma(result); - if (level.size() > 0) + if (!level.empty()) result += "\n "; result += "],"; @@ -1144,7 +1144,7 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) Debug::log(LOG, "Hyprctl: keyword {} : {}", COMMAND, VALUE); - if (retval == "") + if (retval.empty()) return "ok"; return retval; @@ -1528,7 +1528,7 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "["; - if (PLUGINS.size() == 0) + if (PLUGINS.empty()) return "[]"; for (auto const& p : PLUGINS) { @@ -1546,7 +1546,7 @@ static std::string dispatchPlugin(eHyprCtlOutputFormat format, std::string reque trimTrailingComma(result); result += "]"; } else { - if (PLUGINS.size() == 0) + if (PLUGINS.empty()) return "no plugins loaded"; for (auto const& p : PLUGINS) { diff --git a/src/debug/HyprDebugOverlay.cpp b/src/debug/HyprDebugOverlay.cpp index 332800dd..6c5d8000 100644 --- a/src/debug/HyprDebugOverlay.cpp +++ b/src/debug/HyprDebugOverlay.cpp @@ -83,7 +83,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { avgFrametime += ft; } float varFrametime = maxFrametime - minFrametime; - avgFrametime /= m_lastFrametimes.size() == 0 ? 1 : m_lastFrametimes.size(); + avgFrametime /= m_lastFrametimes.empty() ? 1 : m_lastFrametimes.size(); float avgRenderTime = 0; float maxRenderTime = 0; @@ -96,7 +96,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { avgRenderTime += rt; } float varRenderTime = maxRenderTime - minRenderTime; - avgRenderTime /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size(); + avgRenderTime /= m_lastRenderTimes.empty() ? 1 : m_lastRenderTimes.size(); float avgRenderTimeNoOverlay = 0; float maxRenderTimeNoOverlay = 0; @@ -109,7 +109,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { avgRenderTimeNoOverlay += rt; } float varRenderTimeNoOverlay = maxRenderTimeNoOverlay - minRenderTimeNoOverlay; - avgRenderTimeNoOverlay /= m_lastRenderTimes.size() == 0 ? 1 : m_lastRenderTimes.size(); + avgRenderTimeNoOverlay /= m_lastRenderTimes.empty() ? 1 : m_lastRenderTimes.size(); float avgAnimMgrTick = 0; float maxAnimMgrTick = 0; @@ -122,7 +122,7 @@ int CHyprMonitorDebugOverlay::draw(int offset) { avgAnimMgrTick += at; } float varAnimMgrTick = maxAnimMgrTick - minAnimMgrTick; - avgAnimMgrTick /= m_lastAnimationTicks.size() == 0 ? 1 : m_lastAnimationTicks.size(); + avgAnimMgrTick /= m_lastAnimationTicks.empty() ? 1 : m_lastAnimationTicks.size(); const float FPS = 1.f / (avgFrametime / 1000.f); // frametimes are in ms const float idealFPS = m_lastFrametimes.size(); diff --git a/src/debug/HyprNotificationOverlay.cpp b/src/debug/HyprNotificationOverlay.cpp index bfa5c4e4..c50abfe6 100644 --- a/src/debug/HyprNotificationOverlay.cpp +++ b/src/debug/HyprNotificationOverlay.cpp @@ -23,7 +23,7 @@ static inline auto iconBackendFromLayout(PangoLayout* layout) { CHyprNotificationOverlay::CHyprNotificationOverlay() { static auto P = g_pHookSystem->hookDynamic("focusedMon", [&](void* self, SCallbackInfo& info, std::any param) { - if (m_notifications.size() == 0) + if (m_notifications.empty()) return; g_pHyprRenderer->damageBox(m_lastDamage); @@ -210,7 +210,7 @@ void CHyprNotificationOverlay::draw(PHLMONITOR pMonitor) { } // Draw the notifications - if (m_notifications.size() == 0) + if (m_notifications.empty()) return; // Render to the monitor diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index cc3c9390..555b99f0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1624,13 +1624,13 @@ PHLWINDOW CWindow::getSwallower() { if (!(*PSWALLOWREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_class, *PSWALLOWREGEX); }); - if (candidates.size() == 0) + if (candidates.empty()) return nullptr; if (!(*PSWALLOWEXREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_title, *PSWALLOWEXREGEX); }); - if (candidates.size() == 0) + if (candidates.empty()) return nullptr; if (candidates.size() == 1) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index b019adff..da1e5263 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -418,8 +418,8 @@ void Events::listener_mapWindow(void* owner, void* data) { PWINDOW->m_swallowed->m_currentlySwallowed = true; // emit the IPC event before the layout might focus the window to avoid a focus event first - g_pEventManager->postEvent( - SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", PWINDOW, requestedWorkspace != "" ? requestedWorkspace : PWORKSPACE->m_name, PWINDOW->m_class, PWINDOW->m_title)}); + g_pEventManager->postEvent(SHyprIPCEvent{ + "openwindow", std::format("{:x},{},{},{}", PWINDOW, !requestedWorkspace.empty() ? requestedWorkspace : PWORKSPACE->m_name, PWINDOW->m_class, PWINDOW->m_title)}); if (PWINDOW->m_isFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index ddd16144..8069d414 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -326,7 +326,7 @@ SWorkspaceIDName getWorkspaceIDNameFromString(const std::string& in) { finalWSID = curID; } if (finalWSID <= 0 || invalidWSes.contains(finalWSID)) { - if (namedWSes.size()) { + if (!namedWSes.empty()) { // Go to the named workspaces // Need remainingWSes more auto namedWSIdx = namedWSes.size() - remainingWSes; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 5afd0123..b0b31526 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -988,7 +988,7 @@ void CMonitor::setupDefaultWS(const SMonitorRule& monitorRule) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(m_id); PNEWWORKSPACE->startAnim(true, true, true); } else { - if (newDefaultWorkspaceName == "") + if (newDefaultWorkspaceName.empty()) newDefaultWorkspaceName = std::to_string(wsID); PNEWWORKSPACE = g_pCompositor->m_workspaces.emplace_back(CWorkspace::create(wsID, m_self.lock(), newDefaultWorkspaceName)); diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 22744c93..b6080306 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -165,8 +165,8 @@ void CHyprError::createQueued() { } void CHyprError::draw() { - if (!m_isCreated || m_queued != "") { - if (m_queued != "") + if (!m_isCreated || !m_queued.empty()) { + if (!m_queued.empty()) createQueued(); return; } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index cb1313a8..abdf8032 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -1359,7 +1359,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi if (vars != nullptr) buildOrientationCycleVectorFromVars(cycle, *vars); - if (cycle.size() == 0) + if (cycle.empty()) buildOrientationCycleVectorFromEOperation(cycle); const auto PWINDOW = header.pWindow; diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f935d3dc..d1da1a36 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -306,7 +306,7 @@ void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, Vector2D posOffset; - if (force != "") { + if (!force.empty()) { if (force == "bottom") posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y + PMONITOR->m_size.y); else if (force == "left") @@ -490,7 +490,7 @@ std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& conf return ""; return "unknown style"; } else if (config.starts_with("layers")) { - if (style == "fade" || style == "" || style == "slide") + if (style.empty() || style == "fade" || style == "slide") return ""; else if (style.starts_with("popin")) { // try parsing diff --git a/src/managers/CursorManager.cpp b/src/managers/CursorManager.cpp index 9211fc20..cb46dd65 100644 --- a/src/managers/CursorManager.cpp +++ b/src/managers/CursorManager.cpp @@ -183,7 +183,7 @@ void CCursorManager::setCursorFromName(const std::string& name) { auto setHyprCursor = [this](auto const& name) { m_currentCursorShapeData = m_hyprcursor->getShape(name.c_str(), m_currentStyleInfo); - if (m_currentCursorShapeData.images.size() < 1) { + if (m_currentCursorShapeData.images.empty()) { // try with '_' first (old hc, etc) std::string newName = name; std::ranges::replace(newName, '-', '_'); @@ -191,18 +191,18 @@ void CCursorManager::setCursorFromName(const std::string& name) { m_currentCursorShapeData = m_hyprcursor->getShape(newName.c_str(), m_currentStyleInfo); } - if (m_currentCursorShapeData.images.size() < 1) { + if (m_currentCursorShapeData.images.empty()) { // fallback to a default if available constexpr const std::array fallbackShapes = {"default", "left_ptr", "left-ptr"}; for (auto const& s : fallbackShapes) { m_currentCursorShapeData = m_hyprcursor->getShape(s, m_currentStyleInfo); - if (m_currentCursorShapeData.images.size() > 0) + if (!m_currentCursorShapeData.images.empty()) break; } - if (m_currentCursorShapeData.images.size() < 1) { + if (m_currentCursorShapeData.images.empty()) { Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName"); return false; } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 58951281..976e292d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -164,7 +164,7 @@ CKeybindManager::CKeybindManager() { m_repeatKeyTimer = makeShared( std::nullopt, [this](SP self, void* data) { - if (m_activeKeybinds.size() == 0 || g_pSeatManager->m_keyboard.expired()) + if (m_activeKeybinds.empty() || g_pSeatManager->m_keyboard.expired()) return; const auto PACTIVEKEEB = g_pSeatManager->m_keyboard.lock(); @@ -288,7 +288,7 @@ void CKeybindManager::updateXKBTranslationState() { xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()}; const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - FILE* const KEYMAPFILE = FILEPATH == "" ? nullptr : fopen(absolutePath(FILEPATH, g_pConfigManager->m_configCurrentPath).c_str(), "r"); + FILE* const KEYMAPFILE = FILEPATH.empty() ? nullptr : fopen(absolutePath(FILEPATH, g_pConfigManager->m_configCurrentPath).c_str(), "r"); auto PKEYMAP = KEYMAPFILE ? xkb_keymap_new_from_file(PCONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS) : xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); @@ -630,7 +630,7 @@ eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set k if (boundKeysNotPressed.empty() && pressedKeysNotBound.empty()) return MK_FULL_MATCH; - if (boundKeysNotPressed.size() && pressedKeysNotBound.empty()) + if (!boundKeysNotPressed.empty() && pressedKeysNotBound.empty()) return MK_PARTIAL_MATCH; return MK_NO_MATCH; @@ -2398,7 +2398,7 @@ SDispatchResult CKeybindManager::toggleSwallow(std::string args) { } SDispatchResult CKeybindManager::setSubmap(std::string submap) { - if (submap == "reset" || submap == "") { + if (submap == "reset" || submap.empty()) { m_currentSelectedSubmap = ""; Debug::log(LOG, "Reset active submap to the default one."); g_pEventManager->postEvent(SHyprIPCEvent{"submap", ""}); @@ -2576,7 +2576,7 @@ SDispatchResult CKeybindManager::sendshortcut(std::string args) { //if regexp is not empty, send shortcut to current window //else, dont change focus - if (regexp != "") { + if (!regexp.empty()) { PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) { diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index ab542fc2..942e7954 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -209,7 +209,7 @@ CProtocolManager::CProtocolManager() { break; } - if (g_pHyprOpenGL->getDRMFormats().size() > 0) { + if (!g_pHyprOpenGL->getDRMFormats().empty()) { PROTO::mesaDRM = makeUnique(&wl_drm_interface, 2, "MesaDRM"); PROTO::linuxDma = makeUnique(&zwp_linux_dmabuf_v1_interface, 5, "LinuxDMABUF"); } else diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index a7660854..9fe2b26b 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -493,7 +493,7 @@ void CSeatManager::refocusGrab() { if (!m_seatGrab) return; - if (m_seatGrab->m_surfs.size() > 0) { + if (!m_seatGrab->m_surfs.empty()) { // try to find a surf in focus first const auto MOUSE = g_pInputManager->getMouseCoordsInternal(); for (auto const& s : m_seatGrab->m_surfs) { diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index cc0485d8..70f92023 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1082,7 +1082,7 @@ void CInputManager::applyConfigToKeyboard(SP pKeyboard) { pKeyboard->m_allowed = PERM == PERMISSION_RULE_ALLOW_MODE_ALLOW; try { - if (NUMLOCKON == pKeyboard->m_numlockOn && REPEATDELAY == pKeyboard->m_repeatDelay && REPEATRATE == pKeyboard->m_repeatRate && RULES != "" && + if (NUMLOCKON == pKeyboard->m_numlockOn && REPEATDELAY == pKeyboard->m_repeatDelay && REPEATRATE == pKeyboard->m_repeatRate && !RULES.empty() && RULES == pKeyboard->m_currentRules.rules && MODEL == pKeyboard->m_currentRules.model && LAYOUT == pKeyboard->m_currentRules.layout && VARIANT == pKeyboard->m_currentRules.variant && OPTIONS == pKeyboard->m_currentRules.options && FILEPATH == pKeyboard->m_xkbFilePath) { Debug::log(LOG, "Not applying config to keyboard, it did not change."); @@ -1205,7 +1205,7 @@ void CInputManager::setPointerConfigs() { libinput_device_config_middle_emulation_set_enabled(LIBINPUTDEV, LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); const auto TAP_MAP = g_pConfigManager->getDeviceString(devname, "tap_button_map", "input:touchpad:tap_button_map"); - if (TAP_MAP == "" || TAP_MAP == "lrm") + if (TAP_MAP.empty() || TAP_MAP == "lrm") libinput_device_config_tap_set_button_map(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_MAP_LRM); else if (TAP_MAP == "lmr") libinput_device_config_tap_set_button_map(LIBINPUTDEV, LIBINPUT_CONFIG_TAP_MAP_LMR); @@ -1214,7 +1214,7 @@ void CInputManager::setPointerConfigs() { } const auto SCROLLMETHOD = g_pConfigManager->getDeviceString(devname, "scroll_method", "input:scroll_method"); - if (SCROLLMETHOD == "") { + if (SCROLLMETHOD.empty()) { libinput_device_config_scroll_set_method(LIBINPUTDEV, libinput_device_config_scroll_get_default_method(LIBINPUTDEV)); } else if (SCROLLMETHOD == "no_scroll") { libinput_device_config_scroll_set_method(LIBINPUTDEV, LIBINPUT_CONFIG_SCROLL_NO_SCROLL); @@ -1330,7 +1330,7 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { std::erase_if(m_keyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); - if (m_keyboards.size() > 0) { + if (!m_keyboards.empty()) { bool found = false; for (auto const& k : m_keyboards | std::views::reverse) { if (!k) @@ -1354,7 +1354,7 @@ void CInputManager::destroyPointer(SP mouse) { std::erase_if(m_pointers, [mouse](const auto& other) { return other == mouse; }); - g_pSeatManager->setMouse(m_pointers.size() > 0 ? m_pointers.front() : nullptr); + g_pSeatManager->setMouse(!m_pointers.empty() ? m_pointers.front() : nullptr); if (!g_pSeatManager->m_mouse.expired()) unconstrainMouse(); diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 8bb660e6..f39eb145 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -167,7 +167,7 @@ bool CFunctionHook::hook() { const auto PROBEFIXEDASM = fixInstructionProbeRIPCalls(probe); - if (PROBEFIXEDASM.bytes.size() == 0) { + if (PROBEFIXEDASM.bytes.empty()) { Debug::log(ERR, "[functionhook] failed, unsupported asm / failed assembling:\n{}", probe.assembly); return false; } diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 89d769b3..d589e3cf 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -415,7 +415,7 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo } // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) - if (!linearIsExternal && std::ranges::find(mods, DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) + if (!linearIsExternal && std::ranges::find(mods, DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.empty()) mods.push_back(DRM_FORMAT_MOD_LINEAR); return result; @@ -444,7 +444,7 @@ void CHyprOpenGLImpl::initDRMFormats() { m_proc.eglQueryDmaBufFormatsEXT(m_eglDisplay, len, formats.data(), &len); } - if (formats.size() == 0) { + if (formats.empty()) { Debug::log(ERR, "EGL: Failed to get formats, DMABufs will not work."); return; } @@ -466,7 +466,7 @@ void CHyprOpenGLImpl::initDRMFormats() { } else mods = {DRM_FORMAT_MOD_LINEAR}; - m_hasModifiers = m_hasModifiers || mods.size() > 0; + m_hasModifiers = m_hasModifiers || !mods.empty(); // EGL can always do implicit modifiers. mods.push_back(DRM_FORMAT_MOD_INVALID); @@ -506,7 +506,7 @@ void CHyprOpenGLImpl::initDRMFormats() { Debug::log(LOG, "EGL: {} formats found in total. Some modifiers may be omitted as they are external-only.", dmaFormats.size()); - if (dmaFormats.size() == 0) + if (dmaFormats.empty()) Debug::log(WARN, "EGL: WARNING: No dmabuf formats were found, dmabuf will be disabled. This will degrade performance, but is most likely a driver issue or a very old GPU."); @@ -1193,7 +1193,7 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) { m_finalScreenShader.destroy(); - if (path == "" || path == STRVAL_EMPTY) + if (path.empty() || path == STRVAL_EMPTY) return; std::ifstream infile(absolutePath(path, g_pConfigManager->getMainConfigPath())); @@ -2362,7 +2362,7 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const CGradientValueData& gr glUniform4fv(m_shaders->m_shBORDER1.gradient, grad1.m_colorsOkLabA.size() / 4, (float*)grad1.m_colorsOkLabA.data()); glUniform1i(m_shaders->m_shBORDER1.gradientLength, grad1.m_colorsOkLabA.size() / 4); glUniform1f(m_shaders->m_shBORDER1.angle, (int)(grad1.m_angle / (PI / 180.0)) % 360 * (PI / 180.0)); - if (grad2.m_colorsOkLabA.size() > 0) + if (!grad2.m_colorsOkLabA.empty()) glUniform4fv(m_shaders->m_shBORDER1.gradient2, grad2.m_colorsOkLabA.size() / 4, (float*)grad2.m_colorsOkLabA.data()); glUniform1i(m_shaders->m_shBORDER1.gradient2Length, grad2.m_colorsOkLabA.size() / 4); glUniform1f(m_shaders->m_shBORDER1.angle2, (int)(grad2.m_angle / (PI / 180.0)) % 360 * (PI / 180.0)); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 28f078aa..71d22d3c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2077,7 +2077,7 @@ std::tuple CHyprRenderer::getRenderTimes(PHLMONITOR pMonito minRenderTime = rt; avgRenderTime += rt; } - avgRenderTime /= POVERLAY->m_lastRenderTimes.size() == 0 ? 1 : POVERLAY->m_lastRenderTimes.size(); + avgRenderTime /= POVERLAY->m_lastRenderTimes.empty() ? 1 : POVERLAY->m_lastRenderTimes.size(); return std::make_tuple<>(avgRenderTime, maxRenderTime, minRenderTime); } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 65d7d7ff..7a6eebba 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -81,7 +81,7 @@ void CHyprGroupBarDecoration::updateWindow(PHLWINDOW pWindow) { damageEntire(); - if (m_dwGroupMembers.size() == 0) { + if (m_dwGroupMembers.empty()) { m_window->removeWindowDeco(this); return; } From 82b854954230a45d590c1287a8c2c1f0076f3392 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Sun, 1 Jun 2025 21:53:20 +0200 Subject: [PATCH 1547/2393] hyprpm: refuse adding a new repo without update --- hyprpm/src/core/PluginManager.cpp | 5 +++++ src/xwayland/Dnd.cpp | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 90eba579..b7316fdb 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -159,6 +159,11 @@ bool CPluginManager::addNewPluginRepo(const std::string& url, const std::string& DataState::updateGlobalState(GLOBALSTATE); } + if (GLOBALSTATE.headersHashCompiled.empty()) { + std::println("\n{}", failureString("Cannot find headers in the global state. Try running hyprpm update first.")); + return false; + } + std::cout << Colors::GREEN << "✔" << Colors::RESET << Colors::RED << " adding a new plugin repository " << Colors::RESET << "from " << url << "\n " << Colors::RED << "MAKE SURE" << Colors::RESET << " that you trust the authors. " << Colors::RED << "DO NOT" << Colors::RESET << " install random plugins without verifying the code and author.\n " diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index e4c60920..9d2012fb 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -286,8 +286,8 @@ void CX11DataDevice::forceCleanupDnd() { if (m_lastOffer) { auto source = m_lastOffer->getSource(); if (source) { - source->cancelled(); source->sendDndFinished(); + source->cancelled(); } } From 2d1c6f88d2202ae40671277759b1edc3ecc51c45 Mon Sep 17 00:00:00 2001 From: Jasson Date: Sun, 1 Jun 2025 16:02:17 -0400 Subject: [PATCH 1548/2393] xwm: Refactored functions in XWM.cpp (#10569) * Refactored SXSelection::onSelection in XWM.cpp - Made the function more readable and less redundant - Extracted repeated conditions into booleans. - Reduced nested conditionals - Reused (conn) pointer * Refectd readProp * Refactor initSelection --- src/xwayland/XWM.cpp | 261 ++++++++++++++++++++++++------------------- 1 file changed, 147 insertions(+), 114 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 76ae1d88..5b423dca 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1,5 +1,6 @@ #include "helpers/math/Math.hpp" #include +#include #ifndef NO_XWAYLAND #include @@ -198,104 +199,125 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ if (Debug::m_trace) propName = getAtomName(atom); - if (atom == XCB_ATOM_WM_CLASS) { - size_t len = xcb_get_property_value_length(reply); - char* string = (char*)xcb_get_property_value(reply); - XSURF->m_state.appid = std::string{string, len}; - if (std::ranges::count(XSURF->m_state.appid, '\000') == 2) - XSURF->m_state.appid = XSURF->m_state.appid.substr(XSURF->m_state.appid.find_first_of('\000') + 1); // fuck you X + const auto valueLen = xcb_get_property_value_length(reply); + const auto* value = (const char*)xcb_get_property_value(reply); + + auto handleWMClass = [&]() { + XSURF->m_state.appid = std::string{value, valueLen}; + if (std::count(XSURF->m_state.appid.begin(), XSURF->m_state.appid.end(), '\000') == 2) + XSURF->m_state.appid = XSURF->m_state.appid.substr(XSURF->m_state.appid.find_first_of('\000') + 1); + if (!XSURF->m_state.appid.empty()) XSURF->m_state.appid.pop_back(); XSURF->m_events.metadataChanged.emit(); - } else if (atom == XCB_ATOM_WM_NAME || atom == HYPRATOMS["_NET_WM_NAME"]) { - size_t len = xcb_get_property_value_length(reply); - char* string = (char*)xcb_get_property_value(reply); + }; + + auto handleWMName = [&]() { if (reply->type != HYPRATOMS["UTF8_STRING"] && reply->type != HYPRATOMS["TEXT"] && reply->type != XCB_ATOM_STRING) return; - XSURF->m_state.title = std::string{string, len}; + XSURF->m_state.title = std::string{value, valueLen}; XSURF->m_events.metadataChanged.emit(); - } else if (atom == HYPRATOMS["_NET_WM_WINDOW_TYPE"]) { - xcb_atom_t* atomsArr = (xcb_atom_t*)xcb_get_property_value(reply); - size_t atomsNo = reply->value_len; - XSURF->m_atoms.clear(); - for (size_t i = 0; i < atomsNo; ++i) { - XSURF->m_atoms.push_back(atomsArr[i]); - } - } else if (atom == HYPRATOMS["_NET_WM_STATE"]) { - xcb_atom_t* atoms = (xcb_atom_t*)xcb_get_property_value(reply); + }; + + auto handleWindowType = [&]() { + auto* atomsArr = (xcb_atom_t*)value; + XSURF->m_atoms.assign(atomsArr, atomsArr + reply->value_len); + }; + + auto handleWMState = [&]() { + auto* atoms = (xcb_atom_t*)value; for (uint32_t i = 0; i < reply->value_len; i++) { if (atoms[i] == HYPRATOMS["_NET_WM_STATE_MODAL"]) XSURF->m_modal = true; } - } else if (atom == HYPRATOMS["WM_HINTS"]) { - if (reply->value_len != 0) { - XSURF->m_hints = makeUnique(); - xcb_icccm_get_wm_hints_from_reply(XSURF->m_hints.get(), reply); + }; - if (!(XSURF->m_hints->flags & XCB_ICCCM_WM_HINT_INPUT)) - XSURF->m_hints->input = true; - } - } else if (atom == HYPRATOMS["WM_WINDOW_ROLE"]) { - size_t len = xcb_get_property_value_length(reply); + auto handleWMHints = [&]() { + if (reply->value_len == 0) + return; + XSURF->m_hints = makeUnique(); + xcb_icccm_get_wm_hints_from_reply(XSURF->m_hints.get(), reply); + if (!(XSURF->m_hints->flags & XCB_ICCCM_WM_HINT_INPUT)) + XSURF->m_hints->input = true; + }; - if (len <= 0) + auto handleWMRole = [&]() { + if (valueLen <= 0) XSURF->m_role = ""; else { - XSURF->m_role = std::string{(char*)xcb_get_property_value(reply), len}; + XSURF->m_role = std::string{value, valueLen}; XSURF->m_role = XSURF->m_role.substr(0, XSURF->m_role.find_first_of('\000')); } - } else if (atom == XCB_ATOM_WM_TRANSIENT_FOR) { - if (reply->type == XCB_ATOM_WINDOW) { - const auto XID = (xcb_window_t*)xcb_get_property_value(reply); - XSURF->m_transient = XID; - if (XID) { - if (const auto NEWXSURF = windowForXID(*XID); NEWXSURF && !lookupParentExists(XSURF, NEWXSURF)) { - XSURF->m_parent = NEWXSURF; - NEWXSURF->m_children.emplace_back(XSURF); - } else - Debug::log(LOG, "[xwm] Denying transient because it would create a loop"); - } + }; + + auto handleTransientFor = [&]() { + if (reply->type != XCB_ATOM_WINDOW) + return; + const auto XID = (xcb_window_t*)value; + XSURF->m_transient = XID; + if (!XID) + return; + + if (const auto NEWXSURF = windowForXID(*XID); NEWXSURF && !lookupParentExists(XSURF, NEWXSURF)) { + XSURF->m_parent = NEWXSURF; + NEWXSURF->m_children.emplace_back(XSURF); + } else + Debug::log(LOG, "[xwm] Denying transient because it would create a loop"); + }; + + auto handleSizeHints = [&]() { + if (reply->type != HYPRATOMS["WM_SIZE_HINTS"] || reply->value_len == 0) + return; + + XSURF->m_sizeHints = makeUnique(); + std::memset(XSURF->m_sizeHints.get(), 0, sizeof(xcb_size_hints_t)); + xcb_icccm_get_wm_size_hints_from_reply(XSURF->m_sizeHints.get(), reply); + + const int32_t FLAGS = XSURF->m_sizeHints->flags; + const bool HASMIN = FLAGS & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE; + const bool HASBASE = FLAGS & XCB_ICCCM_SIZE_HINT_BASE_SIZE; + + if (!HASMIN && !HASBASE) { + XSURF->m_sizeHints->min_width = XSURF->m_sizeHints->min_height = -1; + XSURF->m_sizeHints->base_width = XSURF->m_sizeHints->base_height = -1; + } else if (!HASBASE) { + XSURF->m_sizeHints->base_width = XSURF->m_sizeHints->min_width; + XSURF->m_sizeHints->base_height = XSURF->m_sizeHints->min_height; + } else if (!HASMIN) { + XSURF->m_sizeHints->min_width = XSURF->m_sizeHints->base_width; + XSURF->m_sizeHints->min_height = XSURF->m_sizeHints->base_height; } - } else if (atom == HYPRATOMS["WM_NORMAL_HINTS"]) { - if (reply->type == HYPRATOMS["WM_SIZE_HINTS"] && reply->value_len > 0) { - XSURF->m_sizeHints = makeUnique(); - std::memset(XSURF->m_sizeHints.get(), 0, sizeof(xcb_size_hints_t)); - xcb_icccm_get_wm_size_hints_from_reply(XSURF->m_sizeHints.get(), reply); + if (!(FLAGS & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) + XSURF->m_sizeHints->max_width = XSURF->m_sizeHints->max_height = -1; + }; - const int32_t FLAGS = XSURF->m_sizeHints->flags; - const bool HASMIN = (FLAGS & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE); - const bool HASBASE = (FLAGS & XCB_ICCCM_SIZE_HINT_BASE_SIZE); + auto handleWMProtocols = [&]() { + if (reply->type != XCB_ATOM_ATOM) + return; + auto* atoms = (xcb_atom_t*)value; + XSURF->m_protocols.assign(atoms, atoms + reply->value_len); + }; - if (!HASMIN && !HASBASE) { - XSURF->m_sizeHints->min_width = -1; - XSURF->m_sizeHints->min_height = -1; - XSURF->m_sizeHints->base_width = -1; - XSURF->m_sizeHints->base_height = -1; - } else if (!HASBASE) { - XSURF->m_sizeHints->base_width = XSURF->m_sizeHints->min_width; - XSURF->m_sizeHints->base_height = XSURF->m_sizeHints->min_height; - } else if (!HASMIN) { - XSURF->m_sizeHints->min_width = XSURF->m_sizeHints->base_width; - XSURF->m_sizeHints->min_height = XSURF->m_sizeHints->base_height; - } - - if (!(FLAGS & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)) { - XSURF->m_sizeHints->max_width = -1; - XSURF->m_sizeHints->max_height = -1; - } - } - } else if (atom == HYPRATOMS["WM_PROTOCOLS"]) { - if (reply->type == XCB_ATOM_ATOM) { - auto atoms = (xcb_atom_t*)xcb_get_property_value(reply); - std::vector vec; - vec.reserve(reply->value_len); - for (size_t i = 0; i < reply->value_len; ++i) { - vec.emplace_back(atoms[i]); - } - XSURF->m_protocols = vec; - } - } else { + if (atom == XCB_ATOM_WM_CLASS) + handleWMClass(); + else if (atom == XCB_ATOM_WM_NAME || atom == HYPRATOMS["_NET_WM_NAME"]) + handleWMName(); + else if (atom == HYPRATOMS["_NET_WM_WINDOW_TYPE"]) + handleWindowType(); + else if (atom == HYPRATOMS["_NET_WM_STATE"]) + handleWMState(); + else if (atom == HYPRATOMS["WM_HINTS"]) + handleWMHints(); + else if (atom == HYPRATOMS["WM_WINDOW_ROLE"]) + handleWMRole(); + else if (atom == XCB_ATOM_WM_TRANSIENT_FOR) + handleTransientFor(); + else if (atom == HYPRATOMS["WM_NORMAL_HINTS"]) + handleSizeHints(); + else if (atom == HYPRATOMS["WM_PROTOCOLS"]) + handleWMProtocols(); + else { Debug::log(TRACE, "[xwm] Unhandled prop {} -> {}", atom, propName); return; } @@ -757,7 +779,7 @@ bool CXWM::handleSelectionEvent(xcb_generic_event_t* e) { if (e->response_type - m_xfixes->first_event == XCB_XFIXES_SELECTION_NOTIFY) return handleSelectionXFixesNotify((xcb_xfixes_selection_notify_event_t*)e); - return 0; + return false; } int CXWM::onEvent(int fd, uint32_t mask) { @@ -772,14 +794,14 @@ int CXWM::onEvent(int fd, uint32_t mask) { return 0; } - int count = 0; + int processedEventCount = 0; while (42069) { xcb_generic_event_t* event = xcb_poll_for_event(m_connection); if (!event) break; - count++; + processedEventCount++; if (handleSelectionEvent(event)) { free(event); @@ -806,10 +828,10 @@ int CXWM::onEvent(int fd, uint32_t mask) { free(event); } - if (count) + if (processedEventCount) xcb_flush(m_connection); - return count; + return processedEventCount; } void CXWM::gatherResources() { @@ -1171,35 +1193,37 @@ void CXWM::updateOverrideRedirect(SP surf, bool overrideRedire } void CXWM::initSelection() { - m_clipboard.window = xcb_generate_id(m_connection); - uint32_t mask[1] = {XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE}; - xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_clipboard.window, m_screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, m_screen->root_visual, - XCB_CW_EVENT_MASK, mask); - xcb_set_selection_owner(m_connection, m_clipboard.window, HYPRATOMS["CLIPBOARD_MANAGER"], XCB_TIME_CURRENT_TIME); - - uint32_t mask2 = + const uint32_t windowMask = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; + const uint32_t xfixesMask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY | XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE; - xcb_xfixes_select_selection_input(m_connection, m_clipboard.window, HYPRATOMS["CLIPBOARD"], mask2); - m_clipboard.listeners.setSelection = g_pSeatManager->m_events.setSelection.registerListener([this](std::any d) { m_clipboard.onSelection(); }); - m_clipboard.listeners.keyboardFocusChange = g_pSeatManager->m_events.keyboardFocusChange.registerListener([this](std::any d) { m_clipboard.onKeyboardFocus(); }); + auto createSelectionWindow = [&](xcb_window_t& window, const std::string& atomName, bool inputOnly = false) { + window = xcb_generate_id(m_connection); + const uint16_t width = inputOnly ? 8192 : 10; + const uint16_t height = inputOnly ? 8192 : 10; - m_primarySelection.window = xcb_generate_id(m_connection); - xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_primarySelection.window, m_screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, m_screen->root_visual, - XCB_CW_EVENT_MASK, mask); - xcb_set_selection_owner(m_connection, m_primarySelection.window, HYPRATOMS["PRIMARY"], XCB_TIME_CURRENT_TIME); + xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, window, m_screen->root, 0, 0, width, height, 0, + inputOnly ? XCB_WINDOW_CLASS_INPUT_ONLY : XCB_WINDOW_CLASS_INPUT_OUTPUT, m_screen->root_visual, XCB_CW_EVENT_MASK, &windowMask); - xcb_xfixes_select_selection_input(m_connection, m_primarySelection.window, HYPRATOMS["PRIMARY"], mask2); + if (!inputOnly) { + xcb_set_selection_owner(m_connection, window, HYPRATOMS[atomName], XCB_TIME_CURRENT_TIME); + xcb_xfixes_select_selection_input(m_connection, window, HYPRATOMS[atomName], xfixesMask); + } - m_primarySelection.listeners.setSelection = g_pSeatManager->m_events.setPrimarySelection.registerListener([this](std::any d) { m_primarySelection.onSelection(); }); - m_primarySelection.listeners.keyboardFocusChange = g_pSeatManager->m_events.keyboardFocusChange.registerListener([this](std::any d) { m_primarySelection.onKeyboardFocus(); }); + return window; + }; - m_dndSelection.window = xcb_generate_id(m_connection); - xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, m_dndSelection.window, m_screen->root, 0, 0, 8192, 8192, 0, XCB_WINDOW_CLASS_INPUT_ONLY, m_screen->root_visual, - XCB_CW_EVENT_MASK, mask); + createSelectionWindow(m_clipboard.window, "CLIPBOARD_MANAGER"); + m_clipboard.listeners.setSelection = g_pSeatManager->m_events.setSelection.registerListener([this](std::any) { m_clipboard.onSelection(); }); + m_clipboard.listeners.keyboardFocusChange = g_pSeatManager->m_events.keyboardFocusChange.registerListener([this](std::any) { m_clipboard.onKeyboardFocus(); }); - uint32_t val1 = XDND_VERSION; - xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_dndSelection.window, HYPRATOMS["XdndAware"], XCB_ATOM_ATOM, 32, 1, &val1); + createSelectionWindow(m_primarySelection.window, "PRIMARY"); + m_primarySelection.listeners.setSelection = g_pSeatManager->m_events.setPrimarySelection.registerListener([this](std::any) { m_primarySelection.onSelection(); }); + m_primarySelection.listeners.keyboardFocusChange = g_pSeatManager->m_events.keyboardFocusChange.registerListener([this](std::any) { m_primarySelection.onKeyboardFocus(); }); + + createSelectionWindow(m_dndSelection.window, "XdndAware", true); + const uint32_t xdndVersion = XDND_VERSION; + xcb_change_property(m_connection, XCB_PROP_MODE_REPLACE, m_dndSelection.window, HYPRATOMS["XdndAware"], XCB_ATOM_ATOM, 32, 1, &xdndVersion); } void CXWM::setClipboardToWayland(SXSelection& sel) { @@ -1332,18 +1356,27 @@ SP CXWM::createX11DataOffer(SP surf, SPm_wm->m_clipboard && g_pSeatManager->m_selection.currentSelection && g_pSeatManager->m_selection.currentSelection->type() == DATA_SOURCE_TYPE_X11) || - (this == &g_pXWayland->m_wm->m_primarySelection && g_pSeatManager->m_selection.currentPrimarySelection && - g_pSeatManager->m_selection.currentPrimarySelection->type() == DATA_SOURCE_TYPE_X11)) + const bool isClipboard = this == &g_pXWayland->m_wm->m_clipboard; + const bool isPrimary = this == &g_pXWayland->m_wm->m_primarySelection; + + auto currentSel = g_pSeatManager->m_selection.currentSelection; + auto currentPrimSel = g_pSeatManager->m_selection.currentPrimarySelection; + + const bool isX11Clipboard = isClipboard && currentSel && currentSel->type() == DATA_SOURCE_TYPE_X11; + const bool isX11Primary = isPrimary && currentPrimSel && currentPrimSel->type() == DATA_SOURCE_TYPE_X11; + + if (isX11Clipboard || isX11Primary) return; - if (this == &g_pXWayland->m_wm->m_clipboard && g_pSeatManager->m_selection.currentSelection) { - xcb_set_selection_owner(g_pXWayland->m_wm->m_connection, g_pXWayland->m_wm->m_clipboard.window, HYPRATOMS["CLIPBOARD"], XCB_TIME_CURRENT_TIME); - xcb_flush(g_pXWayland->m_wm->m_connection); + xcb_connection_t* conn = g_pXWayland->m_wm->m_connection; + + if (isClipboard && currentSel) { + xcb_set_selection_owner(conn, g_pXWayland->m_wm->m_clipboard.window, HYPRATOMS["CLIPBOARD"], XCB_TIME_CURRENT_TIME); + xcb_flush(conn); g_pXWayland->m_wm->m_clipboard.notifyOnFocus = true; - } else if (this == &g_pXWayland->m_wm->m_primarySelection && g_pSeatManager->m_selection.currentPrimarySelection) { - xcb_set_selection_owner(g_pXWayland->m_wm->m_connection, g_pXWayland->m_wm->m_primarySelection.window, HYPRATOMS["PRIMARY"], XCB_TIME_CURRENT_TIME); - xcb_flush(g_pXWayland->m_wm->m_connection); + } else if (isPrimary && currentPrimSel) { + xcb_set_selection_owner(conn, g_pXWayland->m_wm->m_primarySelection.window, HYPRATOMS["PRIMARY"], XCB_TIME_CURRENT_TIME); + xcb_flush(conn); g_pXWayland->m_wm->m_primarySelection.notifyOnFocus = true; } } From 16c62a6dbb5f8eee4dcfe903e743f6f144971c06 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Mon, 2 Jun 2025 01:03:53 +0500 Subject: [PATCH 1549/2393] internal: Fix HyprError not displaying at startup (#10606) --- src/render/OpenGL.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index d589e3cf..817944ef 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1183,7 +1183,6 @@ bool CHyprOpenGLImpl::initShaders() { m_shadersInitialized = true; Debug::log(LOG, "Shaders initialized successfully."); - g_pHyprError->destroy(); return true; } From ef2c73af80d37265babc3287b3e5502a40c39374 Mon Sep 17 00:00:00 2001 From: Kamikadze <40305144+Kam1k4dze@users.noreply.github.com> Date: Mon, 2 Jun 2025 22:36:44 +0500 Subject: [PATCH 1550/2393] internal: embed example config (#10608) --- src/config/ConfigManager.cpp | 2 +- src/config/defaultConfig.hpp | 313 +---------------------------------- 2 files changed, 8 insertions(+), 307 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f7fed52f..8dce9f30 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -849,7 +849,7 @@ std::optional CConfigManager::generateConfig(std::string configPath Debug::log(WARN, "No config file found; attempting to generate."); std::ofstream ofs; ofs.open(configPath, std::ios::trunc); - ofs << AUTOCONFIG; + ofs << AUTOGENERATED_PREFIX << EXAMPLE_CONFIG; ofs.close(); if (!std::filesystem::exists(configPath)) diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index a9ea6694..8bdfea39 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -2,316 +2,17 @@ #include -inline const std::string AUTOCONFIG = R"#( +inline constexpr std::string_view AUTOGENERATED_PREFIX = R"#( # ####################################################################################### # AUTOGENERATED HYPRLAND CONFIG. -# PLEASE USE THE CONFIG PROVIDED IN THE GIT REPO /examples/hyprland.conf AND EDIT IT, -# OR EDIT THIS ONE ACCORDING TO THE WIKI INSTRUCTIONS. +# EDIT THIS CONFIG ACCORDING TO THE WIKI INSTRUCTIONS. # ####################################################################################### autogenerated = 1 # remove this line to remove the warning -# This is an example Hyprland config file. -# Refer to the wiki for more information. -# https://wiki.hyprland.org/Configuring/ - -# Please note not all available settings / options are set here. -# For a full list, see the wiki - -# You can split this configuration into multiple files -# Create your files separately and then link them to this file like this: -# source = ~/.config/hypr/myColors.conf - - -################ -### MONITORS ### -################ - -# See https://wiki.hyprland.org/Configuring/Monitors/ -monitor=,preferred,auto,auto - - -################### -### MY PROGRAMS ### -################### - -# See https://wiki.hyprland.org/Configuring/Keywords/ - -# Set programs that you use -$terminal = kitty -$fileManager = dolphin -$menu = wofi --show drun - - -################# -### AUTOSTART ### -################# - -# Autostart necessary processes (like notifications daemons, status bars, etc.) -# Or execute your favorite apps at launch like this: - -# exec-once = $terminal -# exec-once = nm-applet & -# exec-once = waybar & hyprpaper & firefox - - -############################# -### ENVIRONMENT VARIABLES ### -############################# - -# See https://wiki.hyprland.org/Configuring/Environment-variables/ - -env = XCURSOR_SIZE,24 -env = HYPRCURSOR_SIZE,24 - - -################### -### PERMISSIONS ### -################### - -# See https://wiki.hyprland.org/Configuring/Permissions/ -# Please note permission changes here require a Hyprland restart and are not applied on-the-fly -# for security reasons - -# ecosystem { -# enforce_permissions = 1 -# } - -# permission = /usr/(bin|local/bin)/grim, screencopy, allow -# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow -# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow - - -##################### -### LOOK AND FEEL ### -##################### - -# Refer to https://wiki.hyprland.org/Configuring/Variables/ - -# https://wiki.hyprland.org/Configuring/Variables/#general -general { - gaps_in = 5 - gaps_out = 20 - - border_size = 2 - - # https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors - col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg - col.inactive_border = rgba(595959aa) - - # Set to true enable resizing windows by clicking and dragging on borders and gaps - resize_on_border = false - - # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on - allow_tearing = false - - layout = dwindle -} - -# https://wiki.hyprland.org/Configuring/Variables/#decoration -decoration { - rounding = 10 - rounding_power = 2 - - # Change transparency of focused and unfocused windows - active_opacity = 1.0 - inactive_opacity = 1.0 - - shadow { - enabled = true - range = 4 - render_power = 3 - color = rgba(1a1a1aee) - } - - # https://wiki.hyprland.org/Configuring/Variables/#blur - blur { - enabled = true - size = 3 - passes = 1 - - vibrancy = 0.1696 - } -} - -# https://wiki.hyprland.org/Configuring/Variables/#animations -animations { - enabled = yes, please :) - - # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more - - bezier = easeOutQuint,0.23,1,0.32,1 - bezier = easeInOutCubic,0.65,0.05,0.36,1 - bezier = linear,0,0,1,1 - bezier = almostLinear,0.5,0.5,0.75,1.0 - bezier = quick,0.15,0,0.1,1 - - animation = global, 1, 10, default - animation = border, 1, 5.39, easeOutQuint - animation = windows, 1, 4.79, easeOutQuint - animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% - animation = windowsOut, 1, 1.49, linear, popin 87% - animation = fadeIn, 1, 1.73, almostLinear - animation = fadeOut, 1, 1.46, almostLinear - animation = fade, 1, 3.03, quick - animation = layers, 1, 3.81, easeOutQuint - animation = layersIn, 1, 4, easeOutQuint, fade - animation = layersOut, 1, 1.5, linear, fade - animation = fadeLayersIn, 1, 1.79, almostLinear - animation = fadeLayersOut, 1, 1.39, almostLinear - animation = workspaces, 1, 1.94, almostLinear, fade - animation = workspacesIn, 1, 1.21, almostLinear, fade - animation = workspacesOut, 1, 1.94, almostLinear, fade -} - -# Ref https://wiki.hyprland.org/Configuring/Workspace-Rules/ -# "Smart gaps" / "No gaps when only" -# uncomment all if you wish to use that. -# workspace = w[tv1], gapsout:0, gapsin:0 -# workspace = f[1], gapsout:0, gapsin:0 -# windowrule = bordersize 0, floating:0, onworkspace:w[tv1] -# windowrule = rounding 0, floating:0, onworkspace:w[tv1] -# windowrule = bordersize 0, floating:0, onworkspace:f[1] -# windowrule = rounding 0, floating:0, onworkspace:f[1] - -# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more -dwindle { - pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below - preserve_split = true # You probably want this -} - -# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more -master { - new_status = master -} - -# https://wiki.hyprland.org/Configuring/Variables/#misc -misc { - force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers - disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( -} - - -############# -### INPUT ### -############# - -# https://wiki.hyprland.org/Configuring/Variables/#input -input { - kb_layout = us - kb_variant = - kb_model = - kb_options = - kb_rules = - - follow_mouse = 1 - - sensitivity = 0 # -1.0 - 1.0, 0 means no modification. - - touchpad { - natural_scroll = false - } -} - -# https://wiki.hyprland.org/Configuring/Variables/#gestures -gestures { - workspace_swipe = false -} - -# Example per-device config -# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more -device { - name = epic-mouse-v1 - sensitivity = -0.5 -} - - -################### -### KEYBINDINGS ### -################### - -# See https://wiki.hyprland.org/Configuring/Keywords/ -$mainMod = SUPER # Sets "Windows" key as main modifier - -# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more -bind = $mainMod, Q, exec, $terminal -bind = $mainMod, C, killactive, -bind = $mainMod, M, exit, -bind = $mainMod, E, exec, $fileManager -bind = $mainMod, V, togglefloating, -bind = $mainMod, R, exec, $menu -bind = $mainMod, P, pseudo, # dwindle -bind = $mainMod, J, togglesplit, # dwindle - -# Move focus with mainMod + arrow keys -bind = $mainMod, left, movefocus, l -bind = $mainMod, right, movefocus, r -bind = $mainMod, up, movefocus, u -bind = $mainMod, down, movefocus, d - -# Switch workspaces with mainMod + [0-9] -bind = $mainMod, 1, workspace, 1 -bind = $mainMod, 2, workspace, 2 -bind = $mainMod, 3, workspace, 3 -bind = $mainMod, 4, workspace, 4 -bind = $mainMod, 5, workspace, 5 -bind = $mainMod, 6, workspace, 6 -bind = $mainMod, 7, workspace, 7 -bind = $mainMod, 8, workspace, 8 -bind = $mainMod, 9, workspace, 9 -bind = $mainMod, 0, workspace, 10 - -# Move active window to a workspace with mainMod + SHIFT + [0-9] -bind = $mainMod SHIFT, 1, movetoworkspace, 1 -bind = $mainMod SHIFT, 2, movetoworkspace, 2 -bind = $mainMod SHIFT, 3, movetoworkspace, 3 -bind = $mainMod SHIFT, 4, movetoworkspace, 4 -bind = $mainMod SHIFT, 5, movetoworkspace, 5 -bind = $mainMod SHIFT, 6, movetoworkspace, 6 -bind = $mainMod SHIFT, 7, movetoworkspace, 7 -bind = $mainMod SHIFT, 8, movetoworkspace, 8 -bind = $mainMod SHIFT, 9, movetoworkspace, 9 -bind = $mainMod SHIFT, 0, movetoworkspace, 10 - -# Example special workspace (scratchpad) -bind = $mainMod, S, togglespecialworkspace, magic -bind = $mainMod SHIFT, S, movetoworkspace, special:magic - -# Scroll through existing workspaces with mainMod + scroll -bind = $mainMod, mouse_down, workspace, e+1 -bind = $mainMod, mouse_up, workspace, e-1 - -# Move/resize windows with mainMod + LMB/RMB and dragging -bindm = $mainMod, mouse:272, movewindow -bindm = $mainMod, mouse:273, resizewindow - -# Laptop multimedia keys for volume and LCD brightness -bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ -bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%- -bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle -bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle -bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+ -bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%- - -# Requires playerctl -bindl = , XF86AudioNext, exec, playerctl next -bindl = , XF86AudioPause, exec, playerctl play-pause -bindl = , XF86AudioPlay, exec, playerctl play-pause -bindl = , XF86AudioPrev, exec, playerctl previous - -############################## -### WINDOWS AND WORKSPACES ### -############################## - -# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more -# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules - -# Example windowrule -# windowrule = float,class:^(kitty)$,title:^(kitty)$ - -# Ignore maximize requests from apps. You'll probably like this. -windowrule = suppressevent maximize, class:.* - -# Fix some dragging issues with XWayland -windowrule = nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0 )#"; +inline constexpr char EXAMPLE_CONFIG_BYTES[] = { +#embed "../../example/hyprland.conf" +}; + +inline constexpr std::string_view EXAMPLE_CONFIG = {EXAMPLE_CONFIG_BYTES, sizeof(EXAMPLE_CONFIG_BYTES)}; From b1d0a727cc594e5329c5971d73391c7529e1c80e Mon Sep 17 00:00:00 2001 From: sam Date: Tue, 3 Jun 2025 02:22:51 +0800 Subject: [PATCH 1551/2393] internal: Center window on parent if available (#10582) Fixes #10537 --- src/layout/IHyprLayout.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index fbde7344..40794b3e 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -158,6 +158,7 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { } // TODO: detect a popup in a more consistent way. + bool centeredOnParent = false; if ((desiredGeometry.x == 0 && desiredGeometry.y == 0) || !visible || !pWindow->m_isX11) { // if the pos isn't set, fall back to the center placement if it's not a child auto pos = PMONITOR->m_position + PMONITOR->m_size / 2.F - desiredGeometry.size() / 2.F; @@ -168,10 +169,11 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { *pWindow->m_realPosition = PARENT->m_realPosition->goal() + PARENT->m_realSize->goal() / 2.F - desiredGeometry.size() / 2.F; pWindow->m_workspace = PARENT->m_workspace; pWindow->m_monitor = PARENT->m_monitor; + centeredOnParent = true; } } - - *pWindow->m_realPosition = pos; + if (!centeredOnParent) + *pWindow->m_realPosition = pos; } else { // if it is, we respect where it wants to put itself, but apply monitor offset if outside // most of these are popups From b5c0d0b8aa8bb095ac447bf6c73486cb1c172b6e Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Wed, 4 Jun 2025 02:48:56 +0800 Subject: [PATCH 1552/2393] keybinds: add an option to respect gaps out for floating to movewindow (#9360) --- src/config/ConfigDescriptions.hpp | 7 +++++++ src/config/ConfigManager.cpp | 3 +++ src/config/ConfigManager.hpp | 1 + src/managers/KeybindManager.cpp | 21 +++++++++++++++------ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index a77cf757..98214284 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -32,6 +32,13 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_STRING_SHORT, .data = SConfigOptionDescription::SStringData{"20"}, }, + SConfigOptionDescription{ + .value = "general:float_gaps", + .description = "gaps between windows and monitor edges for floating windows\n\nsupports css style gaps (top, right, bottom, left -> 5 10 15 20). \n-1 means default " + "gaps_in/gaps_out\n0 means no gaps", + .type = CONFIG_OPTION_STRING_SHORT, + .data = SConfigOptionDescription::SStringData{"0"}, + }, SConfigOptionDescription{ .value = "general:gaps_workspaces", .description = "gaps between workspaces. Stacks with gaps_out.", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8dce9f30..e2fb26ab 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -444,6 +444,7 @@ CConfigManager::CConfigManager() { registerConfigVar("general:no_border_on_floating", Hyprlang::INT{0}); registerConfigVar("general:gaps_in", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "5"}); registerConfigVar("general:gaps_out", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "20"}); + registerConfigVar("general:float_gaps", Hyprlang::CConfigCustomValueType{configHandleGapSet, configHandleGapDestroy, "0"}); registerConfigVar("general:gaps_workspaces", Hyprlang::INT{0}); registerConfigVar("general:no_focus_fallback", Hyprlang::INT{0}); registerConfigVar("general:resize_on_border", Hyprlang::INT{0}); @@ -1318,6 +1319,8 @@ SWorkspaceRule CConfigManager::mergeWorkspaceRules(const SWorkspaceRule& rule1, mergedRule.gapsIn = rule2.gapsIn; if (rule2.gapsOut.has_value()) mergedRule.gapsOut = rule2.gapsOut; + if (rule2.floatGaps) + mergedRule.floatGaps = rule2.floatGaps; if (rule2.borderSize.has_value()) mergedRule.borderSize = rule2.borderSize; if (rule2.noBorder.has_value()) diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 5cb95bac..134292e5 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -36,6 +36,7 @@ struct SWorkspaceRule { bool isPersistent = false; std::optional gapsIn; std::optional gapsOut; + std::optional floatGaps = gapsOut; std::optional borderSize; std::optional decorate; std::optional noRounding; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 976e292d..43558d9d 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1682,16 +1682,25 @@ SDispatchResult CKeybindManager::moveActiveTo(std::string args) { if (PLASTWINDOW->m_isFloating) { std::optional vPosx, vPosy; - const auto PMONITOR = PLASTWINDOW->m_monitor.lock(); - const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); + const auto PMONITOR = PLASTWINDOW->m_monitor.lock(); + const auto BORDERSIZE = PLASTWINDOW->getRealBorderSize(); + static auto PGAPSCUSTOMDATA = CConfigValue("general:float_gaps"); + static auto PGAPSOUTDATA = CConfigValue("general:gaps_out"); + auto* PGAPSOUT = (CCssGapData*)PGAPSCUSTOMDATA.ptr()->getData(); + if (PGAPSOUT->m_left < 0 || PGAPSOUT->m_right < 0 || PGAPSOUT->m_top < 0 || PGAPSOUT->m_bottom < 0) + PGAPSOUT = (CCssGapData*)PGAPSOUTDATA.ptr()->getData(); switch (arg) { - case 'l': vPosx = PMONITOR->m_reservedTopLeft.x + BORDERSIZE + PMONITOR->m_position.x; break; - case 'r': vPosx = PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x - PLASTWINDOW->m_realSize->goal().x - BORDERSIZE + PMONITOR->m_position.x; break; + case 'l': vPosx = PMONITOR->m_reservedTopLeft.x + BORDERSIZE + PMONITOR->m_position.x + PGAPSOUT->m_left; break; + case 'r': + vPosx = PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x - PLASTWINDOW->m_realSize->goal().x - BORDERSIZE + PMONITOR->m_position.x - PGAPSOUT->m_right; + break; case 't': - case 'u': vPosy = PMONITOR->m_reservedTopLeft.y + BORDERSIZE + PMONITOR->m_position.y; break; + case 'u': vPosy = PMONITOR->m_reservedTopLeft.y + BORDERSIZE + PMONITOR->m_position.y + PGAPSOUT->m_top; break; case 'b': - case 'd': vPosy = PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y - PLASTWINDOW->m_realSize->goal().y - BORDERSIZE + PMONITOR->m_position.y; break; + case 'd': + vPosy = PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y - PLASTWINDOW->m_realSize->goal().y - BORDERSIZE + PMONITOR->m_position.y - PGAPSOUT->m_bottom; + break; } *PLASTWINDOW->m_realPosition = Vector2D(vPosx.value_or(PLASTWINDOW->m_realPosition->goal().x), vPosy.value_or(PLASTWINDOW->m_realPosition->goal().y)); From d9f7448d82132f4c1c07105f4bc3a4f717915d30 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 4 Jun 2025 16:54:12 +0200 Subject: [PATCH 1553/2393] xwayland: pad pid with leading zeroes in lockfile fixes #10652 --- src/xwayland/Server.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 814bd20c..0cc16fef 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -199,8 +199,9 @@ bool CXWaylandServer::tryOpenSockets() { continue; } - const std::string pidStr = std::to_string(getpid()); - if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + const std::string pidStr = std::format("{:010d}\n", getpid()); + ASSERT(pidStr.length() == 11); + if (write(fd.get(), pidStr.c_str(), 11) != 11L) { safeRemove(lockPath); continue; } From d7a87ce6e2535f1029fc93b062d2828e8549c525 Mon Sep 17 00:00:00 2001 From: Jasson Date: Wed, 4 Jun 2025 11:00:55 -0400 Subject: [PATCH 1554/2393] xwayland: fix xwayland -> wayland clipboard (#10646) --- src/xwayland/XWM.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 5b423dca..1da8c71e 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1214,6 +1214,7 @@ void CXWM::initSelection() { }; createSelectionWindow(m_clipboard.window, "CLIPBOARD_MANAGER"); + createSelectionWindow(m_clipboard.window, "CLIPBOARD"); m_clipboard.listeners.setSelection = g_pSeatManager->m_events.setSelection.registerListener([this](std::any) { m_clipboard.onSelection(); }); m_clipboard.listeners.keyboardFocusChange = g_pSeatManager->m_events.keyboardFocusChange.registerListener([this](std::any) { m_clipboard.onKeyboardFocus(); }); From 59c886d85500cf4c8ae11eaf2ebe50ec25b596f6 Mon Sep 17 00:00:00 2001 From: sam Date: Thu, 5 Jun 2025 22:19:54 +0800 Subject: [PATCH 1555/2393] internal: Catch filesystem exceptions while iterating RunTimeDir (#10648) --- hyprctl/main.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 25a4eef3..4a8b9819 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -72,10 +72,13 @@ std::vector instances() { return {}; } catch (std::exception& e) { return {}; } - for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) { + std::error_code ec; + std::filesystem::directory_iterator it = std::filesystem::directory_iterator(getRuntimeDir(), std::filesystem::directory_options::skip_permission_denied, ec); + if (ec) + return {}; + for (const auto& el : it) { if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock")) continue; - // read lock SInstanceData* data = &result.emplace_back(); data->id = el.path().filename().string(); From abdfc5ea40c0793117f34bf6c465840500cf7cb0 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:56:46 +0300 Subject: [PATCH 1556/2393] config: add a new monitor v2 config syntax (#9761) --- src/config/ConfigManager.cpp | 443 ++++++++++++++++++++++------------- src/config/ConfigManager.hpp | 33 +++ src/debug/HyprCtl.cpp | 3 + 3 files changed, 322 insertions(+), 157 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e2fb26ab..735d9703 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -791,6 +791,20 @@ CConfigManager::CConfigManager() { m_config->addSpecialConfigValue("device", "flip_y", Hyprlang::INT{0}); // only for touchpads m_config->addSpecialConfigValue("device", "keybinds", Hyprlang::INT{1}); // enable/disable keybinds + m_config->addSpecialCategory("monitorv2", {.key = "output"}); + m_config->addSpecialConfigValue("monitorv2", "disabled", Hyprlang::INT{0}); + m_config->addSpecialConfigValue("monitorv2", "mode", {"preferred"}); + m_config->addSpecialConfigValue("monitorv2", "position", {"auto"}); + m_config->addSpecialConfigValue("monitorv2", "scale", Hyprlang::FLOAT{1.0}); + m_config->addSpecialConfigValue("monitorv2", "addreserved", {STRVAL_EMPTY}); + m_config->addSpecialConfigValue("monitorv2", "mirror", {STRVAL_EMPTY}); + m_config->addSpecialConfigValue("monitorv2", "bitdepth", {STRVAL_EMPTY}); // TODO use correct type + m_config->addSpecialConfigValue("monitorv2", "cm", {"auto"}); + m_config->addSpecialConfigValue("monitorv2", "sdrbrightness", Hyprlang::FLOAT{1.0}); + m_config->addSpecialConfigValue("monitorv2", "sdrsaturation", Hyprlang::FLOAT{1.0}); + m_config->addSpecialConfigValue("monitorv2", "vrr", Hyprlang::INT{0}); + m_config->addSpecialConfigValue("monitorv2", "transform", {STRVAL_EMPTY}); // TODO use correct type + // keywords m_config->registerHandler(&::handleExec, "exec", {false}); m_config->registerHandler(&::handleRawExec, "execr", {false}); @@ -918,8 +932,9 @@ void CConfigManager::reload() { resetHLConfig(); m_configCurrentPath = getMainConfigPath(); const auto ERR = m_config->parse(); - m_lastConfigVerificationWasSuccessful = !ERR.error; - postConfigReload(ERR); + const auto monitorError = handleMonitorv2(); + m_lastConfigVerificationWasSuccessful = !ERR.error && !monitorError.error; + postConfigReload(ERR.error || !monitorError.error ? ERR : monitorError); } std::string CConfigManager::verify() { @@ -1009,6 +1024,68 @@ void CConfigManager::updateWatcher() { g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); } +std::optional CConfigManager::handleMonitorv2(const std::string& output) { + auto parser = CMonitorRuleParser(output); + auto VAL = m_config->getSpecialConfigValuePtr("monitorv2", "disabled", output.c_str()); + if (VAL && VAL->m_bSetByUser && std::any_cast(VAL->getValue())) + parser.setDisabled(); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "mode", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.parseMode(std::any_cast(VAL->getValue())); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "position", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.parsePosition(std::any_cast(VAL->getValue())); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "scale", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.rule().scale = std::any_cast(VAL->getValue()); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "addreserved", output.c_str()); + if (VAL && VAL->m_bSetByUser) { + const auto ARGS = CVarList(std::any_cast(VAL->getValue())); + parser.setReserved({.top = std::stoi(ARGS[0]), .bottom = std::stoi(ARGS[1]), .left = std::stoi(ARGS[2]), .right = std::stoi(ARGS[3])}); + } + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "mirror", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.setMirror(std::any_cast(VAL->getValue())); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "bitdepth", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.parseBitdepth(std::any_cast(VAL->getValue())); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "cm", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.parseCM(std::any_cast(VAL->getValue())); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "sdrbrightness", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.rule().sdrBrightness = std::any_cast(VAL->getValue()); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "sdrsaturation", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.rule().sdrSaturation = std::any_cast(VAL->getValue()); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "vrr", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.rule().vrr = std::any_cast(VAL->getValue()); + VAL = m_config->getSpecialConfigValuePtr("monitorv2", "transform", output.c_str()); + if (VAL && VAL->m_bSetByUser) + parser.parseTransform(std::any_cast(VAL->getValue())); + + auto newrule = parser.rule(); + + std::erase_if(m_monitorRules, [&](const auto& other) { return other.name == newrule.name; }); + + m_monitorRules.push_back(newrule); + + return parser.getError(); +} + +Hyprlang::CParseResult CConfigManager::handleMonitorv2() { + Hyprlang::CParseResult result; + for (const auto& output : m_config->listKeysForSpecialCategory("monitorv2")) { + const auto error = handleMonitorv2(output); + if (error.has_value()) { + result.setError(error.value().c_str()); + return result; + } + } + return result; +} + void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static int prevEnabledExplicit = *PENABLEEXPLICIT; @@ -1607,6 +1684,7 @@ void CConfigManager::dispatchExecShutdown() { } void CConfigManager::performMonitorReload() { + handleMonitorv2(); bool overAgain = false; @@ -1956,30 +2034,207 @@ static bool parseModeLine(const std::string& modeline, drmModeModeInfo& mode) { return true; } +CMonitorRuleParser::CMonitorRuleParser(const std::string& name) { + m_rule.name = name; +} + +const std::string& CMonitorRuleParser::name() { + return m_rule.name; +} + +SMonitorRule& CMonitorRuleParser::rule() { + return m_rule; +} + +std::optional CMonitorRuleParser::getError() { + if (m_error.empty()) + return {}; + return m_error; +} + +bool CMonitorRuleParser::parseMode(const std::string& value) { + if (value.starts_with("pref")) + m_rule.resolution = Vector2D(); + else if (value.starts_with("highrr")) + m_rule.resolution = Vector2D(-1, -1); + else if (value.starts_with("highres")) + m_rule.resolution = Vector2D(-1, -2); + else if (parseModeLine(value, m_rule.drmMode)) { + m_rule.resolution = Vector2D(m_rule.drmMode.hdisplay, m_rule.drmMode.vdisplay); + m_rule.refreshRate = float(m_rule.drmMode.vrefresh) / 1000; + } else { + + if (!value.contains("x")) { + m_error += "invalid resolution "; + m_rule.resolution = Vector2D(); + return false; + } else { + try { + m_rule.resolution.x = stoi(value.substr(0, value.find_first_of('x'))); + m_rule.resolution.y = stoi(value.substr(value.find_first_of('x') + 1, value.find_first_of('@'))); + + if (value.contains("@")) + m_rule.refreshRate = stof(value.substr(value.find_first_of('@') + 1)); + } catch (...) { + m_error += "invalid resolution "; + m_rule.resolution = Vector2D(); + return false; + } + } + } + return true; +} + +bool CMonitorRuleParser::parsePosition(const std::string& value, bool isFirst) { + if (value.starts_with("auto")) { + m_rule.offset = Vector2D(-INT32_MAX, -INT32_MAX); + // If this is the first monitor rule needs to be on the right. + if (value == "auto-right" || value == "auto" || isFirst) + m_rule.autoDir = eAutoDirs::DIR_AUTO_RIGHT; + else if (value == "auto-left") + m_rule.autoDir = eAutoDirs::DIR_AUTO_LEFT; + else if (value == "auto-up") + m_rule.autoDir = eAutoDirs::DIR_AUTO_UP; + else if (value == "auto-down") + m_rule.autoDir = eAutoDirs::DIR_AUTO_DOWN; + else { + Debug::log(WARN, + "Invalid auto direction. Valid options are 'auto'," + "'auto-up', 'auto-down', 'auto-left', and 'auto-right'."); + m_error += "invalid auto direction "; + return false; + } + } else { + if (!value.contains("x")) { + m_error += "invalid offset "; + m_rule.offset = Vector2D(-INT32_MAX, -INT32_MAX); + return false; + } else { + m_rule.offset.x = stoi(value.substr(0, value.find_first_of('x'))); + m_rule.offset.y = stoi(value.substr(value.find_first_of('x') + 1)); + } + } + return true; +} + +bool CMonitorRuleParser::parseScale(const std::string& value) { + if (value.starts_with("auto")) + m_rule.scale = -1; + else { + if (!isNumber(value, true)) { + m_error += "invalid scale "; + return false; + } else { + m_rule.scale = stof(value); + + if (m_rule.scale < 0.25f) { + m_error += "invalid scale "; + m_rule.scale = 1; + return false; + } + } + } + return true; +} + +bool CMonitorRuleParser::parseTransform(const std::string& value) { + const auto TSF = std::stoi(value); + if (std::clamp(TSF, 0, 7) != TSF) { + Debug::log(ERR, "Invalid transform {} in monitor", TSF); + m_error += "invalid transform "; + return false; + } + m_rule.transform = (wl_output_transform)TSF; + return true; +} + +bool CMonitorRuleParser::parseBitdepth(const std::string& value) { + m_rule.enable10bit = value == "10"; + return true; +} + +bool CMonitorRuleParser::parseCM(const std::string& value) { + if (value == "auto") + m_rule.cmType = CM_AUTO; + else if (value == "srgb") + m_rule.cmType = CM_SRGB; + else if (value == "wide") + m_rule.cmType = CM_WIDE; + else if (value == "edid") + m_rule.cmType = CM_EDID; + else if (value == "hdr") + m_rule.cmType = CM_HDR; + else if (value == "hdredid") + m_rule.cmType = CM_HDR_EDID; + else { + m_error += "invalid cm "; + return false; + } + return true; +} + +bool CMonitorRuleParser::parseSDRBrightness(const std::string& value) { + try { + m_rule.sdrBrightness = stof(value); + } catch (...) { + m_error += "invalid sdrbrightness "; + return false; + } + return true; +} + +bool CMonitorRuleParser::parseSDRSaturation(const std::string& value) { + try { + m_rule.sdrSaturation = stof(value); + } catch (...) { + m_error += "invalid sdrsaturation "; + return false; + } + return true; +} + +bool CMonitorRuleParser::parseVRR(const std::string& value) { + if (!isNumber(value)) { + m_error += "invalid vrr "; + return false; + } + + m_rule.vrr = std::stoi(value); + return true; +} + +void CMonitorRuleParser::setDisabled() { + m_rule.disabled = true; +} + +void CMonitorRuleParser::setMirror(const std::string& value) { + m_rule.mirrorOf = value; +} + +bool CMonitorRuleParser::setReserved(const SMonitorAdditionalReservedArea& value) { + g_pConfigManager->m_mAdditionalReservedAreas[name()] = value; + return true; +} + std::optional CConfigManager::handleMonitor(const std::string& command, const std::string& args) { // get the monitor config - SMonitorRule newrule; + const auto ARGS = CVarList(args); - const auto ARGS = CVarList(args); - - newrule.name = ARGS[0]; + auto parser = CMonitorRuleParser(ARGS[0]); if (ARGS[1] == "disable" || ARGS[1] == "disabled" || ARGS[1] == "addreserved" || ARGS[1] == "transform") { if (ARGS[1] == "disable" || ARGS[1] == "disabled") - newrule.disabled = true; + parser.setDisabled(); else if (ARGS[1] == "transform") { - const auto TSF = std::stoi(ARGS[2]); - if (std::clamp(TSF, 0, 7) != TSF) { - Debug::log(ERR, "Invalid transform {} in monitor", TSF); - return "invalid transform"; - } + if (!parser.parseTransform(ARGS[2])) + return parser.getError(); - const auto TRANSFORM = (wl_output_transform)TSF; + const auto TRANSFORM = parser.rule().transform; // overwrite if exists for (auto& r : m_monitorRules) { - if (r.name == newrule.name) { + if (r.name == parser.name()) { r.transform = TRANSFORM; return {}; } @@ -1987,179 +2242,53 @@ std::optional CConfigManager::handleMonitor(const std::string& comm return {}; } else if (ARGS[1] == "addreserved") { - int top = std::stoi(ARGS[2]); - - int bottom = std::stoi(ARGS[3]); - - int left = std::stoi(ARGS[4]); - - int right = std::stoi(ARGS[5]); - - m_mAdditionalReservedAreas[newrule.name] = {top, bottom, left, right}; - + parser.setReserved({.top = std::stoi(ARGS[2]), .bottom = std::stoi(ARGS[3]), .left = std::stoi(ARGS[4]), .right = std::stoi(ARGS[5])}); return {}; } else { Debug::log(ERR, "ConfigManager parseMonitor, curitem bogus???"); return "parse error: curitem bogus"; } - std::erase_if(m_monitorRules, [&](const auto& other) { return other.name == newrule.name; }); + std::erase_if(m_monitorRules, [&](const auto& other) { return other.name == parser.name(); }); - m_monitorRules.push_back(newrule); + m_monitorRules.push_back(parser.rule()); return {}; } - std::string error = ""; - - if (ARGS[1].starts_with("pref")) { - newrule.resolution = Vector2D(); - } else if (ARGS[1].starts_with("highrr")) { - newrule.resolution = Vector2D(-1, -1); - } else if (ARGS[1].starts_with("highres")) { - newrule.resolution = Vector2D(-1, -2); - } else if (ARGS[1].starts_with("maxwidth")) { - newrule.resolution = Vector2D(-1, -3); - } else if (parseModeLine(ARGS[1], newrule.drmMode)) { - newrule.resolution = Vector2D(newrule.drmMode.hdisplay, newrule.drmMode.vdisplay); - newrule.refreshRate = float(newrule.drmMode.vrefresh) / 1000; - } else { - - if (!ARGS[1].contains("x")) { - error += "invalid resolution "; - newrule.resolution = Vector2D(); - } else { - try { - newrule.resolution.x = stoi(ARGS[1].substr(0, ARGS[1].find_first_of('x'))); - newrule.resolution.y = stoi(ARGS[1].substr(ARGS[1].find_first_of('x') + 1, ARGS[1].find_first_of('@'))); - - if (ARGS[1].contains("@")) - newrule.refreshRate = stof(ARGS[1].substr(ARGS[1].find_first_of('@') + 1)); - } catch (...) { - error += "invalid resolution "; - newrule.resolution = Vector2D(); - } - } - } - - if (ARGS[2].starts_with("auto")) { - newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX); - // If this is the first monitor rule needs to be on the right. - if (ARGS[2] == "auto-right" || ARGS[2] == "auto" || m_monitorRules.empty()) - newrule.autoDir = eAutoDirs::DIR_AUTO_RIGHT; - else if (ARGS[2] == "auto-left") - newrule.autoDir = eAutoDirs::DIR_AUTO_LEFT; - else if (ARGS[2] == "auto-up") - newrule.autoDir = eAutoDirs::DIR_AUTO_UP; - else if (ARGS[2] == "auto-down") - newrule.autoDir = eAutoDirs::DIR_AUTO_DOWN; - else if (ARGS[2] == "auto-center-right") - newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_RIGHT; - else if (ARGS[2] == "auto-center-left") - newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_LEFT; - else if (ARGS[2] == "auto-center-up") - newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_UP; - else if (ARGS[2] == "auto-center-down") - newrule.autoDir = eAutoDirs::DIR_AUTO_CENTER_DOWN; - else { - Debug::log(WARN, - "Invalid auto direction. Valid options are 'auto'," - "'auto-up', 'auto-down', 'auto-left', 'auto-right'," - "'auto-center-up', 'auto-center-down'," - "'auto-center-left', and 'auto-center-right'."); - error += "invalid auto direction "; - } - } else { - if (!ARGS[2].contains("x")) { - error += "invalid offset "; - newrule.offset = Vector2D(-INT32_MAX, -INT32_MAX); - } else { - newrule.offset.x = stoi(ARGS[2].substr(0, ARGS[2].find_first_of('x'))); - newrule.offset.y = stoi(ARGS[2].substr(ARGS[2].find_first_of('x') + 1)); - } - } - - if (ARGS[3].starts_with("auto")) { - newrule.scale = -1; - } else { - if (!isNumber(ARGS[3], true)) - error += "invalid scale "; - else { - newrule.scale = stof(ARGS[3]); - - if (newrule.scale < 0.25f) { - error += "invalid scale "; - newrule.scale = 1; - } - } - } + parser.parseMode(ARGS[1]); + parser.parsePosition(ARGS[2]); + parser.parseScale(ARGS[3]); int argno = 4; while (!ARGS[argno].empty()) { if (ARGS[argno] == "mirror") { - newrule.mirrorOf = ARGS[argno + 1]; + parser.setMirror(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "bitdepth") { - newrule.enable10bit = ARGS[argno + 1] == "10"; + parser.parseBitdepth(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "cm") { - if (ARGS[argno + 1] == "auto") - newrule.cmType = CM_AUTO; - else if (ARGS[argno + 1] == "srgb") - newrule.cmType = CM_SRGB; - else if (ARGS[argno + 1] == "wide") - newrule.cmType = CM_WIDE; - else if (ARGS[argno + 1] == "edid") - newrule.cmType = CM_EDID; - else if (ARGS[argno + 1] == "hdr") - newrule.cmType = CM_HDR; - else if (ARGS[argno + 1] == "hdredid") - newrule.cmType = CM_HDR_EDID; - else - error = "invalid cm "; + parser.parseCM(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "sdrsaturation") { - try { - newrule.sdrSaturation = stof(ARGS[argno + 1]); - } catch (...) { error = "invalid sdrsaturation "; } + parser.parseSDRSaturation(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "sdrbrightness") { - try { - newrule.sdrBrightness = stof(ARGS[argno + 1]); - } catch (...) { error = "invalid sdrbrightness "; } + parser.parseSDRBrightness(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "transform") { - if (!isNumber(ARGS[argno + 1])) { - error = "invalid transform "; - argno++; - continue; - } - - const auto NUM = std::stoi(ARGS[argno + 1]); - - if (NUM < 0 || NUM > 7) { - error = "invalid transform "; - argno++; - continue; - } - - newrule.transform = (wl_output_transform)std::stoi(ARGS[argno + 1]); + parser.parseTransform(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "vrr") { - if (!isNumber(ARGS[argno + 1])) { - error = "invalid vrr "; - argno++; - continue; - } - - newrule.vrr = std::stoi(ARGS[argno + 1]); + parser.parseVRR(ARGS[argno + 1]); argno++; } else if (ARGS[argno] == "workspace") { const auto& [id, name] = getWorkspaceIDNameFromString(ARGS[argno + 1]); SWorkspaceRule wsRule; - wsRule.monitor = newrule.name; + wsRule.monitor = parser.name(); wsRule.workspaceString = ARGS[argno + 1]; wsRule.workspaceId = id; wsRule.workspaceName = name; @@ -2174,13 +2303,13 @@ std::optional CConfigManager::handleMonitor(const std::string& comm argno++; } + auto newrule = parser.rule(); + std::erase_if(m_monitorRules, [&](const auto& other) { return other.name == newrule.name; }); m_monitorRules.push_back(newrule); - if (error.empty()) - return {}; - return error; + return parser.getError(); } std::optional CConfigManager::handleBezier(const std::string& command, const std::string& args) { diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index 134292e5..2d8446b5 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -27,6 +27,8 @@ #define HANDLE void* +class CConfigManager; + struct SWorkspaceRule { std::string monitor = ""; std::string workspaceString = ""; @@ -170,6 +172,32 @@ namespace std { }; } +class CMonitorRuleParser { + public: + CMonitorRuleParser(const std::string& name); + + const std::string& name(); + SMonitorRule& rule(); + std::optional getError(); + bool parseMode(const std::string& value); + bool parsePosition(const std::string& value, bool isFirst = false); + bool parseScale(const std::string& value); + bool parseTransform(const std::string& value); + bool parseBitdepth(const std::string& value); + bool parseCM(const std::string& value); + bool parseSDRBrightness(const std::string& value); + bool parseSDRSaturation(const std::string& value); + bool parseVRR(const std::string& value); + + void setDisabled(); + void setMirror(const std::string& value); + bool setReserved(const SMonitorAdditionalReservedArea& value); + + private: + SMonitorRule m_rule; + std::string m_error = ""; +}; + class CConfigManager { public: CConfigManager(); @@ -257,6 +285,9 @@ class CConfigManager { std::optional handlePlugin(const std::string&, const std::string&); std::optional handlePermission(const std::string&, const std::string&); + std::optional handleMonitorv2(const std::string& output); + Hyprlang::CParseResult handleMonitorv2(); + std::string m_configCurrentPath; bool m_wantsMonitorReload = false; @@ -307,6 +338,7 @@ class CConfigManager { std::optional resetHLConfig(); std::optional generateConfig(std::string configPath); std::optional verifyConfigExists(); + void postConfigReload(const Hyprlang::CParseResult& result); SWorkspaceRule mergeWorkspaceRules(const SWorkspaceRule&, const SWorkspaceRule&); @@ -319,6 +351,7 @@ class CConfigManager { std::unordered_map m_mStoredFloatingSizes; friend struct SConfigOptionDescription; + friend class CMonitorRuleParser; }; inline UP g_pConfigManager; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 77f54c2b..11f8b39a 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1109,6 +1109,9 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) if (COMMAND == "monitor" || COMMAND == "source") g_pConfigManager->m_wantsMonitorReload = true; // for monitor keywords + if (COMMAND.contains("monitorv2")) + g_pEventLoopManager->doLater([] { g_pConfigManager->m_wantsMonitorReload = true; }); + if (COMMAND.contains("input") || COMMAND.contains("device") || COMMAND == "source") { g_pInputManager->setKeyboardLayout(); // update kb layout g_pInputManager->setPointerConfigs(); // update mouse cfgs From 423b69f5d3c76762e05c1511a10942714dea4e8e Mon Sep 17 00:00:00 2001 From: Eric Li Date: Thu, 5 Jun 2025 16:17:04 -0400 Subject: [PATCH 1557/2393] config: add group: selector (#10588) --- src/config/ConfigManager.cpp | 19 +++++++++++++++++-- src/desktop/WindowRule.hpp | 3 ++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 735d9703..025be9f7 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1434,6 +1434,7 @@ std::vector> CConfigManager::getMatchingRules(PHLWINDOW pWindow, // since some rules will be applied later, we need to store some flags bool hasFloating = pWindow->m_isFloating; bool hasFullscreen = pWindow->isFullscreen(); + bool isGrouped = pWindow->m_groupData.pNextWindow; // local tags for dynamic tag rule match auto tags = pWindow->m_tags; @@ -1482,6 +1483,11 @@ std::vector> CConfigManager::getMatchingRules(PHLWINDOW pWindow, continue; } + if (rule->m_group != -1) { + if (rule->m_group != isGrouped) + continue; + } + if (!rule->m_fullscreenState.empty()) { const auto ARGS = CVarList(rule->m_fullscreenState, 2, ' '); // @@ -2576,6 +2582,7 @@ std::optional CConfigManager::handleWindowRule(const std::string& c const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); const auto CONTENTTYPEPOS = VALUE.find("content:"); const auto XDGTAGPOS = VALUE.find("xdgTag:"); + const auto GROUPPOS = VALUE.find("group:"); // find workspacepos that isn't onworkspacepos size_t WORKSPACEPOS = std::string::npos; @@ -2588,8 +2595,8 @@ std::optional CConfigManager::handleWindowRule(const std::string& c currentPos = VALUE.find("workspace:", currentPos + 1); } - const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, - PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, CONTENTTYPEPOS, XDGTAGPOS}; + const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, FULLSCREENPOS, + PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, CONTENTTYPEPOS, XDGTAGPOS, GROUPPOS}; if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; @@ -2630,6 +2637,8 @@ std::optional CConfigManager::handleWindowRule(const std::string& c min = CONTENTTYPEPOS; if (XDGTAGPOS > pos && XDGTAGPOS < min) min = XDGTAGPOS; + if (GROUPPOS > pos && GROUPPOS < min) + min = GROUPPOS; result = result.substr(0, min - pos); @@ -2694,6 +2703,9 @@ std::optional CConfigManager::handleWindowRule(const std::string& c if (XDGTAGPOS != std::string::npos) rule->m_xdgTag = extract(XDGTAGPOS + 8); + if (GROUPPOS != std::string::npos) + rule->m_group = extract(GROUPPOS + 6) == "1" ? 1 : 0; + if (RULE == "unset") { std::erase_if(m_windowRules, [&](const auto& other) { if (!other->m_v2) @@ -2741,6 +2753,9 @@ std::optional CConfigManager::handleWindowRule(const std::string& c if (!rule->m_contentType.empty() && rule->m_contentType != other->m_contentType) return false; + if (rule->m_group != -1 && rule->m_group != other->m_group) + return false; + return true; } }); diff --git a/src/desktop/WindowRule.hpp b/src/desktop/WindowRule.hpp index 9af3909a..b828c8ee 100644 --- a/src/desktop/WindowRule.hpp +++ b/src/desktop/WindowRule.hpp @@ -58,6 +58,7 @@ class CWindowRule { int m_fullscreen = -1; int m_pinned = -1; int m_focus = -1; + int m_group = -1; std::string m_fullscreenState = ""; // empty means any std::string m_onWorkspace = ""; // empty means any std::string m_workspace = ""; // empty means any @@ -70,4 +71,4 @@ class CWindowRule { CRuleRegexContainer m_initialTitleRegex; CRuleRegexContainer m_initialClassRegex; CRuleRegexContainer m_v1Regex; -}; \ No newline at end of file +}; From fb7548cb41d82f12db2d51b50af29abe4704a1a4 Mon Sep 17 00:00:00 2001 From: XPhyro Date: Thu, 5 Jun 2025 23:29:01 +0300 Subject: [PATCH 1558/2393] screencopy: fix applying `noscreenshare` to invisible special workspaces (#10628) --- src/protocols/Screencopy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8002776a..3ad57ed7 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -206,7 +206,7 @@ void CScreencopyFrame::renderMon() { if (!w->m_windowData.noScreenShare.valueOrDefault()) continue; - if (!g_pHyprRenderer->shouldRenderWindow(w)) + if (!g_pHyprRenderer->shouldRenderWindow(w, m_monitor.lock())) continue; const auto PWORKSPACE = w->m_workspace; From d6fbd89336f2f0b631856e6a68a9d62c772ef50f Mon Sep 17 00:00:00 2001 From: Friday Date: Thu, 5 Jun 2025 22:02:58 +0100 Subject: [PATCH 1559/2393] nix: use gcc15-built dependencies --- flake.lock | 66 +++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/flake.lock b/flake.lock index 01b437e6..ba7d34bf 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1747864449, - "narHash": "sha256-PIjVAWghZhr3L0EFM2UObhX84UQxIACbON0IC0zzSKA=", + "lastModified": 1749155310, + "narHash": "sha256-t0HfHg/1+TbSra5s6nNM0o4tnb3uqWedShSpZXsUMYY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "389372c5f4dc1ac0e7645ed29a35fd6d71672ef5", + "rev": "94981cf75a9f11da0b6dd6a1abbd7c50a36ab2d3", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1745948457, - "narHash": "sha256-lzTV10FJTCGNtMdgW5YAhCAqezeAzKOd/97HbQK8GTU=", + "lastModified": 1749155331, + "narHash": "sha256-XR9fsI0zwLiFWfqi/pdS/VD+YNorKb3XIykgTg4l1nA=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "ac903e80b33ba6a88df83d02232483d99f327573", + "rev": "45fcc10b4c282746d93ec406a740c43b48b4ef80", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1745015490, - "narHash": "sha256-apEJ9zoSzmslhJ2vOKFcXTMZLUFYzh1ghfB6Rbw3Low=", + "lastModified": 1749145600, + "narHash": "sha256-v2kY5RDk9oyo1x9m8u83GdklC96xlJ7ka1rrvZoYL78=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "60754910946b4e2dc1377b967b7156cb989c5873", + "rev": "80b754e38e836777ad3a9d5d1ffc3491b0332471", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1743714874, - "narHash": "sha256-yt8F7NhMFCFHUHy/lNjH/pjZyIDFNk52Q4tivQ31WFo=", + "lastModified": 1749046714, + "narHash": "sha256-kymV5FMnddYGI+UjwIw8ceDjdeg7ToDVjbHCvUlhn14=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "3a5c2bda1c1a4e55cc1330c782547695a93f05b2", + "rev": "613878cb6f459c5e323aaafe1e6f388ac8a36330", "type": "github" }, "original": { @@ -157,11 +157,11 @@ ] }, "locked": { - "lastModified": 1737634706, - "narHash": "sha256-nGCibkfsXz7ARx5R+SnisRtMq21IQIhazp6viBU8I/A=", + "lastModified": 1749154592, + "narHash": "sha256-DO7z5CeT/ddSGDEnK9mAXm1qlGL47L3VAHLlLXoCjhE=", "owner": "hyprwm", "repo": "hyprland-qt-support", - "rev": "8810df502cdee755993cb803eba7b23f189db795", + "rev": "4c8053c3c888138a30c3a6c45c2e45f5484f2074", "type": "github" }, "original": { @@ -189,11 +189,11 @@ ] }, "locked": { - "lastModified": 1745951494, - "narHash": "sha256-2dModE32doiyQMmd6EDAQeZnz+5LOs6KXyE0qX76WIg=", + "lastModified": 1749155776, + "narHash": "sha256-t1PM0wxQLQwv2F2AW23uA7pm5giwmcgYEWbNIRct9r4=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "4be1d324faf8d6e82c2be9f8510d299984dfdd2e", + "rev": "396e8aa1c06274835b69da7f9a015fff9a9b7522", "type": "github" }, "original": { @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1747484975, - "narHash": "sha256-+LAQ81HBwG0lwshHlWe0kfWg4KcChIPpnwtnwqmnoEU=", + "lastModified": 1749145882, + "narHash": "sha256-qr0KXeczF8Sma3Ae7+dR2NHhvG7YeLBJv19W4oMu6ZE=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "163c83b3db48a17c113729c220a60b94596c9291", + "rev": "1bfb84f54d50c7ae6558c794d3cfd5f6a7e6e676", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1746635225, - "narHash": "sha256-W9G9bb0zRYDBRseHbVez0J8qVpD5QbizX67H/vsudhM=", + "lastModified": 1749135356, + "narHash": "sha256-Q8mAKMDsFbCEuq7zoSlcTuxgbIBVhfIYpX0RjE32PS0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "674ea57373f08b7609ce93baff131117a0dfe70d", + "rev": "e36db00dfb3a3d3fdcc4069cb292ff60d2699ccb", "type": "github" }, "original": { @@ -261,11 +261,11 @@ ] }, "locked": { - "lastModified": 1747584298, - "narHash": "sha256-PH9qZqWLHvSBQiUnA0NzAyQA3tu2no2z8kz0ZeHWj4w=", + "lastModified": 1749145760, + "narHash": "sha256-IHaGWpGrv7seFWdw/1A+wHtTsPlOGIKMrk1TUIYJEFI=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "e511882b9c2e1d7a75d45d8fddd2160daeafcbc3", + "rev": "817918315ea016cc2d94004bfb3223b5fd9dfcc6", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1748460289, - "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=", + "lastModified": 1748929857, + "narHash": "sha256-lcZQ8RhsmhsK8u7LIFsJhsLh/pzR9yZ8yqpTzyGdj+Q=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102", + "rev": "c2a03962b8e24e669fb37b7df10e7c79531ff1a4", "type": "github" }, "original": { @@ -365,11 +365,11 @@ ] }, "locked": { - "lastModified": 1745871725, - "narHash": "sha256-M24SNc2flblWGXFkGQfqSlEOzAGZnMc9QG3GH4K/KbE=", + "lastModified": 1749155346, + "narHash": "sha256-KIkJu3zF8MF3DuGwzAmo3Ww9wsWXolwV30SjJRTAxYE=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "76bbf1a6b1378e4ab5230bad00ad04bc287c969e", + "rev": "44bf29f1df45786098920c655af523535a9191ae", "type": "github" }, "original": { From c35c2fea409a845b1023151a2b642f4aa077dacc Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 6 Jun 2025 10:01:19 +0300 Subject: [PATCH 1560/2393] config: Restore auto-center-* for monitors (#10660) --- src/config/ConfigManager.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 025be9f7..0632018c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2103,10 +2103,20 @@ bool CMonitorRuleParser::parsePosition(const std::string& value, bool isFirst) { m_rule.autoDir = eAutoDirs::DIR_AUTO_UP; else if (value == "auto-down") m_rule.autoDir = eAutoDirs::DIR_AUTO_DOWN; + else if (value == "auto-center-right") + m_rule.autoDir = eAutoDirs::DIR_AUTO_CENTER_RIGHT; + else if (value == "auto-center-left") + m_rule.autoDir = eAutoDirs::DIR_AUTO_CENTER_LEFT; + else if (value == "auto-center-up") + m_rule.autoDir = eAutoDirs::DIR_AUTO_CENTER_UP; + else if (value == "auto-center-down") + m_rule.autoDir = eAutoDirs::DIR_AUTO_CENTER_DOWN; else { Debug::log(WARN, "Invalid auto direction. Valid options are 'auto'," - "'auto-up', 'auto-down', 'auto-left', and 'auto-right'."); + "'auto-up', 'auto-down', 'auto-left', 'auto-right'," + "'auto-center-up', 'auto-center-down'," + "'auto-center-left', and 'auto-center-right'."); m_error += "invalid auto direction "; return false; } From 456c820d52263579e4afdc3429fdaecab12f37a5 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 6 Jun 2025 15:11:12 +0200 Subject: [PATCH 1561/2393] assets: update header --- assets/header.svg | 128 ++++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/assets/header.svg b/assets/header.svg index c8cf8222..a2b32551 100644 --- a/assets/header.svg +++ b/assets/header.svg @@ -1,72 +1,64 @@ - - -
- - - -

Hyprland

-
-
-
-
+ .st4 { + fill: url(#e); + } + + .st5 { + fill: url(#f); + } + + .st6 { + fill: url(#g); + } + + .st7 { + fill: url(#h); + } + + .st8 { + fill: url(#i); + } +