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 01/92] 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 02/92] 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 03/92] 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 04/92] 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 05/92] 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 06/92] 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 07/92] 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 08/92] 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 09/92] 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 10/92] 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 11/92] 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 12/92] 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 13/92] 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 14/92] 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 15/92] 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 16/92] 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 17/92] 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 18/92] 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 19/92] 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 20/92] 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 21/92] 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 22/92] 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 23/92] 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 24/92] 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 25/92] 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 26/92] 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 27/92] 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 28/92] 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 29/92] 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 30/92] 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 31/92] 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 32/92] 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 33/92] 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 34/92] [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 35/92] 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 36/92] 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 37/92] 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 38/92] 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 39/92] 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 40/92] 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 41/92] 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 42/92] 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 43/92] 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 44/92] 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 45/92] 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 46/92] 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 47/92] 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 48/92] 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 49/92] 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 50/92] 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 51/92] 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 52/92] 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 53/92] 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 54/92] 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 55/92] 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 56/92] 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 57/92] 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 58/92] 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 59/92] 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 60/92] 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 61/92] 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 62/92] 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 63/92] 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 64/92] 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 65/92] 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 66/92] 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 67/92] 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 68/92] 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 69/92] 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 70/92] 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 71/92] 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 72/92] 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 73/92] 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 74/92] 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 75/92] 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 76/92] 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 77/92] 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 78/92] 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 79/92] 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 80/92] 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 81/92] 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 82/92] 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 83/92] 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 84/92] 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 85/92] 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 86/92] 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 87/92] 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 88/92] 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 89/92] 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 90/92] 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 91/92] 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 92/92] 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) {