From 2a478c30cab89c8c608936ca966155da5b16728d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 27 Jan 2025 13:41:38 +0000 Subject: [PATCH 0001/1257] core: fix clang-format --- src/render/Renderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 3f6448d5..67d8b58b 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -337,7 +337,8 @@ void CHyprRenderer::renderWorkspaceWindowsFullscreen(PHLMONITOR pMonitor, PHLWOR // then render windows over fullscreen. for (auto const& w : g_pCompositor->m_vWindows) { - if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || !w->m_bIsFloating || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || w->isFullscreen()) + if (w->m_pWorkspace != pWorkspaceWindow->m_pWorkspace || !w->m_bIsFloating || (!w->m_bCreatedOverFullscreen && !w->m_bPinned) || (!w->m_bIsMapped && !w->m_bFadingOut) || + w->isFullscreen()) continue; if (w->m_pMonitor == pWorkspace->m_pMonitor && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) From cb7ed4f62b195ab7d5f21fa393218170cfbb95c8 Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Tue, 28 Jan 2025 00:41:26 +0800 Subject: [PATCH 0002/1257] ci: clang-format fix (#9145) * move * revert, comment via peter-evans/commit-comment@v3 * remove --- .github/workflows/ci.yaml | 24 --------------- .github/workflows/clang-format.yml | 48 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/clang-format.yml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 34c45d6b..416ea93b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -127,27 +127,3 @@ jobs: - name: clang-format check run: ninja -C build clang-format-check - - - name: clang-format apply - if: ${{ failure() && github.event_name == 'pull_request' }} - run: ninja -C build clang-format - - - name: Create patch - if: ${{ failure() && github.event_name == 'pull_request' }} - run: | - echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch - echo '
' >> clang-format.patch - echo 'clang-format.patch' >> clang-format.patch - echo >> clang-format.patch - echo '```diff' >> clang-format.patch - git diff >> clang-format.patch - echo '```' >> clang-format.patch - echo >> clang-format.patch - echo '
' >> clang-format.patch - - - name: Comment patch - if: ${{ failure() && github.event_name == 'pull_request' }} - uses: mshick/add-pr-comment@v2 - with: - message-path: | - clang-format.patch diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 00000000..e935a605 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,48 @@ +name: clang-format +on: pull_request_target +jobs: + clang-format: + permissions: write-all + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork + name: "Code Style (Arch)" + runs-on: ubuntu-latest + container: + image: archlinux + steps: + - name: Checkout repository actions + uses: actions/checkout@v4 + with: + sparse-checkout: .github/actions + + - name: Setup base + uses: ./.github/actions/setup_base + + - name: Configure + run: meson setup build -Ddefault_library=static + + - name: clang-format check + run: ninja -C build clang-format-check + + - name: clang-format apply + if: ${{ failure() && github.event_name == 'pull_request' }} + run: ninja -C build clang-format + + - name: Create patch + if: ${{ failure() && github.event_name == 'pull_request' }} + run: | + echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style), or directly apply this patch:' > clang-format.patch + echo '
' >> clang-format.patch + echo 'clang-format.patch' >> clang-format.patch + echo >> clang-format.patch + echo '```diff' >> clang-format.patch + git diff >> clang-format.patch + echo '```' >> clang-format.patch + echo >> clang-format.patch + echo '
' >> clang-format.patch + + - name: Comment patch + if: ${{ failure() && github.event_name == 'pull_request' }} + uses: mshick/add-pr-comment@v2 + with: + message-path: | + clang-format.patch From e7a72de9b5550784ea804c7bb4e84a28a74326a8 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Tue, 28 Jan 2025 00:45:15 +0800 Subject: [PATCH 0003/1257] xwayland: send synthetic configure events (#9193) --- src/xwayland/XSurface.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index b5ee75f6..91f20be5 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -169,6 +169,22 @@ void CXWaylandSurface::configure(const CBox& box) { uint32_t values[] = {box.x, box.y, box.width, box.height, 0}; xcb_configure_window(g_pXWayland->pWM->connection, xID, mask, values); + if (geometry.width == box.width && geometry.height == box.height) { + // ICCCM requires a synthetic event when window size is not changed + xcb_configure_notify_event_t e; + e.response_type = XCB_CONFIGURE_NOTIFY; + e.event = xID; + e.window = xID; + e.x = box.x; + e.y = box.y; + e.width = box.width; + e.height = box.height; + e.border_width = 0; + e.above_sibling = XCB_NONE; + e.override_redirect = overrideRedirect; + xcb_send_event(g_pXWayland->pWM->connection, false, xID, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char*)&e); + } + g_pXWayland->pWM->updateClientList(); xcb_flush(g_pXWayland->pWM->connection); From 25d5ce4833a481325a2a948f51cabb6f4a6e1896 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 27 Jan 2025 22:25:27 +0200 Subject: [PATCH 0004/1257] CI/setup_base: add libspng --- .github/actions/setup_base/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index 6df442b3..b4c9cf78 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -35,6 +35,7 @@ runs: libinput \ libjxl \ libliftoff \ + libspng \ libwebp \ libxcursor \ libxcvt \ From 5fd90548dc99d79dd2677e027a620c8ada9f4869 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Mon, 27 Jan 2025 14:19:47 -0500 Subject: [PATCH 0005/1257] nix: fix duplicate inputs and update flake.lock --- flake.lock | 95 +++++++++++++----------------------------------------- flake.nix | 2 +- 2 files changed, 24 insertions(+), 73 deletions(-) diff --git a/flake.lock b/flake.lock index 34249b0a..ac73e5f7 100644 --- a/flake.lock +++ b/flake.lock @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1737634889, - "narHash": "sha256-9JZE3KxcXOqZH9zs3UeadngDiK/yIACTiAR8HSA/TNI=", + "lastModified": 1737985436, + "narHash": "sha256-zx8FdI4zr2GhNyD1YGAqa2ymodAObTSAdwuWwVucewo=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "0d77b4895ad5f1bb3b0ee43103a5246c58b65591", + "rev": "23783b96036f5506fdaf8b2250a1ef849d57f0d3", "type": "github" }, "original": { @@ -143,7 +143,10 @@ }, "hyprland-qt-support": { "inputs": { - "hyprlang": "hyprlang", + "hyprlang": [ + "hyprland-qtutils", + "hyprlang" + ], "nixpkgs": [ "hyprland-qtutils", "nixpkgs" @@ -170,7 +173,12 @@ "hyprland-qtutils": { "inputs": { "hyprland-qt-support": "hyprland-qt-support", + "hyprlang": [ + "hyprlang" + ], "hyprutils": [ + "hyprland-qtutils", + "hyprlang", "hyprutils" ], "nixpkgs": [ @@ -181,11 +189,11 @@ ] }, "locked": { - "lastModified": 1737811848, - "narHash": "sha256-WZ7LeiKHk5Y94MU5gHIWn0r8asWxYOvie4LqfCjVIZU=", + "lastModified": 1737981711, + "narHash": "sha256-lh6cL5D8nPplB3WovCQjLUZ7k7MViiBrMlpkfm4R7/c=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "9c0831ff98856c0f312fcb8b57553fbe3dd34d5b", + "rev": "96bf0677fa9cd13508294e3d4559dfbbc8beff73", "type": "github" }, "original": { @@ -195,34 +203,6 @@ } }, "hyprlang": { - "inputs": { - "hyprutils": "hyprutils", - "nixpkgs": [ - "hyprland-qtutils", - "hyprland-qt-support", - "nixpkgs" - ], - "systems": [ - "hyprland-qtutils", - "hyprland-qt-support", - "systems" - ] - }, - "locked": { - "lastModified": 1737634606, - "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", - "owner": "hyprwm", - "repo": "hyprlang", - "rev": "f41271d35cc0f370d300413d756c2677f386af9d", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprlang", - "type": "github" - } - }, - "hyprlang_2": { "inputs": { "hyprutils": [ "hyprutils" @@ -249,35 +229,6 @@ } }, "hyprutils": { - "inputs": { - "nixpkgs": [ - "hyprland-qtutils", - "hyprland-qt-support", - "hyprlang", - "nixpkgs" - ], - "systems": [ - "hyprland-qtutils", - "hyprland-qt-support", - "hyprlang", - "systems" - ] - }, - "locked": { - "lastModified": 1737632363, - "narHash": "sha256-X9I8POSlHxBVjD0fiX1O2j7U9Zi1+4rIkrsyHP0uHXY=", - "owner": "hyprwm", - "repo": "hyprutils", - "rev": "006620eb29d54ea9086538891404c78563d1bae1", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprutils", - "type": "github" - } - }, - "hyprutils_2": { "inputs": { "nixpkgs": [ "nixpkgs" @@ -287,11 +238,11 @@ ] }, "locked": { - "lastModified": 1737725508, - "narHash": "sha256-jGmcPc6y/prg/4A8KGYqJ27nSPaProCMiFadaxNAKvA=", + "lastModified": 1737978343, + "narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "fb0c2d1de3d1ef7396d19c18ac09e12bd956929e", + "rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab", "type": "github" }, "original": { @@ -325,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737632463, - "narHash": "sha256-38J9QfeGSej341ouwzqf77WIHAScihAKCt8PQJ+NH28=", + "lastModified": 1737885589, + "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0aa475546ed21629c4f5bbf90e38c846a99ec9e9", + "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", "type": "github" }, "original": { @@ -368,8 +319,8 @@ "hyprgraphics": "hyprgraphics", "hyprland-protocols": "hyprland-protocols", "hyprland-qtutils": "hyprland-qtutils", - "hyprlang": "hyprlang_2", - "hyprutils": "hyprutils_2", + "hyprlang": "hyprlang", + "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "pre-commit-hooks": "pre-commit-hooks", diff --git a/flake.nix b/flake.nix index 821a5f90..c1c580ae 100644 --- a/flake.nix +++ b/flake.nix @@ -39,7 +39,7 @@ url = "github:hyprwm/hyprland-qtutils"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; - inputs.hyprutils.follows = "hyprutils"; + inputs.hyprlang.follows = "hyprlang"; }; hyprlang = { From d2773d7a4ecde7111af4ec71b51b1996ec1d96bf Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Mon, 27 Jan 2025 22:06:48 +0000 Subject: [PATCH 0006/1257] deps: add libinotify-kqueue on BSDs after 8dd2cd41fb4c (#9197) src/config/ConfigWatcher.cpp:2:10: fatal error: 'sys/inotify.h' file not found 2 | #include | ^~~~~~~~~~~~~~~ --- CMakeLists.txt | 6 ++++++ meson.build | 1 + src/meson.build | 1 + 3 files changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cfb8688..a34d677c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,6 +197,12 @@ if(NOT HAS_TIMERFD AND epoll_FOUND) target_link_libraries(Hyprland PkgConfig::epoll) endif() +check_include_file("sys/inotify.h" HAS_INOTIFY) +pkg_check_modules(inotify IMPORTED_TARGET libinotify) +if(NOT HAS_INOTIFY AND inotify_FOUND) + target_link_libraries(Hyprland PkgConfig::inotify) +endif() + if(LEGACY_RENDERER) message(STATUS "Using the legacy GLES2 renderer!") add_compile_definitions(LEGACY_RENDERER) diff --git a/meson.build b/meson.build index 6b50ff2d..ae6e3940 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,7 @@ endif backtrace_dep = cpp_compiler.find_library('execinfo', required: false) epoll_dep = dependency('epoll-shim', required: false) # timerfd on BSDs +inotify_dep = dependency('libinotify', required: false) # inotify on BSDs re2 = dependency('re2', required: true) diff --git a/src/meson.build b/src/meson.build index 7054d8e4..3973dc4c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -32,6 +32,7 @@ executable( xcb_xfixes_dep, backtrace_dep, epoll_dep, + inotify_dep, gio_dep, tracy, From d3042e5358a91287d6ff9d8c745dc70af1ebdc90 Mon Sep 17 00:00:00 2001 From: DDoSolitary Date: Tue, 28 Jan 2025 18:04:57 +0800 Subject: [PATCH 0007/1257] xwayland: respect window size set by configure requests (#9190) --- src/managers/XWaylandManager.cpp | 26 +++----------------------- src/xwayland/XWM.cpp | 4 ++-- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index f103266d..a5506329 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -82,29 +82,9 @@ CBox CHyprXWaylandManager::getGeometryForWindow(PHLWINDOW pWindow) { CBox box; - if (pWindow->m_bIsX11) { - const auto SIZEHINTS = pWindow->m_pXWaylandSurface->sizeHints.get(); - - if (SIZEHINTS && !pWindow->isX11OverrideRedirect()) { - // WM_SIZE_HINTS' x,y,w,h is deprecated it seems. - // Source: https://x.org/releases/X11R7.6/doc/xorg-docs/specs/ICCCM/icccm.html#wm_normal_hints_property - box.x = pWindow->m_pXWaylandSurface->geometry.x; - box.y = pWindow->m_pXWaylandSurface->geometry.y; - - constexpr int ICCCM_USSize = 0x2; - constexpr int ICCCM_PSize = 0x8; - - if ((SIZEHINTS->flags & ICCCM_USSize) || (SIZEHINTS->flags & ICCCM_PSize)) { - box.w = SIZEHINTS->base_width; - box.h = SIZEHINTS->base_height; - } else { - box.w = pWindow->m_pXWaylandSurface->geometry.w; - box.h = pWindow->m_pXWaylandSurface->geometry.h; - } - } else - box = pWindow->m_pXWaylandSurface->geometry; - - } else if (pWindow->m_pXDGSurface) + if (pWindow->m_bIsX11) + box = pWindow->m_pXWaylandSurface->geometry; + else if (pWindow->m_pXDGSurface) box = pWindow->m_pXDGSurface->current.geometry; return box; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index ef139b38..6673105e 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -102,8 +102,8 @@ void CXWM::handleMapRequest(xcb_map_request_event_t* e) { const bool HAS_HINTS = XSURF->sizeHints && Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} > Vector2D{5, 5}; const auto DESIREDSIZE = HAS_HINTS ? Vector2D{XSURF->sizeHints->base_width, XSURF->sizeHints->base_height} : Vector2D{800, 800}; - // if it's too small, or its base size is set, configure it. - if ((SMALL || HAS_HINTS) && !XSURF->overrideRedirect) // default to 800 x 800 + // if it's too small, configure it. + if (SMALL && !XSURF->overrideRedirect) // default to 800 x 800 XSURF->configure({XSURF->geometry.pos(), DESIREDSIZE}); Debug::log(LOG, "[xwm] Mapping window {} in X (geometry {}x{} at {}x{}))", e->window, XSURF->geometry.width, XSURF->geometry.height, XSURF->geometry.x, XSURF->geometry.y); From 529ad4eaf450e558998e7417db5db6602e7fb497 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 28 Jan 2025 10:15:08 +0100 Subject: [PATCH 0008/1257] ikeyboard: free xkbSymState in clearManuallyAllocd asan reported a leak on xkbSymState on destruction, because it wasnt beeing unrefed, was only being unrefed on calls to updateXKBTranslationState. --- src/devices/IKeyboard.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index d1119772..4623fe84 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -44,6 +44,10 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymapFD >= 0) close(xkbKeymapFD); + if (xkbSymState) + xkb_state_unref(xkbSymState); + + xkbSymState = nullptr; xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; From 1d3904c3e7a8b74ea83669f73ee408bd38390b11 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Tue, 28 Jan 2025 10:20:54 +0100 Subject: [PATCH 0009/1257] configmgr: properly free glob memory globfree is only freeing internally allocated resources, so also call free the on glob_t memory we allocated. --- src/config/ConfigManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 93289bf7..daff9285 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2690,8 +2690,14 @@ std::optional CConfigManager::handleSource(const std::string& comma Debug::log(ERR, "source= path garbage"); return "source= path " + rawpath + " bogus!"; } - std::unique_ptr glob_buf{new glob_t, [](glob_t* g) { globfree(g); }}; - memset(glob_buf.get(), 0, sizeof(glob_t)); + + std::unique_ptr glob_buf{static_cast(calloc(1, sizeof(glob_t))), // allocate and zero-initialize + [](glob_t* g) { + if (g) { + globfree(g); // free internal resources allocated by glob() + free(g); // free the memory for the glob_t structure + } + }}; if (auto r = glob(absolutePath(rawpath, configCurrentPath).c_str(), GLOB_TILDE, nullptr, glob_buf.get()); r != 0) { std::string err = std::format("source= globbing error: {}", r == GLOB_NOMATCH ? "found no match" : GLOB_ABORTED ? "read error" : "out of memory"); From 3d1dd6b5c7b90e513e86c1ad27c6c01a5c69e4f8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 28 Jan 2025 23:43:26 +0000 Subject: [PATCH 0010/1257] presentation: log a fixme when there is a feedback leak ref #8087 --- src/protocols/PresentationTime.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index a9139ac0..05fda8ea 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -130,6 +130,11 @@ void CPresentationProtocol::onPresented(PHLMONITOR pMonitor, timespec* when, uin } } + if (m_vFeedbacks.size() > 10000 /* arbitrary number I chose as fitting */) { + LOGM(ERR, "FIXME: presentation has a feedback leak, and has grown to {} pending entries!!! Dropping!!!!!", m_vFeedbacks.size()); + m_vFeedbacks = {m_vFeedbacks.begin() + 9000, m_vFeedbacks.end()}; + } + std::erase_if(m_vFeedbacks, [](const auto& other) { return !other->surface || other->done; }); std::erase_if(m_vQueue, [pMonitor](const auto& other) { return !other->surface || other->pMonitor == pMonitor || !other->pMonitor || other->done; }); } From b884f1f7c88b798ba5d1b6a794615bf046ff1f14 Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 29 Jan 2025 03:41:56 -0500 Subject: [PATCH 0011/1257] renderer: calculate UV using both pixel and monitor dimensions (#9210) --- src/render/OpenGL.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index ee5d9a86..78b53c9b 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -2147,14 +2147,20 @@ void CHyprOpenGLImpl::renderTextureWithBlur(SP tex, const CBox& box, f glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // stencil done. Render everything. - CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; - // render our great blurred FB - // calculate the uv for it const auto LASTTL = m_RenderData.primarySurfaceUVTopLeft; const auto LASTBR = m_RenderData.primarySurfaceUVBottomRight; - m_RenderData.primarySurfaceUVTopLeft = box.pos() / MONITORBOX.size(); - m_RenderData.primarySurfaceUVBottomRight = (box.pos() + box.size()) / MONITORBOX.size(); + CBox transformedBox = box; + transformedBox.transform(wlTransformToHyprutils(invertTransform(m_RenderData.pMonitor->transform)), m_RenderData.pMonitor->vecTransformedSize.x, + m_RenderData.pMonitor->vecTransformedSize.y); + + CBox monitorSpaceBox = {transformedBox.pos().x / m_RenderData.pMonitor->vecPixelSize.x * m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.pos().y / m_RenderData.pMonitor->vecPixelSize.y * m_RenderData.pMonitor->vecTransformedSize.y, + transformedBox.width / m_RenderData.pMonitor->vecPixelSize.x * m_RenderData.pMonitor->vecTransformedSize.x, + transformedBox.height / m_RenderData.pMonitor->vecPixelSize.y * m_RenderData.pMonitor->vecTransformedSize.y}; + + m_RenderData.primarySurfaceUVTopLeft = monitorSpaceBox.pos() / m_RenderData.pMonitor->vecTransformedSize; + m_RenderData.primarySurfaceUVBottomRight = (monitorSpaceBox.pos() + monitorSpaceBox.size()) / m_RenderData.pMonitor->vecTransformedSize; static auto PBLURIGNOREOPACITY = CConfigValue("decoration:blur:ignore_opacity"); setMonitorTransformEnabled(true); From d41135d07c15f122d1ca2a03ace9ed3e080b2e28 Mon Sep 17 00:00:00 2001 From: "Owen L." <32573897+mageowl@users.noreply.github.com> Date: Wed, 29 Jan 2025 01:27:34 -0800 Subject: [PATCH 0012/1257] input: change window grab cursor to closed hand (#9196) --- src/layout/IHyprLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 5e5669b8..57ae5f40 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -307,7 +307,7 @@ void IHyprLayout::onBeginDragWindow() { } if (g_pInputManager->dragMode != MBIND_RESIZE && g_pInputManager->dragMode != MBIND_RESIZE_FORCE_RATIO && g_pInputManager->dragMode != MBIND_RESIZE_BLOCK_RATIO) - g_pInputManager->setCursorImageUntilUnset("grab"); + g_pInputManager->setCursorImageUntilUnset("grabbing"); g_pHyprRenderer->damageWindow(DRAGGINGWINDOW); From 344e32d71bf115a32434da3fa72b2b6238706625 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 29 Jan 2025 10:42:46 +0000 Subject: [PATCH 0013/1257] pass/rect: fix bounding / opaque regions fixes #9212 --- src/render/pass/PassElement.hpp | 4 ++-- src/render/pass/RectPassElement.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/render/pass/PassElement.hpp b/src/render/pass/PassElement.hpp index b45970aa..a006ce9e 100644 --- a/src/render/pass/PassElement.hpp +++ b/src/render/pass/PassElement.hpp @@ -13,7 +13,7 @@ class IPassElement { virtual const char* passName() = 0; virtual void discard(); virtual bool undiscardable(); - virtual std::optional boundingBox(); - virtual CRegion opaqueRegion(); + virtual std::optional boundingBox(); // in monitor-local logical coordinates + virtual CRegion opaqueRegion(); // in monitor-local logical coordinates virtual bool disableSimplification(); }; diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index a9ab737d..fba06286 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -24,7 +24,7 @@ bool CRectPassElement::needsPrecomputeBlur() { } std::optional CRectPassElement::boundingBox() { - return data.box; + return data.box.copy().scale(1.F / g_pHyprOpenGL->m_RenderData.pMonitor->scale).round(); } CRegion CRectPassElement::opaqueRegion() { From aaa5573c73636a76dd3ae4758bfd89ae4d5eeb8a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 29 Jan 2025 10:50:39 +0000 Subject: [PATCH 0014/1257] config/hyprctl: fix keyword not updating autoreload ref #9139 --- src/config/ConfigManager.cpp | 8 ++++++-- src/config/ConfigManager.hpp | 1 + src/debug/HyprCtl.cpp | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index daff9285..047c58d9 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -912,12 +912,16 @@ std::optional CConfigManager::resetHLConfig() { return RET; } +void CConfigManager::updateWatcher() { + static const auto PDISABLEAUTORELOAD = CConfigValue("misc:disable_autoreload"); + g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); +} + void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) { static const auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); - static const auto PDISABLEAUTORELOAD = CConfigValue("misc:disable_autoreload"); static int prevEnabledExplicit = *PENABLEEXPLICIT; - g_pConfigWatcher->setWatchList(*PDISABLEAUTORELOAD ? std::vector{} : m_configPaths); + updateWatcher(); for (auto const& w : g_pCompositor->m_vWindows) { w->uncacheWindowDecos(); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index ae0ba759..f0696882 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -190,6 +190,7 @@ class CConfigManager { void ensureVRR(PHLMONITOR pMonitor = nullptr); bool shouldUseSoftwareCursors(); + void updateWatcher(); std::string parseKeyword(const std::string&, const std::string&); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cfdba100..359428b1 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1100,6 +1100,9 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) } } + if (COMMAND.contains("misc:disable_autoreload")) + g_pConfigManager->updateWatcher(); + // decorations will probably need a repaint if (COMMAND.contains("decoration:") || COMMAND.contains("border") || COMMAND == "workspace" || COMMAND.contains("zoom_factor") || COMMAND == "source" || COMMAND.starts_with("windowrule")) { From 61319197155cbcb3b8d5f004f46c2249029ec1f3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 13:16:50 +0000 Subject: [PATCH 0015/1257] monitor: round refresh rates in sorting modes fixes #9209 --- src/helpers/Monitor.cpp | 7 ++++--- src/helpers/Monitor.hpp | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 19d68a56..9ea85bca 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -456,9 +456,9 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { // sort prioritizing refresh rate 1st and resolution 2nd, then add best 3 addBest3Modes([](auto const& a, auto const& b) { - if (a->refreshRate > b->refreshRate) + if (std::round(a->refreshRate) > std::round(b->refreshRate)) return true; - else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1000) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) + else if (DELTALESSTHAN((float)a->refreshRate, (float)b->refreshRate, 1.F) && a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) return true; return false; }); @@ -469,7 +469,8 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { addBest3Modes([](auto const& a, auto const& b) { if (a->pixelSize.x > b->pixelSize.x && a->pixelSize.y > b->pixelSize.y) return true; - else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) && a->refreshRate > b->refreshRate) + else if (DELTALESSTHAN(a->pixelSize.x, b->pixelSize.x, 1) && DELTALESSTHAN(a->pixelSize.y, b->pixelSize.y, 1) && + std::round(a->refreshRate) > std::round(b->refreshRate)) return true; return false; }); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 7c19b57c..1b207f7d 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -33,7 +33,7 @@ struct SMonitorRule { Vector2D resolution = Vector2D(1280, 720); Vector2D offset = Vector2D(0, 0); float scale = 1; - float refreshRate = 60; + float refreshRate = 60; // Hz bool disabled = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; std::string mirrorOf = ""; @@ -92,7 +92,7 @@ class CMonitor { CDamageRing damage; SP output; - float refreshRate = 60; + float refreshRate = 60; // Hz int forceFullFrames = 0; bool scheduledRecalc = false; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; From 6fc9c8e4797a272c688fc74b872db5d828c21f02 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Wed, 29 Jan 2025 22:45:38 +0200 Subject: [PATCH 0016/1257] flake.lock: update --- flake.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index ac73e5f7..dfdd8c5b 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1737636397, - "narHash": "sha256-F5MbBj3QVorycVSFE9qjuOTLtIQBqt2VWbXa0uwzm98=", + "lastModified": 1738183445, + "narHash": "sha256-C1He3N1SA8D2u+TSlldbA9wiYwDvXI4GxX3zKaeD7qU=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "7fe006981fae53e931f513026fc754e322f13145", + "rev": "48a000cf35dd10bfeb231152735aebbe875f4b74", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1737634937, - "narHash": "sha256-Ffw4ujFpi++6pPHe+gCBOfDgAoNlzVPZN6MReC1beu8=", + "lastModified": 1738178255, + "narHash": "sha256-+D6Nu2ewXbMTFzx/Q4jDOo+LAOUPr0cxQJg5k33daIE=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "9c5dd1f7c825ee47f72727ad0a4e16ca46a2688e", + "rev": "dcadd3398abe146d60c67e0d9ee6e27b301cae82", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1737985436, - "narHash": "sha256-zx8FdI4zr2GhNyD1YGAqa2ymodAObTSAdwuWwVucewo=", + "lastModified": 1738018829, + "narHash": "sha256-5Ol5iahMlELx3lWuChyZsqqLk6sP6aqaJCJFw92OZGo=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "23783b96036f5506fdaf8b2250a1ef849d57f0d3", + "rev": "12cd7034e441a5ebfdef1a090c0788413b4a635b", "type": "github" }, "original": { From 09ec1cca51e1880dfc855c168a0dd810ff1ddcd6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 23:05:54 +0000 Subject: [PATCH 0017/1257] popup: stop refocusing at unmap fixes #9018 --- src/desktop/Popup.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 93a810ff..dea94f55 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -138,10 +138,11 @@ void CPopup::onUnmap() { }, nullptr); - const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource(); + // TODO: probably refocus, but without a motion event? + // const bool WASLASTFOCUS = g_pSeatManager->state.keyboardFocus == m_pWLSurface->resource() || g_pSeatManager->state.pointerFocus == m_pWLSurface->resource(); - if (WASLASTFOCUS) - g_pInputManager->simulateMouseMovement(); + // if (WASLASTFOCUS) + // g_pInputManager->simulateMouseMovement(); } void CPopup::onCommit(bool ignoreSiblings) { From d462cc7fa166e1e6a6f14b58a2dd1e8b92e15426 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 29 Jan 2025 23:16:25 +0000 Subject: [PATCH 0018/1257] subsurface: fix invalid parent typo fixes #9224 --- src/desktop/Subsurface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index a68cf8f3..d7a53954 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -143,7 +143,7 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { ASSERT(PSUBSURFACE); - PSUBSURFACE->m_pParent = PSUBSURFACE; + PSUBSURFACE->m_pParent = m_pSelf; } void CSubsurface::onMap() { From 7d1c78f4a3720b693fedeb5d4f2d3f4da37f7fd3 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:07:06 +0500 Subject: [PATCH 0019/1257] core,hyprctl: clang, clang-tidy, typo fixes and dtors changes (#9233) * declare dtor once + DMABBUF typo fix * dup include + clang moment * linux-dmabuf: last minute nit change --- hyprctl/main.cpp | 3 --- src/Compositor.cpp | 1 - src/config/ConfigDataValues.hpp | 2 +- src/config/ConfigManager.cpp | 4 ---- src/desktop/Subsurface.cpp | 4 ---- src/desktop/Subsurface.hpp | 4 ++-- src/helpers/Monitor.cpp | 4 ---- src/helpers/Monitor.hpp | 3 +-- src/hyprerror/HyprError.cpp | 2 -- src/hyprerror/HyprError.hpp | 2 +- src/layout/IHyprLayout.cpp | 2 -- src/layout/IHyprLayout.hpp | 2 +- src/layout/MasterLayout.hpp | 1 - src/managers/EventManager.hpp | 1 - src/managers/XCursorManager.hpp | 8 +++---- src/protocols/FocusGrab.cpp | 4 ---- src/protocols/FocusGrab.hpp | 2 +- src/protocols/LinuxDMABUF.cpp | 22 ++++++------------- src/protocols/LinuxDMABUF.hpp | 16 +++++++------- src/protocols/SinglePixel.cpp | 8 ------- src/protocols/SinglePixel.hpp | 6 ++--- src/protocols/core/Shm.cpp | 4 ---- src/protocols/core/Shm.hpp | 2 +- .../decorations/CHyprBorderDecoration.cpp | 4 ---- .../decorations/CHyprBorderDecoration.hpp | 2 +- .../decorations/CHyprDropShadowDecoration.cpp | 2 -- .../decorations/CHyprDropShadowDecoration.hpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 4 ---- .../decorations/CHyprGroupBarDecoration.hpp | 4 ++-- .../decorations/IHyprWindowDecoration.cpp | 2 -- .../decorations/IHyprWindowDecoration.hpp | 2 +- 31 files changed, 35 insertions(+), 94 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 16d66223..4cc73bdf 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -21,13 +21,10 @@ #include #include #include -#include #include #include #include -#include #include -#include using namespace Hyprutils::String; #include "Strings.hpp" diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 3421c314..1daccbfd 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index 80e45a05..901fb317 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -11,7 +11,7 @@ enum eConfigValueDataTypes : int8_t { class ICustomConfigValueData { public: - virtual ~ICustomConfigValueData() = 0; + virtual ~ICustomConfigValueData() = default; virtual eConfigValueDataTypes getDataType() = 0; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 047c58d9..86581b10 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1709,10 +1709,6 @@ void CConfigManager::handlePluginLoads() { } } -ICustomConfigValueData::~ICustomConfigValueData() { - ; // empty -} - const std::unordered_map>& CConfigManager::getAnimationConfig() { return m_AnimationTree.getFullConfig(); } diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index d7a53954..1d938f39 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -31,10 +31,6 @@ CSubsurface::CSubsurface(SP pSubsurface, WP pOwne initExistingSubsurfaces(pSubsurface->surface.lock()); } -CSubsurface::~CSubsurface() { - ; -} - void CSubsurface::initSignals() { if (m_pSubsurface) { listeners.commitSubsurface = m_pSubsurface->surface->events.commit.registerListener([this](std::any d) { onCommit(); }); diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index f16a11ea..41958671 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -17,7 +17,7 @@ class CSubsurface { CSubsurface(SP pSubsurface, PHLWINDOW pOwner); CSubsurface(SP pSubsurface, WP pOwner); - ~CSubsurface(); + ~CSubsurface() = default; Vector2D coordsRelativeToParent(); Vector2D coordsGlobal(); @@ -62,4 +62,4 @@ class CSubsurface { void initSignals(); void initExistingSubsurfaces(SP pSurface); void checkSiblingDamage(); -}; \ No newline at end of file +}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9ea85bca..42acf485 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1434,10 +1434,6 @@ CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) { ; } -CMonitorState::~CMonitorState() { - ; -} - void CMonitorState::ensureBufferPresent() { const auto STATE = m_pOwner->output->state->state(); if (!STATE.enabled) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 1b207f7d..2b02c30a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -6,7 +6,6 @@ #include "../SharedDefs.hpp" #include "MiscFunctions.hpp" #include "WLClasses.hpp" -#include #include #include @@ -48,7 +47,7 @@ class CSyncTimeline; class CMonitorState { public: CMonitorState(CMonitor* owner); - ~CMonitorState(); + ~CMonitorState() = default; bool commit(); bool test(); diff --git a/src/hyprerror/HyprError.cpp b/src/hyprerror/HyprError.cpp index 4076ed3a..9f889fdf 100644 --- a/src/hyprerror/HyprError.cpp +++ b/src/hyprerror/HyprError.cpp @@ -32,8 +32,6 @@ CHyprError::CHyprError() { m_pTexture = makeShared(); } -CHyprError::~CHyprError() = default; - void CHyprError::queueCreate(std::string message, const CHyprColor& color) { m_szQueued = message; m_cQueued = color; diff --git a/src/hyprerror/HyprError.hpp b/src/hyprerror/HyprError.hpp index 771e50f0..12de0c81 100644 --- a/src/hyprerror/HyprError.hpp +++ b/src/hyprerror/HyprError.hpp @@ -9,7 +9,7 @@ class CHyprError { public: CHyprError(); - ~CHyprError(); + ~CHyprError() = default; void queueCreate(std::string message, const CHyprColor& color); void draw(); diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 57ae5f40..9a0ba6ee 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -950,5 +950,3 @@ Vector2D IHyprLayout::predictSizeForNewWindow(PHLWINDOW pWindow) { return sizePredicted; } - -IHyprLayout::~IHyprLayout() = default; diff --git a/src/layout/IHyprLayout.hpp b/src/layout/IHyprLayout.hpp index ab188b9b..e31bb63e 100644 --- a/src/layout/IHyprLayout.hpp +++ b/src/layout/IHyprLayout.hpp @@ -43,7 +43,7 @@ enum eDirection : int8_t { class IHyprLayout { public: - virtual ~IHyprLayout() = 0; + virtual ~IHyprLayout() = default; virtual void onEnable() = 0; virtual void onDisable() = 0; diff --git a/src/layout/MasterLayout.hpp b/src/layout/MasterLayout.hpp index 381ccc9d..f658fdaa 100644 --- a/src/layout/MasterLayout.hpp +++ b/src/layout/MasterLayout.hpp @@ -5,7 +5,6 @@ #include "../helpers/varlist/VarList.hpp" #include #include -#include #include enum eFullscreenMode : int8_t; diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 5a88963e..6b506d33 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,5 @@ #pragma once #include -#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" diff --git a/src/managers/XCursorManager.hpp b/src/managers/XCursorManager.hpp index 2517e85e..3052206f 100644 --- a/src/managers/XCursorManager.hpp +++ b/src/managers/XCursorManager.hpp @@ -13,10 +13,10 @@ extern "C" { // gangsta bootleg XCursor impl. adidas balkanized struct SXCursorImage { - Vector2D size; - Vector2D hotspot; - std::vector pixels; // XPixel is a u32 - uint32_t delay; // animation delay to next frame (ms) + Hyprutils::Math::Vector2D size; + Hyprutils::Math::Vector2D hotspot; + std::vector pixels; // XPixel is a u32 + uint32_t delay; // animation delay to next frame (ms) }; struct SXCursors { diff --git a/src/protocols/FocusGrab.cpp b/src/protocols/FocusGrab.cpp index ab9d22ef..bef69f62 100644 --- a/src/protocols/FocusGrab.cpp +++ b/src/protocols/FocusGrab.cpp @@ -11,10 +11,6 @@ CFocusGrabSurfaceState::CFocusGrabSurfaceState(CFocusGrab* grab, SPevents.destroy.registerListener([=](std::any d) { grab->eraseSurface(surface); }); } -CFocusGrabSurfaceState::~CFocusGrabSurfaceState() { - ; -} - CFocusGrab::CFocusGrab(SP resource_) : resource(resource_) { if UNLIKELY (!resource->resource()) return; diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 3c907ed0..1445a24c 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -15,7 +15,7 @@ class CWLSurfaceResource; class CFocusGrabSurfaceState { public: CFocusGrabSurfaceState(CFocusGrab* grab, SP surface); - ~CFocusGrabSurfaceState(); + ~CFocusGrabSurfaceState() = default; enum State { PendingAddition, diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index 82d31c84..d3135da0 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -125,7 +125,7 @@ bool CLinuxDMABuffer::good() { return buffer && buffer->good(); } -CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP resource_) : resource(resource_) { +CLinuxDMABUFParamsResource::CLinuxDMABUFParamsResource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -197,15 +197,11 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SPresource(); } -void CLinuxDMABBUFParamsResource::create(uint32_t id) { +void CLinuxDMABUFParamsResource::create(uint32_t id) { used = true; if UNLIKELY (!verify()) { @@ -237,7 +233,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { createdBuffer = buf; } -bool CLinuxDMABBUFParamsResource::commence() { +bool CLinuxDMABUFParamsResource::commence() { if (PROTO::linuxDma->mainDeviceFD < 0) return true; @@ -258,7 +254,7 @@ bool CLinuxDMABBUFParamsResource::commence() { return true; } -bool CLinuxDMABBUFParamsResource::verify() { +bool CLinuxDMABUFParamsResource::verify() { if UNLIKELY (attrs->planes <= 0) { resource->error(ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE, "No planes added"); return false; @@ -311,10 +307,6 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPresource(); } @@ -384,7 +376,7 @@ CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : re }); resource->setCreateParams([](CZwpLinuxDmabufV1* r, uint32_t id) { - const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + const auto RESOURCE = PROTO::linuxDma->m_vParams.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); @@ -550,7 +542,7 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFFeedbackResource* resou std::erase_if(m_vFeedbacks, [&](const auto& other) { return other.get() == resource; }); } -void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resource) { +void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABUFParamsResource* resource) { std::erase_if(m_vParams, [&](const auto& other) { return other.get() == resource; }); } diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 8c574dbc..91cf3283 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -27,7 +27,7 @@ class CLinuxDMABuffer { CHyprSignalListener bufferResourceDestroy; } listeners; - friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABUFParamsResource; }; #pragma pack(push, 1) @@ -56,10 +56,10 @@ class CDMABUFFormatTable { std::vector> monitorTranches; }; -class CLinuxDMABBUFParamsResource { +class CLinuxDMABUFParamsResource { public: - CLinuxDMABBUFParamsResource(SP resource_); - ~CLinuxDMABBUFParamsResource(); + CLinuxDMABUFParamsResource(SP resource_); + ~CLinuxDMABUFParamsResource() = default; bool good(); void create(uint32_t id); // 0 means not immed @@ -78,7 +78,7 @@ class CLinuxDMABBUFParamsResource { class CLinuxDMABUFFeedbackResource { public: CLinuxDMABUFFeedbackResource(SP resource_, SP surface_); - ~CLinuxDMABUFFeedbackResource(); + ~CLinuxDMABUFFeedbackResource() = default; bool good(); void sendDefaultFeedback(); @@ -115,7 +115,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { private: void destroyResource(CLinuxDMABUFResource* resource); void destroyResource(CLinuxDMABUFFeedbackResource* resource); - void destroyResource(CLinuxDMABBUFParamsResource* resource); + void destroyResource(CLinuxDMABUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); void resetFormatTable(); @@ -123,7 +123,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { // std::vector> m_vManagers; std::vector> m_vFeedbacks; - std::vector> m_vParams; + std::vector> m_vParams; std::vector> m_vBuffers; UP formatTable; @@ -132,7 +132,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; - friend class CLinuxDMABBUFParamsResource; + friend class CLinuxDMABUFParamsResource; friend class CLinuxDMABuffer; }; diff --git a/src/protocols/SinglePixel.cpp b/src/protocols/SinglePixel.cpp index 2fbfc93d..4d643a53 100644 --- a/src/protocols/SinglePixel.cpp +++ b/src/protocols/SinglePixel.cpp @@ -24,10 +24,6 @@ CSinglePixelBuffer::CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColo Debug::log(ERR, "Failed creating a single pixel texture: null texture id"); } -CSinglePixelBuffer::~CSinglePixelBuffer() { - ; -} - Aquamarine::eBufferCapability CSinglePixelBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } @@ -74,10 +70,6 @@ CSinglePixelBufferResource::CSinglePixelBufferResource(uint32_t id, wl_client* c }); } -CSinglePixelBufferResource::~CSinglePixelBufferResource() { - ; -} - bool CSinglePixelBufferResource::good() { return buffer->good(); } diff --git a/src/protocols/SinglePixel.hpp b/src/protocols/SinglePixel.hpp index 2a86d050..bd0607d6 100644 --- a/src/protocols/SinglePixel.hpp +++ b/src/protocols/SinglePixel.hpp @@ -9,7 +9,7 @@ class CSinglePixelBuffer : public IHLBuffer { public: CSinglePixelBuffer(uint32_t id, wl_client* client, CHyprColor col); - virtual ~CSinglePixelBuffer(); + virtual ~CSinglePixelBuffer() = default; virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); @@ -33,7 +33,7 @@ class CSinglePixelBuffer : public IHLBuffer { class CSinglePixelBufferResource { public: CSinglePixelBufferResource(uint32_t id, wl_client* client, CHyprColor color); - ~CSinglePixelBufferResource(); + ~CSinglePixelBufferResource() = default; bool good(); @@ -75,4 +75,4 @@ class CSinglePixelProtocol : public IWaylandProtocol { namespace PROTO { inline UP singlePixel; -}; \ No newline at end of file +}; diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 28585aeb..1649f82f 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -36,10 +36,6 @@ CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t of Debug::log(ERR, "Failed creating a shm texture: null texture id"); } -CWLSHMBuffer::~CWLSHMBuffer() { - ; -} - Aquamarine::eBufferCapability CWLSHMBuffer::caps() { return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 23a465fb..d7e81367 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -31,7 +31,7 @@ class CSHMPool { class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); - virtual ~CWLSHMBuffer(); + virtual ~CWLSHMBuffer() = default; virtual Aquamarine::eBufferCapability caps(); virtual Aquamarine::eBufferType type(); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 6fb0ff88..5f2fdbda 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -10,10 +10,6 @@ CHyprBorderDecoration::CHyprBorderDecoration(PHLWINDOW pWindow) : IHyprWindowDec ; } -CHyprBorderDecoration::~CHyprBorderDecoration() { - ; -} - SDecorationPositioningInfo CHyprBorderDecoration::getPositioningInfo() { const auto BORDERSIZE = m_pWindow->getRealBorderSize(); m_seExtents = {{BORDERSIZE, BORDERSIZE}, {BORDERSIZE, BORDERSIZE}}; diff --git a/src/render/decorations/CHyprBorderDecoration.hpp b/src/render/decorations/CHyprBorderDecoration.hpp index bc9d7836..332c08b7 100644 --- a/src/render/decorations/CHyprBorderDecoration.hpp +++ b/src/render/decorations/CHyprBorderDecoration.hpp @@ -5,7 +5,7 @@ class CHyprBorderDecoration : public IHyprWindowDecoration { public: CHyprBorderDecoration(PHLWINDOW); - virtual ~CHyprBorderDecoration(); + virtual ~CHyprBorderDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 0b2a96d9..60b1b33a 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -9,8 +9,6 @@ CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprW ; } -CHyprDropShadowDecoration::~CHyprDropShadowDecoration() = default; - eDecorationType CHyprDropShadowDecoration::getDecorationType() { return DECORATION_SHADOW; } diff --git a/src/render/decorations/CHyprDropShadowDecoration.hpp b/src/render/decorations/CHyprDropShadowDecoration.hpp index 3b1c67c5..b5ee7276 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.hpp +++ b/src/render/decorations/CHyprDropShadowDecoration.hpp @@ -5,7 +5,7 @@ class CHyprDropShadowDecoration : public IHyprWindowDecoration { public: CHyprDropShadowDecoration(PHLWINDOW); - virtual ~CHyprDropShadowDecoration(); + virtual ~CHyprDropShadowDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 4e7c3cbc..88501d74 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -29,8 +29,6 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindo refreshGroupBarGradients(); } -CHyprGroupBarDecoration::~CHyprGroupBarDecoration() = default; - SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { static auto PHEIGHT = CConfigValue("group:groupbar:height"); static auto PENABLED = CConfigValue("group:groupbar:enabled"); @@ -231,8 +229,6 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float texSize = tex->m_vSize; } -CTitleTex::~CTitleTex() = default; - void renderGradientTo(SP tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp index 7277955d..0cdf8a6b 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.hpp +++ b/src/render/decorations/CHyprGroupBarDecoration.hpp @@ -10,7 +10,7 @@ class CTitleTex { public: CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale); - ~CTitleTex(); + ~CTitleTex() = default; SP tex; std::string szContent; @@ -24,7 +24,7 @@ void refreshGroupBarGradients(); class CHyprGroupBarDecoration : public IHyprWindowDecoration { public: CHyprGroupBarDecoration(PHLWINDOW); - virtual ~CHyprGroupBarDecoration(); + virtual ~CHyprGroupBarDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo(); diff --git a/src/render/decorations/IHyprWindowDecoration.cpp b/src/render/decorations/IHyprWindowDecoration.cpp index cb9e166b..c71ee186 100644 --- a/src/render/decorations/IHyprWindowDecoration.cpp +++ b/src/render/decorations/IHyprWindowDecoration.cpp @@ -6,8 +6,6 @@ IHyprWindowDecoration::IHyprWindowDecoration(PHLWINDOW pWindow) : m_pWindow(pWin ; } -IHyprWindowDecoration::~IHyprWindowDecoration() = default; - bool IHyprWindowDecoration::onInputOnDeco(const eInputType, const Vector2D&, std::any) { return false; } diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 10145f40..2703eb61 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -33,7 +33,7 @@ class CDecorationPositioner; class IHyprWindowDecoration { public: IHyprWindowDecoration(PHLWINDOW); - virtual ~IHyprWindowDecoration() = 0; + virtual ~IHyprWindowDecoration() = default; virtual SDecorationPositioningInfo getPositioningInfo() = 0; From 32c0fa2f2fe02254d5887b38cf2cffa72ddfd769 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 30 Jan 2025 12:30:12 +0100 Subject: [PATCH 0020/1257] core: begin using CFileDescriptor from hyprutils (#9122) * config: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * hyprctl: make fd use CFileDescriptor make use of the new hyprutils CFileDescriptor instead of manual FD handling. * ikeyboard: make fd use CFileDescriptor make use of the new CFileDescriptor instead of manual FD handling, also in sendKeymap remove dead code, it already early returns if keyboard isnt valid, and dont try to close the FD that ikeyboard owns. * core: make SHMFile functions use CFileDescriptor make SHMFile misc functions use CFileDescriptor and its associated usage in dmabuf and keyboard. * core: make explicit sync use CFileDescriptor begin using CFileDescriptor in explicit sync and its timelines and eglsync usage in opengl, there is still a bit left with manual handling that requires future aquamarine change aswell. * eventmgr: make fd and sockets use CFileDescriptor make use of the hyprutils CFileDescriptor instead of manual FD and socket handling and closing. * eventloopmgr: make timerfd use CFileDescriptor make the timerfd use CFileDescriptor instead of manual fd handling * opengl: make gbm fd use CFileDescriptor make the gbm rendernode fd use CFileDescriptor instead of manual fd handling * core: make selection source/offer use CFileDescriptor make data selection source and offers use CFileDescriptor and its associated use in xwm and protocols * protocols: convert protocols fd to CFileDescriptor make most fd handling use CFileDescriptor in protocols * shm: make SHMPool use CfileDescriptor make SHMPool use CFileDescriptor instead of manual fd handling. * opengl: duplicate fd with CFileDescriptor duplicate fenceFD with CFileDescriptor duplicate instead. * xwayland: make sockets and fds use CFileDescriptor instead of manual opening/closing make sockets and fds use CFileDescriptor * keybindmgr: make sockets and fds use CFileDescriptor make sockets and fds use CFileDescriptor instead of manual handling. --- src/config/ConfigWatcher.cpp | 25 ++- src/config/ConfigWatcher.hpp | 15 +- src/debug/HyprCtl.cpp | 18 +- src/debug/HyprCtl.hpp | 11 +- src/devices/IKeyboard.cpp | 26 ++- src/devices/IKeyboard.hpp | 3 +- src/helpers/MiscFunctions.cpp | 44 +++-- src/helpers/MiscFunctions.hpp | 5 +- src/helpers/Monitor.cpp | 17 +- src/helpers/Monitor.hpp | 1 + src/helpers/sync/SyncTimeline.cpp | 26 ++- src/helpers/sync/SyncTimeline.hpp | 28 ++-- src/managers/EventManager.cpp | 44 +++-- src/managers/EventManager.hpp | 14 +- src/managers/KeybindManager.cpp | 29 ++-- src/managers/eventLoop/EventLoopManager.cpp | 13 +- src/managers/eventLoop/EventLoopManager.hpp | 3 +- src/protocols/DRMLease.cpp | 17 +- src/protocols/DRMLease.hpp | 1 + src/protocols/DRMSyncobj.cpp | 12 +- src/protocols/DRMSyncobj.hpp | 7 +- src/protocols/DataDeviceWlr.cpp | 12 +- src/protocols/DataDeviceWlr.hpp | 3 +- src/protocols/GammaControl.cpp | 15 +- src/protocols/InputMethodV2.cpp | 11 +- src/protocols/LinuxDMABUF.cpp | 37 ++--- src/protocols/LinuxDMABUF.hpp | 9 +- src/protocols/PrimarySelection.cpp | 12 +- src/protocols/PrimarySelection.hpp | 3 +- src/protocols/SecurityContext.cpp | 21 ++- src/protocols/SecurityContext.hpp | 19 ++- src/protocols/VirtualKeyboard.cpp | 10 +- src/protocols/VirtualKeyboard.hpp | 1 + src/protocols/core/DataDevice.cpp | 12 +- src/protocols/core/DataDevice.hpp | 3 +- src/protocols/core/Seat.cpp | 29 +--- src/protocols/core/Shm.cpp | 23 +-- src/protocols/core/Shm.hpp | 14 +- src/protocols/types/DataDevice.hpp | 9 +- src/render/OpenGL.cpp | 41 ++--- src/render/OpenGL.hpp | 13 +- src/render/Renderer.cpp | 20 +-- src/xwayland/Dnd.cpp | 4 +- src/xwayland/Dnd.hpp | 3 +- src/xwayland/Server.cpp | 173 +++++++------------- src/xwayland/Server.hpp | 27 +-- src/xwayland/XDataSource.cpp | 13 +- src/xwayland/XDataSource.hpp | 5 +- src/xwayland/XWM.cpp | 20 +-- src/xwayland/XWM.hpp | 27 +-- 50 files changed, 422 insertions(+), 526 deletions(-) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index c0a9c591..8d086bac 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -5,27 +5,24 @@ #include #include +using namespace Hyprutils::OS; + CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) { - if (m_inotifyFd < 0) { + if (!m_inotifyFd.isValid()) { Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded"); return; } - const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0); - if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor take F_GETFL, F_SETFL + const int FLAGS = fcntl(m_inotifyFd.get(), F_GETFL, 0); + if (fcntl(m_inotifyFd.get(), F_SETFL, FLAGS | O_NONBLOCK) < 0) { Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded"); - close(m_inotifyFd); - m_inotifyFd = -1; + m_inotifyFd.reset(); return; } } -CConfigWatcher::~CConfigWatcher() { - if (m_inotifyFd >= 0) - close(m_inotifyFd); -} - -int CConfigWatcher::getInotifyFD() { +CFileDescriptor& CConfigWatcher::getInotifyFD() { return m_inotifyFd; } @@ -38,7 +35,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // cleanup old paths for (auto& watch : m_watches) { - inotify_rm_watch(m_inotifyFd, watch.wd); + inotify_rm_watch(m_inotifyFd.get(), watch.wd); } m_watches.clear(); @@ -46,7 +43,7 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), .file = path, }); } @@ -58,7 +55,7 @@ void CConfigWatcher::setOnChange(const std::function 0) { + while (read(m_inotifyFd.get(), &ev, sizeof(ev)) > 0) { const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; }); if (WD == m_watches.end()) { diff --git a/src/config/ConfigWatcher.hpp b/src/config/ConfigWatcher.hpp index c36ecd17..97945689 100644 --- a/src/config/ConfigWatcher.hpp +++ b/src/config/ConfigWatcher.hpp @@ -3,20 +3,21 @@ #include #include #include +#include class CConfigWatcher { public: CConfigWatcher(); - ~CConfigWatcher(); + ~CConfigWatcher() = default; struct SConfigWatchEvent { std::string file; }; - int getInotifyFD(); - void setWatchList(const std::vector& paths); - void setOnChange(const std::function& fn); - void onInotifyEvent(); + Hyprutils::OS::CFileDescriptor& getInotifyFD(); + void setWatchList(const std::vector& paths); + void setOnChange(const std::function& fn); + void onInotifyEvent(); private: struct SInotifyWatch { @@ -26,7 +27,7 @@ class CConfigWatcher { std::function m_watchCallback; std::vector m_watches; - int m_inotifyFd = -1; + Hyprutils::OS::CFileDescriptor m_inotifyFd; }; -inline UP g_pConfigWatcher = makeUnique(); \ No newline at end of file +inline UP g_pConfigWatcher = makeUnique(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 359428b1..cd6451e2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -25,6 +25,7 @@ #include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include "../config/ConfigDataValues.hpp" @@ -1680,8 +1681,6 @@ CHyprCtl::CHyprCtl() { CHyprCtl::~CHyprCtl() { if (m_eventSource) wl_event_source_remove(m_eventSource); - if (m_iSocketFD >= 0) - close(m_iSocketFD); if (!m_socketPath.empty()) unlink(m_socketPath.c_str()); } @@ -1840,10 +1839,13 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; + if (!g_pHyprCtl->m_iSocketFD.isValid()) + return 0; + sockaddr_in clientAddress; socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); + const auto ACCEPTEDCONNECTION = accept4(g_pHyprCtl->m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC); std::array readBuffer; @@ -1900,9 +1902,9 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { } void CHyprCtl::startHyprCtlSocket() { - m_iSocketFD = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + m_iSocketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } @@ -1913,15 +1915,15 @@ void CHyprCtl::startHyprCtlSocket() { strcpy(SERVERADDRESS.sun_path, m_socketPath.c_str()); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); return; } // 10 max queued. - listen(m_iSocketFD, 10); + listen(m_iSocketFD.get(), 10); Debug::log(LOG, "Hypr socket started at {}", m_socketPath); - m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, hyprCtlFDTick, nullptr); + m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp index eed8265c..a95a5f93 100644 --- a/src/debug/HyprCtl.hpp +++ b/src/debug/HyprCtl.hpp @@ -4,6 +4,7 @@ #include "../helpers/MiscFunctions.hpp" #include "../desktop/Window.hpp" #include +#include // exposed for main.cpp std::string systemInfoRequest(eHyprCtlOutputFormat format, std::string request); @@ -14,12 +15,12 @@ class CHyprCtl { CHyprCtl(); ~CHyprCtl(); - std::string makeDynamicCall(const std::string& input); - SP registerCommand(SHyprCtlCommand cmd); - void unregisterCommand(const SP& cmd); - std::string getReply(std::string); + std::string makeDynamicCall(const std::string& input); + SP registerCommand(SHyprCtlCommand cmd); + void unregisterCommand(const SP& cmd); + std::string getReply(std::string); - int m_iSocketFD = -1; + Hyprutils::OS::CFileDescriptor m_iSocketFD; struct { bool all = false; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 4623fe84..307d840b 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -8,6 +8,8 @@ #include #include +using namespace Hyprutils::OS; + #define LED_COUNT 3 constexpr static std::array MODNAMES = { @@ -41,9 +43,6 @@ void IKeyboard::clearManuallyAllocd() { if (xkbKeymap) xkb_keymap_unref(xkbKeymap); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - if (xkbSymState) xkb_state_unref(xkbSymState); @@ -51,7 +50,7 @@ void IKeyboard::clearManuallyAllocd() { xkbKeymap = nullptr; xkbState = nullptr; xkbStaticState = nullptr; - xkbKeymapFD = -1; + xkbKeymapFD.reset(); } void IKeyboard::setKeymap(const SStringRuleNames& rules) { @@ -147,31 +146,30 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { void IKeyboard::updateKeymapFD() { Debug::log(LOG, "Updating keymap fd for keyboard {}", deviceName); - if (xkbKeymapFD >= 0) - close(xkbKeymapFD); - xkbKeymapFD = -1; + if (xkbKeymapFD.isValid()) + xkbKeymapFD.reset(); auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1); xkbKeymapString = cKeymapStr; free(cKeymapStr); - int rw, ro; - if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro)) + CFileDescriptor rw, ro; + if (!allocateSHMFilePair(xkbKeymapString.length() + 1, rw, ro)) Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap"); else { - auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0); - close(rw); + auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw.get(), 0); + rw.reset(); if (keymapFDDest == MAP_FAILED) { Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap"); - close(ro); + ro.reset(); } else { memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length()); munmap(keymapFDDest, xkbKeymapString.length() + 1); - xkbKeymapFD = ro; + xkbKeymapFD = std::move(ro); } } - Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD); + Debug::log(LOG, "Updated keymap fd to {}", xkbKeymapFD.get()); } void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) { diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp index dce2127a..aabf4cc2 100644 --- a/src/devices/IKeyboard.hpp +++ b/src/devices/IKeyboard.hpp @@ -6,6 +6,7 @@ #include #include +#include AQUAMARINE_FORWARD(IKeyboard); @@ -96,7 +97,7 @@ class IKeyboard : public IHID { std::string xkbFilePath = ""; std::string xkbKeymapString = ""; - int xkbKeymapFD = -1; + Hyprutils::OS::CFileDescriptor xkbKeymapFD; SStringRuleNames currentRules; int repeatRate = 0; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 5ebb0842..f532617c 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -836,50 +836,48 @@ bool envEnabled(const std::string& env) { return std::string(ENV) == "1"; } -std::pair openExclusiveShm() { +std::pair openExclusiveShm() { // Only absolute paths can be shared across different shm_open() calls std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { - int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); - if (fd >= 0) - return {fd, name}; + CFileDescriptor fd{shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)}; + if (fd.isValid()) + return {std::move(fd), name}; } - return {-1, ""}; + return {{}, ""}; } -int allocateSHMFile(size_t len) { +CFileDescriptor allocateSHMFile(size_t len) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) - return -1; + if (!fd.isValid()) + return {}; shm_unlink(name.c_str()); int ret; do { - ret = ftruncate(fd, len); + ret = ftruncate(fd.get(), len); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - return -1; + return {}; } - return fd; + return std::move(fd); } -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { +bool allocateSHMFilePair(size_t size, CFileDescriptor& rw_fd_ptr, CFileDescriptor& ro_fd_ptr) { auto [fd, name] = openExclusiveShm(); - if (fd < 0) { + if (!fd.isValid()) { return false; } // CLOEXEC is guaranteed to be set by shm_open - int ro_fd = shm_open(name.c_str(), O_RDONLY, 0); - if (ro_fd < 0) { + CFileDescriptor ro_fd{shm_open(name.c_str(), O_RDONLY, 0)}; + if (!ro_fd.isValid()) { shm_unlink(name.c_str()); - close(fd); return false; } @@ -887,24 +885,20 @@ bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr) { // Make sure the file cannot be re-opened in read-write mode (e.g. via // "/proc/self/fd/" on Linux) - if (fchmod(fd, 0) != 0) { - close(fd); - close(ro_fd); + if (fchmod(fd.get(), 0) != 0) { return false; } int ret; do { - ret = ftruncate(fd, size); + ret = ftruncate(fd.get(), size); } while (ret < 0 && errno == EINTR); if (ret < 0) { - close(fd); - close(ro_fd); return false; } - *rw_fd_ptr = fd; - *ro_fd_ptr = ro_fd; + rw_fd_ptr = std::move(fd); + ro_fd_ptr = std::move(ro_fd); return true; } diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index d0824284..bd288638 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../SharedDefs.hpp" #include "../macros.hpp" @@ -35,8 +36,8 @@ double normalizeAngleRad(double ang); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); -int allocateSHMFile(size_t len); -bool allocateSHMFilePair(size_t size, int* rw_fd_ptr, int* ro_fd_ptr); +Hyprutils::OS::CFileDescriptor allocateSHMFile(size_t len); +bool allocateSHMFilePair(size_t size, Hyprutils::OS::CFileDescriptor& rw_fd_ptr, Hyprutils::OS::CFileDescriptor& ro_fd_ptr); float stringToPercentage(const std::string& VALUE, const float REL); template diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 42acf485..fc3de3aa 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -32,6 +32,7 @@ #include using namespace Hyprutils::String; using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -1301,19 +1302,15 @@ bool CMonitor::attemptDirectScanout() { // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; - int explicitWaitFD = -1; + CFileDescriptor explicitWaitFD; if (DOEXPLICIT) { explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint); - if (explicitWaitFD < 0) + if (!explicitWaitFD.isValid()) Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd"); } - DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0; + DOEXPLICIT = DOEXPLICIT && explicitWaitFD.isValid(); - auto cleanup = CScopeGuard([explicitWaitFD, this]() { - output->state->resetExplicitFences(); - if (explicitWaitFD >= 0) - close(explicitWaitFD); - }); + auto cleanup = CScopeGuard([this]() { output->state->resetExplicitFences(); }); timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1323,8 +1320,8 @@ bool CMonitor::attemptDirectScanout() { output->state->resetExplicitFences(); if (DOEXPLICIT) { - Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD); - output->state->setExplicitInFence(explicitWaitFD); + Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD.get()); + output->state->setExplicitInFence(explicitWaitFD.get()); } bool ok = output->commit(); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 2b02c30a..c67bccc5 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -16,6 +16,7 @@ #include "DamageRing.hpp" #include #include +#include // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs : uint8_t { diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp index 16b5bd92..46b617bc 100644 --- a/src/helpers/sync/SyncTimeline.cpp +++ b/src/helpers/sync/SyncTimeline.cpp @@ -4,6 +4,7 @@ #include #include +using namespace Hyprutils::OS; SP CSyncTimeline::create(int drmFD_) { auto timeline = SP(new CSyncTimeline); @@ -85,10 +86,9 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin auto w = makeShared(); w->fn = waiter; w->timeline = self; + w->eventFd = CFileDescriptor{eventfd(0, EFD_CLOEXEC)}; - int eventFD = eventfd(0, EFD_CLOEXEC); - - if (eventFD < 0) { + if (!w->eventFd.isValid()) { Debug::log(ERR, "CSyncTimeline::addWaiter: failed to acquire an eventfd"); return false; } @@ -97,19 +97,17 @@ bool CSyncTimeline::addWaiter(const std::function& waiter, uint64_t poin .handle = handle, .flags = flags, .point = point, - .fd = eventFD, + .fd = w->eventFd.get(), }; if (drmIoctl(drmFD, DRM_IOCTL_SYNCOBJ_EVENTFD, &syncobjEventFD) != 0) { Debug::log(ERR, "CSyncTimeline::addWaiter: drmIoctl failed"); - close(eventFD); return false; } - w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, eventFD, WL_EVENT_READABLE, ::handleWaiterFD, w.get()); + w->source = wl_event_loop_add_fd(g_pEventLoopManager->m_sWayland.loop, w->eventFd.get(), WL_EVENT_READABLE, ::handleWaiterFD, w.get()); if (!w->source) { Debug::log(ERR, "CSyncTimeline::addWaiter: wl_event_loop_add_fd failed"); - close(eventFD); return false; } @@ -126,32 +124,32 @@ void CSyncTimeline::removeWaiter(SWaiter* w) { std::erase_if(waiters, [w](const auto& e) { return e.get() == w; }); } -int CSyncTimeline::exportAsSyncFileFD(uint64_t src) { +CFileDescriptor CSyncTimeline::exportAsSyncFileFD(uint64_t src) { int sync = -1; uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjCreate failed"); - return -1; + return {}; } if (drmSyncobjTransfer(drmFD, syncHandle, 0, handle, src, 0)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjTransfer failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } if (drmSyncobjExportSyncFile(drmFD, syncHandle, &sync)) { Debug::log(ERR, "exportAsSyncFileFD: drmSyncobjExportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); - return -1; + return {}; } drmSyncobjDestroy(drmFD, syncHandle); - return sync; + return CFileDescriptor{sync}; } -bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { +bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, CFileDescriptor& fd) { uint32_t syncHandle = 0; if (drmSyncobjCreate(drmFD, 0, &syncHandle)) { @@ -159,7 +157,7 @@ bool CSyncTimeline::importFromSyncFileFD(uint64_t dst, int fd) { return false; } - if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd)) { + if (drmSyncobjImportSyncFile(drmFD, syncHandle, fd.get())) { Debug::log(ERR, "importFromSyncFileFD: drmSyncobjImportSyncFile failed"); drmSyncobjDestroy(drmFD, syncHandle); return false; diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp index 88ad4921..ba65e004 100644 --- a/src/helpers/sync/SyncTimeline.hpp +++ b/src/helpers/sync/SyncTimeline.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../memory/Memory.hpp" /* @@ -20,26 +21,27 @@ class CSyncTimeline { ~CSyncTimeline(); struct SWaiter { - std::function fn; - wl_event_source* source = nullptr; - WP timeline; + std::function fn; + wl_event_source* source = nullptr; + WP timeline; + Hyprutils::OS::CFileDescriptor eventFd; }; // check if the timeline point has been signaled // flags: DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT or DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE // std::nullopt on fail - std::optional check(uint64_t point, uint32_t flags); + std::optional check(uint64_t point, uint32_t flags); - bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); - void removeWaiter(SWaiter*); - int exportAsSyncFileFD(uint64_t src); - bool importFromSyncFileFD(uint64_t dst, int fd); - bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); - void signal(uint64_t point); + bool addWaiter(const std::function& waiter, uint64_t point, uint32_t flags); + void removeWaiter(SWaiter*); + Hyprutils::OS::CFileDescriptor exportAsSyncFileFD(uint64_t src); + bool importFromSyncFileFD(uint64_t dst, Hyprutils::OS::CFileDescriptor& fd); + bool transfer(SP from, uint64_t fromPoint, uint64_t toPoint); + void signal(uint64_t point); - int drmFD = -1; - uint32_t handle = 0; - WP self; + int drmFD = -1; + uint32_t handle = 0; + WP self; private: CSyncTimeline() = default; diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp index fc55b472..6231f0bc 100644 --- a/src/managers/EventManager.cpp +++ b/src/managers/EventManager.cpp @@ -9,9 +9,10 @@ #include #include #include +using namespace Hyprutils::OS; CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) { - if (m_iSocketFD < 0) { + if (!m_iSocketFD.isValid()) { Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); return; } @@ -25,31 +26,27 @@ CEventManager::CEventManager() : m_iSocketFD(socket(AF_UNIX, SOCK_STREAM | SOCK_ strncpy(SERVERADDRESS.sun_path, PATH.c_str(), sizeof(SERVERADDRESS.sun_path) - 1); - if (bind(m_iSocketFD, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + if (bind(m_iSocketFD.get(), (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { Debug::log(ERR, "Couldn't bind the Hyprland Socket 2. (3) IPC will not work."); return; } // 10 max queued. - if (listen(m_iSocketFD, 10) < 0) { + if (listen(m_iSocketFD.get(), 10) < 0) { Debug::log(ERR, "Couldn't listen on the Hyprland Socket 2. (4) IPC will not work."); return; } - m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD, WL_EVENT_READABLE, onClientEvent, nullptr); + m_pEventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, m_iSocketFD.get(), WL_EVENT_READABLE, onClientEvent, nullptr); } CEventManager::~CEventManager() { for (const auto& client : m_vClients) { wl_event_source_remove(client.eventSource); - close(client.fd); } if (m_pEventSource != nullptr) wl_event_source_remove(m_pEventSource); - - if (m_iSocketFD >= 0) - close(m_iSocketFD); } int CEventManager::onServerEvent(int fd, uint32_t mask, void* data) { @@ -66,33 +63,31 @@ int CEventManager::onServerEvent(int fd, uint32_t mask) { wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); return 0; } - sockaddr_in clientAddress; - socklen_t clientSize = sizeof(clientAddress); - const auto ACCEPTEDCONNECTION = accept4(m_iSocketFD, (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK); - if (ACCEPTEDCONNECTION < 0) { + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + CFileDescriptor ACCEPTEDCONNECTION{accept4(m_iSocketFD.get(), (sockaddr*)&clientAddress, &clientSize, SOCK_CLOEXEC | SOCK_NONBLOCK)}; + if (!ACCEPTEDCONNECTION.isValid()) { if (errno != EAGAIN) { Debug::log(ERR, "Socket2 failed receiving connection, errno: {}", errno); wl_event_source_remove(m_pEventSource); m_pEventSource = nullptr; - close(fd); - m_iSocketFD = -1; + m_iSocketFD.reset(); } return 0; } - Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION); + Debug::log(LOG, "Socket2 accepted a new client at FD {}", ACCEPTEDCONNECTION.get()); // add to event loop so we can close it when we need to - auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION, 0, onServerEvent, nullptr); + auto* eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, ACCEPTEDCONNECTION.get(), 0, onServerEvent, nullptr); m_vClients.emplace_back(SClient{ - ACCEPTEDCONNECTION, + std::move(ACCEPTEDCONNECTION), {}, eventSource, }); @@ -113,7 +108,7 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { // send all queued events while (!CLIENTIT->events.empty()) { const auto& event = CLIENTIT->events.front(); - if (write(CLIENTIT->fd, event->c_str(), event->length()) < 0) + if (write(CLIENTIT->fd.get(), event->c_str(), event->length()) < 0) break; CLIENTIT->events.erase(CLIENTIT->events.begin()); @@ -128,13 +123,12 @@ int CEventManager::onClientEvent(int fd, uint32_t mask) { } std::vector::iterator CEventManager::findClientByFD(int fd) { - return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd == fd; }); + return std::find_if(m_vClients.begin(), m_vClients.end(), [fd](const auto& client) { return client.fd.get() == fd; }); } std::vector::iterator CEventManager::removeClientByFD(int fd) { const auto CLIENTIT = findClientByFD(fd); wl_event_source_remove(CLIENTIT->eventSource); - close(fd); return m_vClients.erase(CLIENTIT); } @@ -157,11 +151,11 @@ void CEventManager::postEvent(const SHyprIPCEvent& event) { for (auto it = m_vClients.begin(); it != m_vClients.end();) { // try to send the event immediately if the queue is empty const auto QUEUESIZE = it->events.size(); - if (QUEUESIZE > 0 || write(it->fd, sharedEvent->c_str(), sharedEvent->length()) < 0) { + if (QUEUESIZE > 0 || write(it->fd.get(), sharedEvent->c_str(), sharedEvent->length()) < 0) { if (QUEUESIZE >= MAX_QUEUED_EVENTS) { // too many events queued, remove the client - Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd); - it = removeClientByFD(it->fd); + Debug::log(ERR, "Socket2 fd {} overflowed event queue, removing", it->fd.get()); + it = removeClientByFD(it->fd.get()); continue; } diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 6b506d33..c8335d20 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -1,6 +1,6 @@ #pragma once #include - +#include #include "../defines.hpp" #include "../helpers/memory/Memory.hpp" @@ -26,19 +26,19 @@ class CEventManager { int onClientEvent(int fd, uint32_t mask); struct SClient { - int fd = -1; - std::vector> events; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor fd; + std::vector> events; + wl_event_source* eventSource = nullptr; }; std::vector::iterator findClientByFD(int fd); std::vector::iterator removeClientByFD(int fd); private: - int m_iSocketFD = -1; - wl_event_source* m_pEventSource = nullptr; + Hyprutils::OS::CFileDescriptor m_iSocketFD; + wl_event_source* m_pEventSource = nullptr; - std::vector m_vClients; + std::vector m_vClients; }; inline UP g_pEventManager; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2cb77d21..247550ae 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -28,7 +28,9 @@ #include #include +#include using namespace Hyprutils::String; +using namespace Hyprutils::OS; #include #include @@ -853,19 +855,18 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) { const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1; // vtnr is bugged for some reason. - unsigned int ttynum = 0; - int fd; - if ((fd = open("/dev/tty", O_RDONLY | O_NOCTTY)) >= 0) { + unsigned int ttynum = 0; + Hyprutils::OS::CFileDescriptor fd{open("/dev/tty", O_RDONLY | O_NOCTTY)}; + if (fd.isValid()) { #if defined(VT_GETSTATE) struct vt_stat st; - if (!ioctl(fd, VT_GETSTATE, &st)) + if (!ioctl(fd.get(), VT_GETSTATE, &st)) ttynum = st.v_active; #elif defined(VT_GETACTIVE) int vt; - if (!ioctl(fd, VT_GETACTIVE, &vt)) + if (!ioctl(fd.get(), VT_GETACTIVE, &vt)) ttynum = vt; #endif - close(fd); } if (ttynum == TTY) @@ -944,11 +945,11 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo Debug::log(LOG, "Unable to create pipe for fork"); } - pid_t child, grandchild; + CFileDescriptor pipeSock[2] = {CFileDescriptor{socket[0]}, CFileDescriptor{socket[1]}}; + + pid_t child, grandchild; child = fork(); if (child < 0) { - close(socket[0]); - close(socket[1]); Debug::log(LOG, "Fail to create the first fork"); return 0; } @@ -967,22 +968,16 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); - close(socket[0]); - close(socket[1]); execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); } - close(socket[0]); - write(socket[1], &grandchild, sizeof(grandchild)); - close(socket[1]); + write(pipeSock[1].get(), &grandchild, sizeof(grandchild)); // exit child _exit(0); } // run in parent - close(socket[1]); - read(socket[0], &grandchild, sizeof(grandchild)); - close(socket[0]); + read(pipeSock[0].get(), &grandchild, sizeof(grandchild)); // clear child and leave grandchild to init waitpid(child, nullptr, 0); if (grandchild < 0) { diff --git a/src/managers/eventLoop/EventLoopManager.cpp b/src/managers/eventLoop/EventLoopManager.cpp index 4021c171..83bdf4a0 100644 --- a/src/managers/eventLoop/EventLoopManager.cpp +++ b/src/managers/eventLoop/EventLoopManager.cpp @@ -11,11 +11,12 @@ #include #include +using namespace Hyprutils::OS; #define TIMESPEC_NSEC_PER_SEC 1000000000L CEventLoopManager::CEventLoopManager(wl_display* display, wl_event_loop* wlEventLoop) { - m_sTimers.timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + m_sTimers.timerfd = CFileDescriptor{timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC)}; m_sWayland.loop = wlEventLoop; m_sWayland.display = display; } @@ -31,8 +32,6 @@ CEventLoopManager::~CEventLoopManager() { wl_event_source_remove(m_sIdle.eventSource); if (m_configWatcherInotifySource) wl_event_source_remove(m_configWatcherInotifySource); - if (m_sTimers.timerfd >= 0) - close(m_sTimers.timerfd); } static int timerWrite(int fd, uint32_t mask, void* data) { @@ -52,10 +51,10 @@ static int configWatcherWrite(int fd, uint32_t mask, void* data) { } void CEventLoopManager::enterLoop() { - m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr); + m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd.get(), WL_EVENT_READABLE, timerWrite, nullptr); - if (const auto FD = g_pConfigWatcher->getInotifyFD(); FD >= 0) - m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD, WL_EVENT_READABLE, configWatcherWrite, nullptr); + if (const auto& FD = g_pConfigWatcher->getInotifyFD(); FD.isValid()) + m_configWatcherInotifySource = wl_event_loop_add_fd(m_sWayland.loop, FD.get(), WL_EVENT_READABLE, configWatcherWrite, nullptr); syncPollFDs(); m_sListeners.pollFDsChanged = g_pCompositor->m_pAqBackend->events.pollFDsChanged.registerListener([this](std::any d) { syncPollFDs(); }); @@ -120,7 +119,7 @@ void CEventLoopManager::nudgeTimers() { itimerspec ts = {.it_value = now}; - timerfd_settime(m_sTimers.timerfd, TFD_TIMER_ABSTIME, &ts, nullptr); + timerfd_settime(m_sTimers.timerfd.get(), TFD_TIMER_ABSTIME, &ts, nullptr); } void CEventLoopManager::doLater(const std::function& fn) { diff --git a/src/managers/eventLoop/EventLoopManager.hpp b/src/managers/eventLoop/EventLoopManager.hpp index 95cc6109..ebeb2160 100644 --- a/src/managers/eventLoop/EventLoopManager.hpp +++ b/src/managers/eventLoop/EventLoopManager.hpp @@ -6,6 +6,7 @@ #include #include #include "helpers/signal/Signal.hpp" +#include #include "EventLoopTimer.hpp" @@ -54,7 +55,7 @@ class CEventLoopManager { struct { std::vector> timers; - int timerfd = -1; + Hyprutils::OS::CFileDescriptor timerfd; } m_sTimers; SIdleData m_sIdle; diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp index 6fdbaf4b..e70f0441 100644 --- a/src/protocols/DRMLease.cpp +++ b/src/protocols/DRMLease.cpp @@ -4,6 +4,7 @@ #include "managers/eventLoop/EventLoopManager.hpp" #include #include +using namespace Hyprutils::OS; CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { if UNLIKELY (!good()) @@ -185,15 +186,14 @@ CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resourc RESOURCE->parent = self; }); - int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); - if (fd < 0) { + CFileDescriptor fd{((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD()}; + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd in lease"); return; } - LOGM(LOG, "Sending DRMFD {} to new lease device", fd); - resource->sendDrmFd(fd); - close(fd); + LOGM(LOG, "Sending DRMFD {} to new lease device", fd.get()); + resource->sendDrmFd(fd.get()); for (auto const& m : PROTO::lease->primaryDevice->offeredOutputs) { if (m) @@ -231,16 +231,15 @@ void CDRMLeaseDeviceResource::sendConnector(PHLMONITOR monitor) { } CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { - auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); - auto fd = drm->getNonMasterFD(); + CFileDescriptor fd{drm->getNonMasterFD()}; - if (fd < 0) { + if (!fd.isValid()) { LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); return; } - close(fd); success = true; name = drm->gpuName; } diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp index ec1e73f2..c7849149 100644 --- a/src/protocols/DRMLease.hpp +++ b/src/protocols/DRMLease.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "drm-lease-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include /* TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index ce598385..23dafbca 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -6,6 +6,7 @@ #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { if UNLIKELY (!good()) @@ -103,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; @@ -112,7 +113,7 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SPsetOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); - timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd.get()); if (!timeline) { resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); @@ -120,11 +121,6 @@ CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP= 0) - close(fd); -} - SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); return data ? data->self.lock() : nullptr; @@ -171,7 +167,7 @@ CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SPsetImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { - auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), CFileDescriptor{fd}); if UNLIKELY (!RESOURCE->good()) { resource->noMemory(); return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 42ecdb3e..8677576f 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -4,6 +4,7 @@ #include "WaylandProtocol.hpp" #include "linux-drm-syncobj-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CWLSurfaceResource; class CDRMSyncobjTimelineResource; @@ -32,14 +33,14 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, int fd_); - ~CDRMSyncobjTimelineResource(); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); bool good(); WP self; - int fd = -1; + Hyprutils::OS::CFileDescriptor fd; SP timeline; private: diff --git a/src/protocols/DataDeviceWlr.cpp b/src/protocols/DataDeviceWlr.cpp index 71ee1c4a..3da5afd6 100644 --- a/src/protocols/DataDeviceWlr.cpp +++ b/src/protocols/DataDeviceWlr.cpp @@ -2,6 +2,7 @@ #include #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" +using namespace Hyprutils::OS; CWLRDataOffer::CWLRDataOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -11,21 +12,20 @@ CWLRDataOffer::CWLRDataOffer(SP resource_, SPsetOnDestroy([this](CZwlrDataControlOfferV1* r) { PROTO::dataWlr->destroyResource(this); }); resource->setReceive([this](CZwlrDataControlOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -77,15 +77,13 @@ std::vector CWLRDataSource::mimes() { return mimeTypes; } -void CWLRDataSource::send(const std::string& mime, uint32_t fd) { +void CWLRDataSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLRDataSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLRDataSource::accepted(const std::string& mime) { diff --git a/src/protocols/DataDeviceWlr.hpp b/src/protocols/DataDeviceWlr.hpp index 5eef163c..7f14b320 100644 --- a/src/protocols/DataDeviceWlr.hpp +++ b/src/protocols/DataDeviceWlr.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "wlr-data-control-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CWLRDataControlManagerResource; class CWLRDataSource; @@ -38,7 +39,7 @@ class CWLRDataSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 43ba9d41..0a383e2e 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -4,6 +4,7 @@ #include "../helpers/Monitor.hpp" #include "../protocols/core/Output.hpp" #include "../render/Renderer.hpp" +using namespace Hyprutils::OS; CGammaControl::CGammaControl(SP resource_, wl_resource* output) : resource(resource_) { if UNLIKELY (!resource_->resource()) @@ -46,34 +47,33 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); }); resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) { + CFileDescriptor gammaFd{fd}; if UNLIKELY (!pMonitor) { LOGM(ERR, "setGamma for a dead monitor"); resource->sendFailed(); - close(fd); return; } LOGM(LOG, "setGamma for {}", pMonitor->szName); - int fdFlags = fcntl(fd, F_GETFL, 0); + // TODO: make CFileDescriptor getflags use F_GETFL + int fdFlags = fcntl(gammaFd.get(), F_GETFL, 0); if UNLIKELY (fdFlags < 0) { LOGM(ERR, "Failed to get fd flags"); resource->sendFailed(); - close(fd); return; } - if UNLIKELY (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) { + // TODO: make CFileDescriptor setflags use F_SETFL + if UNLIKELY (fcntl(gammaFd.get(), F_SETFL, fdFlags | O_NONBLOCK) < 0) { LOGM(ERR, "Failed to set fd flags"); resource->sendFailed(); - close(fd); return; } - ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); + ssize_t readBytes = pread(gammaFd.get(), gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0); if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { LOGM(ERR, "Failed to read bytes"); - close(fd); if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) { gamma->error(ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch"); @@ -85,7 +85,6 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } gammaTableSet = true; - close(fd); // translate the table to AQ format std::vector red, green, blue; diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 796cec06..33121ecd 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -33,25 +33,22 @@ void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); - if UNLIKELY (keymapFD < 0) { + auto keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); + if UNLIKELY (!keymapFD.isValid()) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD.get(), 0); if UNLIKELY (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); - close(keymapFD); return; } memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); - - close(keymapFD); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD.get(), keyboard->xkbKeymapString.length() + 1); sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index d3135da0..b7b91594 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -14,6 +14,8 @@ #include "../render/OpenGL.hpp" #include "../Compositor.hpp" +using namespace Hyprutils::OS; + static std::optional devIDFromFD(int fd) { struct stat stat; if (fstat(fd, &stat) != 0) @@ -77,29 +79,21 @@ CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vec tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); - int fds[2] = {0}; - allocateSHMFilePair(tableSize, &fds[0], &fds[1]); + CFileDescriptor fds[2]; + allocateSHMFilePair(tableSize, fds[0], fds[1]); - auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0].get(), 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); - close(fds[0]); - close(fds[1]); return; } - close(fds[0]); - std::copy(formatsVec.begin(), formatsVec.end(), arr); munmap(arr, tableSize); - tableFD = fds[1]; -} - -CDMABUFFormatTable::~CDMABUFFormatTable() { - close(tableFD); + tableFD = std::move(fds[1]); } CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { @@ -234,18 +228,18 @@ void CLinuxDMABUFParamsResource::create(uint32_t id) { } bool CLinuxDMABUFParamsResource::commence() { - if (PROTO::linuxDma->mainDeviceFD < 0) + if (!PROTO::linuxDma->mainDeviceFD.isValid()) return true; for (int i = 0; i < attrs->planes; i++) { uint32_t handle = 0; - if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD, attrs->fds.at(i), &handle)) { + if (drmPrimeFDToHandle(PROTO::linuxDma->mainDeviceFD.get(), attrs->fds.at(i), &handle)) { LOGM(ERR, "Failed to import dmabuf fd"); return false; } - if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD, handle)) { + if (drmCloseBufferHandle(PROTO::linuxDma->mainDeviceFD.get(), handle)) { LOGM(ERR, "Failed to close dmabuf handle"); return false; } @@ -303,7 +297,7 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); auto& formatTable = PROTO::linuxDma->formatTable; - resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + resource->sendFormatTable(formatTable->tableFD.get(), formatTable->tableSize); sendDefaultFeedback(); } @@ -472,9 +466,9 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const if (device->available_nodes & (1 << DRM_NODE_RENDER)) { const char* name = device->nodes[DRM_NODE_RENDER]; - mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); + mainDeviceFD = CFileDescriptor{open(name, O_RDWR | O_CLOEXEC)}; drmFreeDevice(&device); - if (mainDeviceFD < 0) { + if (!mainDeviceFD.isValid()) { LOGM(ERR, "failed to open drm dev, disabling linux dmabuf"); removeGlobal(); return; @@ -496,7 +490,7 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { auto newFormatTable = makeUnique(formatTable->rendererTranche, formatTable->monitorTranches); for (auto const& feedback : m_vFeedbacks) { - feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + feedback->resource->sendFormatTable(newFormatTable->tableFD.get(), newFormatTable->tableSize); if (feedback->lastFeedbackWasScanout) { PHLMONITOR mon; auto HLSurface = CWLSurface::fromResource(feedback->surface); @@ -519,11 +513,6 @@ void CLinuxDMABufV1Protocol::resetFormatTable() { formatTable = std::move(newFormatTable); } -CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { - if (mainDeviceFD >= 0) - close(mainDeviceFD); -} - void CLinuxDMABufV1Protocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 91cf3283..6c967878 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -9,6 +9,7 @@ #include "../helpers/Format.hpp" #include "../helpers/Monitor.hpp" #include +#include class CDMABuffer; class CWLSurfaceResource; @@ -48,9 +49,9 @@ struct SDMABUFTranche { class CDMABUFFormatTable { public: CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector> tranches); - ~CDMABUFFormatTable(); + ~CDMABUFFormatTable() = default; - int tableFD = -1; + Hyprutils::OS::CFileDescriptor tableFD; size_t tableSize = 0; SDMABUFTranche rendererTranche; std::vector> monitorTranches; @@ -107,7 +108,7 @@ class CLinuxDMABUFResource { class CLinuxDMABufV1Protocol : public IWaylandProtocol { public: CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name); - ~CLinuxDMABufV1Protocol(); + ~CLinuxDMABufV1Protocol() = default; virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); void updateScanoutTranche(SP surface, PHLMONITOR pMonitor); @@ -128,7 +129,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { UP formatTable; dev_t mainDevice; - int mainDeviceFD = -1; + Hyprutils::OS::CFileDescriptor mainDeviceFD; friend class CLinuxDMABUFResource; friend class CLinuxDMABUFFeedbackResource; diff --git a/src/protocols/PrimarySelection.cpp b/src/protocols/PrimarySelection.cpp index 567bfdd2..620f262e 100644 --- a/src/protocols/PrimarySelection.cpp +++ b/src/protocols/PrimarySelection.cpp @@ -3,6 +3,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "../config/ConfigValue.hpp" +using namespace Hyprutils::OS; CPrimarySelectionOffer::CPrimarySelectionOffer(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -12,21 +13,20 @@ CPrimarySelectionOffer::CPrimarySelectionOffer(SP r resource->setOnDestroy([this](CZwpPrimarySelectionOfferV1* r) { PROTO::primarySelection->destroyResource(this); }); resource->setReceive([this](CZwpPrimarySelectionOfferV1* r, const char* mime, int32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } LOGM(LOG, "Offer {:x} asks to send data from source {:x}", (uintptr_t)this, (uintptr_t)source.get()); - source->send(mime, fd); + source->send(mime, std::move(sendFd)); }); } @@ -78,15 +78,13 @@ std::vector CPrimarySelectionSource::mimes() { return mimeTypes; } -void CPrimarySelectionSource::send(const std::string& mime, uint32_t fd) { +void CPrimarySelectionSource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CPrimarySelectionSource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CPrimarySelectionSource::accepted(const std::string& mime) { diff --git a/src/protocols/PrimarySelection.hpp b/src/protocols/PrimarySelection.hpp index aeebe03c..0ecc962b 100644 --- a/src/protocols/PrimarySelection.hpp +++ b/src/protocols/PrimarySelection.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "primary-selection-unstable-v1.hpp" #include "types/DataDevice.hpp" +#include class CPrimarySelectionOffer; class CPrimarySelectionSource; @@ -38,7 +39,7 @@ class CPrimarySelectionSource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); diff --git a/src/protocols/SecurityContext.cpp b/src/protocols/SecurityContext.cpp index e5b3cf2a..30fca260 100644 --- a/src/protocols/SecurityContext.cpp +++ b/src/protocols/SecurityContext.cpp @@ -1,6 +1,7 @@ #include "SecurityContext.hpp" #include "../Compositor.hpp" #include +using namespace Hyprutils::OS; static int onListenFdEvent(int fd, uint32_t mask, void* data) { auto sc = (CSecurityContext*)data; @@ -14,8 +15,8 @@ static int onCloseFdEvent(int fd, uint32_t mask, void* data) { return 0; } -SP CSecurityContextSandboxedClient::create(int clientFD_) { - auto p = SP(new CSecurityContextSandboxedClient(clientFD_)); +SP CSecurityContextSandboxedClient::create(CFileDescriptor clientFD_) { + auto p = SP(new CSecurityContextSandboxedClient(std::move(clientFD_))); if (!p->client) return nullptr; return p; @@ -27,8 +28,8 @@ static void onSecurityContextClientDestroy(wl_listener* l, void* d) { client->onDestroy(); } -CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) : clientFD(clientFD_) { - client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD); +CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(CFileDescriptor clientFD_) : clientFD(std::move(clientFD_)) { + client = wl_client_create(g_pCompositor->m_sWLDisplay, clientFD.get()); if (!client) return; @@ -41,7 +42,6 @@ CSecurityContextSandboxedClient::CSecurityContextSandboxedClient(int clientFD_) CSecurityContextSandboxedClient::~CSecurityContextSandboxedClient() { wl_list_remove(&destroyListener.listener.link); wl_list_init(&destroyListener.listener.link); - close(clientFD); } void CSecurityContextSandboxedClient::onDestroy() { @@ -113,8 +113,8 @@ CSecurityContext::CSecurityContext(SP resource_, int liste LOGM(LOG, "security_context at 0x{:x} commits", (uintptr_t)this); - listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD, WL_EVENT_READABLE, ::onListenFdEvent, this); - closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD, 0, ::onCloseFdEvent, this); + listenSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, listenFD.get(), WL_EVENT_READABLE, ::onListenFdEvent, this); + closeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, closeFD.get(), 0, ::onCloseFdEvent, this); if (!listenSource || !closeSource) { r->noMemory(); @@ -144,16 +144,15 @@ void CSecurityContext::onListen(uint32_t mask) { if (!(mask & WL_EVENT_READABLE)) return; - int clientFD = accept(listenFD, nullptr, nullptr); - if UNLIKELY (clientFD < 0) { + CFileDescriptor clientFD{accept(listenFD.get(), nullptr, nullptr)}; + if UNLIKELY (!clientFD.isValid()) { LOGM(ERR, "security_context at 0x{:x} couldn't accept", (uintptr_t)this); return; } - auto newClient = CSecurityContextSandboxedClient::create(clientFD); + auto newClient = CSecurityContextSandboxedClient::create(std::move(clientFD)); if UNLIKELY (!newClient) { LOGM(ERR, "security_context at 0x{:x} couldn't create a client", (uintptr_t)this); - close(clientFD); return; } diff --git a/src/protocols/SecurityContext.hpp b/src/protocols/SecurityContext.hpp index 2bec08d4..56d4f7b4 100644 --- a/src/protocols/SecurityContext.hpp +++ b/src/protocols/SecurityContext.hpp @@ -4,19 +4,20 @@ #include #include "WaylandProtocol.hpp" #include "security-context-v1.hpp" +#include class CSecurityContext { public: CSecurityContext(SP resource_, int listenFD_, int closeFD_); ~CSecurityContext(); - bool good(); + bool good(); - std::string sandboxEngine, appID, instanceID; - int listenFD = -1, closeFD = -1; + std::string sandboxEngine, appID, instanceID; + Hyprutils::OS::CFileDescriptor listenFD, closeFD; - void onListen(uint32_t mask); - void onClose(uint32_t mask); + void onListen(uint32_t mask); + void onClose(uint32_t mask); private: SP resource; @@ -44,7 +45,7 @@ struct SCSecurityContextSandboxedClientDestroyWrapper { class CSecurityContextSandboxedClient { public: - static SP create(int clientFD); + static SP create(Hyprutils::OS::CFileDescriptor clientFD); ~CSecurityContextSandboxedClient(); void onDestroy(); @@ -52,10 +53,10 @@ class CSecurityContextSandboxedClient { SCSecurityContextSandboxedClientDestroyWrapper destroyListener; private: - CSecurityContextSandboxedClient(int clientFD_); + CSecurityContextSandboxedClient(Hyprutils::OS::CFileDescriptor clientFD_); - wl_client* client = nullptr; - int clientFD = -1; + wl_client* client = nullptr; + Hyprutils::OS::CFileDescriptor clientFD; friend class CSecurityContextProtocol; friend class CSecurityContext; diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 4fec57c0..00aca041 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,6 +1,7 @@ #include "VirtualKeyboard.hpp" #include #include "../devices/IKeyboard.hpp" +using namespace Hyprutils::OS; CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -51,20 +52,19 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { - auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + auto xkbContext = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + CFileDescriptor keymapFd{fd}; if UNLIKELY (!xkbContext) { LOGM(ERR, "xkbContext creation failed"); r->noMemory(); - close(fd); return; } - auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, fd, 0); + auto keymapData = mmap(nullptr, len, PROT_READ, MAP_PRIVATE, keymapFd.get(), 0); if UNLIKELY (keymapData == MAP_FAILED) { LOGM(ERR, "keymapData alloc failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -75,7 +75,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP LOGM(ERR, "xkbKeymap creation failed"); xkb_context_unref(xkbContext); r->noMemory(); - close(fd); return; } @@ -86,7 +85,6 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP xkb_keymap_unref(xkbKeymap); xkb_context_unref(xkbContext); - close(fd); }); name = "hl-virtual-keyboard"; diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 8157b276..0a13003b 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -5,6 +5,7 @@ #include "WaylandProtocol.hpp" #include "virtual-keyboard-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CVirtualKeyboardV1Resource { public: diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index e17b5612..0931608a 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,6 +13,7 @@ #include "../../managers/HookSystemManager.hpp" #include "../../helpers/Monitor.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLDataOfferResource::CWLDataOfferResource(SP resource_, SP source_) : source(source_), resource(resource_) { if UNLIKELY (!good()) @@ -39,15 +40,14 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); - close(fd); return; } if (dead) { LOGM(WARN, "Possible bug: Receive on an offer that's dead"); - close(fd); return; } @@ -58,7 +58,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPaccepted(mime ? mime : ""); } - source->send(mime ? mime : "", fd); + source->send(mime ? mime : "", std::move(sendFd)); recvd = true; @@ -182,15 +182,13 @@ std::vector CWLDataSourceResource::mimes() { return mimeTypes; } -void CWLDataSourceResource::send(const std::string& mime, uint32_t fd) { +void CWLDataSourceResource::send(const std::string& mime, CFileDescriptor fd) { if (std::find(mimeTypes.begin(), mimeTypes.end(), mime) == mimeTypes.end()) { LOGM(ERR, "Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime"); - close(fd); return; } - resource->sendSend(mime.c_str(), fd); - close(fd); + resource->sendSend(mime.c_str(), fd.get()); } void CWLDataSourceResource::cancelled() { diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index d8bc2b9c..dfea4a71 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -16,6 +16,7 @@ #include "../../helpers/signal/Signal.hpp" #include "../../helpers/math/Math.hpp" #include "../types/DataDevice.hpp" +#include class CWLDataDeviceResource; class CWLDataDeviceManagerResource; @@ -63,7 +64,7 @@ class CWLDataSourceResource : public IDataSource { bool good(); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index c6b2de05..1f07a15e 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -321,35 +321,18 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { if (!(PROTO::seat->currentCaps & eHIDCapabilityType::HID_INPUT_CAPABILITY_KEYBOARD)) return; - std::string_view keymap; - int fd; - uint32_t size; - if (keyboard) { - keymap = keyboard->xkbKeymapString; - fd = keyboard->xkbKeymapFD; - size = keyboard->xkbKeymapString.length() + 1; - } else { - fd = open("/dev/null", O_RDONLY | O_CLOEXEC); - if (fd < 0) { - LOGM(ERR, "Failed to open /dev/null"); - return; - } - size = 0; - } + std::string_view keymap = keyboard->xkbKeymapString; + Hyprutils::OS::CFileDescriptor& fd = keyboard->xkbKeymapFD; + uint32_t size = keyboard->xkbKeymapString.length() + 1; - if (keymap == lastKeymap) { - if (!keyboard) - close(fd); + if (keymap == lastKeymap) return; - } + lastKeymap = keymap; const wl_keyboard_keymap_format format = keyboard ? WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 : WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP; - resource->sendKeymap(format, fd, size); - - if (!keyboard) - close(fd); + resource->sendKeymap(format, fd.get(), size); } void CWLKeyboardResource::sendEnter(SP surface) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 1649f82f..e0e62560 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -7,6 +7,7 @@ #include "../types/WLBuffer.hpp" #include "../../helpers/Format.hpp" #include "../../render/Renderer.hpp" +using namespace Hyprutils::OS; CWLSHMBuffer::CWLSHMBuffer(SP pool_, uint32_t id, int32_t offset_, const Vector2D& size_, int32_t stride_, uint32_t fmt_) { if UNLIKELY (!pool_->pool->data) @@ -51,7 +52,7 @@ bool CWLSHMBuffer::isSynchronous() { Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { Aquamarine::SSHMAttrs attrs; attrs.success = true; - attrs.fd = pool->fd; + attrs.fd = pool->fd.get(); attrs.format = NFormatUtils::shmToDRM(fmt); attrs.size = size; attrs.stride = stride; @@ -75,13 +76,12 @@ void CWLSHMBuffer::update(const CRegion& damage) { texture->update(NFormatUtils::shmToDRM(fmt), (uint8_t*)pool->data + offset, stride, damage); } -CSHMPool::CSHMPool(int fd_, size_t size_) : fd(fd_), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) { +CSHMPool::CSHMPool(CFileDescriptor fd_, size_t size_) : fd(std::move(fd_)), size(size_), data(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0)) { ; } CSHMPool::~CSHMPool() { munmap(data, size); - close(fd); } void CSHMPool::resize(size_t size_) { @@ -90,23 +90,23 @@ void CSHMPool::resize(size_t size_) { if (data) munmap(data, size); size = size_; - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); if UNLIKELY (data == MAP_FAILED) - LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd); + LOGM(ERR, "Couldn't mmap {} bytes from fd {} of shm client", size, fd.get()); } -static int shmIsSizeValid(int fd, size_t size) { +static int shmIsSizeValid(CFileDescriptor& fd, size_t size) { struct stat st; - if UNLIKELY (fstat(fd, &st) == -1) { - LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd); + if UNLIKELY (fstat(fd.get(), &st) == -1) { + LOGM(ERR, "Couldn't get stat for fd {} of shm client", fd.get()); return 0; } return (size_t)st.st_size >= size; } -CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t size_) : resource(resource_) { +CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, CFileDescriptor fd_, size_t size_) : resource(resource_) { if UNLIKELY (!good()) return; @@ -115,7 +115,7 @@ CWLSHMPoolResource::CWLSHMPoolResource(SP resource_, int fd_, size_t return; } - pool = makeShared(fd_, size_); + pool = makeShared(std::move(fd_), size_); resource->setDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); resource->setOnDestroy([this](CWlShmPool* r) { PROTO::shm->destroyResource(this); }); @@ -176,7 +176,8 @@ CWLSHMResource::CWLSHMResource(SP resource_) : resource(resource_) { resource->setOnDestroy([this](CWlShm* r) { PROTO::shm->destroyResource(this); }); resource->setCreatePool([](CWlShm* r, uint32_t id, int32_t fd, int32_t size) { - const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), fd, size)); + CFileDescriptor poolFd{fd}; + const auto RESOURCE = PROTO::shm->m_vPools.emplace_back(makeShared(makeShared(r->client(), r->version(), id), std::move(poolFd), size)); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index d7e81367..fef821cb 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -7,6 +7,8 @@ - wl_buffer with shm */ +#include +#include #include #include #include "../WaylandProtocol.hpp" @@ -18,14 +20,14 @@ class CWLSHMPoolResource; class CSHMPool { public: - CSHMPool(int fd, size_t size); + CSHMPool(Hyprutils::OS::CFileDescriptor fd, size_t size); ~CSHMPool(); - int fd = 0; - size_t size = 0; - void* data = nullptr; + Hyprutils::OS::CFileDescriptor fd; + size_t size = 0; + void* data = nullptr; - void resize(size_t size); + void resize(size_t size); }; class CWLSHMBuffer : public IHLBuffer { @@ -57,7 +59,7 @@ class CWLSHMBuffer : public IHLBuffer { class CWLSHMPoolResource { public: - CWLSHMPoolResource(SP resource_, int fd, size_t size); + CWLSHMPoolResource(SP resource_, Hyprutils::OS::CFileDescriptor fd, size_t size); bool good(); diff --git a/src/protocols/types/DataDevice.hpp b/src/protocols/types/DataDevice.hpp index 62f10de2..cbb4b271 100644 --- a/src/protocols/types/DataDevice.hpp +++ b/src/protocols/types/DataDevice.hpp @@ -7,6 +7,7 @@ #include #include "../../helpers/memory/Memory.hpp" #include "../../helpers/math/Math.hpp" +#include class CWLDataOfferResource; class CX11DataOffer; @@ -24,10 +25,10 @@ class IDataSource { IDataSource() = default; virtual ~IDataSource() = default; - virtual std::vector mimes() = 0; - virtual void send(const std::string& mime, uint32_t fd) = 0; - virtual void accepted(const std::string& mime) = 0; - virtual void cancelled() = 0; + virtual std::vector mimes() = 0; + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd) = 0; + virtual void accepted(const std::string& mime) = 0; + virtual void cancelled() = 0; virtual bool hasDnd(); virtual bool dndDone(); virtual void sendDndFinished(); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 78b53c9b..e4aadd63 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -19,6 +19,7 @@ #include #include #include +using namespace Hyprutils::OS; const std::vector ASSET_PATHS = { #ifdef DATAROOTDIR @@ -301,11 +302,11 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() : m_iDRMFD(g_pCompositor->m_iDRMFD) { Debug::log(WARN, "EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm"); if (EGLEXTENSIONS.contains("KHR_platform_gbm")) { success = true; - m_iGBMFD = openRenderNode(m_iDRMFD); - if (m_iGBMFD < 0) + m_iGBMFD = CFileDescriptor{openRenderNode(m_iDRMFD)}; + if (!m_iGBMFD.isValid()) RASSERT(false, "Couldn't open a gbm fd"); - m_pGbmDevice = gbm_create_device(m_iGBMFD); + m_pGbmDevice = gbm_create_device(m_iGBMFD.get()); if (!m_pGbmDevice) RASSERT(false, "Couldn't open a gbm device"); @@ -371,9 +372,6 @@ CHyprOpenGLImpl::~CHyprOpenGLImpl() { if (m_pGbmDevice) gbm_device_destroy(m_pGbmDevice); - - if (m_iGBMFD >= 0) - close(m_iGBMFD); } std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { @@ -2954,29 +2952,28 @@ std::vector CHyprOpenGLImpl::getDRMFormats() { return drmFormats; } -SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { +SP CHyprOpenGLImpl::createEGLSync(CFileDescriptor fenceFD) { std::vector attribs; - int dupFd = -1; - if (fenceFD > 0) { - dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0); - if (dupFd < 0) { + CFileDescriptor dupFd; + if (fenceFD.isValid()) { + dupFd = fenceFD.duplicate(); + if (!dupFd.isValid()) { Debug::log(ERR, "createEGLSync: dup failed"); return nullptr; } // reserve number of elements to avoid reallocations attribs.reserve(3); attribs.push_back(EGL_SYNC_NATIVE_FENCE_FD_ANDROID); - attribs.push_back(dupFd); + attribs.push_back(dupFd.get()); attribs.push_back(EGL_NONE); } EGLSyncKHR sync = m_sProc.eglCreateSyncKHR(m_pEglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs.data()); if (sync == EGL_NO_SYNC_KHR) { Debug::log(ERR, "eglCreateSyncKHR failed"); - if (dupFd >= 0) - close(dupFd); return nullptr; - } + } else + dupFd.take(); // eglCreateSyncKHR only takes ownership on success // we need to flush otherwise we might not get a valid fd glFlush(); @@ -2989,19 +2986,18 @@ SP CHyprOpenGLImpl::createEGLSync(int fenceFD) { auto eglsync = SP(new CEGLSync); eglsync->sync = sync; - eglsync->m_iFd = fd; + eglsync->m_iFd = CFileDescriptor{fd}; return eglsync; } bool CHyprOpenGLImpl::waitForTimelinePoint(SP timeline, uint64_t point) { - int fd = timeline->exportAsSyncFileFD(point); - if (fd < 0) { + auto fd = timeline->exportAsSyncFileFD(point); + if (!fd.isValid()) { Debug::log(ERR, "waitForTimelinePoint: failed to get a fd from explicit timeline"); return false; } - auto sync = g_pHyprOpenGL->createEGLSync(fd); - close(fd); + auto sync = g_pHyprOpenGL->createEGLSync(std::move(fd)); if (!sync) { Debug::log(ERR, "waitForTimelinePoint: failed to get an eglsync from explicit timeline"); return false; @@ -3082,12 +3078,9 @@ CEGLSync::~CEGLSync() { if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE) Debug::log(ERR, "eglDestroySyncKHR failed"); - - if (m_iFd >= 0) - close(m_iFd); } -int CEGLSync::fd() { +CFileDescriptor& CEGLSync::fd() { return m_iFd; } diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 1ebb0162..d7abdf63 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "../debug/TracyDefines.hpp" @@ -146,15 +147,15 @@ class CEGLSync { public: ~CEGLSync(); - EGLSyncKHR sync = nullptr; + EGLSyncKHR sync = nullptr; - int fd(); - bool wait(); + Hyprutils::OS::CFileDescriptor& fd(); + bool wait(); private: CEGLSync() = default; - int m_iFd = -1; + Hyprutils::OS::CFileDescriptor m_iFd; friend class CHyprOpenGLImpl; }; @@ -228,14 +229,14 @@ class CHyprOpenGLImpl { uint32_t getPreferredReadFormat(PHLMONITOR pMonitor); std::vector getDRMFormats(); EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - SP createEGLSync(int fenceFD); + SP createEGLSync(Hyprutils::OS::CFileDescriptor fenceFD); bool waitForTimelinePoint(SP timeline, uint64_t point); SCurrentRenderData m_RenderData; GLint m_iCurrentOutputFb = 0; - int m_iGBMFD = -1; + Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; EGLDisplay m_pEglDisplay = nullptr; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 67d8b58b..42445728 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -36,6 +36,7 @@ #include using namespace Hyprutils::Utils; +using namespace Hyprutils::OS; extern "C" { #include @@ -1462,10 +1463,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, Aquamar bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { // apply timelines for explicit sync // save inFD otherwise reset will reset it - auto inFD = pMonitor->output->state->state().explicitInFence; + CFileDescriptor inFD{pMonitor->output->state->state().explicitInFence}; pMonitor->output->state->resetExplicitFences(); - if (inFD >= 0) - pMonitor->output->state->setExplicitInFence(inFD); + if (inFD.isValid()) + pMonitor->output->state->setExplicitInFence(inFD.get()); static auto PHDR = CConfigValue("experimental:hdr"); @@ -1515,7 +1516,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { bool ok = pMonitor->state.commit(); if (!ok) { - if (inFD >= 0) { + if (inFD.isValid()) { Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); pMonitor->output->state->resetExplicitFences(); ok = pMonitor->state.commit(); @@ -1534,11 +1535,8 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { if (!explicitOptions.explicitEnabled) return ok; - if (inFD >= 0) - close(inFD); - Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); @@ -2272,7 +2270,7 @@ void CHyprRenderer::endRender() { auto explicitOptions = getExplicitSyncSettings(); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { - auto sync = g_pHyprOpenGL->createEGLSync(-1); + auto sync = g_pHyprOpenGL->createEGLSync({}); if (!sync) { Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; @@ -2285,12 +2283,12 @@ void CHyprRenderer::endRender() { } auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); - if (fd <= 0) { + if (!fd.isValid()) { Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } - PMONITOR->output->state->setExplicitInFence(fd); + PMONITOR->output->state->setExplicitInFence(fd.take()); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); diff --git a/src/xwayland/Dnd.cpp b/src/xwayland/Dnd.cpp index d4ae3780..16d166ce 100644 --- a/src/xwayland/Dnd.cpp +++ b/src/xwayland/Dnd.cpp @@ -7,6 +7,8 @@ #include "../managers/XWaylandManager.hpp" #include "../desktop/WLSurface.hpp" +using namespace Hyprutils::OS; + #ifndef NO_XWAYLAND static xcb_atom_t dndActionToAtom(uint32_t actions) { if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) @@ -172,7 +174,7 @@ std::vector CX11DataSource::mimes() { return mimeTypes; } -void CX11DataSource::send(const std::string& mime, uint32_t fd) { +void CX11DataSource::send(const std::string& mime, CFileDescriptor fd) { ; } diff --git a/src/xwayland/Dnd.hpp b/src/xwayland/Dnd.hpp index 8da60ddd..fb030796 100644 --- a/src/xwayland/Dnd.hpp +++ b/src/xwayland/Dnd.hpp @@ -2,6 +2,7 @@ #include "../protocols/types/DataDevice.hpp" #include +#include #define XDND_VERSION 5 @@ -35,7 +36,7 @@ class CX11DataSource : public IDataSource { ~CX11DataSource() = default; virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual bool hasDnd(); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index d5dce333..99bcdf62 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -24,70 +24,41 @@ #include "../defines.hpp" #include "../Compositor.hpp" #include "../managers/CursorManager.hpp" +using namespace Hyprutils::OS; // Constants -constexpr int SOCKET_DIR_PERMISSIONS = 0755; -constexpr int SOCKET_BACKLOG = 1; -constexpr int MAX_SOCKET_RETRIES = 32; -constexpr int LOCK_FILE_MODE = 0444; +constexpr int SOCKET_DIR_PERMISSIONS = 0755; +constexpr int SOCKET_BACKLOG = 1; +constexpr int MAX_SOCKET_RETRIES = 32; +constexpr int LOCK_FILE_MODE = 0444; -static bool setCloseOnExec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - if (cloexec) - flags = flags | FD_CLOEXEC; - else - flags = flags & ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) == -1) { - Debug::log(ERR, "fcntl failed"); - return false; - } - - return true; -} - -static void cleanUpSocket(int fd, const char* path) { - close(fd); - if (path[0]) - unlink(path); -} - -static inline void closeSocketSafely(int& fd) { - if (fd >= 0) - close(fd); -} - -static int createSocket(struct sockaddr_un* addr, size_t path_size) { - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; - int fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { +static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) { + socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; + CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; + if (!fd.isValid()) { Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - return -1; + return {}; } - if (!setCloseOnExec(fd, true)) { - close(fd); - return -1; + if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) { + return {}; } if (addr->sun_path[0]) unlink(addr->sun_path); - if (bind(fd, (struct sockaddr*)addr, size) < 0) { + if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) { Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } - if (listen(fd, SOCKET_BACKLOG) < 0) { + if (listen(fd.get(), SOCKET_BACKLOG) < 0) { Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - cleanUpSocket(fd, addr->sun_path); - return -1; + if (addr->sun_path[0]) + unlink(addr->sun_path); + return {}; } return fd; @@ -141,7 +112,7 @@ static std::string getSocketPath(int display, bool isLinux) { return std::format("/tmp/.X11-unix/X{}_", display); } -static bool openSockets(std::array& sockets, int display) { +static bool openSockets(std::array& sockets, int display) { if (!ensureSocketDirExists()) return false; @@ -151,17 +122,16 @@ static bool openSockets(std::array& sockets, int display) { path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[0] = createSocket(&addr, path.length()); - if (sockets[0] < 0) + sockets[0] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[0].isValid()) return false; path = getSocketPath(display, true); strncpy(addr.sun_path, path.c_str(), path.length() + 1); - sockets[1] = createSocket(&addr, path.length()); - if (sockets[1] < 0) { - close(sockets[0]); - sockets[0] = -1; + sockets[1] = CFileDescriptor{createSocket(&addr, path.length())}; + if (!sockets[1].isValid()) { + sockets[0].reset(); return false; } @@ -174,7 +144,8 @@ static void startServer(void* data) { } static int xwaylandReady(int fd, uint32_t mask, void* data) { - return g_pXWayland->pServer->ready(fd, mask); + CFileDescriptor xwlFd{fd}; + return g_pXWayland->pServer->ready(std::move(xwlFd), mask); } static bool safeRemove(const std::string& path) { @@ -186,38 +157,34 @@ static bool safeRemove(const std::string& path) { bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= MAX_SOCKET_RETRIES; ++i) { - std::string lockPath = std::format("/tmp/.X{}-lock", i); + std::string lockPath = std::format("/tmp/.X{}-lock", i); - int fd = open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE); - if (fd >= 0) { + CFileDescriptor fd{open(lockPath.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, LOCK_FILE_MODE)}; + if (fd.isValid()) { // we managed to open the lock if (!openSockets(xFDs, i)) { safeRemove(lockPath); - close(fd); continue; } const std::string pidStr = std::to_string(getpid()); - if (write(fd, pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { + if (write(fd.get(), pidStr.c_str(), pidStr.length()) != (long)pidStr.length()) { safeRemove(lockPath); - close(fd); continue; } - close(fd); display = i; displayName = std::format(":{}", display); break; } - fd = open(lockPath.c_str(), O_RDONLY | O_CLOEXEC); + fd = CFileDescriptor{open(lockPath.c_str(), O_RDONLY | O_CLOEXEC)}; - if (fd < 0) + if (!fd.isValid()) continue; char pidstr[12] = {0}; - read(fd, pidstr, sizeof(pidstr) - 1); - close(fd); + read(fd.get(), pidstr, sizeof(pidstr) - 1); int32_t pid = 0; try { @@ -249,9 +216,6 @@ CXWaylandServer::~CXWaylandServer() { if (display < 0) return; - closeSocketSafely(xFDs[0]); - closeSocketSafely(xFDs[1]); - std::string lockPath = std::format("/tmp/.X{}-lock", display); safeRemove(lockPath); @@ -277,21 +241,11 @@ void CXWaylandServer::die() { if (pipeSource) wl_event_source_remove(pipeSource); - if (pipeFd >= 0) - close(pipeFd); - - closeSocketSafely(waylandFDs[0]); - closeSocketSafely(waylandFDs[1]); - closeSocketSafely(xwmFDs[0]); - closeSocketSafely(xwmFDs[1]); - // possible crash. Better to leak a bit. //if (xwaylandClient) // wl_client_destroy(xwaylandClient); xwaylandClient = nullptr; - waylandFDs = {-1, -1}; - xwmFDs = {-1, -1}; } bool CXWaylandServer::create() { @@ -307,15 +261,17 @@ bool CXWaylandServer::create() { return true; } -void CXWaylandServer::runXWayland(int notifyFD) { - if (!setCloseOnExec(xFDs[0], false) || !setCloseOnExec(xFDs[1], false) || !setCloseOnExec(waylandFDs[1], false) || !setCloseOnExec(xwmFDs[1], false)) { +void CXWaylandServer::runXWayland(CFileDescriptor& notifyFD) { + if (!xFDs[0].setFlags(xFDs[0].getFlags() & ~FD_CLOEXEC) || !xFDs[1].setFlags(xFDs[1].getFlags() & ~FD_CLOEXEC) || + !waylandFDs[1].setFlags(waylandFDs[1].getFlags() & ~FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() & ~FD_CLOEXEC)) { Debug::log(ERR, "Failed to unset cloexec on fds"); _exit(EXIT_FAILURE); } - auto cmd = std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0], xFDs[1], notifyFD, xwmFDs[1]); + auto cmd = + std::format("Xwayland {} -rootless -core -listenfd {} -listenfd {} -displayfd {} -wm {}", displayName, xFDs[0].get(), xFDs[1].get(), notifyFD.get(), xwmFDs[1].get()); - auto waylandSocket = std::format("{}", waylandFDs[1]); + auto waylandSocket = std::format("{}", waylandFDs[1].get()); setenv("WAYLAND_SOCKET", waylandSocket.c_str(), true); Debug::log(LOG, "Starting XWayland with \"{}\", bon voyage!", cmd); @@ -327,40 +283,46 @@ void CXWaylandServer::runXWayland(int notifyFD) { } bool CXWaylandServer::start() { - idleSource = nullptr; - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, waylandFDs.data()) != 0) { + idleSource = nullptr; + int wlPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, wlPair) != 0) { Debug::log(ERR, "socketpair failed (1)"); die(); return false; } + waylandFDs[0] = CFileDescriptor{wlPair[0]}; + waylandFDs[1] = CFileDescriptor{wlPair[1]}; - if (!setCloseOnExec(waylandFDs[0], true) || !setCloseOnExec(waylandFDs[1], true)) { + if (!waylandFDs[0].setFlags(waylandFDs[0].getFlags() | FD_CLOEXEC) || !waylandFDs[1].setFlags(waylandFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (1)"); die(); return false; } - if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmFDs.data()) != 0) { + int xwmPair[2] = {-1, -1}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, xwmPair) != 0) { Debug::log(ERR, "socketpair failed (2)"); die(); return false; } - if (!setCloseOnExec(xwmFDs[0], true) || !setCloseOnExec(xwmFDs[1], true)) { + xwmFDs[0] = CFileDescriptor{xwmPair[0]}; + xwmFDs[1] = CFileDescriptor{xwmPair[1]}; + + if (!xwmFDs[0].setFlags(xwmFDs[0].getFlags() | FD_CLOEXEC) || !xwmFDs[1].setFlags(xwmFDs[1].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (2)"); die(); return false; } - xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0]); + xwaylandClient = wl_client_create(g_pCompositor->m_sWLDisplay, waylandFDs[0].get()); if (!xwaylandClient) { Debug::log(ERR, "wl_client_create failed"); die(); return false; } - waylandFDs[0] = -1; + waylandFDs[0].take(); // does this leak? int notify[2] = {-1, -1}; if (pipe(notify) < 0) { @@ -369,22 +331,20 @@ bool CXWaylandServer::start() { return false; } - if (!setCloseOnExec(notify[0], true)) { + CFileDescriptor notifyFds[2] = {CFileDescriptor{notify[0]}, CFileDescriptor{notify[1]}}; + + if (!notifyFds[0].setFlags(notifyFds[0].getFlags() | FD_CLOEXEC)) { Debug::log(ERR, "set_cloexec failed (3)"); - close(notify[0]); - close(notify[1]); die(); return false; } - pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notify[0], WL_EVENT_READABLE, ::xwaylandReady, nullptr); - pipeFd = notify[0]; + pipeSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, notifyFds[0].get(), WL_EVENT_READABLE, ::xwaylandReady, nullptr); + pipeFd = std::move(notifyFds[0]); serverPID = fork(); if (serverPID < 0) { Debug::log(ERR, "fork failed"); - close(notify[0]); - close(notify[1]); die(); return false; } else if (serverPID == 0) { @@ -393,25 +353,19 @@ bool CXWaylandServer::start() { Debug::log(ERR, "second fork failed"); _exit(1); } else if (pid == 0) - runXWayland(notify[1]); + runXWayland(notifyFds[1]); _exit(0); } - close(notify[1]); - close(waylandFDs[1]); - closeSocketSafely(xwmFDs[1]); - waylandFDs[1] = -1; - xwmFDs[1] = -1; - return true; } -int CXWaylandServer::ready(int fd, uint32_t mask) { +int CXWaylandServer::ready(CFileDescriptor fd, uint32_t mask) { if (mask & WL_EVENT_READABLE) { // xwayland writes twice char buf[64]; - ssize_t n = read(fd, buf, sizeof(buf)); + ssize_t n = read(fd.get(), buf, sizeof(buf)); if (n < 0 && errno != EINTR) { Debug::log(ERR, "Xwayland: read from displayFd failed"); mask = 0; @@ -436,7 +390,6 @@ int CXWaylandServer::ready(int fd, uint32_t mask) { Debug::log(LOG, "XWayland is ready"); - close(fd); wl_event_source_remove(pipeSource); pipeSource = nullptr; diff --git a/src/xwayland/Server.hpp b/src/xwayland/Server.hpp index 7a36a965..ccbcf6ea 100644 --- a/src/xwayland/Server.hpp +++ b/src/xwayland/Server.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../helpers/signal/Signal.hpp" struct wl_event_source; @@ -19,7 +20,7 @@ class CXWaylandServer { bool start(); // called on ready - int ready(int fd, uint32_t mask); + int ready(Hyprutils::OS::CFileDescriptor fd, uint32_t mask); void die(); @@ -30,20 +31,20 @@ class CXWaylandServer { wl_client* xwaylandClient = nullptr; private: - bool tryOpenSockets(); - void runXWayland(int notifyFD); + bool tryOpenSockets(); + void runXWayland(Hyprutils::OS::CFileDescriptor& notifyFD); - pid_t serverPID = 0; + pid_t serverPID = 0; - std::string displayName; - int display = -1; - std::array xFDs = {-1, -1}; - std::array xFDReadEvents = {nullptr, nullptr}; - wl_event_source* idleSource = nullptr; - wl_event_source* pipeSource = nullptr; - int pipeFd = -1; - std::array xwmFDs = {-1, -1}; - std::array waylandFDs = {-1, -1}; + std::string displayName; + int display = -1; + std::array xFDs; + std::array xFDReadEvents = {nullptr, nullptr}; + wl_event_source* idleSource = nullptr; + wl_event_source* pipeSource = nullptr; + Hyprutils::OS::CFileDescriptor pipeFd; + std::array xwmFDs; + std::array waylandFDs; friend class CXWM; }; diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 4b0c5a29..e6282dcb 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -5,6 +5,7 @@ #include "XDataSource.hpp" #include +using namespace Hyprutils::OS; CXDataSource::CXDataSource(SXSelection& sel_) : selection(sel_) { xcb_get_property_cookie_t cookie = xcb_get_property(g_pXWayland->pWM->connection, @@ -47,7 +48,7 @@ std::vector CXDataSource::mimes() { return mimeTypes; } -void CXDataSource::send(const std::string& mime, uint32_t fd) { +void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { xcb_atom_t mimeAtom = 0; if (mime == "text/plain") @@ -65,11 +66,10 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { if (!mimeAtom) { Debug::log(ERR, "[XDataSource] mime atom not found"); - close(fd); return; } - Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd); + Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); selection.transfer = makeUnique(selection); selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); @@ -81,8 +81,9 @@ void CXDataSource::send(const std::string& mime, uint32_t fd) { xcb_flush(g_pXWayland->pWM->connection); - fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = fd; + //TODO: make CFileDescriptor setflags take SETFL aswell + fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); + selection.transfer->wlFD = std::move(fd); } void CXDataSource::accepted(const std::string& mime) { @@ -101,4 +102,4 @@ eDataSourceType CXDataSource::type() { return DATA_SOURCE_TYPE_X11; } -#endif \ No newline at end of file +#endif diff --git a/src/xwayland/XDataSource.hpp b/src/xwayland/XDataSource.hpp index c629aa2a..a61ffcc9 100644 --- a/src/xwayland/XDataSource.hpp +++ b/src/xwayland/XDataSource.hpp @@ -1,6 +1,7 @@ #pragma once #include "../protocols/types/DataDevice.hpp" +#include struct SXSelection; @@ -9,7 +10,7 @@ class CXDataSource : public IDataSource { CXDataSource(SXSelection&); virtual std::vector mimes(); - virtual void send(const std::string& mime, uint32_t fd); + virtual void send(const std::string& mime, Hyprutils::OS::CFileDescriptor fd); virtual void accepted(const std::string& mime); virtual void cancelled(); virtual void error(uint32_t code, const std::string& msg); @@ -19,4 +20,4 @@ class CXDataSource : public IDataSource { SXSelection& selection; std::vector mimeTypes; // these two have shared idx std::vector mimeAtoms; // -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 6673105e..81900c7b 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -17,6 +17,7 @@ #include "../managers/SeatManager.hpp" #include "../protocols/XWaylandShell.hpp" #include "../protocols/core/Compositor.hpp" +using namespace Hyprutils::OS; #define XCB_EVENT_RESPONSE_TYPE_MASK 0x7f #define INCR_CHUNK_SIZE (64 * 1024) @@ -883,7 +884,7 @@ void CXWM::getRenderFormat() { free(reply); } -CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { +CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0].get()) { if (connection.hasError()) { Debug::log(ERR, "[xwm] Couldn't start, error {}", connection.hasError()); @@ -901,7 +902,7 @@ CXWM::CXWM() : connection(g_pXWayland->pServer->xwmFDs[0]) { xcb_screen_iterator_t screen_iterator = xcb_setup_roots_iterator(xcb_get_setup(connection)); screen = screen_iterator.data; - eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0], WL_EVENT_READABLE, ::onX11Event, nullptr); + eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, g_pXWayland->pServer->xwmFDs[0].get(), WL_EVENT_READABLE, ::onX11Event, nullptr); wl_event_source_check(eventSource); gatherResources(); @@ -1180,13 +1181,12 @@ void CXWM::getTransferData(SXSelection& sel) { if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - close(sel.transfer->wlFD); sel.transfer.reset(); return; } else { sel.onWrite(); if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD, WL_EVENT_WRITABLE, ::writeDataSource, &sel); + sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } } @@ -1361,13 +1361,13 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { // the wayland client might not expect a non-blocking fd // fcntl(p[1], F_SETFL, O_NONBLOCK); - transfer->wlFD = p[0]; + transfer->wlFD = CFileDescriptor{p[0]}; Debug::log(LOG, "[xwm] sending wayland selection to xwayland with mime {}, target {}, fds {} {}", mime, e->target, p[0], p[1]); - selection->send(mime, p[1]); + selection->send(mime, CFileDescriptor{p[1]}); - transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD, WL_EVENT_READABLE, ::readDataSource, this); + transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); return true; } @@ -1376,10 +1376,9 @@ int SXSelection::onWrite() { char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; - ssize_t len = write(transfer->wlFD, property + transfer->propertyStart, remainder); + ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - close(transfer->wlFD); transfer.reset(); return 0; } @@ -1389,7 +1388,6 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - close(transfer->wlFD); transfer.reset(); } @@ -1397,8 +1395,6 @@ int SXSelection::onWrite() { } SXTransfer::~SXTransfer() { - if (wlFD) - close(wlFD); if (eventSource) wl_event_source_remove(eventSource); if (incomingWindow) diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index dfaf33b9..73a02a86 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -10,6 +10,7 @@ #include #include #include +#include struct wl_event_source; class CXWaylandSurfaceResource; @@ -18,25 +19,25 @@ struct SXSelection; struct SXTransfer { ~SXTransfer(); - SXSelection& selection; - bool out = true; + SXSelection& selection; + bool out = true; - bool incremental = false; - bool flushOnDelete = false; - bool propertySet = false; + bool incremental = false; + bool flushOnDelete = false; + bool propertySet = false; - int wlFD = -1; - wl_event_source* eventSource = nullptr; + Hyprutils::OS::CFileDescriptor wlFD; + wl_event_source* eventSource = nullptr; - std::vector data; + std::vector data; - xcb_selection_request_event_t request; + xcb_selection_request_event_t request; - int propertyStart; - xcb_get_property_reply_t* propertyReply; - xcb_window_t incomingWindow; + int propertyStart; + xcb_get_property_reply_t* propertyReply; + xcb_window_t incomingWindow; - bool getIncomingSelectionProp(bool erase); + bool getIncomingSelectionProp(bool erase); }; struct SXSelection { From ef03f6911694413b1b06aba727ad9ab089a511f7 Mon Sep 17 00:00:00 2001 From: nyx Date: Thu, 30 Jan 2025 16:36:42 -0500 Subject: [PATCH 0021/1257] xwayland: handle window coords correctly (#9238) --- src/desktop/Window.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index e59a8d4e..09037cbd 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1706,9 +1706,15 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional // TODO: this should be decoupled from setWindowSize IMO Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); - if (m_bIsX11) { - if (const auto XWAYLANDPOS = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); XWAYLANDPOS != Vector2D{}) - windowPos = XWAYLANDPOS; + if (m_bIsX11 && PMONITOR) { + windowPos -= PMONITOR->vecPosition; + + if (*PXWLFORCESCALEZERO) { + windowPos *= PMONITOR->scale; + size *= PMONITOR->scale; + } + + windowPos += PMONITOR->vecXWaylandPosition; } if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) @@ -1716,13 +1722,10 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional m_vReportedPosition = windowPos; m_vPendingReportedSize = size; + m_fX11SurfaceScaledBy = 1.0f; - m_fX11SurfaceScaledBy = 1.0f; - - if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) { - size *= PMONITOR->scale; + if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) m_fX11SurfaceScaledBy = PMONITOR->scale; - } if (m_bIsX11 && m_pXWaylandSurface) m_pXWaylandSurface->configure({windowPos, size}); From e6a9cfab9199788ee0dcefd8b1bda46f93e6a001 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Fri, 31 Jan 2025 06:23:32 -0600 Subject: [PATCH 0022/1257] monitor: preferred mode now tries first 3 modes if preferred fails before erroring (#9246) --- src/helpers/Monitor.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fc3de3aa..9aa6efce 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -435,7 +435,7 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { // accumulate requested modes in reverse order (cause inesrting at front is inefficient) std::vector> requestedModes; - std::string requestedStr = "preferred"; + std::string requestedStr = "unknown"; // use sortFunc, add best 3 to requestedModes in reverse, since we test in reverse auto addBest3Modes = [&](auto const& sortFunc) { @@ -446,13 +446,24 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { requestedModes.insert(requestedModes.end(), sortedModes.rbegin(), sortedModes.rend()); }; - // last fallback is preferred mode, btw this covers resolution == Vector2D() + // last fallback is always preferred mode if (!output->preferredMode()) Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", output->name); else requestedModes.push_back(output->preferredMode()); - if (RULE->resolution == Vector2D(-1, -1)) { + if (RULE->resolution == Vector2D()) { + requestedStr = "preferred"; + + // fallback to first 3 modes if preferred fails/doesn't exist + requestedModes = output->modes; + if (requestedModes.size() > 3) + requestedModes.erase(requestedModes.begin() + 3, requestedModes.end()); + std::ranges::reverse(requestedModes.begin(), requestedModes.end()); + + if (output->preferredMode()) + requestedModes.push_back(output->preferredMode()); + } else if (RULE->resolution == Vector2D(-1, -1)) { requestedStr = "highrr"; // sort prioritizing refresh rate 1st and resolution 2nd, then add best 3 From ea16b64ec169afcd21020dfb819a73c37428c7f2 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 07:26:08 -0500 Subject: [PATCH 0023/1257] xwayland: prevent invalid window configurations for X11 apps (#9253) * fix(xwayland): prevent invalid window configurations for X11 apps * refact(xwayland): remove unneeded line --- src/desktop/Window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 09037cbd..91c76e7c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1700,7 +1700,7 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional const auto PMONITOR = m_pMonitor.lock(); - size = size.clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); // calculate pos // TODO: this should be decoupled from setWindowSize IMO From 7d51dee103e22742d425d14faebb0273a64ac8c1 Mon Sep 17 00:00:00 2001 From: Aaron Tulino <13600347+aaronjamt@users.noreply.github.com> Date: Fri, 31 Jan 2025 05:33:36 -0700 Subject: [PATCH 0024/1257] hyprctl: Extract IPC code to separate method (#9223) This makes it possible to use the same IPC code for more projects in the future --- hyprctl/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 4cc73bdf..ac88f1da 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -225,7 +225,7 @@ int request(std::string arg, int minArgs = 0, bool needRoll = false) { return 0; } -int requestHyprpaper(std::string arg) { +int requestIPC(std::string filename, std::string arg) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SERVERSOCKET < 0) { @@ -243,7 +243,7 @@ int requestHyprpaper(std::string arg) { const std::string USERID = std::to_string(getUID()); - std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock"; + std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/" + filename; strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1); @@ -278,6 +278,10 @@ int requestHyprpaper(std::string arg) { return 0; } +int requestHyprpaper(std::string arg) { + return requestIPC(".hyprpaper.sock", arg); +} + void batchRequest(std::string arg, bool json) { std::string commands = arg.substr(arg.find_first_of(' ') + 1); From ac5668192ed56c50b5612c7670e397a2128eeba6 Mon Sep 17 00:00:00 2001 From: Brayden Zee Date: Fri, 31 Jan 2025 07:33:51 -0500 Subject: [PATCH 0025/1257] desktop: fix segfault when destroying a partially create layer surface (#9247) --- src/desktop/LayerSurface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index e2d0177b..78dae0a9 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -98,7 +98,8 @@ void CLayerSurface::onDestroy() { onUnmap(); } else { Debug::log(LOG, "Removing LayerSurface that wasn't mapped."); - alpha->setValueAndWarp(0.f); + if (alpha) + alpha->setValueAndWarp(0.f); fadingOut = true; g_pCompositor->addToFadingOutSafe(self.lock()); } From 9c38287410b305503f921e411eb39686b23ccc42 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 31 Jan 2025 13:32:36 +0000 Subject: [PATCH 0026/1257] groupbar: various visual improvements added rounding, round at edges, and indicator height --- src/config/ConfigDescriptions.hpp | 32 ++++++- src/config/ConfigManager.cpp | 7 +- .../decorations/CHyprGroupBarDecoration.cpp | 91 +++++++++++++++---- src/render/pass/RectPassElement.cpp | 5 + src/render/pass/RectPassElement.hpp | 1 + src/render/pass/TexPassElement.cpp | 6 +- src/render/pass/TexPassElement.hpp | 1 + 7 files changed, 121 insertions(+), 22 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 483f1f1f..01ef392e 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -883,7 +883,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "group:groupbar:gradients", .description = "enables gradients", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, SConfigOptionDescription{ .value = "group:groupbar:height", @@ -891,6 +891,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{14, 1, 64}, }, + SConfigOptionDescription{ + .value = "group:groupbar:indicator_height", + .description = "height of the groupbar indicator", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{3, 1, 64}, + }, SConfigOptionDescription{ .value = "group:groupbar:stacked", .description = "render the groupbar as a vertical stack", @@ -915,6 +921,30 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, + SConfigOptionDescription{ + .value = "group:groupbar:rounding", + .description = "how much to round the groupbar", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:gradient_rounding", + .description = "how much to round the groupbar gradient", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{1, 0, 20}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:round_only_edges", + .description = "if yes, will only round at the groupbar edges", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, + SConfigOptionDescription{ + .value = "group:groupbar:groupbar_round_only_edges", + .description = "if yes, will only round at the groupbar gradient edges", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, SConfigOptionDescription{ .value = "group:groupbar:text_color", .description = "controls the group bar text color", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 86581b10..e36a2914 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -441,13 +441,18 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("group:groupbar:enabled", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:font_family", {STRVAL_EMPTY}); m_pConfig->addConfigValue("group:groupbar:font_size", Hyprlang::INT{8}); - m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradients", Hyprlang::INT{0}); m_pConfig->addConfigValue("group:groupbar:height", Hyprlang::INT{14}); + m_pConfig->addConfigValue("group:groupbar:indicator_height", Hyprlang::INT{3}); m_pConfig->addConfigValue("group:groupbar:priority", Hyprlang::INT{3}); m_pConfig->addConfigValue("group:groupbar:render_titles", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:scrolling", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:groupbar:text_color", Hyprlang::INT{0xffffffff}); m_pConfig->addConfigValue("group:groupbar:stacked", Hyprlang::INT{0}); + m_pConfig->addConfigValue("group:groupbar:rounding", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradient_rounding", Hyprlang::INT{2}); + m_pConfig->addConfigValue("group:groupbar:round_only_edges", Hyprlang::INT{1}); + m_pConfig->addConfigValue("group:groupbar:gradient_round_only_edges", Hyprlang::INT{1}); m_pConfig->addConfigValue("debug:int", Hyprlang::INT{0}); m_pConfig->addConfigValue("debug:log_damage", Hyprlang::INT{0}); diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 88501d74..1a64b024 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -15,7 +15,6 @@ static SP m_tGradientInactive = makeShared(); static SP m_tGradientLockedActive = makeShared(); static SP m_tGradientLockedInactive = makeShared(); -constexpr int BAR_INDICATOR_HEIGHT = 3; constexpr int BAR_PADDING_OUTER_VERT = 2; constexpr int BAR_PADDING_OUTER_HORZ = 2; constexpr int BAR_TEXT_PAD = 2; @@ -30,12 +29,13 @@ CHyprGroupBarDecoration::CHyprGroupBarDecoration(PHLWINDOW pWindow) : IHyprWindo } SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { - static auto PHEIGHT = CConfigValue("group:groupbar:height"); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); - static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); - static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); - static auto PPRIORITY = CConfigValue("group:groupbar:priority"); - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PHEIGHT = CConfigValue("group:groupbar:height"); + static auto PINDICATORHEIGHT = CConfigValue("group:groupbar:indicator_height"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); + static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); + static auto PPRIORITY = CConfigValue("group:groupbar:priority"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); SDecorationPositioningInfo info; info.policy = DECORATION_POSITION_STICKY; @@ -45,10 +45,10 @@ SDecorationPositioningInfo CHyprGroupBarDecoration::getPositioningInfo() { if (*PENABLED && m_pWindow->m_sWindowData.decorate.valueOrDefault()) { if (*PSTACKED) { - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); info.desiredExtents = {{0, (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT}, {0, 0}}; } else - info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; + info.desiredExtents = {{0, BAR_PADDING_OUTER_VERT * 2 + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0) + 2}, {0, 0}}; } else info.desiredExtents = {{0, 0}, {0, 0}}; return info; @@ -99,19 +99,24 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); - static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); - static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); - static auto PHEIGHT = CConfigValue("group:groupbar:height"); - static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); - static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); + static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); + static auto PHEIGHT = CConfigValue("group:groupbar:height"); + static auto PINDICATORHEIGHT = CConfigValue("group:groupbar:indicator_height"); + static auto PGRADIENTS = CConfigValue("group:groupbar:gradients"); + static auto PSTACKED = CConfigValue("group:groupbar:stacked"); + static auto PROUNDING = CConfigValue("group:groupbar:rounding"); + static auto PGRADIENTROUNDING = CConfigValue("group:groupbar:gradient_rounding"); + static auto PGRADIENTROUNDINGONLYEDGES = CConfigValue("group:groupbar:gradient_round_only_edges"); + static auto PROUNDONLYEDGES = CConfigValue("group:groupbar:round_only_edges"); if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) return; const auto ASSIGNEDBOX = assignedBoxGlobal(); - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + BAR_INDICATOR_HEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; m_fBarHeight = *PSTACKED ? ((ASSIGNEDBOX.h - 2 - BAR_PADDING_OUTER_VERT) - BAR_PADDING_OUTER_VERT * (barsToDraw)) / barsToDraw : ASSIGNEDBOX.h - BAR_PADDING_OUTER_VERT; @@ -126,8 +131,8 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i; CBox rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, - m_fBarWidth, BAR_INDICATOR_HEIGHT}; + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - *PINDICATORHEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, + m_fBarWidth, *PINDICATORHEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -152,6 +157,30 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { CRectPassElement::SRectData rectdata; rectdata.color = color; rectdata.box = rect; + if (*PROUNDING) { + if (*PROUNDONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + rectdata.round = *PROUNDING; + else if (i == 0) { + double first = rect.w - (*PROUNDING * 2); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PROUNDING * 2; + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else + rectdata.round = *PROUNDING; + } g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, @@ -166,6 +195,30 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { CTexPassElement::SRenderData data; data.tex = GRADIENTTEX; data.box = rect; + if (*PGRADIENTROUNDING) { + if (*PGRADIENTROUNDINGONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + data.round = *PGRADIENTROUNDING; + else if (i == 0) { + double first = rect.w - (*PGRADIENTROUNDING * 2); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = 0; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PGRADIENTROUNDING * 2; + data.round = 0; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else + rectdata.round = *PGRADIENTROUNDING; + } g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } } @@ -229,7 +282,7 @@ CTitleTex::CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float texSize = tex->m_vSize; } -void renderGradientTo(SP tex, CGradientValueData* grad) { +static void renderGradientTo(SP tex, CGradientValueData* grad) { if (!g_pCompositor->m_pLastMonitor) return; diff --git a/src/render/pass/RectPassElement.cpp b/src/render/pass/RectPassElement.cpp index fba06286..aa024577 100644 --- a/src/render/pass/RectPassElement.cpp +++ b/src/render/pass/RectPassElement.cpp @@ -9,10 +9,15 @@ void CRectPassElement::draw(const CRegion& damage) { if (data.box.w <= 0 || data.box.h <= 0) return; + if (!data.clipBox.empty()) + g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox; + if (data.color.a == 1.F || !data.blur) g_pHyprOpenGL->renderRectWithDamage(data.box, data.color, damage, data.round, data.roundingPower); else g_pHyprOpenGL->renderRectWithBlur(data.box, data.color, data.round, data.roundingPower, data.blurA, data.xray); + + g_pHyprOpenGL->m_RenderData.clipBox = {}; } bool CRectPassElement::needsLiveBlur() { diff --git a/src/render/pass/RectPassElement.hpp b/src/render/pass/RectPassElement.hpp index d27abdcc..f798dbf9 100644 --- a/src/render/pass/RectPassElement.hpp +++ b/src/render/pass/RectPassElement.hpp @@ -10,6 +10,7 @@ class CRectPassElement : public IPassElement { float roundingPower = 2.0f; bool blur = false, xray = false; float blurA = 1.F; + CBox clipBox; }; CRectPassElement(const SRectData& data); diff --git a/src/render/pass/TexPassElement.cpp b/src/render/pass/TexPassElement.cpp index c7eab292..8b577373 100644 --- a/src/render/pass/TexPassElement.cpp +++ b/src/render/pass/TexPassElement.cpp @@ -13,9 +13,13 @@ void CTexPassElement::draw(const CRegion& damage) { CScopeGuard x = {[]() { // - g_pHyprOpenGL->m_bEndFrame = false; + g_pHyprOpenGL->m_bEndFrame = false; + g_pHyprOpenGL->m_RenderData.clipBox = {}; }}; + if (!data.clipBox.empty()) + g_pHyprOpenGL->m_RenderData.clipBox = data.clipBox; + if (data.replaceProjection) g_pHyprOpenGL->m_RenderData.monitorProjection = *data.replaceProjection; g_pHyprOpenGL->renderTextureInternalWithDamage(data.tex, data.box, data.a, data.damage.empty() ? damage : data.damage, data.round, data.roundingPower, data.syncTimeline, diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp index 036b89fe..6faa0872 100644 --- a/src/render/pass/TexPassElement.hpp +++ b/src/render/pass/TexPassElement.hpp @@ -19,6 +19,7 @@ class CTexPassElement : public IPassElement { SP syncTimeline; int64_t syncPoint = 0; std::optional replaceProjection; + CBox clipBox; }; CTexPassElement(const SRenderData& data); From 12b5034c99f28025e6c6be29c33bde9f4a24ac9f Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Fri, 31 Jan 2025 15:36:22 +0200 Subject: [PATCH 0027/1257] configWatcher: watch both symlinks and canonical paths (#9219) --- src/config/ConfigWatcher.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp index 8d086bac..e5db1e86 100644 --- a/src/config/ConfigWatcher.cpp +++ b/src/config/ConfigWatcher.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace Hyprutils::OS; @@ -43,9 +44,19 @@ void CConfigWatcher::setWatchList(const std::vector& paths) { // add new paths for (const auto& path : paths) { m_watches.emplace_back(SInotifyWatch{ - .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY), + .wd = inotify_add_watch(m_inotifyFd.get(), path.c_str(), IN_MODIFY | IN_DONT_FOLLOW), .file = path, }); + + std::error_code ec, ec2; + const auto CANONICAL = std::filesystem::canonical(path, ec); + const auto IS_SYMLINK = std::filesystem::is_symlink(path, ec2); + if (!ec && !ec2 && IS_SYMLINK) { + m_watches.emplace_back(SInotifyWatch{ + .wd = inotify_add_watch(m_inotifyFd.get(), CANONICAL.c_str(), IN_MODIFY), + .file = path, + }); + } } } From a4b7d1c2d7538068ab4832a66f86801f5f75cc65 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 08:36:56 -0500 Subject: [PATCH 0028/1257] xwayland: correct pointer coordinate mismatch in X11 windows (#9259) refactor(xwayland): add back comments --- src/desktop/Window.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 91c76e7c..0f6bac99 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1697,8 +1697,7 @@ Vector2D CWindow::requestedMaxSize() { void CWindow::sendWindowSize(Vector2D size, bool force, std::optional overridePos) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - - const auto PMONITOR = m_pMonitor.lock(); + const auto PMONITOR = m_pMonitor.lock(); size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); @@ -1707,14 +1706,9 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); if (m_bIsX11 && PMONITOR) { - windowPos -= PMONITOR->vecPosition; - - if (*PXWLFORCESCALEZERO) { - windowPos *= PMONITOR->scale; + windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); + if (*PXWLFORCESCALEZERO) size *= PMONITOR->scale; - } - - windowPos += PMONITOR->vecXWaylandPosition; } if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) From ddf180fa304e71b1d6eaa9f2b250a907131b05d9 Mon Sep 17 00:00:00 2001 From: nyx Date: Fri, 31 Jan 2025 11:08:43 -0500 Subject: [PATCH 0029/1257] render: enforce framebuffer offloading and remove introspection toggle (#9217) --- src/config/ConfigDescriptions.hpp | 7 -- src/config/ConfigManager.cpp | 1 - src/render/OpenGL.cpp | 147 ++---------------------------- src/render/OpenGL.hpp | 3 - src/render/pass/Pass.cpp | 4 - src/render/pass/Pass.hpp | 1 - 6 files changed, 10 insertions(+), 153 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 01ef392e..2fa86817 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1294,13 +1294,6 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{true}, }, - SConfigOptionDescription{ - .value = "opengl:force_introspection", - .description = "forces introspection at all times. Introspection is aimed at reducing GPU usage in certain cases, but might cause graphical glitches on nvidia. 0 - " - "nothing, 1 - force always on, 2 - force always on if nvidia", - .type = CONFIG_OPTION_INT, - .data = SConfigOptionDescription::SRangeData{2, 0, 2}, - }, /* * render: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e36a2914..8bb6d157 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -619,7 +619,6 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("xwayland:force_zero_scaling", Hyprlang::INT{0}); m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); - m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{1}); // TODO: remove this. I don't think it does us any good to disable intro. m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e4aadd63..75a5eadb 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -650,112 +650,6 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool return shader; } -bool CHyprOpenGLImpl::passRequiresIntrospection(PHLMONITOR pMonitor) { - // passes requiring introspection are the ones that need to render blur, - // or when we are rendering to a multigpu target - - static auto PBLUR = CConfigValue("decoration:blur:enabled"); - static auto PXRAY = CConfigValue("decoration:blur:xray"); - static auto POPTIM = CConfigValue("decoration:blur:new_optimizations"); - static auto PBLURSPECIAL = CConfigValue("decoration:blur:special"); - static auto PBLURPOPUPS = CConfigValue("decoration:blur:popups"); - - if (m_RenderData.mouseZoomFactor != 1.0 || g_pHyprRenderer->m_bCrashingInProgress) - return true; - - // mirrors should not be offloaded (as we then would basically copy the same data twice) - // yes, this breaks mirrors of mirrors - if (pMonitor->isMirror()) - return false; - - // monitors that are mirrored however must be offloaded because we cannot copy from output FBs - if (!pMonitor->mirrors.empty()) - return true; - - if (*PBLUR == 0) - return false; - - if (preBlurQueued()) - return true; - - if (!pMonitor->solitaryClient.expired()) - return false; - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]) { - const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; - if (ls->forceBlur && !XRAYMODE) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { - const auto XRAYMODE = ls->xray == -1 ? *PXRAY : ls->xray; - if (ls->forceBlur && !XRAYMODE) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - // these two block optimization - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]) { - if (ls->forceBlur) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - for (auto const& ls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]) { - if (ls->forceBlur) - return true; - - if (ls->popupsCount() > 0 && ls->forceBlurPopups) - return true; - } - - if (*PBLURSPECIAL) { - for (auto const& ws : g_pCompositor->m_vWorkspaces) { - if (!ws->m_bIsSpecialWorkspace || ws->m_pMonitor != pMonitor) - continue; - - if (ws->m_fAlpha->value() == 0) - continue; - - return true; - } - } - - if (*PXRAY) - return false; - - for (auto const& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden()) - continue; - - if (!g_pHyprRenderer->shouldRenderWindow(w)) - continue; - - if (w->popupsCount() > 0 && *PBLURPOPUPS) - return true; - - if (!w->m_bIsFloating && *POPTIM && !w->onSpecialWorkspace()) - continue; - - if (w->m_sWindowData.noBlur.valueOrDefault() || w->m_sWindowData.xray.valueOrDefault()) - continue; - - if (w->opaque()) - continue; - - return true; - } - - return false; -} - void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP rb, CFramebuffer* fb) { m_RenderData.pMonitor = pMonitor; @@ -811,8 +705,6 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional finalDamage) { m_RenderData.pMonitor = pMonitor; - static auto PFORCEINTROSPECTION = CConfigValue("opengl:force_introspection"); - #ifndef GLES2 const GLenum RESETSTATUS = glGetGraphicsResetStatus(); if (RESETSTATUS != GL_NO_ERROR) { @@ -871,30 +763,12 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, CFrameb applyScreenShader(*PSHADER); } - const auto PRBO = g_pHyprRenderer->getCurrentRBO(); - const bool FBPROPERSIZE = !fb || fb->m_vSize == pMonitor->vecPixelSize; - const bool USERFORCEDINTROSPECTION = *PFORCEINTROSPECTION == 1 ? true : (*PFORCEINTROSPECTION == 2 ? g_pHyprRenderer->isNvidia() : false); // 0 - no, 1 - yes, 2 - nvidia only - - if (USERFORCEDINTROSPECTION || m_RenderData.forceIntrospection || !FBPROPERSIZE || m_sFinalScreenShader.program > 0 || - (PRBO && pMonitor->vecPixelSize != PRBO->getFB()->m_vSize) || passRequiresIntrospection(pMonitor)) { - // we have to offload - // bind the offload Hypr Framebuffer - m_RenderData.pCurrentMonData->offloadFB.bind(); - m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offloadFB; - m_bOffloadedFramebuffer = true; - } else { - // we can render to the rbo / fbo (fake) directly - const auto PFBO = fb ? fb : PRBO->getFB(); - m_RenderData.currentFB = PFBO; - if (PFBO->getStencilTex() != m_RenderData.pCurrentMonData->stencilTex) - PFBO->addStencil(m_RenderData.pCurrentMonData->stencilTex); - - PFBO->bind(); - m_bOffloadedFramebuffer = false; - } + m_RenderData.pCurrentMonData->offloadFB.bind(); + m_RenderData.currentFB = &m_RenderData.pCurrentMonData->offloadFB; + m_bOffloadedFramebuffer = true; m_RenderData.mainFB = m_RenderData.currentFB; - m_RenderData.outFB = fb ? fb : PRBO->getFB(); + m_RenderData.outFB = fb ? fb : g_pHyprRenderer->getCurrentRBO()->getFB(); } void CHyprOpenGLImpl::end() { @@ -952,13 +826,12 @@ void CHyprOpenGLImpl::end() { // reset our data m_RenderData.pMonitor.reset(); - m_RenderData.mouseZoomFactor = 1.f; - m_RenderData.mouseZoomUseMouse = true; - m_RenderData.forceIntrospection = false; - m_RenderData.blockScreenShader = false; - m_RenderData.currentFB = nullptr; - m_RenderData.mainFB = nullptr; - m_RenderData.outFB = nullptr; + m_RenderData.mouseZoomFactor = 1.f; + m_RenderData.mouseZoomUseMouse = true; + m_RenderData.blockScreenShader = false; + m_RenderData.currentFB = nullptr; + m_RenderData.mainFB = nullptr; + m_RenderData.outFB = nullptr; // if we dropped to offMain, release it now. // if there is a plugin constantly using it, this might be a bit slow, diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index d7abdf63..7b7b7e6f 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -126,7 +126,6 @@ struct SCurrentRenderData { float mouseZoomFactor = 1.f; bool mouseZoomUseMouse = true; // true by default bool useNearestNeighbor = false; - bool forceIntrospection = false; // cleaned in ::end() bool blockScreenShader = false; bool simplePass = false; @@ -322,8 +321,6 @@ class CHyprOpenGLImpl { void preBlurForCurrentMonitor(); - bool passRequiresIntrospection(PHLMONITOR pMonitor); - friend class CHyprRenderer; friend class CTexPassElement; friend class CPreBlurElement; diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 81b918ac..5068cbbc 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -17,10 +17,6 @@ bool CRenderPass::single() const { return m_vPassElements.size() == 1; } -bool CRenderPass::needsIntrospection() const { - return true; -} - void CRenderPass::add(SP el) { m_vPassElements.emplace_back(makeShared(CRegion{}, el)); } diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp index a0810155..bbc55d2c 100644 --- a/src/render/pass/Pass.hpp +++ b/src/render/pass/Pass.hpp @@ -10,7 +10,6 @@ class CRenderPass { public: bool empty() const; bool single() const; - bool needsIntrospection() const; void add(SP elem); void clear(); From d11d0697155e0896c4ab76406e6d5dcf35abff05 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Sat, 1 Feb 2025 09:29:06 +0200 Subject: [PATCH 0030/1257] CI/Nix: remove deprecated magic-nix-cache-action --- .github/workflows/nix-build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml index a98468ac..5b2e81cf 100644 --- a/.github/workflows/nix-build.yml +++ b/.github/workflows/nix-build.yml @@ -19,7 +19,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: DeterminateSystems/nix-installer-action@main - - uses: DeterminateSystems/magic-nix-cache-action@main - uses: cachix/cachix-action@v15 with: From 5b43c106bd1cde9ac0b5626130890cde4de0b245 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sat, 1 Feb 2025 14:44:20 +0000 Subject: [PATCH 0031/1257] animation: don't immediately disconnect active vars during tick (#9272) --- CMakeLists.txt | 2 +- src/managers/AnimationManager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a34d677c..9c286831 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.4.0) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 5be7aa33..29f669dc 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -43,7 +43,7 @@ CHyprAnimationManager::CHyprAnimationManager() { template static void updateVariable(CAnimatedVariable& av, const float POINTY, bool warp = false) { if (warp || av.value() == av.goal()) { - av.warp(); + av.warp(true, false); return; } @@ -53,7 +53,7 @@ static void updateVariable(CAnimatedVariable& av, const float POINTY, b static void updateColorVariable(CAnimatedVariable& av, const float POINTY, bool warp) { if (warp || av.value() == av.goal()) { - av.warp(); + av.warp(true, false); return; } From c6f672257bd2ae98f4fd7a6a273b2d1d3e944baa Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:08:30 +0000 Subject: [PATCH 0032/1257] desktop: move popup and subsurface ctors to factories makes sure m_pSelf is set before we do anything like possibly adding children fixes #9275 supersedes #9276 --- src/desktop/LayerSurface.cpp | 7 ++--- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 41 ++++++++++++++++++---------- src/desktop/Popup.hpp | 8 ++++-- src/desktop/Subsurface.cpp | 53 ++++++++++++++++++++++++------------ src/desktop/Subsurface.hpp | 10 ++++--- src/desktop/Window.cpp | 6 ++-- src/desktop/Window.hpp | 2 +- 8 files changed, 80 insertions(+), 49 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 78dae0a9..f4ffaedf 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -31,10 +31,9 @@ PHLLS CLayerSurface::create(SP resource) { pLS->szNamespace = resource->layerNamespace; - pLS->layer = resource->current.layer; - pLS->popupHead = makeUnique(pLS); - pLS->popupHead->m_pSelf = pLS->popupHead; - pLS->monitor = pMonitor; + pLS->layer = resource->current.layer; + pLS->popupHead = CPopup::create(pLS); + pLS->monitor = pMonitor; pMonitor->m_aLayerSurfaceLayers[resource->current.layer].emplace_back(pLS); pLS->forceBlur = g_pConfigManager->shouldBlurLS(pLS->szNamespace); diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index ab259733..f2be7459 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -59,7 +59,7 @@ class CLayerSurface { CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; - UP popupHead; + SP popupHead; void onDestroy(); void onMap(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index dea94f55..20ff49d7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -12,23 +12,37 @@ #include "../render/OpenGL.hpp" #include -CPopup::CPopup(PHLWINDOW pOwner) : m_pWindowOwner(pOwner) { - initAllSignals(); +SP CPopup::create(PHLWINDOW pOwner) { + auto popup = SP(new CPopup()); + popup->m_pWindowOwner = pOwner; + popup->m_pSelf = popup; + popup->initAllSignals(); + return popup; } -CPopup::CPopup(PHLLS pOwner) : m_pLayerOwner(pOwner) { - initAllSignals(); +SP CPopup::create(PHLLS pOwner) { + auto popup = SP(new CPopup()); + popup->m_pLayerOwner = pOwner; + popup->m_pSelf = popup; + popup->initAllSignals(); + return popup; } -CPopup::CPopup(SP popup, WP pOwner) : - m_pWindowOwner(pOwner->m_pWindowOwner), m_pLayerOwner(pOwner->m_pLayerOwner), m_pParent(pOwner), m_pResource(popup) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(popup->surface->surface.lock(), this); +SP CPopup::create(SP resource, WP pOwner) { + auto popup = SP(new CPopup()); + popup->m_pResource = resource; + popup->m_pWindowOwner = pOwner->m_pWindowOwner; + popup->m_pLayerOwner = pOwner->m_pLayerOwner; + popup->m_pParent = pOwner; + popup->m_pSelf = popup; + popup->m_pWLSurface = CWLSurface::create(); + popup->m_pWLSurface->assign(resource->surface->surface.lock(), popup.get()); - m_vLastSize = popup->surface->current.geometry.size(); - reposition(); + popup->m_vLastSize = resource->surface->current.geometry.size(); + popup->reposition(); - initAllSignals(); + popup->initAllSignals(); + return popup; } CPopup::~CPopup() { @@ -59,7 +73,7 @@ void CPopup::initAllSignals() { } void CPopup::onNewPopup(SP popup) { - const auto& POPUP = m_vChildren.emplace_back(makeShared(popup, m_pSelf)); + const auto& POPUP = m_vChildren.emplace_back(CPopup::create(popup, m_pSelf)); POPUP->m_pSelf = POPUP; Debug::log(LOG, "New popup at {:x}", (uintptr_t)POPUP); } @@ -91,8 +105,7 @@ void CPopup::onMap() { g_pInputManager->simulateMouseMovement(); - m_pSubsurfaceHead = makeUnique(m_pSelf); - m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; + m_pSubsurfaceHead = CSubsurface::create(m_pSelf); //unconstrain(); sendScale(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 6051f7eb..a64af7eb 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -10,11 +10,11 @@ class CXDGPopupResource; class CPopup { public: // dummy head nodes - CPopup(PHLWINDOW pOwner); - CPopup(PHLLS pOwner); + static SP create(PHLWINDOW pOwner); + static SP create(PHLLS pOwner); // real nodes - CPopup(SP popup, WP pOwner); + static SP create(SP popup, WP pOwner); ~CPopup(); @@ -45,6 +45,8 @@ class CPopup { bool m_bMapped = false; private: + CPopup() = default; + // T1 owners, each popup has to have one of these PHLWINDOWREF m_pWindowOwner; PHLLSREF m_pLayerOwner; diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 1d938f39..33ee3553 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -7,28 +7,45 @@ #include "../render/Renderer.hpp" #include "../managers/input/InputManager.hpp" -CSubsurface::CSubsurface(PHLWINDOW pOwner) : m_pWindowParent(pOwner) { - initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); +UP CSubsurface::create(PHLWINDOW pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pWindowParent = pOwner; + subsurface->m_pSelf = subsurface; + + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); + return subsurface; } -CSubsurface::CSubsurface(WP pOwner) : m_pPopupParent(pOwner) { - initSignals(); - initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); +UP CSubsurface::create(WP pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pPopupParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pOwner->m_pWLSurface->resource()); + return subsurface; } -CSubsurface::CSubsurface(SP pSubsurface, PHLWINDOW pOwner) : m_pSubsurface(pSubsurface), m_pWindowParent(pOwner) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(pSubsurface->surface.lock(), this); - initSignals(); - initExistingSubsurfaces(pSubsurface->surface.lock()); +UP CSubsurface::create(SP pSubsurface, PHLWINDOW pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pWindowParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->m_pWLSurface = CWLSurface::create(); + subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); + return subsurface; } -CSubsurface::CSubsurface(SP pSubsurface, WP pOwner) : m_pSubsurface(pSubsurface), m_pPopupParent(pOwner) { - m_pWLSurface = CWLSurface::create(); - m_pWLSurface->assign(pSubsurface->surface.lock(), this); - initSignals(); - initExistingSubsurfaces(pSubsurface->surface.lock()); +UP CSubsurface::create(SP pSubsurface, WP pOwner) { + auto subsurface = UP(new CSubsurface()); + subsurface->m_pPopupParent = pOwner; + subsurface->m_pSelf = subsurface; + subsurface->m_pWLSurface = CWLSurface::create(); + subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); + subsurface->initSignals(); + subsurface->initExistingSubsurfaces(pSubsurface->surface.lock()); + return subsurface; } void CSubsurface::initSignals() { @@ -131,9 +148,9 @@ void CSubsurface::onNewSubsurface(SP pSubsurface) { WP PSUBSURFACE; if (!m_pWindowParent.expired()) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pWindowParent.lock())); + PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pWindowParent.lock())); else if (m_pPopupParent) - PSUBSURFACE = m_vChildren.emplace_back(makeUnique(pSubsurface, m_pPopupParent)); + PSUBSURFACE = m_vChildren.emplace_back(CSubsurface::create(pSubsurface, m_pPopupParent)); PSUBSURFACE->m_pSelf = PSUBSURFACE; diff --git a/src/desktop/Subsurface.hpp b/src/desktop/Subsurface.hpp index 41958671..2983c7c1 100644 --- a/src/desktop/Subsurface.hpp +++ b/src/desktop/Subsurface.hpp @@ -10,12 +10,12 @@ class CWLSubsurfaceResource; class CSubsurface { public: // root dummy nodes - CSubsurface(PHLWINDOW pOwner); - CSubsurface(WP pOwner); + static UP create(PHLWINDOW pOwner); + static UP create(WP pOwner); // real nodes - CSubsurface(SP pSubsurface, PHLWINDOW pOwner); - CSubsurface(SP pSubsurface, WP pOwner); + static UP create(SP pSubsurface, PHLWINDOW pOwner); + static UP create(SP pSubsurface, WP pOwner); ~CSubsurface() = default; @@ -37,6 +37,8 @@ class CSubsurface { WP m_pSelf; private: + CSubsurface() = default; + struct { CHyprSignalListener destroySubsurface; CHyprSignalListener commitSubsurface; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 0f6bac99..6e580e49 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -571,10 +571,8 @@ void CWindow::onMap() { if (m_bIsX11) return; - m_pSubsurfaceHead = makeUnique(m_pSelf.lock()); - m_pSubsurfaceHead->m_pSelf = m_pSubsurfaceHead; - m_pPopupHead = makeUnique(m_pSelf.lock()); - m_pPopupHead->m_pSelf = m_pPopupHead; + m_pSubsurfaceHead = CSubsurface::create(m_pSelf.lock()); + m_pPopupHead = CPopup::create(m_pSelf.lock()); } void CWindow::onBorderAngleAnimEnd(WP pav) { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ce2f8eb2..3573d7ab 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -298,7 +298,7 @@ class CWindow { // desktop components UP m_pSubsurfaceHead; - UP m_pPopupHead; + SP m_pPopupHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; From 88adae73ba3b57490fdef1041f58fcc6a15a54c8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:31:31 +0000 Subject: [PATCH 0033/1257] pass: add input region debug --- src/render/pass/Pass.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index 5068cbbc..60c1bc30 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -8,6 +8,7 @@ #include "../../managers/eventLoop/EventLoopManager.hpp" #include "../../render/Renderer.hpp" #include "../../Compositor.hpp" +#include "../../protocols/core/Compositor.hpp" bool CRenderPass::empty() const { return false; @@ -242,6 +243,22 @@ void CRenderPass::renderDebugData() { if (g_pCompositor->m_pLastWindow) renderHLSurface(debugData.lastWindowText, g_pCompositor->m_pLastWindow->m_pWLSurface->resource(), Colors::LIGHT_BLUE.modifyA(0.1F)); + if (g_pSeatManager->state.pointerFocus) { + if (g_pSeatManager->state.pointerFocus->current.input.intersect(CBox{{}, g_pSeatManager->state.pointerFocus->current.size}).getExtents().size() != + g_pSeatManager->state.pointerFocus->current.size) { + auto hlSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); + if (hlSurface) { + auto BOX = hlSurface->getSurfaceBoxGlobal(); + if (BOX) { + auto region = g_pSeatManager->state.pointerFocus->current.input.copy() + .scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale) + .translate(BOX->pos() - g_pHyprOpenGL->m_RenderData.pMonitor->vecPosition); + g_pHyprOpenGL->renderRectWithDamage(box, CHyprColor{0.8F, 0.8F, 0.2F, 0.4F}, region); + } + } + } + } + const auto DISCARDED_ELEMENTS = std::count_if(m_vPassElements.begin(), m_vPassElements.end(), [](const auto& e) { return e->discard; }); auto tex = g_pHyprOpenGL->renderText(std::format("occlusion layers: {}\npass elements: {} ({} discarded)\nviewport: {:X0}", occludedRegions.size(), m_vPassElements.size(), DISCARDED_ELEMENTS, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize), From e380b6ed66aceeae8fde84b4baed0d91550e9f4c Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 15:49:10 +0000 Subject: [PATCH 0034/1257] popup: take xdg geometry into account in input calcs fixes #9023 --- src/desktop/Popup.cpp | 12 +++++++----- src/protocols/core/Compositor.cpp | 4 +--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 20ff49d7..e66cebcd 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -339,22 +339,24 @@ void CPopup::breadthfirst(std::function, void*)> fn, void* data) WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { std::vector> popups; - breadthfirst([](WP popup, void* data) { ((std::vector>*)data)->push_back(popup); }, &popups); + breadthfirst([&popups](WP popup, void* data) { popups.push_back(popup); }, &popups); for (auto const& p : popups | std::views::reverse) { if (!p->m_pResource || !p->m_bMapped) continue; if (!allowsInput) { - const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); + const Vector2D offset = + p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); const auto BOX = CBox{p->coordsGlobal() + offset, size}; if (BOX.containsPoint(globalCoords)) return p; } else { - const Vector2D offset = p->m_pResource ? (p->size() - p->m_pResource->geometry.size()) / 2.F : Vector2D{}; - const auto REGION = + const Vector2D offset = + p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); if (REGION.containsPoint(globalCoords)) return p; diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 93683993..92c3c425 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -308,9 +308,7 @@ void CWLSurfaceResource::breadthfirst(std::function, std::pair, Vector2D> CWLSurfaceResource::at(const Vector2D& localCoords, bool allowsInput) { std::vector, Vector2D>> surfs; - breadthfirst([](SP surf, const Vector2D& offset, - void* data) { ((std::vector, Vector2D>>*)data)->emplace_back(std::make_pair<>(surf, offset)); }, - &surfs); + breadthfirst([&surfs](SP surf, const Vector2D& offset, void* data) { surfs.emplace_back(std::make_pair<>(surf, offset)); }, &surfs); for (auto const& [surf, pos] : surfs | std::views::reverse) { if (!allowsInput) { From 64fefa3749868e6170b6275963c6528456a7d9f2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 1 Feb 2025 19:10:19 +0000 Subject: [PATCH 0035/1257] desktop: move popups to UPs and fix missing subsurface resource fixes #9283 --- src/desktop/LayerSurface.hpp | 2 +- src/desktop/Popup.cpp | 15 ++++++++------- src/desktop/Popup.hpp | 8 ++++---- src/desktop/Subsurface.cpp | 2 ++ src/desktop/Window.hpp | 2 +- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index f2be7459..ab259733 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -59,7 +59,7 @@ class CLayerSurface { CBox geometry = {0, 0, 0, 0}; Vector2D position; std::string szNamespace = ""; - SP popupHead; + UP popupHead; void onDestroy(); void onMap(); diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index e66cebcd..4accb58f 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -12,24 +12,24 @@ #include "../render/OpenGL.hpp" #include -SP CPopup::create(PHLWINDOW pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(PHLWINDOW pOwner) { + auto popup = UP(new CPopup()); popup->m_pWindowOwner = pOwner; popup->m_pSelf = popup; popup->initAllSignals(); return popup; } -SP CPopup::create(PHLLS pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(PHLLS pOwner) { + auto popup = UP(new CPopup()); popup->m_pLayerOwner = pOwner; popup->m_pSelf = popup; popup->initAllSignals(); return popup; } -SP CPopup::create(SP resource, WP pOwner) { - auto popup = SP(new CPopup()); +UP CPopup::create(SP resource, WP pOwner) { + auto popup = UP(new CPopup()); popup->m_pResource = resource; popup->m_pWindowOwner = pOwner->m_pWindowOwner; popup->m_pLayerOwner = pOwner->m_pLayerOwner; @@ -282,7 +282,8 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { - auto cpy = m_vChildren; + std::vector> cpy; + std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); for (auto const& c : cpy) { c->onCommit(true); c->recheckChildrenRecursive(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index a64af7eb..0bca436c 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -10,11 +10,11 @@ class CXDGPopupResource; class CPopup { public: // dummy head nodes - static SP create(PHLWINDOW pOwner); - static SP create(PHLLS pOwner); + static UP create(PHLWINDOW pOwner); + static UP create(PHLLS pOwner); // real nodes - static SP create(SP popup, WP pOwner); + static UP create(SP popup, WP pOwner); ~CPopup(); @@ -64,7 +64,7 @@ class CPopup { bool m_bInert = false; // - std::vector> m_vChildren; + std::vector> m_vChildren; UP m_pSubsurfaceHead; struct { diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index 33ee3553..db106a09 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -29,6 +29,7 @@ UP CSubsurface::create(WP pOwner) { UP CSubsurface::create(SP pSubsurface, PHLWINDOW pOwner) { auto subsurface = UP(new CSubsurface()); subsurface->m_pWindowParent = pOwner; + subsurface->m_pSubsurface = pSubsurface; subsurface->m_pSelf = subsurface; subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); @@ -40,6 +41,7 @@ UP CSubsurface::create(SP pSubsurface, PHLWI UP CSubsurface::create(SP pSubsurface, WP pOwner) { auto subsurface = UP(new CSubsurface()); subsurface->m_pPopupParent = pOwner; + subsurface->m_pSubsurface = pSubsurface; subsurface->m_pSelf = subsurface; subsurface->m_pWLSurface = CWLSurface::create(); subsurface->m_pWLSurface->assign(pSubsurface->surface.lock(), subsurface.get()); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 3573d7ab..ce2f8eb2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -298,7 +298,7 @@ class CWindow { // desktop components UP m_pSubsurfaceHead; - SP m_pPopupHead; + UP m_pPopupHead; // Animated border CGradientValueData m_cRealBorderColor = {0}; From 97a24ec6f3abd2b2ce4c2e00627679a2713848dd Mon Sep 17 00:00:00 2001 From: micha4w Date: Sun, 2 Feb 2025 12:39:32 +0100 Subject: [PATCH 0036/1257] Nix: change meson buildtype from debugoptimized to debug --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index a4ddc63b..6a703713 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -155,7 +155,7 @@ in mesonBuildType = if debug - then "debugoptimized" + then "debug" else "release"; mesonFlags = flatten [ From 373108102c85f9568a8f28b7a85c5500634ca9a4 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Sun, 2 Feb 2025 09:31:04 -0800 Subject: [PATCH 0037/1257] protocols: implement hyprland-ctm-control rev 2 (#9267) * protocols: implement hyprland-ctm-control v2 * bump h-p and nix --- CMakeLists.txt | 2 +- flake.lock | 24 ++++++++++++------------ protocols/meson.build | 2 +- src/managers/ProtocolManager.cpp | 2 +- src/protocols/CTMControl.cpp | 22 +++++++++++++++++++++- src/protocols/CTMControl.hpp | 5 ++++- subprojects/hyprland-protocols | 2 +- 7 files changed, 41 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c286831..34e9a8ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,7 @@ endfunction() target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) -pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.0) +pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2) if(hyprland_protocols_dep_FOUND) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") diff --git a/flake.lock b/flake.lock index dfdd8c5b..7637a2c7 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1738183445, - "narHash": "sha256-C1He3N1SA8D2u+TSlldbA9wiYwDvXI4GxX3zKaeD7qU=", + "lastModified": 1738456976, + "narHash": "sha256-cufyHbOMnSt9V4w4OVSzNcpJ+8DwzRZRJaca2Q89KVI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "48a000cf35dd10bfeb231152735aebbe875f4b74", + "rev": "257b2050790ab3b1eb389e0f8bdc400eb9510139", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1738018829, - "narHash": "sha256-5Ol5iahMlELx3lWuChyZsqqLk6sP6aqaJCJFw92OZGo=", + "lastModified": 1738437059, + "narHash": "sha256-J+8ecqaP3zD9GHeN8Y4hUapoELSoggp0IZI8laTFt/0=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "12cd7034e441a5ebfdef1a090c0788413b4a635b", + "rev": "5ac80e3686a4dfa55d2bd15c81a266b89594a295", "type": "github" }, "original": { @@ -128,11 +128,11 @@ ] }, "locked": { - "lastModified": 1737556638, - "narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=", + "lastModified": 1738422629, + "narHash": "sha256-5v+bv75wJWvahyM2xcMTSNNxmV8a7hb01Eey5zYnBJw=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5", + "rev": "755aef8dab49d0fc4663c715fa4ad221b2aedaed", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1737885589, - "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=", + "lastModified": 1738410390, + "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8", + "rev": "3a228057f5b619feb3186e986dbe76278d707b6e", "type": "github" }, "original": { diff --git a/protocols/meson.build b/protocols/meson.build index aa20940d..6ed1b11a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,7 +7,7 @@ wayland_protos = dependency( hyprland_protos = dependency( 'hyprland-protocols', - version: '>=0.6', + version: '>=0.6.2', fallback: 'hyprland-protocols', ) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index d3270fe2..62736ae5 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -167,7 +167,7 @@ CProtocolManager::CProtocolManager() { PROTO::xdgDialog = makeUnique(&xdg_dialog_v1_interface, 1, "XDGDialog"); PROTO::singlePixel = makeUnique(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); - PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl"); + PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); if (*PENABLEXXCM) { diff --git a/src/protocols/CTMControl.cpp b/src/protocols/CTMControl.cpp index 5560271f..322f95e2 100644 --- a/src/protocols/CTMControl.cpp +++ b/src/protocols/CTMControl.cpp @@ -15,6 +15,9 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPsetSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4, wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) { + if (blocked) + return; + const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output); if UNLIKELY (!OUTPUTRESOURCE) @@ -41,6 +44,9 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPsetCommit([this](CHyprlandCtmControlManagerV1* r) { + if (blocked) + return; + LOGM(LOG, "Committing ctms to outputs"); for (auto& m : g_pCompositor->m_vMonitors) { @@ -54,7 +60,17 @@ CHyprlandCTMControlResource::CHyprlandCTMControlResource(SPversion() >= 2) + resource->sendBlocked(); +} + CHyprlandCTMControlResource::~CHyprlandCTMControlResource() { + if (blocked) + return; + for (auto& m : g_pCompositor->m_vMonitors) { PROTO::ctm->setCTM(m, Mat3x3::identity()); } @@ -69,7 +85,6 @@ CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* ifa } void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); if UNLIKELY (!RESOURCE->good()) { @@ -78,6 +93,11 @@ void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uin return; } + if (m_pManager) + RESOURCE->block(); + else + m_pManager = RESOURCE; + LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get()); } diff --git a/src/protocols/CTMControl.hpp b/src/protocols/CTMControl.hpp index 2c168acd..eb54a3aa 100644 --- a/src/protocols/CTMControl.hpp +++ b/src/protocols/CTMControl.hpp @@ -16,11 +16,13 @@ class CHyprlandCTMControlResource { ~CHyprlandCTMControlResource(); bool good(); + void block(); private: SP resource; std::unordered_map ctms; + bool blocked = false; }; class CHyprlandCTMControlProtocol : public IWaylandProtocol { @@ -37,6 +39,7 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { // std::vector> m_vManagers; + WP m_pManager; // struct SCTMData { @@ -51,4 +54,4 @@ class CHyprlandCTMControlProtocol : public IWaylandProtocol { namespace PROTO { inline UP ctm; -}; \ No newline at end of file +}; diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 4c75dd5c..755aef8d 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 +Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed From 70d94fec134c4b91916812901310e7765acf8405 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:34:26 +0300 Subject: [PATCH 0038/1257] refactor: clang-tidy in compositor (#9241) Co-authored-by: Alexandr Krylov --- src/Compositor.cpp | 90 ++++++++++++++------------------- src/Compositor.hpp | 5 +- src/macros.hpp | 3 +- src/managers/KeybindManager.cpp | 2 - 4 files changed, 40 insertions(+), 60 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 1daccbfd..6a241472 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,3 +1,4 @@ +#include #include #include "Compositor.hpp" @@ -21,14 +22,12 @@ #include #include #include -#include #include #include "debug/HyprCtl.hpp" #include "debug/CrashReporter.hpp" #ifdef USES_SYSTEMD #include // for SdNotify #endif -#include "helpers/varlist/VarList.hpp" #include "helpers/fs/FsUtils.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" @@ -264,7 +263,6 @@ static bool filterGlobals(const wl_client* client, const wl_global* global, void // void CCompositor::initServer(std::string socketName, int socketFd) { - if (m_bOnlyConfigVerification) { g_pHookSystem = makeUnique(); g_pKeybindManager = makeUnique(); @@ -500,7 +498,7 @@ void CCompositor::cleanEnvironment() { "dbus-update-activation-environment 2>/dev/null && " #endif "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; - g_pKeybindManager->spawn(CMD); + CKeybindManager::spawn(CMD); } } @@ -738,7 +736,7 @@ void CCompositor::startCompositor() { "dbus-update-activation-environment 2>/dev/null && " #endif "dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS"; - g_pKeybindManager->spawn(CMD); + CKeybindManager::spawn(CMD); } Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket); @@ -839,12 +837,7 @@ void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) { } bool CCompositor::monitorExists(PHLMONITOR pMonitor) { - for (auto const& m : m_vRealMonitors) { - if (m == pMonitor) - return true; - } - - return false; + return std::ranges::any_of(m_vRealMonitors, [&](const PHLMONITOR& m) { return m == pMonitor; }); } PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t properties, PHLWINDOW pIgnoreWindow) { @@ -1175,8 +1168,8 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface pWindow->m_bIsUrgent = false; // Send an event - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", pWindow->m_szClass + "," + pWindow->m_szTitle}); - g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", std::format("{:x}", (uintptr_t)pWindow.get())}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = pWindow->m_szClass + "," + pWindow->m_szTitle}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", (uintptr_t)pWindow.get())}); EMIT_HOOK_EVENT("activeWindow", pWindow); @@ -1217,8 +1210,8 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo if (!pSurface) { g_pSeatManager->setKeyboardFocus(nullptr); - g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","}); // unfocused - g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = ","}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = ""}); EMIT_HOOK_EVENT("keyboardFocus", (SP)nullptr); m_pLastFocus.reset(); return; @@ -1395,7 +1388,7 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { toMove.insert(toMove.begin(), pw); for (auto const& w : m_vWindows) { - if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::find(toMove.begin(), toMove.end(), w) == toMove.end()) { + if (w->m_bIsMapped && !w->isHidden() && w->m_bIsX11 && w->x11TransientFor() == pw && w != pw && std::ranges::find(toMove, w) == toMove.end()) { x11Stack(w, top, x11Stack); } } @@ -1454,7 +1447,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { if (ls->fadingOut && ls->readyToDelete && ls->isFadedOut()) { for (auto const& m : m_vMonitors) { for (auto& lsl : m->m_aLayerSurfaceLayers) { - if (!lsl.empty() && std::find_if(lsl.begin(), lsl.end(), [&](auto& other) { return other == ls; }) != lsl.end()) { + if (!lsl.empty() && std::ranges::find_if(lsl, [&](auto& other) { return other == ls; }) != lsl.end()) { std::erase_if(lsl, [&](auto& other) { return other == ls || !other; }); } } @@ -1477,7 +1470,7 @@ void CCompositor::cleanupFadingOut(const MONITORID& monid) { } void CCompositor::addToFadingOutSafe(PHLLS pLS) { - const auto FOUND = std::find_if(m_vSurfacesFadingOut.begin(), m_vSurfacesFadingOut.end(), [&](auto& other) { return other.lock() == pLS; }); + const auto FOUND = std::ranges::find_if(m_vSurfacesFadingOut, [&](auto& other) { return other.lock() == pLS; }); if (FOUND != m_vSurfacesFadingOut.end()) return; // if it's already added, don't add it. @@ -1490,7 +1483,7 @@ void CCompositor::removeFromFadingOutSafe(PHLLS ls) { } void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { - const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); + const auto FOUND = std::ranges::find_if(m_vWindowsFadingOut, [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); if (FOUND != m_vWindowsFadingOut.end()) return; // if it's already added, don't add it. @@ -1609,7 +1602,7 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks // auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double { - double dot = a.x * b.x + a.y * b.y; + double dot = (a.x * b.x) + (a.y * b.y); double ang = std::acos(dot / (a.size() * b.size())); return ang; }; @@ -1728,7 +1721,7 @@ bool CCompositor::isPointOnReservedArea(const Vector2D& point, const PHLMONITOR const auto XY1 = PMONITOR->vecPosition + PMONITOR->vecReservedTopLeft; const auto XY2 = PMONITOR->vecPosition + PMONITOR->vecSize - PMONITOR->vecReservedBottomRight; - return !VECINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); + return VECNOTINRECT(point, XY1.x, XY1.y, XY2.x, XY2.y); } PHLMONITOR CCompositor::getMonitorInDirection(const char& dir) { @@ -1902,7 +1895,7 @@ void CCompositor::updateWindowAnimatedDecorationValues(PHLWINDOW pWindow) { MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { // reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor - if (m_mMonitorIDMap.contains(name) && !std::any_of(m_vRealMonitors.begin(), m_vRealMonitors.end(), [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) + if (m_mMonitorIDMap.contains(name) && !std::ranges::any_of(m_vRealMonitors, [&](auto m) { return m->ID == m_mMonitorIDMap[name]; })) return m_mMonitorIDMap[name]; // otherwise, find minimum available ID that is not in the map @@ -1912,7 +1905,7 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { } MONITORID nextID = 0; - while (usedIDs.count(nextID) > 0) { + while (usedIDs.contains(nextID)) { nextID++; } m_mMonitorIDMap[name] = nextID; @@ -1920,7 +1913,6 @@ MONITORID CCompositor::getNextAvailableMonitorID(std::string const& name) { } void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitorB) { - const auto PWORKSPACEA = pMonitorA->activeWorkspace; const auto PWORKSPACEB = pMonitorB->activeWorkspace; @@ -1992,17 +1984,18 @@ void CCompositor::swapActiveWorkspaces(PHLMONITOR pMonitorA, PHLMONITOR pMonitor (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING))); const auto PNEWWORKSPACE = pMonitorA->ID == g_pCompositor->m_pLastMonitor->ID ? PWORKSPACEB : PWORKSPACEA; - g_pEventManager->postEvent(SHyprIPCEvent{"workspace", PNEWWORKSPACE->m_szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"workspacev2", std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspace", .data = PNEWWORKSPACE->m_szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "workspacev2", .data = std::format("{},{}", PNEWWORKSPACE->m_iID, PNEWWORKSPACE->m_szName)}); EMIT_HOOK_EVENT("workspace", PNEWWORKSPACE); } // event - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEA->m_szName + "," + pMonitorB->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEA->m_szName + "," + pMonitorB->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEA->m_iID, PWORKSPACEA->m_szName, pMonitorB->szName)}); EMIT_HOOK_EVENT("moveWorkspace", (std::vector{PWORKSPACEA, pMonitorB})); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", PWORKSPACEB->m_szName + "," + pMonitorA->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = PWORKSPACEB->m_szName + "," + pMonitorA->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", PWORKSPACEB->m_iID, PWORKSPACEB->m_szName, pMonitorA->szName)}); + EMIT_HOOK_EVENT("moveWorkspace", (std::vector{PWORKSPACEB, pMonitorA})); } @@ -2081,7 +2074,6 @@ PHLMONITOR CCompositor::getMonitorFromString(const std::string& name) { } void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMonitor, bool noWarpCursor) { - if (!pWorkspace || !pMonitor) return; @@ -2188,8 +2180,8 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, PHLMONITOR pMo updateSuspendedStates(); // event - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName}); - g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspacev2", std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspace", .data = pWorkspace->m_szName + "," + pMonitor->szName}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "moveworkspacev2", .data = std::format("{},{},{}", pWorkspace->m_iID, pWorkspace->m_szName, pMonitor->szName)}); EMIT_HOOK_EVENT("moveWorkspace", (std::vector{pWorkspace, pMonitor})); } @@ -2200,12 +2192,8 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { for (auto const& w : m_vWorkspaces) { if (w->m_bIsSpecialWorkspace) continue; - - if (w->m_iID < lowestID) - lowestID = w->m_iID; - - if (w->m_iID > highestID) - highestID = w->m_iID; + lowestID = std::min(w->m_iID, lowestID); + highestID = std::max(w->m_iID, highestID); } return std::clamp(id, lowestID, highestID) != id; @@ -2281,7 +2269,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS if (PWORKSPACE->m_bHasFullscreenWindow && !PWINDOW->isFullscreen()) setWindowFullscreenInternal(PWORKSPACE->getFullscreenWindow(), FSMODE_NONE); - const bool CHANGEINTERNAL = !(PWINDOW->m_bPinned || CURRENT_EFFECTIVE_MODE == EFFECTIVE_MODE); + const bool CHANGEINTERNAL = !PWINDOW->m_bPinned && CURRENT_EFFECTIVE_MODE != EFFECTIVE_MODE; if (*PALLOWPINFULLSCREEN && PWINDOW->m_bPinFullscreened && PWINDOW->isFullscreen() && !PWINDOW->m_bPinned && state.internal == FSMODE_NONE) { PWINDOW->m_bPinned = true; @@ -2308,7 +2296,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS PWORKSPACE->m_efFullscreenMode = EFFECTIVE_MODE; PWORKSPACE->m_bHasFullscreenWindow = EFFECTIVE_MODE != FSMODE_NONE; - g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "fullscreen", .data = std::to_string((int)EFFECTIVE_MODE != FSMODE_NONE)}); EMIT_HOOK_EVENT("fullscreen", PWINDOW); PWINDOW->updateDynamicRules(); @@ -2575,8 +2563,8 @@ Vector2D CCompositor::parseWindowVectorArgsRelative(const std::string& args, con X = xIsPercent ? std::stof(x) * 0.01 * PMONITOR->vecSize.x : std::stoi(x); Y = yIsPercent ? std::stof(y) * 0.01 * PMONITOR->vecSize.y : std::stoi(y); } else { - X = xIsPercent ? std::stof(x) * 0.01 * relativeTo.x + relativeTo.x : std::stoi(x) + relativeTo.x; - Y = yIsPercent ? std::stof(y) * 0.01 * relativeTo.y + relativeTo.y : std::stoi(y) + relativeTo.y; + X = xIsPercent ? (std::stof(x) * 0.01 * relativeTo.x) + relativeTo.x : std::stoi(x) + relativeTo.x; + Y = yIsPercent ? (std::stof(y) * 0.01 * relativeTo.y) + relativeTo.y : std::stoi(y) + relativeTo.y; } return Vector2D(X, Y); @@ -2613,8 +2601,8 @@ void CCompositor::setActiveMonitor(PHLMONITOR pMonitor) { const auto WORKSPACE_ID = PWORKSPACE ? std::to_string(PWORKSPACE->m_iID) : std::to_string(WORKSPACE_INVALID); const auto WORKSPACE_NAME = PWORKSPACE ? PWORKSPACE->m_szName : "?"; - g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + WORKSPACE_NAME}); - g_pEventManager->postEvent(SHyprIPCEvent{"focusedmonv2", pMonitor->szName + "," + WORKSPACE_ID}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmon", .data = pMonitor->szName + "," + WORKSPACE_NAME}); + g_pEventManager->postEvent(SHyprIPCEvent{.event = "focusedmonv2", .data = pMonitor->szName + "," + WORKSPACE_ID}); EMIT_HOOK_EVENT("focusedMon", pMonitor); m_pLastMonitor = pMonitor->self; @@ -2804,14 +2792,10 @@ void CCompositor::arrangeMonitors() { // Finds the max and min values of explicitely placed monitors. for (auto const& m : arranged) { - if (m->vecPosition.x + m->vecSize.x > maxXOffsetRight) - maxXOffsetRight = m->vecPosition.x + m->vecSize.x; - if (m->vecPosition.x < maxXOffsetLeft) - maxXOffsetLeft = m->vecPosition.x; - if (m->vecPosition.y + m->vecSize.y > maxYOffsetDown) - maxYOffsetDown = m->vecPosition.y + m->vecSize.y; - if (m->vecPosition.y < maxYOffsetUp) - maxYOffsetUp = m->vecPosition.y; + maxXOffsetRight = std::max(m->vecPosition.x + m->vecSize.x, maxXOffsetRight); + maxXOffsetLeft = std::min(m->vecPosition.x, maxXOffsetLeft); + maxYOffsetDown = std::max(m->vecPosition.y + m->vecSize.y, maxYOffsetDown); + maxYOffsetUp = std::min(m->vecPosition.y, maxYOffsetUp); } }; diff --git a/src/Compositor.hpp b/src/Compositor.hpp index e55d7e1e..787ead08 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -1,15 +1,12 @@ #pragma once -#include #include -#include "defines.hpp" #include "managers/XWaylandManager.hpp" #include "managers/KeybindManager.hpp" #include "managers/SessionLockManager.hpp" #include "desktop/Window.hpp" #include "protocols/types/ColorManagement.hpp" -#include "helpers/memory/Memory.hpp" #include #include @@ -170,7 +167,7 @@ class CCompositor { uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; - rlimit m_sOriginalNofile = {0}; + rlimit m_sOriginalNofile = {}; }; inline UP g_pCompositor; diff --git a/src/macros.hpp b/src/macros.hpp index 0a3be8bc..a5176675 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -38,7 +38,8 @@ #define DYNLISTENER(name) CHyprWLListener hyprListener_##name #define DYNMULTILISTENER(name) wl_listener listen_##name -#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) +#define VECINRECT(vec, x1, y1, x2, y2) ((vec).x >= (x1) && (vec).x < (x2) && (vec).y >= (y1) && (vec).y < (y2)) +#define VECNOTINRECT(vec, x1, y1, x2, y2) ((vec).x < (x1) || (vec).x >= (x2) || (vec).y < (y1) || (vec).y >= (y2)) #define DELTALESSTHAN(a, b, delta) (abs((a) - (b)) < (delta)) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 247550ae..bc5d36c8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -12,8 +12,6 @@ #include "TokenManager.hpp" #include "eventLoop/EventLoopManager.hpp" #include "debug/Log.hpp" -#include "helpers/varlist/VarList.hpp" -#include "../helpers/signal/Signal.hpp" #include "../managers/HookSystemManager.hpp" #include "../managers/input/InputManager.hpp" #include "../managers/LayoutManager.hpp" From 31431a92714ab7f53c25d2ececb26c5b7264b7e3 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Sun, 2 Feb 2025 22:25:29 +0300 Subject: [PATCH 0039/1257] protocols: Support content-type-v1 proto (#9226) --- CMakeLists.txt | 9 ++ meson.build | 4 + protocols/meson.build | 1 + src/Compositor.cpp | 3 +- src/config/ConfigDescriptions.hpp | 13 +-- src/config/ConfigManager.cpp | 24 ++++- src/desktop/Window.cpp | 15 +++ src/desktop/Window.hpp | 159 ++++++++++++++-------------- src/desktop/WindowRule.cpp | 7 +- src/desktop/WindowRule.hpp | 2 + src/events/Windows.cpp | 9 +- src/helpers/Monitor.cpp | 5 +- src/macros.hpp | 1 + src/managers/ProtocolManager.cpp | 3 + src/protocols/ContentType.cpp | 95 +++++++++++++++++ src/protocols/ContentType.hpp | 59 +++++++++++ src/protocols/core/Compositor.hpp | 2 + src/protocols/types/ContentType.cpp | 37 +++++++ src/protocols/types/ContentType.hpp | 18 ++++ src/render/Renderer.cpp | 14 ++- 20 files changed, 386 insertions(+), 94 deletions(-) create mode 100644 src/protocols/ContentType.cpp create mode 100644 src/protocols/ContentType.hpp create mode 100644 src/protocols/types/ContentType.cpp create mode 100644 src/protocols/types/ContentType.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 34e9a8ed..a98f697d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,15 @@ pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) +string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) +list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR) +list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR) +list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH) + add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") +add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR}) +add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR}) +add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH}) add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") @@ -368,6 +376,7 @@ protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false) protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false) protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false) protocolnew("staging/security-context" "security-context-v1" false) +protocolnew("staging/content-type" "content-type-v1" false) protocolwayland() diff --git a/meson.build b/meson.build index ae6e3940..a367b166 100644 --- a/meson.build +++ b/meson.build @@ -36,7 +36,11 @@ hyprcursor = dependency('hyprcursor', version: '>=0.1.7') hyprgraphics = dependency('hyprgraphics', version: '>= 0.1.1') hyprlang = dependency('hyprlang', version: '>= 0.3.2') hyprutils = dependency('hyprutils', version: '>= 0.2.3') +aquamarine_version_list = aquamarine.version().split('.') add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_MAJOR=@0@'.format(aquamarine_version_list.get(0))], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_MINOR=@0@'.format(aquamarine_version_list.get(1))], language: 'cpp') +add_project_arguments(['-DAQUAMARINE_VERSION_PATCH=@0@'.format(aquamarine_version_list.get(2))], language: 'cpp') add_project_arguments(['-DHYPRCURSOR_VERSION="@0@"'.format(hyprcursor.version())], language: 'cpp') add_project_arguments(['-DHYPRGRAPHICS_VERSION="@0@"'.format(hyprgraphics.version())], language: 'cpp') add_project_arguments(['-DHYPRLANG_VERSION="@0@"'.format(hyprlang.version())], language: 'cpp') diff --git a/protocols/meson.build b/protocols/meson.build index 6ed1b11a..7c57470b 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -70,6 +70,7 @@ protocols = [ wayland_protocol_dir / 'staging/xdg-dialog/xdg-dialog-v1.xml', wayland_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', wayland_protocol_dir / 'staging/security-context/security-context-v1.xml', + wayland_protocol_dir / 'staging/content-type/content-type-v1.xml', ] wl_protocols = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6a241472..0aa0f13d 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -72,6 +72,7 @@ using namespace Hyprutils::String; using namespace Aquamarine; +using enum NContentType::eContentType; static int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -2323,7 +2324,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS // send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't. // ignore if DS is disabled. - if (*PDIRECTSCANOUT) + if (*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && PWINDOW->getContentType() == CONTENT_TYPE_GAME)) g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr); g_pConfigManager->ensureVRR(PMONITOR); diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 2fa86817..28cd29c4 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1314,9 +1314,9 @@ inline static const std::vector CONFIG_OPTIONS = { SConfigOptionDescription{ .value = "render:direct_scanout", .description = "Enables direct scanout. Direct scanout attempts to reduce lag when there is only one fullscreen application on a screen (e.g. game). It is also " - "recommended to set this to false if the fullscreen application shows graphical glitches.", - .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + "recommended to set this to false if the fullscreen application shows graphical glitches. 0 - off, 1 - on, 2 - auto (on with content type 'game')", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 0, .min = 0, .max = 2}, }, SConfigOptionDescription{ .value = "render:expand_undersized_textures", @@ -1362,9 +1362,10 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "cursor:no_break_fs_vrr", - .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (requires no_hardware_cursors = true)", - .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{false}, + .description = "disables scheduling new frames on cursor movement for fullscreen apps with VRR enabled to avoid framerate spikes (may require no_hardware_cursors = true) " + "0 - off, 1 - on, 2 - auto (on with content type 'game')", + .type = CONFIG_OPTION_INT, + .data = SConfigOptionDescription::SRangeData{.value = 2, .min = 0, .max = 2}, }, SConfigOptionDescription{ .value = "cursor:min_refresh_rate", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 8bb6d157..42a1a91c 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -26,6 +26,7 @@ #include "../plugins/PluginSystem.hpp" #include "managers/HookSystemManager.hpp" +#include "protocols/types/ContentType.hpp" #include #include #include @@ -621,7 +622,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); - m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:inactive_timeout", {0.f}); @@ -1347,6 +1348,14 @@ std::vector> CConfigManager::getMatchingRules(PHLWINDOW pWindow, continue; } + if (!rule->szContentType.empty()) { + try { + const auto contentType = NContentType::fromString(rule->szContentType); + if (pWindow->getContentType() != contentType) + continue; + } catch (std::exception& e) { Debug::log(ERR, "Rule \"content:{}\" failed with: {}", rule->szContentType, e.what()); } + } + if (!rule->szWorkspace.empty()) { const auto PWORKSPACE = pWindow->m_pWorkspace; @@ -2361,6 +2370,7 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& const auto FOCUSPOS = VALUE.find("focus:"); const auto FULLSCREENSTATEPOS = VALUE.find("fullscreenstate:"); const auto ONWORKSPACEPOS = VALUE.find("onworkspace:"); + const auto CONTENTTYPEPOS = VALUE.find("content:"); // find workspacepos that isn't onworkspacepos size_t WORKSPACEPOS = std::string::npos; @@ -2373,8 +2383,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& currentPos = VALUE.find("workspace:", currentPos + 1); } - const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, - FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS}; + const auto checkPos = std::unordered_set{TAGPOS, TITLEPOS, CLASSPOS, INITIALTITLEPOS, INITIALCLASSPOS, X11POS, FLOATPOS, + FULLSCREENPOS, PINNEDPOS, FULLSCREENSTATEPOS, WORKSPACEPOS, FOCUSPOS, ONWORKSPACEPOS, CONTENTTYPEPOS}; if (checkPos.size() == 1 && checkPos.contains(std::string::npos)) { Debug::log(ERR, "Invalid rulev2 syntax: {}", VALUE); return "Invalid rulev2 syntax: " + VALUE; @@ -2411,6 +2421,8 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& min = WORKSPACEPOS; if (FOCUSPOS > pos && FOCUSPOS < min) min = FOCUSPOS; + if (CONTENTTYPEPOS > pos && CONTENTTYPEPOS < min) + min = CONTENTTYPEPOS; result = result.substr(0, min - pos); @@ -2469,6 +2481,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (ONWORKSPACEPOS != std::string::npos) rule->szOnWorkspace = extract(ONWORKSPACEPOS + 12); + if (CONTENTTYPEPOS != std::string::npos) + rule->szContentType = extract(CONTENTTYPEPOS + 8); + if (RULE == "unset") { std::erase_if(m_vWindowRules, [&](const auto& other) { if (!other->v2) @@ -2513,6 +2528,9 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& if (!rule->szOnWorkspace.empty() && rule->szOnWorkspace != other->szOnWorkspace) return false; + if (!rule->szContentType.empty() && rule->szContentType != other->szContentType) + return false; + return true; } }); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 6e580e49..6a523eec 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -15,6 +15,7 @@ #include "../managers/AnimationManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" +#include "../protocols/ContentType.hpp" #include "../xwayland/XWayland.hpp" #include "../helpers/Color.hpp" #include "../events/Events.hpp" @@ -29,6 +30,7 @@ using namespace Hyprutils::String; using namespace Hyprutils::Animation; +using enum NContentType::eContentType; PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -1724,3 +1726,16 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional else if (m_pXDGSurface && m_pXDGSurface->toplevel) m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor()); } + +NContentType::eContentType CWindow::getContentType() { + return m_pWLSurface->resource()->contentType.valid() ? m_pWLSurface->resource()->contentType->value : CONTENT_TYPE_NONE; +} + +void CWindow::setContentType(NContentType::eContentType contentType) { + if (!m_pWLSurface->resource()->contentType.valid()) + m_pWLSurface->resource()->contentType = PROTO::contentType->getContentType(m_pWLSurface->resource()); + // else disallow content type change if proto is used? + + Debug::log(INFO, "ContentType for window {}", (int)contentType); + m_pWLSurface->resource()->contentType->value = contentType; +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index ce2f8eb2..b3c3d84f 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -19,6 +19,7 @@ #include "WLSurface.hpp" #include "Workspace.hpp" #include "WindowRule.hpp" +#include "protocols/types/ContentType.hpp" class CXDGSurfaceResource; class CXWaylandSurface; @@ -393,85 +394,87 @@ class CWindow { } // methods - CBox getFullWindowBoundingBox(); - SBoxExtents getFullWindowExtents(); - CBox getWindowBoxUnified(uint64_t props); - CBox getWindowIdealBoundingBoxIgnoreReserved(); - void addWindowDeco(UP deco); - void updateWindowDecos(); - void removeWindowDeco(IHyprWindowDecoration* deco); - void uncacheWindowDecos(); - bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); - pid_t getPID(); - IHyprWindowDecoration* getDecorationByType(eDecorationType); - void updateToplevel(); - void updateSurfaceScaleTransformDetails(bool force = false); - void moveToWorkspace(PHLWORKSPACE); - PHLWINDOW x11TransientFor(); - void onUnmap(); - void onMap(); - void setHidden(bool hidden); - bool isHidden(); - void applyDynamicRule(const SP& r); - void updateDynamicRules(); - SBoxExtents getFullWindowReservedArea(); - Vector2D middle(); - bool opaque(); - float rounding(); - float roundingPower(); - bool canBeTorn(); - void setSuspended(bool suspend); - bool visibleOnMonitor(PHLMONITOR pMonitor); - WORKSPACEID workspaceID(); - MONITORID monitorID(); - bool onSpecialWorkspace(); - void activate(bool force = false); - int surfacesCount(); - void clampWindowSize(const std::optional minSize, const std::optional maxSize); - bool isFullscreen(); - bool isEffectiveInternalFSMode(const eFullscreenMode); - int getRealBorderSize(); - float getScrollMouse(); - float getScrollTouchpad(); - void updateWindowData(); - void updateWindowData(const struct SWorkspaceRule&); - void onBorderAngleAnimEnd(WP pav); - bool isInCurvedCorner(double x, double y); - bool hasPopupAt(const Vector2D& pos); - int popupsCount(); - void applyGroupRules(); - void createGroup(); - void destroyGroup(); - PHLWINDOW getGroupHead(); - PHLWINDOW getGroupTail(); - PHLWINDOW getGroupCurrent(); - PHLWINDOW getGroupPrevious(); - PHLWINDOW getGroupWindowByIndex(int); - int getGroupSize(); - bool canBeGroupedInto(PHLWINDOW pWindow); - void setGroupCurrent(PHLWINDOW pWindow); - void insertWindowToGroup(PHLWINDOW pWindow); - void updateGroupOutputs(); - void switchWithWindowInGroup(PHLWINDOW pWindow); - void setAnimationsToMove(); - void onWorkspaceAnimUpdate(); - void onFocusAnimUpdate(); - void onUpdateState(); - void onUpdateMeta(); - void onX11Configure(CBox box); - void onResourceChangeX11(); - std::string fetchTitle(); - std::string fetchClass(); - void warpCursor(bool force = false); - PHLWINDOW getSwallower(); - void unsetWindowData(eOverridePriority priority); - bool isX11OverrideRedirect(); - bool isModal(); - Vector2D requestedMinSize(); - Vector2D requestedMaxSize(); - void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + CBox getFullWindowBoundingBox(); + SBoxExtents getFullWindowExtents(); + CBox getWindowBoxUnified(uint64_t props); + CBox getWindowIdealBoundingBoxIgnoreReserved(); + void addWindowDeco(UP deco); + void updateWindowDecos(); + void removeWindowDeco(IHyprWindowDecoration* deco); + void uncacheWindowDecos(); + bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {}); + pid_t getPID(); + IHyprWindowDecoration* getDecorationByType(eDecorationType); + void updateToplevel(); + void updateSurfaceScaleTransformDetails(bool force = false); + void moveToWorkspace(PHLWORKSPACE); + PHLWINDOW x11TransientFor(); + void onUnmap(); + void onMap(); + void setHidden(bool hidden); + bool isHidden(); + void applyDynamicRule(const SP& r); + void updateDynamicRules(); + SBoxExtents getFullWindowReservedArea(); + Vector2D middle(); + bool opaque(); + float rounding(); + float roundingPower(); + bool canBeTorn(); + void setSuspended(bool suspend); + bool visibleOnMonitor(PHLMONITOR pMonitor); + WORKSPACEID workspaceID(); + MONITORID monitorID(); + bool onSpecialWorkspace(); + void activate(bool force = false); + int surfacesCount(); + void clampWindowSize(const std::optional minSize, const std::optional maxSize); + bool isFullscreen(); + bool isEffectiveInternalFSMode(const eFullscreenMode); + int getRealBorderSize(); + float getScrollMouse(); + float getScrollTouchpad(); + void updateWindowData(); + void updateWindowData(const struct SWorkspaceRule&); + void onBorderAngleAnimEnd(WP pav); + bool isInCurvedCorner(double x, double y); + bool hasPopupAt(const Vector2D& pos); + int popupsCount(); + void applyGroupRules(); + void createGroup(); + void destroyGroup(); + PHLWINDOW getGroupHead(); + PHLWINDOW getGroupTail(); + PHLWINDOW getGroupCurrent(); + PHLWINDOW getGroupPrevious(); + PHLWINDOW getGroupWindowByIndex(int); + int getGroupSize(); + bool canBeGroupedInto(PHLWINDOW pWindow); + void setGroupCurrent(PHLWINDOW pWindow); + void insertWindowToGroup(PHLWINDOW pWindow); + void updateGroupOutputs(); + void switchWithWindowInGroup(PHLWINDOW pWindow); + void setAnimationsToMove(); + void onWorkspaceAnimUpdate(); + void onFocusAnimUpdate(); + void onUpdateState(); + void onUpdateMeta(); + void onX11Configure(CBox box); + void onResourceChangeX11(); + std::string fetchTitle(); + std::string fetchClass(); + void warpCursor(bool force = false); + PHLWINDOW getSwallower(); + void unsetWindowData(eOverridePriority priority); + bool isX11OverrideRedirect(); + bool isModal(); + Vector2D requestedMinSize(); + Vector2D requestedMaxSize(); + void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + NContentType::eContentType getContentType(); + void setContentType(NContentType::eContentType contentType); - CBox getWindowMainSurfaceBox() const { + CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; } diff --git a/src/desktop/WindowRule.cpp b/src/desktop/WindowRule.cpp index 306a25ce..fea2d43b 100644 --- a/src/desktop/WindowRule.cpp +++ b/src/desktop/WindowRule.cpp @@ -8,8 +8,9 @@ static const auto RULES = std::unordered_set{ "float", "fullscreen", "maximize", "noinitialfocus", "pin", "stayfocused", "tile", "renderunfocused", }; static const auto RULES_PREFIX = std::unordered_set{ - "animation", "bordercolor", "bordersize", "center", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", "monitor", "move", "opacity", - "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", "size", "suppressevent", "tag", "workspace", "xray", + "animation", "bordercolor", "bordersize", "center", "content", "fullscreenstate", "group", "idleinhibit", "maxsize", "minsize", + "monitor", "move", "opacity", "plugin:", "prop", "pseudo", "rounding", "roundingpower", "scrollmouse", "scrolltouchpad", + "size", "suppressevent", "tag", "workspace", "xray", }; CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool isV2, bool isExecRule) : szValue(value), szRule(rule), v2(isV2), execRule(isExecRule) { @@ -74,6 +75,8 @@ CWindowRule::CWindowRule(const std::string& rule, const std::string& value, bool ruleType = RULE_WORKSPACE; else if (rule.starts_with("prop")) ruleType = RULE_PROP; + else if (rule.starts_with("content")) + ruleType = RULE_CONTENT; else { // check if this is a prop. const CVarList VARS(rule, 0, 's', true); diff --git a/src/desktop/WindowRule.hpp b/src/desktop/WindowRule.hpp index be9c2d9c..50e221f3 100644 --- a/src/desktop/WindowRule.hpp +++ b/src/desktop/WindowRule.hpp @@ -36,6 +36,7 @@ class CWindowRule { RULE_TAG, RULE_WORKSPACE, RULE_PROP, + RULE_CONTENT, }; eRuleType ruleType = RULE_INVALID; @@ -58,6 +59,7 @@ class CWindowRule { std::string szFullscreenState = ""; // empty means any std::string szOnWorkspace = ""; // empty means any std::string szWorkspace = ""; // empty means any + std::string szContentType = ""; // empty means any // precompiled regexes CRuleRegexContainer rTitle; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index f6ef9ced..8eaabd29 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -11,11 +11,11 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" +#include "protocols/types/ContentType.hpp" #include "../xwayland/XSurface.hpp" #include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" #include "../desktop/LayerSurface.hpp" -#include "../managers/input/InputManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../managers/AnimationManager.hpp" @@ -307,6 +307,13 @@ void Events::listener_mapWindow(void* owner, void* data) { } break; } + case CWindowRule::RULE_CONTENT: { + const CVarList VARS(r->szRule, 0, ' '); + try { + PWINDOW->setContentType(NContentType::fromString(VARS[1])); + } catch (std::exception& e) { Debug::log(ERR, "Rule \"{}\" failed with: {}", r->szRule, e.what()); } + break; + } default: break; } diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 9aa6efce..3ea6d49b 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -33,6 +33,7 @@ using namespace Hyprutils::String; using namespace Hyprutils::Utils; using namespace Hyprutils::OS; +using enum NContentType::eContentType; static int ratHandler(void* data) { g_pHyprRenderer->renderMonitor(((CMonitor*)data)->self.lock()); @@ -799,8 +800,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); // skip scheduling extra frames for fullsreen apps with vrr - bool shouldSkip = - *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN; + const bool shouldSkip = activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN && + (*PNOBREAK == 1 || (*PNOBREAK == 2 && activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && output->state->state().adaptiveSync; // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) { diff --git a/src/macros.hpp b/src/macros.hpp index a5176675..d2cad6b7 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -111,6 +111,7 @@ } \ } +#define AQUAMARINE_VERSION_NUMBER (AQUAMARINE_VERSION_MAJOR * 10000 + AQUAMARINE_VERSION_MINOR * 100 + AQUAMARINE_VERSION_PATCH) #define AQUAMARINE_FORWARD(name) \ namespace Aquamarine { \ class name; \ diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 62736ae5..6cd3a608 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -58,10 +58,12 @@ #include "../protocols/core/Shm.hpp" #include "../protocols/ColorManagement.hpp" #include "../protocols/FrogColorManagement.hpp" +#include "../protocols/ContentType.hpp" #include "../helpers/Monitor.hpp" #include "../render/Renderer.hpp" #include "../Compositor.hpp" +#include "content-type-v1.hpp" #include #include @@ -169,6 +171,7 @@ CProtocolManager::CProtocolManager() { PROTO::securityContext = makeUnique(&wp_security_context_manager_v1_interface, 1, "SecurityContext"); PROTO::ctm = makeUnique(&hyprland_ctm_control_manager_v1_interface, 2, "CTMControl"); PROTO::hyprlandSurface = makeUnique(&hyprland_surface_manager_v1_interface, 2, "HyprlandSurface"); + PROTO::contentType = makeUnique(&wp_content_type_manager_v1_interface, 1, "ContentType"); if (*PENABLEXXCM) { PROTO::colorManagement = makeUnique(&xx_color_manager_v4_interface, 1, "ColorManagement"); diff --git a/src/protocols/ContentType.cpp b/src/protocols/ContentType.cpp new file mode 100644 index 00000000..0dd5481a --- /dev/null +++ b/src/protocols/ContentType.cpp @@ -0,0 +1,95 @@ +#include "ContentType.hpp" +#include "content-type-v1.hpp" +#include "protocols/types/ContentType.hpp" + +CContentTypeManager::CContentTypeManager(SP resource) : m_resource(resource) { + if UNLIKELY (!good()) + return; + + resource->setDestroy([](CWpContentTypeManagerV1* r) {}); + resource->setOnDestroy([this](CWpContentTypeManagerV1* r) { PROTO::contentType->destroyResource(this); }); + + resource->setGetSurfaceContentType([](CWpContentTypeManagerV1* r, uint32_t id, wl_resource* surface) { + LOGM(TRACE, "Get surface for id={}, surface={}", id, (uintptr_t)surface); + auto SURF = CWLSurfaceResource::fromResource(surface); + + if (!SURF) { + LOGM(ERR, "No surface for resource {}", (uintptr_t)surface); + r->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->colorManagement) { + r->error(WP_CONTENT_TYPE_MANAGER_V1_ERROR_ALREADY_CONSTRUCTED, "CT manager already exists"); + return; + } + + const auto RESOURCE = PROTO::contentType->m_vContentTypes.emplace_back(makeShared(makeShared(r->client(), r->version(), id))); + if UNLIKELY (!RESOURCE->good()) { + r->noMemory(); + PROTO::contentType->m_vContentTypes.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; + + SURF->contentType = RESOURCE; + }); +} + +bool CContentTypeManager::good() { + return m_resource->resource(); +} + +CContentType::CContentType(WP surface) { + destroy = surface->events.destroy.registerListener([this](std::any d) { PROTO::contentType->destroyResource(this); }); +} + +CContentType::CContentType(SP resource) : m_resource(resource) { + if UNLIKELY (!good()) + return; + + m_pClient = resource->client(); + + resource->setDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); }); + resource->setOnDestroy([this](CWpContentTypeV1* r) { PROTO::contentType->destroyResource(this); }); + + resource->setSetContentType([this](CWpContentTypeV1* r, wpContentTypeV1Type type) { value = NContentType::fromWP(type); }); +} + +bool CContentType::good() { + return m_resource && m_resource->resource(); +} + +wl_client* CContentType::client() { + return m_pClient; +} + +CContentTypeProtocol::CContentTypeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CContentTypeProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if UNLIKELY (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +SP CContentTypeProtocol::getContentType(WP surface) { + if (surface->contentType.valid()) + return surface->contentType.lock(); + + return m_vContentTypes.emplace_back(makeShared(surface)); +} + +void CContentTypeProtocol::destroyResource(CContentTypeManager* resource) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; }); +} + +void CContentTypeProtocol::destroyResource(CContentType* resource) { + std::erase_if(m_vContentTypes, [&](const auto& other) { return other.get() == resource; }); +} diff --git a/src/protocols/ContentType.hpp b/src/protocols/ContentType.hpp new file mode 100644 index 00000000..c0359bf1 --- /dev/null +++ b/src/protocols/ContentType.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "WaylandProtocol.hpp" +#include "core/Compositor.hpp" +#include "content-type-v1.hpp" +#include "protocols/types/ContentType.hpp" + +class CContentTypeManager { + public: + CContentTypeManager(SP resource); + + bool good(); + + private: + SP m_resource; +}; + +class CContentType { + public: + CContentType(SP resource); + CContentType(WP surface); + + bool good(); + wl_client* client(); + NContentType::eContentType value = NContentType::CONTENT_TYPE_NONE; + + WP self; + + private: + SP m_resource; + wl_client* m_pClient = nullptr; + + CHyprSignalListener destroy; + + friend class CContentTypeProtocol; +}; + +class CContentTypeProtocol : public IWaylandProtocol { + public: + CContentTypeProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + SP getContentType(WP surface); + + private: + void destroyResource(CContentTypeManager* resource); + void destroyResource(CContentType* resource); + + std::vector> m_vManagers; + std::vector> m_vContentTypes; + + friend class CContentTypeManager; + friend class CContentType; +}; + +namespace PROTO { + inline UP contentType; +}; diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 20614813..aaaf9b1a 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -26,6 +26,7 @@ class CViewportResource; class CDRMSyncobjSurfaceResource; class CColorManagementSurface; class CFrogColorManagementSurface; +class CContentType; class CWLCallbackResource { public: @@ -123,6 +124,7 @@ class CWLSurfaceResource { WP viewportResource; WP syncobj; // may not be present WP colorManagement; + WP contentType; void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); diff --git a/src/protocols/types/ContentType.cpp b/src/protocols/types/ContentType.cpp new file mode 100644 index 00000000..c0a3d30f --- /dev/null +++ b/src/protocols/types/ContentType.cpp @@ -0,0 +1,37 @@ +#include "ContentType.hpp" +#include +#include +#include + +namespace NContentType { + static std::unordered_map const table = { + {"none", CONTENT_TYPE_NONE}, {"photo", CONTENT_TYPE_PHOTO}, {"video", CONTENT_TYPE_VIDEO}, {"game", CONTENT_TYPE_GAME}}; + + eContentType fromString(const std::string name) { + auto it = table.find(name); + if (it != table.end()) + return it->second; + else + throw std::invalid_argument(std::format("Unknown content type {}", name)); + } + + eContentType fromWP(wpContentTypeV1Type contentType) { + switch (contentType) { + case WP_CONTENT_TYPE_V1_TYPE_NONE: return CONTENT_TYPE_NONE; + case WP_CONTENT_TYPE_V1_TYPE_PHOTO: return CONTENT_TYPE_PHOTO; + case WP_CONTENT_TYPE_V1_TYPE_VIDEO: return CONTENT_TYPE_VIDEO; + case WP_CONTENT_TYPE_V1_TYPE_GAME: return CONTENT_TYPE_GAME; + default: return CONTENT_TYPE_NONE; + } + } + + uint16_t toDRM(eContentType contentType) { + switch (contentType) { + case CONTENT_TYPE_NONE: return DRM_MODE_CONTENT_TYPE_GRAPHICS; + case CONTENT_TYPE_PHOTO: return DRM_MODE_CONTENT_TYPE_PHOTO; + case CONTENT_TYPE_VIDEO: return DRM_MODE_CONTENT_TYPE_CINEMA; + case CONTENT_TYPE_GAME: return DRM_MODE_CONTENT_TYPE_GAME; + default: return DRM_MODE_CONTENT_TYPE_NO_DATA; + } + } +} \ No newline at end of file diff --git a/src/protocols/types/ContentType.hpp b/src/protocols/types/ContentType.hpp new file mode 100644 index 00000000..66fcbca7 --- /dev/null +++ b/src/protocols/types/ContentType.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "content-type-v1.hpp" +#include + +namespace NContentType { + + enum eContentType : uint8_t { + CONTENT_TYPE_NONE = 0, + CONTENT_TYPE_PHOTO = 1, + CONTENT_TYPE_VIDEO = 2, + CONTENT_TYPE_GAME = 3, + }; + + eContentType fromString(const std::string name); + eContentType fromWP(wpContentTypeV1Type contentType); + uint16_t toDRM(eContentType contentType); +} \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 42445728..6d7b409c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -33,10 +33,14 @@ #include "pass/SurfacePassElement.hpp" #include "debug/Log.hpp" #include "protocols/ColorManagement.hpp" +#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2 +#include "protocols/types/ContentType.hpp" +#endif #include using namespace Hyprutils::Utils; using namespace Hyprutils::OS; +using enum NContentType::eContentType; extern "C" { #include @@ -1192,7 +1196,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if (*PDIRECTSCANOUT && !shouldTear) { + if ((*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { @@ -1509,6 +1513,14 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { } } +#if AQUAMARINE_VERSION_NUMBER > 702 // >0.7.2 + if (pMonitor->activeWorkspace && pMonitor->activeWorkspace->m_bHasFullscreenWindow && pMonitor->activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN) { + const auto WINDOW = pMonitor->activeWorkspace->getFullscreenWindow(); + pMonitor->output->state->setContentType(NContentType::toDRM(WINDOW->getContentType())); + } else + pMonitor->output->state->setContentType(NContentType::toDRM(CONTENT_TYPE_NONE)); +#endif + if (pMonitor->ctmUpdated) { pMonitor->ctmUpdated = false; pMonitor->output->state->setCTM(pMonitor->ctm); From 44004abc0189b9ba49444431e2a39d2df7e930bb Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 2 Feb 2025 22:16:00 +0000 Subject: [PATCH 0040/1257] config: fix includes --- src/config/ConfigManager.cpp | 4 ++-- src/desktop/Window.hpp | 2 +- src/events/Windows.cpp | 2 +- src/protocols/ContentType.hpp | 2 +- subprojects/hyprland-protocols | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 42a1a91c..3f45ddfe 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -25,8 +25,8 @@ #include "../debug/HyprNotificationOverlay.hpp" #include "../plugins/PluginSystem.hpp" -#include "managers/HookSystemManager.hpp" -#include "protocols/types/ContentType.hpp" +#include "../managers/HookSystemManager.hpp" +#include "../protocols/types/ContentType.hpp" #include #include #include diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index b3c3d84f..2d004855 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -19,7 +19,7 @@ #include "WLSurface.hpp" #include "Workspace.hpp" #include "WindowRule.hpp" -#include "protocols/types/ContentType.hpp" +#include "../protocols/types/ContentType.hpp" class CXDGSurfaceResource; class CXWaylandSurface; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 8eaabd29..a068ba07 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -11,7 +11,7 @@ #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ToplevelExport.hpp" -#include "protocols/types/ContentType.hpp" +#include "../protocols/types/ContentType.hpp" #include "../xwayland/XSurface.hpp" #include "managers/AnimationManager.hpp" #include "managers/PointerManager.hpp" diff --git a/src/protocols/ContentType.hpp b/src/protocols/ContentType.hpp index c0359bf1..4c0c445f 100644 --- a/src/protocols/ContentType.hpp +++ b/src/protocols/ContentType.hpp @@ -3,7 +3,7 @@ #include "WaylandProtocol.hpp" #include "core/Compositor.hpp" #include "content-type-v1.hpp" -#include "protocols/types/ContentType.hpp" +#include "types/ContentType.hpp" class CContentTypeManager { public: diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 755aef8d..4c75dd5c 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed +Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 From 708d16636047c6a311c4e44424cf7d2090219a47 Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Mon, 3 Feb 2025 04:34:30 +0300 Subject: [PATCH 0041/1257] dispatchers: add cyclenext hist option (#9055) --- src/Compositor.cpp | 83 +++++++++++++++++++-------------- src/Compositor.hpp | 7 ++- src/managers/KeybindManager.cpp | 32 ++++++------- src/managers/KeybindManager.hpp | 2 +- 4 files changed, 67 insertions(+), 57 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 0aa0f13d..95a57e03 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1058,7 +1058,7 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP out) { return nullptr; } -void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface) { +void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface, bool preserveFocusHistory) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PSPECIALFALLTHROUGH = CConfigValue("input:special_fallthrough"); @@ -1178,12 +1178,13 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface g_pInputManager->recheckIdleInhibitorStatus(); - // move to front of the window history - const auto HISTORYPIVOT = std::find_if(m_vWindowFocusHistory.begin(), m_vWindowFocusHistory.end(), [&](const auto& other) { return other.lock() == pWindow; }); - if (HISTORYPIVOT == m_vWindowFocusHistory.end()) { - Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow); - } else { - std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); + if (!preserveFocusHistory) { + // move to front of the window history + const auto HISTORYPIVOT = std::ranges::find_if(m_vWindowFocusHistory, [&](const auto& other) { return other.lock() == pWindow; }); + if (HISTORYPIVOT == m_vWindowFocusHistory.end()) + Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow); + else + std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1); } if (*PFOLLOWMOUSE == 0) @@ -1396,7 +1397,6 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) { }; x11Stack(pWindow, top, x11Stack); - for (const auto& it : toMove) { moveToZ(it, top); } @@ -1647,37 +1647,52 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks return nullptr; } -PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { - auto it = std::ranges::find(m_vWindows, pWindow); - const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; - const auto IN_RIGHT = std::find_if(it, m_vWindows.end(), FINDER); - if (IN_RIGHT != m_vWindows.end()) - return *IN_RIGHT; - const auto IN_LEFT = std::find_if(m_vWindows.begin(), it, FINDER); - return *IN_LEFT; -} - -PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional floating, bool visible) { - auto it = std::ranges::find(std::ranges::reverse_view(m_vWindows), pWindow); - const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); }; - const auto IN_LEFT = std::find_if(it, m_vWindows.rend(), FINDER); - if (IN_LEFT != m_vWindows.rend()) - return *IN_LEFT; - const auto IN_RIGHT = std::find_if(m_vWindows.rbegin(), it, FINDER); - return *IN_RIGHT; -} - -inline static bool isWorkspaceMatches(PHLWINDOW pWindow, const PHLWINDOW w, bool anyWorkspace) { +template +static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) { return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace; } -inline static bool isFloatingMatches(PHLWINDOW w, std::optional floating) { +template +static bool isFloatingMatches(WINDOWPTR w, std::optional floating) { return !floating.has_value() || w->m_bIsFloating == floating.value(); -}; +} -bool CCompositor::isWindowAvailableForCycle(PHLWINDOW pWindow, const PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace) { - return isFloatingMatches(w, floating) && w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && - (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()); +template +static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, bool focusableOnly, std::optional floating, bool anyWorkspace = false) { + return isFloatingMatches(w, floating) && + (w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault())); +} + +template +static PHLWINDOW getWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function PRED) { + const auto IN_ONE_SIDE = std::find_if(cur, end, PRED); + if (IN_ONE_SIDE != end) + return *IN_ONE_SIDE; + const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED); + return *IN_OTHER_SIDE; +} + +template +static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function PRED) { + const auto IN_ONE_SIDE = std::find_if(cur, end, PRED); + if (IN_ONE_SIDE != end) + return IN_ONE_SIDE->lock(); + const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED); + return IN_OTHER_SIDE->lock(); +} + +PHLWINDOW CCompositor::getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly, std::optional floating, bool visible, bool next) { + const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; + // also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again + return next ? + getWeakWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindowFocusHistory), cur), m_vWindowFocusHistory.rend(), m_vWindowFocusHistory.rbegin(), FINDER) : + getWeakWindowPred(std::ranges::find(m_vWindowFocusHistory, cur), m_vWindowFocusHistory.end(), m_vWindowFocusHistory.begin(), FINDER); +} + +PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional floating, bool visible, bool prev) { + const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); }; + return prev ? getWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindows), cur), m_vWindows.rend(), m_vWindows.rbegin(), FINDER) : + getWindowPred(std::ranges::find(m_vWindows, cur), m_vWindows.end(), m_vWindows.begin(), FINDER); } WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 787ead08..a57095a3 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -83,7 +83,7 @@ class CCompositor { PHLMONITOR getMonitorFromCursor(); PHLMONITOR getMonitorFromVector(const Vector2D&); void removeWindowFromVectorSafe(PHLWINDOW); - void focusWindow(PHLWINDOW, SP pSurface = nullptr); + void focusWindow(PHLWINDOW, SP pSurface = nullptr, bool preserveFocusHistory = false); void focusSurface(SP, PHLWINDOW pWindowOwner = nullptr); bool monitorExists(PHLMONITOR); PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr); @@ -105,8 +105,8 @@ class CCompositor { void cleanupFadingOut(const MONITORID& monid); PHLWINDOW getWindowInDirection(PHLWINDOW, char); PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false); - PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); - PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional floating = {}, bool visible = false); + PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional floating = std::nullopt, bool visible = false, bool prev = false); + PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional floating = std::nullopt, bool visible = false, bool next = false); WORKSPACEID getNextAvailableNamedWorkspace(); bool isPointOnAnyMonitor(const Vector2D&); bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr); @@ -163,7 +163,6 @@ class CCompositor { void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); - bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional floating, bool anyWorkspace = false); uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index bc5d36c8..47cc4f67 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -367,7 +367,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) { return true; } -void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { +void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory) { static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); static auto PNOWARPS = CConfigValue("cursor:no_warps"); @@ -386,7 +386,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE); - g_pCompositor->focusWindow(PWINDOWTOCHANGETO); + g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); if (!PWINDOWTOCHANGETO->m_bPinned) g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE); @@ -396,7 +396,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) { PWINDOWTOCHANGETO->m_vRealSize->warp(); } else { updateRelativeCursorCoords(); - g_pCompositor->focusWindow(PWINDOWTOCHANGETO); + g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory); PWINDOWTOCHANGETO->warpCursor(); // Move mouse focus to the new window if required by current follow_mouse and warp modes @@ -1473,7 +1473,7 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) { } const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ? - (arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) : + g_pCompositor->getWindowCycle(PLASTWINDOW, true, {}, false, arg != 'd' && arg != 'b' && arg != 'r') : g_pCompositor->getWindowInDirection(PLASTWINDOW, arg); // Prioritize focus change within groups if the window is a part of it. @@ -2221,11 +2221,13 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) { floatStatus = true; const auto VISIBLE = args.contains("visible") || args.contains("v"); - const auto& w = (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) ? - g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE) : - g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE); + const auto PREV = args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"); + const auto NEXT = args.contains("next") || args.contains("n"); // prev is default in classic alt+tab + const auto HIST = args.contains("hist") || args.contains("h"); + const auto& w = HIST ? g_pCompositor->getWindowCycleHist(g_pCompositor->m_pLastWindow, true, floatStatus, VISIBLE, NEXT) : + g_pCompositor->getWindowCycle(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE, PREV); - switchToWindow(w); + switchToWindow(w, HIST); return {}; } @@ -2620,18 +2622,12 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) { g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() : nullptr; - if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true); - else - toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true); + const bool NEED_PREV = arg == "last" || arg == "l" || arg == "prev" || arg == "p"; + toSwap = g_pCompositor->getWindowCycle(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true, std::nullopt, false, NEED_PREV); // sometimes we may come back to ourselves. - if (toSwap == PLASTWINDOW) { - if (arg == "last" || arg == "l" || arg == "prev" || arg == "p") - toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true); - else - toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true); - } + if (toSwap == PLASTWINDOW) + toSwap = g_pCompositor->getWindowCycle(PLASTWINDOW, true, std::nullopt, false, NEED_PREV); g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap); diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 1848ca78..cea3e3cf 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -148,7 +148,7 @@ class CKeybindManager { static bool tryMoveFocusToMonitor(PHLMONITOR monitor); static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = ""); static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection); - static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO); + static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory = false); static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace); static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace); From 1da0b2c02e99d3bd35f4d1a6f9a55dc403715913 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 19:45:26 +0000 Subject: [PATCH 0042/1257] subprojects: update h-p fixes #9309 --- subprojects/hyprland-protocols | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/hyprland-protocols b/subprojects/hyprland-protocols index 4c75dd5c..755aef8d 160000 --- a/subprojects/hyprland-protocols +++ b/subprojects/hyprland-protocols @@ -1 +1 @@ -Subproject commit 4c75dd5c015c8a0e5a34c6d02a018a650f57feb5 +Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed From 70cfc7cc9c4ecadbb9dd9a75f096fc70177a8ca5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 19:53:14 +0000 Subject: [PATCH 0043/1257] cmonitor: guard old workspace --- src/helpers/Monitor.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 3ea6d49b..e4843211 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1019,15 +1019,17 @@ void CMonitor::changeWorkspace(const PHLWORKSPACE& pWorkspace, bool internal, bo if (pWorkspace == activeWorkspace) return; - const auto POLDWORKSPACE = activeWorkspace; - POLDWORKSPACE->m_bVisible = false; - pWorkspace->m_bVisible = true; + const auto POLDWORKSPACE = activeWorkspace; + if (POLDWORKSPACE) + POLDWORKSPACE->m_bVisible = false; + pWorkspace->m_bVisible = true; activeWorkspace = pWorkspace; if (!internal) { - const auto ANIMTOLEFT = pWorkspace->m_iID > POLDWORKSPACE->m_iID; - POLDWORKSPACE->startAnim(false, ANIMTOLEFT); + const auto ANIMTOLEFT = POLDWORKSPACE && pWorkspace->m_iID > POLDWORKSPACE->m_iID; + if (POLDWORKSPACE) + POLDWORKSPACE->startAnim(false, ANIMTOLEFT); pWorkspace->startAnim(true, ANIMTOLEFT); // move pinned windows From 5e7292434a9189d0550187f8a6fb687848194a41 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Mon, 3 Feb 2025 22:36:10 +0000 Subject: [PATCH 0044/1257] compositor: guard null ws in updating fade --- src/Compositor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 95a57e03..22cb70fb 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2217,6 +2217,9 @@ bool CCompositor::workspaceIDOutOfBounds(const WORKSPACEID& id) { void CCompositor::updateFullscreenFadeOnWorkspace(PHLWORKSPACE pWorkspace) { + if (!pWorkspace) + return; + const auto FULLSCREEN = pWorkspace->m_bHasFullscreenWindow; for (auto const& w : g_pCompositor->m_vWindows) { From 3b99e906df8b439d65e740301940e57efc057012 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 4 Feb 2025 10:18:08 +0000 Subject: [PATCH 0045/1257] compositor: don't iterate over unmapped ls-es in vectorToLS fixes #9312 --- src/Compositor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 22cb70fb..a8cbae3a 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1245,7 +1245,7 @@ void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindo SP CCompositor::vectorToLayerPopupSurface(const Vector2D& pos, PHLMONITOR monitor, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& lsl : monitor->m_aLayerSurfaceLayers | std::views::reverse) { for (auto const& ls : lsl | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) + if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->mapped) || ls->alpha->value() == 0.f) continue; auto SURFACEAT = ls->popupHead->at(pos, true); @@ -1263,7 +1263,7 @@ SP CCompositor::vectorToLayerPopupSurface(const Vector2D& po SP CCompositor::vectorToLayerSurface(const Vector2D& pos, std::vector* layerSurfaces, Vector2D* sCoords, PHLLS* ppLayerSurfaceFound) { for (auto const& ls : *layerSurfaces | std::views::reverse) { - if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) + if (!ls->mapped || ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha->value() == 0.f) continue; auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); From 84c9baecc6b73f6321b2739061e3c232710f73bf Mon Sep 17 00:00:00 2001 From: Tom Benham <38216488+tomben13@users.noreply.github.com> Date: Wed, 5 Feb 2025 10:56:41 +0100 Subject: [PATCH 0046/1257] keybinds: Added `toggleswallow` dispatcher (#5548) * Added `toggleswallow` dispatcher * clang-format * Removed brackets for 1-line if --- src/desktop/Window.cpp | 6 ++++-- src/desktop/Window.hpp | 3 ++- src/events/Windows.cpp | 13 +++++++++---- src/managers/KeybindManager.cpp | 22 ++++++++++++++++++++++ src/managers/KeybindManager.hpp | 1 + 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 6a523eec..c71fe652 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -452,8 +452,10 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } if (const auto SWALLOWED = m_pSwallowed.lock()) { - SWALLOWED->moveToWorkspace(pWorkspace); - SWALLOWED->m_pMonitor = m_pMonitor; + if (SWALLOWED->m_bCurrentlySwallowed) { + SWALLOWED->moveToWorkspace(pWorkspace); + SWALLOWED->m_pMonitor = m_pMonitor; + } } // update xwayland coords diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 2d004855..8444a113 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -355,7 +355,8 @@ class CWindow { // swallowing PHLWINDOWREF m_pSwallowed; - bool m_bGroupSwallowed = false; + bool m_bCurrentlySwallowed = false; + bool m_bGroupSwallowed = false; // focus stuff bool m_bStayFocused = false; diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index a068ba07..d96bb332 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -392,6 +392,8 @@ void Events::listener_mapWindow(void* owner, void* data) { // Verify window swallowing. Get the swallower before calling onWindowCreated(PWINDOW) because getSwallower() wouldn't get it after if PWINDOW gets auto grouped. const auto SWALLOWER = PWINDOW->getSwallower(); PWINDOW->m_pSwallowed = SWALLOWER; + if (PWINDOW->m_pSwallowed) + PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = true; if (PWINDOW->m_bIsFloating) { g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW); @@ -731,12 +733,15 @@ void Events::listener_unmapWindow(void* owner, void* data) { // swallowing if (valid(PWINDOW->m_pSwallowed)) { - PWINDOW->m_pSwallowed->setHidden(false); + if (PWINDOW->m_pSwallowed->m_bCurrentlySwallowed) { + PWINDOW->m_pSwallowed->m_bCurrentlySwallowed = false; + PWINDOW->m_pSwallowed->setHidden(false); - if (PWINDOW->m_sGroupData.pNextWindow.lock()) - PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. + if (PWINDOW->m_sGroupData.pNextWindow.lock()) + PWINDOW->m_pSwallowed->m_bGroupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false. - g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(PWINDOW->m_pSwallowed.lock()); + } PWINDOW->m_pSwallowed->m_bGroupSwallowed = false; PWINDOW->m_pSwallowed.reset(); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 47cc4f67..2d6b2cb8 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -113,6 +113,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["focuswindowbyclass"] = focusWindow; m_mDispatchers["focuswindow"] = focusWindow; m_mDispatchers["tagwindow"] = tagWindow; + m_mDispatchers["toggleswallow"] = toggleSwallow; m_mDispatchers["submap"] = setSubmap; m_mDispatchers["pass"] = pass; m_mDispatchers["sendshortcut"] = sendshortcut; @@ -2306,6 +2307,27 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) { return {}; } +SDispatchResult CKeybindManager::toggleSwallow(std::string args) { + PHLWINDOWREF pWindow = g_pCompositor->m_pLastWindow; + + if (!valid(pWindow) || !valid(pWindow->m_pSwallowed)) + return {}; + + if (pWindow->m_pSwallowed->m_bCurrentlySwallowed) { + // Unswallow + pWindow->m_pSwallowed->m_bCurrentlySwallowed = false; + pWindow->m_pSwallowed->setHidden(false); + g_pLayoutManager->getCurrentLayout()->onWindowCreated(pWindow->m_pSwallowed.lock()); + } else { + // Reswallow + pWindow->m_pSwallowed->m_bCurrentlySwallowed = true; + pWindow->m_pSwallowed->setHidden(true); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(pWindow->m_pSwallowed.lock()); + } + + return {}; +} + SDispatchResult CKeybindManager::setSubmap(std::string submap) { if (submap == "reset" || submap == "") { m_szCurrentSelectedSubmap = ""; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index cea3e3cf..712fd58d 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -199,6 +199,7 @@ class CKeybindManager { static SDispatchResult circleNext(std::string); static SDispatchResult focusWindow(std::string); static SDispatchResult tagWindow(std::string); + static SDispatchResult toggleSwallow(std::string); static SDispatchResult setSubmap(std::string); static SDispatchResult pass(std::string); static SDispatchResult sendshortcut(std::string); From 873bff390e56fb379754221d9652d0c3b850eaad Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 5 Feb 2025 09:53:09 -0500 Subject: [PATCH 0047/1257] renderer: fix missing null checks to prevent crashes (#9332) --- src/render/Renderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6d7b409c..0fcda827 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1196,7 +1196,9 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if ((*PDIRECTSCANOUT == 1 || (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && !shouldTear) { + if ((*PDIRECTSCANOUT == 1 || + (*PDIRECTSCANOUT == 2 && pMonitor->activeWorkspace->getFullscreenWindow() && pMonitor->activeWorkspace->getFullscreenWindow()->getContentType() == CONTENT_TYPE_GAME)) && + !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { From 64591c85aa212fe06fab90ea2deaccbec529c0c0 Mon Sep 17 00:00:00 2001 From: raf Date: Wed, 5 Feb 2025 14:55:33 +0000 Subject: [PATCH 0048/1257] nix: add hydraJobs output for aggregating Hyprland build jobs --- flake.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/flake.nix b/flake.nix index c1c580ae..801d96ec 100644 --- a/flake.nix +++ b/flake.nix @@ -157,5 +157,11 @@ nixosModules.default = import ./nix/module.nix inputs; homeManagerModules.default = import ./nix/hm-module.nix self; + + # Hydra build jobs + # Recent versions of Hydra can aggregate jobsets from 'hydraJobs' intead of a release.nix + # or similar. Remember to filter large or incompatible attributes here. More eval jobs can + # be added by merging, e.g., self.packages // self.devShells. + hydraJobs = self.packages; }; } From 8a6778f0a087cdfc4bc1d3751b0be2c2bf3322aa Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 5 Feb 2025 15:41:54 +0000 Subject: [PATCH 0049/1257] scripts: don't overwrite generated version if we're not in a git repo --- scripts/generateVersion.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/generateVersion.sh b/scripts/generateVersion.sh index fdcc4712..e88cef3f 100755 --- a/scripts/generateVersion.sh +++ b/scripts/generateVersion.sh @@ -1,4 +1,13 @@ #!/bin/sh + +# if the git directory doesn't exist, don't gather data to avoid overwriting, unless +# the version file is missing altogether (otherwise compiling will fail) +if [[ ! -d ./.git ]]; then + if [[ -f ./src/version.h ]]; then + exit 0 + fi +fi + cp -fr ./src/version.h.in ./src/version.h HASH=${HASH-$(git rev-parse HEAD)} From 868b2b544abb61764089b0e4e9b0fd153a9db26f Mon Sep 17 00:00:00 2001 From: nyx Date: Thu, 6 Feb 2025 06:16:47 -0500 Subject: [PATCH 0050/1257] window: fix missing surface null checks to prevent crashes (#9350) --- src/desktop/Window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index c71fe652..b5126b67 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1730,7 +1730,10 @@ void CWindow::sendWindowSize(Vector2D size, bool force, std::optional } NContentType::eContentType CWindow::getContentType() { - return m_pWLSurface->resource()->contentType.valid() ? m_pWLSurface->resource()->contentType->value : CONTENT_TYPE_NONE; + if (!m_pWLSurface || !m_pWLSurface->resource() || !m_pWLSurface->resource()->contentType.valid()) + return CONTENT_TYPE_NONE; + + return m_pWLSurface->resource()->contentType->value; } void CWindow::setContentType(NContentType::eContentType contentType) { From f1e32cd122ad64ba7119ee7fe65f7c1074a65b91 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 6 Feb 2025 12:18:04 +0100 Subject: [PATCH 0051/1257] core: avoid .at() and use [] operator (#9347) avoid .at() where it makes sense and use [] operator in loops. --- src/desktop/Window.cpp | 8 ++++---- src/devices/IKeyboard.cpp | 20 ++++++++++---------- src/layout/MasterLayout.cpp | 2 +- src/managers/PointerManager.cpp | 2 +- src/managers/XCursorManager.cpp | 2 +- src/render/OpenGL.cpp | 8 ++++---- src/xwayland/XDataSource.cpp | 4 ++-- src/xwayland/XWM.cpp | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b5126b67..8f6d2cb5 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1626,17 +1626,17 @@ PHLWINDOW CWindow::getSwallower() { if (!(*PSWALLOWREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return !RE2::FullMatch(other->m_szClass, *PSWALLOWREGEX); }); - if (candidates.size() <= 0) + if (candidates.size() == 0) return nullptr; if (!(*PSWALLOWEXREGEX).empty()) std::erase_if(candidates, [&](const auto& other) { return RE2::FullMatch(other->m_szTitle, *PSWALLOWEXREGEX); }); - if (candidates.size() <= 0) + if (candidates.size() == 0) return nullptr; if (candidates.size() == 1) - return candidates.at(0); + return candidates[0]; // walk up the focus history and find the last focused for (auto const& w : g_pCompositor->m_vWindowFocusHistory) { @@ -1648,7 +1648,7 @@ PHLWINDOW CWindow::getSwallower() { } // if none are found (??) then just return the first one - return candidates.at(0); + return candidates[0]; } void CWindow::unsetWindowData(eOverridePriority priority) { diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 307d840b..89891ebd 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -126,14 +126,14 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) { updateModifiers(0, 0, modifiersState.locked, modifiersState.group); } - for (size_t i = 0; i < LEDNAMES.size(); ++i) { - ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i)); - Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), ledIndexes.at(i)); + for (size_t i = 0; i < std::min(LEDNAMES.size(), ledIndexes.size()); ++i) { + ledIndexes[i] = xkb_map_led_get_index(xkbKeymap, LEDNAMES[i]); + Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES[i], ledIndexes[i]); } - for (size_t i = 0; i < MODNAMES.size(); ++i) { - modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i)); - Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i)); + for (size_t i = 0; i < std::min(MODNAMES.size(), modIndexes.size()); ++i) { + modIndexes[i] = xkb_map_mod_get_index(xkbKeymap, MODNAMES[i]); + Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES[i], modIndexes[i]); } updateKeymapFD(); @@ -289,8 +289,8 @@ std::optional IKeyboard::getLEDs() { return {}; uint32_t leds = 0; - for (uint32_t i = 0; i < LED_COUNT; ++i) { - if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i))) + for (uint32_t i = 0; i < std::min((size_t)LED_COUNT, ledIndexes.size()); ++i) { + if (xkb_state_led_index_is_active(xkbState, ledIndexes[i])) leds |= (1 << i); } @@ -323,10 +323,10 @@ uint32_t IKeyboard::getModifiers() { uint32_t modMask = modifiersState.depressed | modifiersState.latched; uint32_t mods = 0; for (size_t i = 0; i < modIndexes.size(); ++i) { - if (modIndexes.at(i) == XKB_MOD_INVALID) + if (modIndexes[i] == XKB_MOD_INVALID) continue; - if (!(modMask & (1 << modIndexes.at(i)))) + if (!(modMask & (1 << modIndexes[i]))) continue; mods |= (1 << i); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 4773147f..dc301bfa 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -1357,7 +1357,7 @@ void CHyprMasterLayout::runOrientationCycle(SLayoutMessageHeader& header, CVarLi int nextOrPrev = 0; for (size_t i = 0; i < cycle.size(); ++i) { - if (PWORKSPACEDATA->orientation == cycle.at(i)) { + if (PWORKSPACEDATA->orientation == cycle[i]) { nextOrPrev = i + direction; break; } diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 48ef5e16..1c8e9976 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -475,7 +475,7 @@ SP CPointerManager::renderHWCursorBuffer(SP> CXCursorManager::loadStandardCursors(std::string cons // load the default xcursor shapes that exist in the theme for (size_t i = 0; i < XCURSOR_STANDARD_NAMES.size(); ++i) { - std::string shape{XCURSOR_STANDARD_NAMES.at(i)}; + std::string shape{XCURSOR_STANDARD_NAMES[i]}; auto xImages = XcursorShapeLoadImages(i << 1 /* wtf xcursor? */, name.c_str(), size); if (!xImages) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 75a5eadb..3b641c36 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -402,14 +402,14 @@ std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint fo result.reserve(mods.size()); bool linearIsExternal = false; - for (size_t i = 0; i < mods.size(); ++i) { - if (external.at(i)) { - if (mods.at(i) == DRM_FORMAT_MOD_LINEAR) + for (size_t i = 0; i < std::min(mods.size(), external.size()); ++i) { + if (external[i]) { + if (mods[i] == DRM_FORMAT_MOD_LINEAR) linearIsExternal = true; continue; } - result.push_back(mods.at(i)); + result.push_back(mods[i]); } // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index e6282dcb..9384db69 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -57,8 +57,8 @@ void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { mimeAtom = HYPRATOMS["UTF8_STRING"]; else { for (size_t i = 0; i < mimeTypes.size(); ++i) { - if (mimeTypes.at(i) == mime) { - mimeAtom = mimeAtoms.at(i); + if (mimeTypes[i] == mime) { + mimeAtom = mimeAtoms[i]; break; } } diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 81900c7b..68552dd6 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -1051,13 +1051,13 @@ void CXWM::readWindowData(SP surf) { }; for (size_t i = 0; i < interestingProps.size(); i++) { - xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, surf->xID, interestingProps.at(i), XCB_ATOM_ANY, 0, 2048); + xcb_get_property_cookie_t cookie = xcb_get_property(connection, 0, surf->xID, interestingProps[i], XCB_ATOM_ANY, 0, 2048); xcb_get_property_reply_t* reply = xcb_get_property_reply(connection, cookie, nullptr); if (!reply) { Debug::log(ERR, "[xwm] Failed to get window property"); continue; } - readProp(surf, interestingProps.at(i), reply); + readProp(surf, interestingProps[i], reply); free(reply); } } From ff9e059de6dd30c813270ff5a74053339cc94765 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 6 Feb 2025 11:21:04 +0000 Subject: [PATCH 0052/1257] window: move size reporting to animation begin callback (#9298) * window: fix resizes with an update callback * window: fixup sendWindowSize Remove the size argument from sendWindowSize, since it is now a member of the Window class and we don't want any mismatches between m_vRealSize and what we report. Remove sendWindowSize from mapWindow, since we shouldn't need it. * window: sendWindowSize on animation begin * window: move most calls to sendWindowSize to the animation begin callback * window: remove sendWindowSize in unmanaged if not fullscreen --- src/Compositor.cpp | 2 +- src/desktop/Window.cpp | 26 +++++++++++-------- src/desktop/Window.hpp | 2 +- src/desktop/Workspace.cpp | 2 +- src/events/Windows.cpp | 9 +------ src/layout/DwindleLayout.cpp | 4 --- src/layout/IHyprLayout.cpp | 18 +++++-------- src/layout/MasterLayout.cpp | 4 --- src/managers/KeybindManager.cpp | 1 - src/managers/XWaylandManager.cpp | 2 +- .../decorations/CHyprGroupBarDecoration.cpp | 3 --- 11 files changed, 26 insertions(+), 47 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index a8cbae3a..e460bbca 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2330,7 +2330,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, SFullscreenS updateFullscreenFadeOnWorkspace(PWORKSPACE); - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(true); PWORKSPACE->forceReportSizesToWindows(); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 8f6d2cb5..b0d7b58c 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -458,9 +458,6 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) { } } - // update xwayland coords - sendWindowSize(m_vRealSize->goal()); - if (OLDWORKSPACE && g_pCompositor->isWorkspaceSpecial(OLDWORKSPACE->m_iID) && OLDWORKSPACE->getWindows() == 0 && *PCLOSEONLASTSPECIAL) { if (const auto PMONITOR = OLDWORKSPACE->m_pMonitor.lock(); PMONITOR) PMONITOR->setSpecialWorkspace(nullptr); @@ -563,6 +560,15 @@ void CWindow::onMap() { *m_fBorderAngleAnimationProgress = 1.f; } + m_vRealSize->setCallbackOnBegin( + [this](auto) { + if (!m_bIsMapped || isX11OverrideRedirect()) + return; + + sendWindowSize(); + }, + false); + m_fMovingFromWorkspaceAlpha->setValueAndWarp(1.F); g_pCompositor->m_vWindowFocusHistory.push_back(m_pSelf); @@ -1315,7 +1321,6 @@ void CWindow::clampWindowSize(const std::optional minSize, const std:: *m_vRealPosition = m_vRealPosition->goal() + DELTA / 2.0; *m_vRealSize = NEWSIZE; - sendWindowSize(NEWSIZE); } bool CWindow::isFullscreen() { @@ -1539,7 +1544,7 @@ void CWindow::onX11Configure(CBox box) { g_pHyprRenderer->damageWindow(m_pSelf.lock()); if (!m_bIsFloating || isFullscreen() || g_pInputManager->currentlyDraggedWindow == m_pSelf) { - sendWindowSize(m_vRealSize->goal(), true); + sendWindowSize(true); g_pInputManager->refocus(); g_pHyprRenderer->damageWindow(m_pSelf.lock()); return; @@ -1566,8 +1571,6 @@ void CWindow::onX11Configure(CBox box) { m_vPosition = m_vRealPosition->goal(); m_vSize = m_vRealSize->goal(); - sendWindowSize(box.size(), true); - m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); @@ -1697,15 +1700,16 @@ Vector2D CWindow::requestedMaxSize() { return maxSize; } -void CWindow::sendWindowSize(Vector2D size, bool force, std::optional overridePos) { +void CWindow::sendWindowSize(bool force) { static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); const auto PMONITOR = m_pMonitor.lock(); - size = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(), + m_vRealSize->goal(), force); - // calculate pos // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = overridePos.value_or(m_vRealPosition->goal()); + Vector2D windowPos = m_vRealPosition->goal(); + Vector2D size = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); if (m_bIsX11 && PMONITOR) { windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 8444a113..9a4a36c2 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -471,7 +471,7 @@ class CWindow { bool isModal(); Vector2D requestedMinSize(); Vector2D requestedMaxSize(); - void sendWindowSize(Vector2D size, bool force = false, std::optional overridePos = std::nullopt); + void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 8dbf30b7..7f8e7fc9 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -624,7 +624,7 @@ void CWorkspace::forceReportSizesToWindows() { if (w->m_pWorkspace != m_pSelf || !w->m_bIsMapped || w->isHidden()) continue; - w->sendWindowSize(w->m_vRealSize->goal(), true); + w->sendWindowSize(true); } } diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index d96bb332..399894f9 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -688,13 +688,6 @@ void Events::listener_mapWindow(void* owner, void* data) { if (PMONITOR && PWINDOW->isX11OverrideRedirect()) PWINDOW->m_fX11SurfaceScaledBy = PMONITOR->scale; - - // Fix some X11 popups being invisible / having incorrect size on open. - // What the ACTUAL FUCK is going on?????? I HATE X11 - if (!PWINDOW->isX11OverrideRedirect() && PWINDOW->m_bIsX11 && PWINDOW->m_bIsFloating) { - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true, PWINDOW->m_vRealPosition->goal() - Vector2D{1, 1}); - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); - } } void Events::listener_unmapWindow(void* owner, void* data) { @@ -964,7 +957,7 @@ void Events::listener_unmanagedSetGeometry(void* owner, void* data) { PWINDOW->setHidden(true); if (PWINDOW->isFullscreen() || !PWINDOW->m_bIsFloating) { - PWINDOW->sendWindowSize(PWINDOW->m_vRealSize->goal(), true); + PWINDOW->sendWindowSize(true); g_pHyprRenderer->damageWindow(PWINDOW); return; } diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 8aaafaa3..ecd7abea 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -198,16 +198,12 @@ void CHyprDwindleLayout::applyNodeDataToWindow(SDwindleNodeData* pNode, bool for *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess *PWINDOW->m_vRealSize = wb.size(); *PWINDOW->m_vRealPosition = wb.pos(); - - PWINDOW->sendWindowSize(wb.size()); } if (force) { diff --git a/src/layout/IHyprLayout.cpp b/src/layout/IHyprLayout.cpp index 9a0ba6ee..e84ffb21 100644 --- a/src/layout/IHyprLayout.cpp +++ b/src/layout/IHyprLayout.cpp @@ -176,11 +176,9 @@ void IHyprLayout::onWindowCreatedFloating(PHLWINDOW pWindow) { pWindow->m_vRealSize->warp(); } - if (!pWindow->isX11OverrideRedirect()) { - pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); - + if (!pWindow->isX11OverrideRedirect()) g_pCompositor->changeWindowZOrder(pWindow, true); - } else { + else { pWindow->m_vPendingReportedSize = pWindow->m_vRealSize->goal(); pWindow->m_vReportedSize = pWindow->m_vPendingReportedSize; } @@ -362,9 +360,6 @@ void IHyprLayout::onEndDragWindow() { DRAGGINGWINDOW->m_vLastFloatingSize = m_vDraggingWindowOriginalFloatSize; DRAGGINGWINDOW->m_bDraggingTiled = false; - if (pWindow->m_bIsFloating) - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); // match the size of the window - static auto USECURRPOS = CConfigValue("group:insert_after_current"); (*USECURRPOS ? pWindow : pWindow->getGroupTail())->insertWindowToGroup(DRAGGINGWINDOW); pWindow->setGroupCurrent(DRAGGINGWINDOW); @@ -606,10 +601,11 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { if (*PANIMATEMOUSE) *DRAGGINGWINDOW->m_vRealPosition = wb.pos(); - else + else { DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->sendWindowSize(); + } - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else if (g_pInputManager->dragMode == MBIND_RESIZE || g_pInputManager->dragMode == MBIND_RESIZE_FORCE_RATIO || g_pInputManager->dragMode == MBIND_RESIZE_BLOCK_RATIO) { if (DRAGGINGWINDOW->m_bIsFloating) { @@ -679,9 +675,8 @@ void IHyprLayout::onMouseMove(const Vector2D& mousePos) { } else { DRAGGINGWINDOW->m_vRealSize->setValueAndWarp(wb.size()); DRAGGINGWINDOW->m_vRealPosition->setValueAndWarp(wb.pos()); + DRAGGINGWINDOW->sendWindowSize(); } - - DRAGGINGWINDOW->sendWindowSize(DRAGGINGWINDOW->m_vRealSize->goal()); } else { resizeActiveWindow(TICKDELTA, m_eGrabbedCorner, DRAGGINGWINDOW); } @@ -787,7 +782,6 @@ void IHyprLayout::changeWindowFloatingMode(PHLWINDOW pWindow) { g_pCompositor->updateWindowAnimatedDecorationValues(pWindow); pWindow->updateToplevel(); - pWindow->sendWindowSize(pWindow->m_vRealSize->goal()); g_pHyprRenderer->damageWindow(pWindow); } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index dc301bfa..a429843f 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -678,16 +678,12 @@ void CHyprMasterLayout::applyNodeDataToWindow(SMasterNodeData* pNode) { *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } else { CBox wb = {calcPos, calcSize}; wb.round(); // avoid rounding mess *PWINDOW->m_vRealPosition = wb.pos(); *PWINDOW->m_vRealSize = wb.size(); - - PWINDOW->sendWindowSize(wb.size()); } if (m_bForceWarps && !*PANIMATE) { diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 2d6b2cb8..8daa6838 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1908,7 +1908,6 @@ SDispatchResult CKeybindManager::workspaceOpt(std::string args) { if (PWORKSPACE->m_bDefaultFloating) { w->m_vRealPosition->setValueAndWarp(SAVEDPOS); w->m_vRealSize->setValueAndWarp(SAVEDSIZE); - w->sendWindowSize(SAVEDSIZE); *w->m_vRealSize = w->m_vRealSize->value() + Vector2D(4, 4); *w->m_vRealPosition = w->m_vRealPosition->value() - Vector2D(2, 2); } diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index a5506329..63b14962 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -55,7 +55,7 @@ void CHyprXWaylandManager::activateWindow(PHLWINDOW pWindow, bool activate) { if (pWindow->m_bIsX11) { if (activate) { - pWindow->sendWindowSize(pWindow->m_vRealSize->value(), true); // update xwayland output pos + pWindow->sendWindowSize(true); // update xwayland output pos pWindow->m_pXWaylandSurface->setMinimized(false); if (!pWindow->isX11OverrideRedirect()) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 1a64b024..32422e14 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -456,9 +456,6 @@ bool CHyprGroupBarDecoration::onEndWindowDragOnDeco(const Vector2D& pos, PHLWIND pDraggedWindow->m_bIsFloating = pWindowInsertAfter->m_bIsFloating; // match the floating state of the window - if (pWindowInsertAfter->m_bIsFloating) - pDraggedWindow->sendWindowSize(pWindowInsertAfter->m_vRealSize->goal()); // match the size of the window - pWindowInsertAfter->insertWindowToGroup(pDraggedWindow); if (WINDOWINDEX == -1) From 30b49c75bf04ceffc9fb1652a4d02e4eebacc24c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Thu, 6 Feb 2025 12:13:35 +0000 Subject: [PATCH 0053/1257] popup: improve ::at() behavior --- src/desktop/Popup.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 4accb58f..82767ead 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -347,18 +347,19 @@ WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { continue; if (!allowsInput) { - const Vector2D offset = - p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; - const Vector2D size = p->m_pResource ? p->m_pResource->geometry.size() : p->size(); + const bool HASSURFACE = p->m_pResource && p->m_pResource->surface; - const auto BOX = CBox{p->coordsGlobal() + offset, size}; + Vector2D offset = HASSURFACE ? p->m_pResource->surface->current.geometry.pos() : Vector2D{}; + Vector2D size = HASSURFACE ? p->m_pResource->surface->current.geometry.size() : p->size(); + + if (size == Vector2D{}) + size = p->size(); + + const auto BOX = CBox{p->coordsGlobal() + offset, size}; if (BOX.containsPoint(globalCoords)) return p; } else { - const Vector2D offset = - p->m_pResource && p->m_pResource->surface ? (p->size() - p->m_pResource->geometry.size()) / 2.F - p->m_pResource->surface->current.geometry.pos() : Vector2D{}; - const auto REGION = - CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal() + offset); + const auto REGION = CRegion{p->m_pWLSurface->resource()->current.input}.intersect(CBox{{}, p->m_pWLSurface->resource()->current.size}).translate(p->coordsGlobal()); if (REGION.containsPoint(globalCoords)) return p; } From acbcf0cf115d55ef80a75ded3223a9e098f77541 Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:42:20 +0100 Subject: [PATCH 0054/1257] toplevelexport: fix transformed origin for shm buffers (#9343) * toplevelexport: fix transformed origin for shm buffers * toplevelexport: fix style nits --- src/protocols/ToplevelExport.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index 8b835b50..a9009aa4 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -11,6 +11,7 @@ #include "../render/Renderer.hpp" #include +#include CToplevelExportClient::CToplevelExportClient(SP resource_) : resource(resource_) { if UNLIKELY (!good()) @@ -289,7 +290,29 @@ bool CToplevelExportFrame::copyShm(timespec* now) { glPixelStorei(GL_PACK_ALIGNMENT, 1); auto glFormat = PFORMAT->flipRB ? GL_BGRA_EXT : GL_RGBA; - glReadPixels(0, 0, box.width, box.height, glFormat, PFORMAT->glType, pixelData); + + auto origin = Vector2D(0, 0); + switch (PMONITOR->transform) { + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + case WL_OUTPUT_TRANSFORM_90: { + origin.y = PMONITOR->vecPixelSize.y - box.height; + break; + } + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + case WL_OUTPUT_TRANSFORM_180: { + origin.x = PMONITOR->vecPixelSize.x - box.width; + origin.y = PMONITOR->vecPixelSize.y - box.height; + break; + } + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_270: { + origin.x = PMONITOR->vecPixelSize.x - box.width; + break; + } + default: break; + } + + glReadPixels(origin.x, origin.y, box.width, box.height, glFormat, PFORMAT->glType, pixelData); if (overlayCursor) { g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock()); From 54441e0c4e51dd182f78876c014446d5d0359ba8 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 6 Feb 2025 17:45:25 +0000 Subject: [PATCH 0055/1257] renderer: fix fade out on silent moves to special --- src/render/Renderer.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0fcda827..6f0bbe44 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -379,7 +379,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (w->m_bIsFloating) continue; // floating are in the second pass - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; // render active window after all others of this pass @@ -390,11 +393,14 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo // render the bad boy renderWindow(w.lock(), pMonitor, time, true, RENDER_PASS_MAIN); + w.reset(); } if (lastWindow) renderWindow(lastWindow, pMonitor, time, true, RENDER_PASS_MAIN); + lastWindow.reset(); + // Non-floating popup for (auto& w : windows) { if (!w) @@ -403,7 +409,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (w->m_bIsFloating) continue; // floating are in the second pass - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; // render the bad boy @@ -419,7 +428,10 @@ void CHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo if (!w->m_bIsFloating || w->m_bPinned) continue; - if (pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) + // some things may force us to ignore the special/not special disparity + const bool IGNORE_SPECIAL_CHECK = w->m_iMonitorMovedFrom != -1 && (w->m_pWorkspace && !w->m_pWorkspace->isVisible()); + + if (!IGNORE_SPECIAL_CHECK && pWorkspace->m_bIsSpecialWorkspace != w->onSpecialWorkspace()) continue; if (pWorkspace->m_bIsSpecialWorkspace && w->m_pMonitor != pWorkspace->m_pMonitor) From a724332eb82c33308a8cb6127172f128e3afe14c Mon Sep 17 00:00:00 2001 From: Paul Cross <3613973+kreejzak@users.noreply.github.com> Date: Sat, 8 Feb 2025 01:45:13 +0100 Subject: [PATCH 0056/1257] desktop: add ability to target pinned windows in workspace rules (#9344) * desktop: add ability to target pinned windows in workspace rules * desktop: add ability to target pinned windows in workspace rules * fix formating --- src/desktop/Workspace.cpp | 21 +++++++++++++++++---- src/desktop/Workspace.hpp | 4 ++-- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 7f8e7fc9..f2c22195 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -261,6 +261,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { // n - named: n[true] or n[s:string] or n[e:string] // m - monitor: m[monitor_selector] // w - windowCount: w[1-4] or w[1], optional flag t or f for tiled or floating and + // flag p to count only pinned windows, e.g. w[p1-2], w[pg4] // flag g to count groups instead of windows, e.g. w[t1-2], w[fg4] // flag v will count only visible windows // f - fullscreen state : f[-1], f[0], f[1], or f[2] for different fullscreen states @@ -370,6 +371,7 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { prop = prop.substr(2, prop.length() - 3); int wantsOnlyTiled = -1; + int wantsOnlyPinned = false; bool wantsCountGroup = false; bool wantsCountVisible = false; @@ -381,6 +383,9 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { } else if (flag == 'f' && wantsOnlyTiled == -1) { wantsOnlyTiled = 0; flagCount++; + } else if (flag == 'p' && !wantsOnlyPinned) { + wantsOnlyPinned = true; + flagCount++; } else if (flag == 'g' && !wantsCountGroup) { wantsCountGroup = true; flagCount++; @@ -411,9 +416,11 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { int count; if (wantsCountGroup) count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (count != from) @@ -444,10 +451,12 @@ bool CWorkspace::matchesStaticSelector(const std::string& selector_) { WORKSPACEID count; if (wantsCountGroup) - count = getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), - wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); + count = + getGroups(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); else count = getWindows(wantsOnlyTiled == -1 ? std::nullopt : std::optional((bool)wantsOnlyTiled), + wantsOnlyPinned ? std::optional(wantsOnlyPinned) : std::nullopt, wantsCountVisible ? std::optional(wantsCountVisible) : std::nullopt); if (std::clamp(count, from, to) != count) @@ -535,13 +544,15 @@ bool CWorkspace::isVisibleNotCovered() { return PMONITOR->activeWorkspace->m_iID == m_iID; } -int CWorkspace::getWindows(std::optional onlyTiled, std::optional onlyVisible) { +int CWorkspace::getWindows(std::optional onlyTiled, std::optional onlyPinned, std::optional onlyVisible) { int no = 0; for (auto const& w : g_pCompositor->m_vWindows) { if (w->workspaceID() != m_iID || !w->m_bIsMapped) continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) continue; + if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) + continue; if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) continue; no++; @@ -550,7 +561,7 @@ int CWorkspace::getWindows(std::optional onlyTiled, std::optional on return no; } -int CWorkspace::getGroups(std::optional onlyTiled, std::optional onlyVisible) { +int CWorkspace::getGroups(std::optional onlyTiled, std::optional onlyPinned, std::optional onlyVisible) { int no = 0; for (auto const& w : g_pCompositor->m_vWindows) { if (w->workspaceID() != m_iID || !w->m_bIsMapped) @@ -559,6 +570,8 @@ int CWorkspace::getGroups(std::optional onlyTiled, std::optional onl continue; if (onlyTiled.has_value() && w->m_bIsFloating == onlyTiled.value()) continue; + if (onlyPinned.has_value() && w->m_bPinned != onlyPinned.value()) + continue; if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value()) continue; no++; diff --git a/src/desktop/Workspace.hpp b/src/desktop/Workspace.hpp index e9859d4f..12dbe328 100644 --- a/src/desktop/Workspace.hpp +++ b/src/desktop/Workspace.hpp @@ -72,8 +72,8 @@ class CWorkspace { SWorkspaceIDName getPrevWorkspaceIDName() const; void updateWindowDecos(); void updateWindowData(); - int getWindows(std::optional onlyTiled = {}, std::optional onlyVisible = {}); - int getGroups(std::optional onlyTiled = {}, std::optional onlyVisible = {}); + int getWindows(std::optional onlyTiled = {}, std::optional onlyPinned = {}, std::optional onlyVisible = {}); + int getGroups(std::optional onlyTiled = {}, std::optional onlyPinned = {}, std::optional onlyVisible = {}); bool hasUrgentWindow(); PHLWINDOW getFirstWindow(); PHLWINDOW getTopLeftWindow(); From f7fcbe32c9f66bcfc86853a5cda95edcf481f573 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sat, 8 Feb 2025 01:46:26 +0100 Subject: [PATCH 0057/1257] renderer: various fixes towards improving gpu calls robustness (#9188) ensure framebuffer textures are detached and deleted, avoid leaving framebuffers bound when not needed * render: avoid calling glDeleteProgram on no program its safe to do so but it adds a bunch of unnecessery lines in apitrace when tracing. if guard it and return early. * opengl: ensure texture and buffers are unbound ensure bound buffers are unbound after use, also detach textures from framebuffer before deleting it otherwise it will become dangling and essentially leak. --- src/protocols/Screencopy.cpp | 6 ++++ src/protocols/ToplevelExport.cpp | 6 ++++ src/render/Framebuffer.cpp | 56 +++++++++++++++++--------------- src/render/Framebuffer.hpp | 3 +- src/render/OpenGL.hpp | 2 -- src/render/Renderbuffer.cpp | 8 ++--- src/render/Shader.cpp | 5 ++- 7 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index e086cc76..aae5caf1 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -289,6 +289,12 @@ bool CScreencopyFrame::copyShm() { g_pHyprOpenGL->m_RenderData.pMonitor.reset(); +#ifndef GLES2 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +#else + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif + LOGM(TRACE, "Copied frame via shm"); return true; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index a9009aa4..fb0bd9c7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -319,6 +319,12 @@ bool CToplevelExportFrame::copyShm(timespec* now) { g_pPointerManager->damageCursor(PMONITOR->self.lock()); } + outFB.unbind(); + +#ifndef GLES2 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); +#endif + return true; } diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp index 93f8fe7f..6905eb36 100644 --- a/src/render/Framebuffer.cpp +++ b/src/render/Framebuffer.cpp @@ -12,29 +12,26 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { uint32_t glFormat = NFormatUtils::drmFormatToGL(drmFormat); uint32_t glType = NFormatUtils::glFormatToType(glFormat); - if (!m_cTex) + if (!m_cTex) { m_cTex = makeShared(); - - if (!m_iFbAllocated) { - firstAlloc = true; - glGenFramebuffers(1, &m_iFb); - m_iFbAllocated = true; - } - - if (m_cTex->m_iTexID == 0) { - firstAlloc = true; m_cTex->allocate(); glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + firstAlloc = true; + } + + if (!m_iFbAllocated) { + glGenFramebuffers(1, &m_iFb); + m_iFbAllocated = true; + firstAlloc = true; } if (firstAlloc || m_vSize != Vector2D(w, h)) { glBindTexture(GL_TEXTURE_2D, m_cTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, glFormat, w, h, 0, GL_RGBA, glType, nullptr); - glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_cTex->m_iTexID, 0); @@ -43,9 +40,6 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { if (m_pStencilTex) { glBindTexture(GL_TEXTURE_2D, m_pStencilTex->m_iTexID); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); - - glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_pStencilTex->m_iTexID, 0); } #endif @@ -57,8 +51,7 @@ bool CFramebuffer::alloc(int w, int h, uint32_t drmFormat) { } glBindTexture(GL_TEXTURE_2D, 0); - if (g_pHyprOpenGL) - glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); + glBindFramebuffer(GL_FRAMEBUFFER, 0); m_vSize = Vector2D(w, h); @@ -80,7 +73,7 @@ void CFramebuffer::addStencil(SP tex) { RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Failed adding a stencil to fbo!", status); glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, g_pHyprOpenGL->m_iCurrentOutputFb); + glBindFramebuffer(GL_FRAMEBUFFER, 0); #endif } @@ -90,25 +83,36 @@ void CFramebuffer::bind() { #else glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); #endif + if (g_pHyprOpenGL) glViewport(0, 0, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.x, g_pHyprOpenGL->m_RenderData.pMonitor->vecPixelSize.y); else glViewport(0, 0, m_vSize.x, m_vSize.y); } +void CFramebuffer::unbind() { +#ifndef GLES2 + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#else + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + void CFramebuffer::release() { - if (!m_iFbAllocated && !m_cTex) - return; + if (m_iFbAllocated) { + glBindFramebuffer(GL_FRAMEBUFFER, m_iFb); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); - Debug::log(TRACE, "fb {} released", m_iFb); - - if (m_iFbAllocated) glDeleteFramebuffers(1, &m_iFb); + m_iFbAllocated = false; + m_iFb = 0; + } - m_cTex.reset(); - m_iFbAllocated = false; - m_vSize = Vector2D(); - m_iFb = 0; + if (m_cTex) + m_cTex.reset(); + + m_vSize = Vector2D(); } CFramebuffer::~CFramebuffer() { diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp index 84dfeef1..092e548e 100644 --- a/src/render/Framebuffer.hpp +++ b/src/render/Framebuffer.hpp @@ -11,6 +11,7 @@ class CFramebuffer { bool alloc(int w, int h, uint32_t format = GL_RGBA); void addStencil(SP tex); void bind(); + void unbind(); void release(); void reset(); bool isAllocated(); @@ -28,4 +29,4 @@ class CFramebuffer { SP m_pStencilTex; friend class CRenderbuffer; -}; \ No newline at end of file +}; diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 7b7b7e6f..cf1d2549 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -233,8 +233,6 @@ class CHyprOpenGLImpl { SCurrentRenderData m_RenderData; - GLint m_iCurrentOutputFb = 0; - Hyprutils::OS::CFileDescriptor m_iGBMFD; gbm_device* m_pGbmDevice = nullptr; EGLContext m_pEglContext = nullptr; diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp index 887f31a9..1ea9f785 100644 --- a/src/render/Renderbuffer.cpp +++ b/src/render/Renderbuffer.cpp @@ -46,7 +46,7 @@ CRenderbuffer::CRenderbuffer(SP buffer, uint32_t format) : return; } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + m_sFramebuffer.unbind(); listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); }); @@ -68,11 +68,7 @@ void CRenderbuffer::bindFB() { void CRenderbuffer::unbind() { glBindRenderbuffer(GL_RENDERBUFFER, 0); -#ifndef GLES2 - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); -#else - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#endif + m_sFramebuffer.unbind(); } CFramebuffer* CRenderbuffer::getFB() { diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index b494d79d..984d8ce3 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -17,7 +17,10 @@ CShader::~CShader() { } void CShader::destroy() { + if (program == 0) + return; + glDeleteProgram(program); program = 0; -} \ No newline at end of file +} From feb8ad48f0153a15b96356f280dbd04849db0e04 Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 8 Feb 2025 09:05:44 -0500 Subject: [PATCH 0058/1257] groups: deactivate unfocused windows in groups (#9354) --- src/Compositor.cpp | 3 +++ src/desktop/Window.cpp | 16 ++++++++++++++++ src/desktop/Window.hpp | 1 + 3 files changed, 20 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e460bbca..aebb0ac1 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1189,6 +1189,9 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP pSurface if (*PFOLLOWMOUSE == 0) g_pInputManager->sendMotionEventsToFocused(); + + if (pWindow->m_sGroupData.pNextWindow) + pWindow->deactivateGroupMembers(); } void CCompositor::focusSurface(SP pSurface, PHLWINDOW pWindowOwner) { diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b0d7b58c..7c0cb741 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1748,3 +1748,19 @@ void CWindow::setContentType(NContentType::eContentType contentType) { Debug::log(INFO, "ContentType for window {}", (int)contentType); m_pWLSurface->resource()->contentType->value = contentType; } + +void CWindow::deactivateGroupMembers() { + auto curr = getGroupHead(); + while (curr) { + if (curr != m_pSelf.lock()) { + if (curr->m_bIsX11) + curr->m_pXWaylandSurface->activate(false); + else if (curr->m_pXDGSurface && curr->m_pXDGSurface->toplevel) + curr->m_pXDGSurface->toplevel->setActive(false); + } + + curr = curr->m_sGroupData.pNextWindow.lock(); + if (curr == getGroupHead()) + break; + } +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 9a4a36c2..171a15f4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -474,6 +474,7 @@ class CWindow { void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); + void deactivateGroupMembers(); CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; From 8e10ddb592977ef2e1836e75b0e5550ba8fb56f0 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Sun, 9 Feb 2025 02:00:55 +0500 Subject: [PATCH 0059/1257] datadevice: fix wrong param (#9370) Reason: look at the setReceive parameters and also at the next line(tries to narrow) --- src/protocols/core/DataDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 0931608a..25117265 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -39,7 +39,7 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetReceive([this](CWlDataOffer* r, const char* mime, uint32_t fd) { + resource->setReceive([this](CWlDataOffer* r, const char* mime, int fd) { CFileDescriptor sendFd{fd}; if (!source) { LOGM(WARN, "Possible bug: Receive on an offer w/o a source"); From 56f6f61596a547cdcdfb7aa7c3550e380b487ee3 Mon Sep 17 00:00:00 2001 From: clamydo <13063485+clamydo@users.noreply.github.com> Date: Sun, 9 Feb 2025 15:30:30 +0100 Subject: [PATCH 0060/1257] tablet: take `active_area_size` into account when sending tip event (#9325) * fixes #9322, take `active_area_size` into account when sending tip event * check if `relative_input` is set As suggested by @y47s5s68tq870r7tc1xpp755pabopg * refactoring active area in own function to keep it DRY * coding style * making transformation static --------- Co-authored-by: clamydo --- src/managers/input/Tablets.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp index 0952a7d4..e1a2f2aa 100644 --- a/src/managers/input/Tablets.cpp +++ b/src/managers/input/Tablets.cpp @@ -88,6 +88,20 @@ static void refocusTablet(SP tab, SP tool, bool motion = f PROTO::tablet->motion(tool, local); } +static Vector2D transformToActiveRegion(const Vector2D pos, const CBox activeArea) { + auto newPos = pos; + + //Calculate transformations if active area is set + if (!activeArea.empty()) { + if (!std::isnan(pos.x)) + newPos.x = (pos.x - activeArea.x) / (activeArea.w - activeArea.x); + if (!std::isnan(pos.y)) + newPos.y = (pos.y - activeArea.y) / (activeArea.h - activeArea.y); + } + + return newPos; +} + void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { const auto PTAB = e.tablet; const auto PTOOL = ensureTabletToolPresent(e.tool); @@ -113,16 +127,9 @@ void CInputManager::onTabletAxis(CTablet::SAxisEvent e) { if (PTAB->relativeInput) g_pPointerManager->move(delta); - else { - //Calculate transformations if active area is set - if (!PTAB->activeArea.empty()) { - if (!std::isnan(x)) - x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x); - if (!std::isnan(y)) - y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y); - } - g_pPointerManager->warpAbsolute({x, y}, PTAB); - } + else + g_pPointerManager->warpAbsolute(transformToActiveRegion({x, y}, PTAB->activeArea), PTAB); + break; } } @@ -160,7 +167,12 @@ void CInputManager::onTabletTip(CTablet::STipEvent e) { const auto PTAB = e.tablet; const auto PTOOL = ensureTabletToolPresent(e.tool); const auto POS = e.tip; - g_pPointerManager->warpAbsolute(POS, PTAB); + + if (PTAB->relativeInput) + g_pPointerManager->move({0, 0}); + else + g_pPointerManager->warpAbsolute(transformToActiveRegion(POS, PTAB->activeArea), PTAB); + refocusTablet(PTAB, PTOOL, true); if (e.in) From 1f97643e830d513cafc2057860bbefa5cc01a0ee Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:38:20 +0000 Subject: [PATCH 0061/1257] core: add mallopt to modify trim threshold --- src/Compositor.cpp | 14 ++++++++++++++ src/Compositor.hpp | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index aebb0ac1..88a2530b 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -69,6 +69,8 @@ #include #include #include +#include +#include using namespace Hyprutils::String; using namespace Aquamarine; @@ -162,10 +164,22 @@ void CCompositor::restoreNofile() { Debug::log(ERR, "Failed restoring NOFILE limits"); } +void CCompositor::setMallocThreshold() { +#ifdef M_TRIM_THRESHOLD + // The default is 128 pages, + // which is very large and can lead to a lot of memory used for no reason + // because trimming hasn't happened + static const int PAGESIZE = sysconf(_SC_PAGESIZE); + mallopt(M_TRIM_THRESHOLD, 6 * PAGESIZE); +#endif +} + CCompositor::CCompositor(bool onlyConfig) : m_bOnlyConfigVerification(onlyConfig), m_iHyprlandPID(getpid()) { if (onlyConfig) return; + setMallocThreshold(); + m_szHyprTempDataRoot = std::string{getenv("XDG_RUNTIME_DIR")} + "/hypr"; if (m_szHyprTempDataRoot.starts_with("/hypr")) { diff --git a/src/Compositor.hpp b/src/Compositor.hpp index a57095a3..893ffadd 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -52,8 +52,6 @@ class CCompositor { void startCompositor(); void stopCompositor(); void cleanup(); - void createLockFile(); - void removeLockFile(); void bumpNofile(); void restoreNofile(); @@ -163,6 +161,9 @@ class CCompositor { void setRandomSplash(); void initManagers(eManagersInitStage stage); void prepareFallbackOutput(); + void createLockFile(); + void removeLockFile(); + void setMallocThreshold(); uint64_t m_iHyprlandPID = 0; wl_event_source* m_critSigSource = nullptr; From 3a43e7bb9a787755639838d7cb005a9d33f8c6f2 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:50:54 +0000 Subject: [PATCH 0062/1257] config: default movefocus_cycles_fullscreen to false less confusing --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 28cd29c4..8d1b73c4 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1234,7 +1234,7 @@ inline static const std::vector CONFIG_OPTIONS = { .value = "binds:movefocus_cycles_fullscreen", .description = "If enabled, when on a fullscreen window, movefocus will cycle fullscreen, if not, it will move the focus in a direction.", .type = CONFIG_OPTION_BOOL, - .data = SConfigOptionDescription::SBoolData{true}, + .data = SConfigOptionDescription::SBoolData{false}, }, SConfigOptionDescription{ .value = "binds:movefocus_cycles_groupfirst", diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 3f45ddfe..f87a5e6b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -594,7 +594,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("binds:workspace_center_on", Hyprlang::INT{1}); m_pConfig->addConfigValue("binds:focus_preferred_method", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:ignore_group_lock", Hyprlang::INT{0}); - m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{1}); + m_pConfig->addConfigValue("binds:movefocus_cycles_fullscreen", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:movefocus_cycles_groupfirst", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:disable_keybind_grabbing", Hyprlang::INT{0}); m_pConfig->addConfigValue("binds:window_direction_monitor_fallback", Hyprlang::INT{1}); From f261fb6fe028a1427cfd672eee6e7d5705cd696f Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 9 Feb 2025 17:58:09 +0000 Subject: [PATCH 0063/1257] groupbar: fix groupbar missing when indicator_height is <= 0 ref #9291 #9372 --- .../decorations/CHyprGroupBarDecoration.cpp | 188 +++++++++--------- 1 file changed, 95 insertions(+), 93 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 32422e14..4e430bef 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -99,7 +99,11 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { // get how many bars we will draw int barsToDraw = m_dwGroupMembers.size(); - static auto PENABLED = CConfigValue("group:groupbar:enabled"); + static auto PENABLED = CConfigValue("group:groupbar:enabled"); + + if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) + return; + static auto PRENDERTITLES = CConfigValue("group:groupbar:render_titles"); static auto PTITLEFONTSIZE = CConfigValue("group:groupbar:font_size"); static auto PHEIGHT = CConfigValue("group:groupbar:height"); @@ -110,14 +114,19 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { static auto PGRADIENTROUNDING = CConfigValue("group:groupbar:gradient_rounding"); static auto PGRADIENTROUNDINGONLYEDGES = CConfigValue("group:groupbar:gradient_round_only_edges"); static auto PROUNDONLYEDGES = CConfigValue("group:groupbar:round_only_edges"); + static auto PGROUPCOLACTIVE = CConfigValue("group:groupbar:col.active"); + static auto PGROUPCOLINACTIVE = CConfigValue("group:groupbar:col.inactive"); + static auto PGROUPCOLACTIVELOCKED = CConfigValue("group:groupbar:col.locked_active"); + static auto PGROUPCOLINACTIVELOCKED = CConfigValue("group:groupbar:col.locked_inactive"); + auto* const GROUPCOLACTIVE = (CGradientValueData*)(PGROUPCOLACTIVE.ptr())->getData(); + auto* const GROUPCOLINACTIVE = (CGradientValueData*)(PGROUPCOLINACTIVE.ptr())->getData(); + auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); + auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - if (!*PENABLED || !m_pWindow->m_sWindowData.decorate.valueOrDefault()) - return; + const auto ASSIGNEDBOX = assignedBoxGlobal(); - const auto ASSIGNEDBOX = assignedBoxGlobal(); - - const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); - m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; + const auto ONEBARHEIGHT = BAR_PADDING_OUTER_VERT + *PINDICATORHEIGHT + (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0); + m_fBarWidth = *PSTACKED ? ASSIGNEDBOX.w : (ASSIGNEDBOX.w - BAR_HORIZONTAL_PADDING * (barsToDraw - 1)) / barsToDraw; m_fBarHeight = *PSTACKED ? ((ASSIGNEDBOX.h - 2 - BAR_PADDING_OUTER_VERT) - BAR_PADDING_OUTER_VERT * (barsToDraw)) / barsToDraw : ASSIGNEDBOX.h - BAR_PADDING_OUTER_VERT; const auto DESIREDHEIGHT = *PSTACKED ? (ONEBARHEIGHT * m_dwGroupMembers.size()) + 2 + BAR_PADDING_OUTER_VERT : BAR_PADDING_OUTER_VERT * 2L + ONEBARHEIGHT; @@ -134,116 +143,109 @@ void CHyprGroupBarDecoration::draw(PHLMONITOR pMonitor, float const& a) { ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - *PINDICATORHEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, *PINDICATORHEIGHT}; - if (rect.width <= 0 || rect.height <= 0) - break; - rect.scale(pMonitor->scale); - static auto PGROUPCOLACTIVE = CConfigValue("group:groupbar:col.active"); - static auto PGROUPCOLINACTIVE = CConfigValue("group:groupbar:col.inactive"); - static auto PGROUPCOLACTIVELOCKED = CConfigValue("group:groupbar:col.locked_active"); - static auto PGROUPCOLINACTIVELOCKED = CConfigValue("group:groupbar:col.locked_inactive"); - auto* const GROUPCOLACTIVE = (CGradientValueData*)(PGROUPCOLACTIVE.ptr())->getData(); - auto* const GROUPCOLINACTIVE = (CGradientValueData*)(PGROUPCOLINACTIVE.ptr())->getData(); - auto* const GROUPCOLACTIVELOCKED = (CGradientValueData*)(PGROUPCOLACTIVELOCKED.ptr())->getData(); - auto* const GROUPCOLINACTIVELOCKED = (CGradientValueData*)(PGROUPCOLINACTIVELOCKED.ptr())->getData(); - const bool GROUPLOCKED = m_pWindow->getGroupHead()->m_sGroupData.locked || g_pKeybindManager->m_bGroupsLocked; const auto* const PCOLACTIVE = GROUPLOCKED ? GROUPCOLACTIVELOCKED : GROUPCOLACTIVE; const auto* const PCOLINACTIVE = GROUPLOCKED ? GROUPCOLINACTIVELOCKED : GROUPCOLINACTIVE; CHyprColor color = m_dwGroupMembers[WINDOWINDEX].lock() == g_pCompositor->m_pLastWindow.lock() ? PCOLACTIVE->m_vColors[0] : PCOLINACTIVE->m_vColors[0]; color.a *= a; - CRectPassElement::SRectData rectdata; - rectdata.color = color; - rectdata.box = rect; - if (*PROUNDING) { - if (*PROUNDONLYEDGES) { - static constexpr double PADDING = 20; - if (i == 0 && barsToDraw == 1) + if (!rect.empty()) { + CRectPassElement::SRectData rectdata; + rectdata.color = color; + rectdata.box = rect; + if (*PROUNDING) { + if (*PROUNDONLYEDGES) { + static constexpr double PADDING = 20; + + if (i == 0 && barsToDraw == 1) + rectdata.round = *PROUNDING; + else if (i == 0) { + double first = rect.w - (*PROUNDING * 2); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PROUNDING * 2; + rectdata.round = 0; + rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); + rectdata.round = *PROUNDING; + rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else rectdata.round = *PROUNDING; - else if (i == 0) { - double first = rect.w - (*PROUNDING * 2); - rectdata.round = *PROUNDING; - rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); - rectdata.round = 0; - rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } else if (i == barsToDraw - 1) { - double first = *PROUNDING * 2; - rectdata.round = 0; - rectdata.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); - rectdata.round = *PROUNDING; - rectdata.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } - } else - rectdata.round = *PROUNDING; + } + g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); } - g_pHyprRenderer->m_sRenderPass.add(makeShared(rectdata)); rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}; rect.scale(pMonitor->scale); - if (*PGRADIENTS) { - const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : - (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); - if (GRADIENTTEX->m_iTexID) { - CTexPassElement::SRenderData data; - data.tex = GRADIENTTEX; - data.box = rect; - if (*PGRADIENTROUNDING) { - if (*PGRADIENTROUNDINGONLYEDGES) { - static constexpr double PADDING = 20; + if (!rect.empty()) { + if (*PGRADIENTS) { + const auto GRADIENTTEX = (m_dwGroupMembers[WINDOWINDEX] == g_pCompositor->m_pLastWindow ? (GROUPLOCKED ? m_tGradientLockedActive : m_tGradientActive) : + (GROUPLOCKED ? m_tGradientLockedInactive : m_tGradientInactive)); + if (GRADIENTTEX->m_iTexID) { + CTexPassElement::SRenderData data; + data.tex = GRADIENTTEX; + data.box = rect; + if (*PGRADIENTROUNDING) { + if (*PGRADIENTROUNDINGONLYEDGES) { + static constexpr double PADDING = 20; - if (i == 0 && barsToDraw == 1) + if (i == 0 && barsToDraw == 1) + data.round = *PGRADIENTROUNDING; + else if (i == 0) { + double first = rect.w - (*PGRADIENTROUNDING * 2); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = 0; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } else if (i == barsToDraw - 1) { + double first = *PGRADIENTROUNDING * 2; + data.round = 0; + data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); + data.round = *PGRADIENTROUNDING; + data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; + } + } else data.round = *PGRADIENTROUNDING; - else if (i == 0) { - double first = rect.w - (*PGRADIENTROUNDING * 2); - data.round = *PGRADIENTROUNDING; - data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - data.round = 0; - data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } else if (i == barsToDraw - 1) { - double first = *PGRADIENTROUNDING * 2; - data.round = 0; - data.clipBox = CBox{rect.pos() - Vector2D{PADDING, 0.F}, Vector2D{first + PADDING, rect.h}}; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - data.round = *PGRADIENTROUNDING; - data.clipBox = CBox{rect.pos() + Vector2D{first, 0.F}, Vector2D{rect.w - first + PADDING, rect.h}}; - } - } else - rectdata.round = *PGRADIENTROUNDING; + } + g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } + } + + if (*PRENDERTITLES) { + CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); + + if (!pTitleTex) + pTitleTex = + m_sTitleTexs.titleTexs + .emplace_back(makeUnique(m_dwGroupMembers[WINDOWINDEX].lock(), + Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) + .get(); + rect.y += std::ceil((rect.height - pTitleTex->texSize.y) / 2.0); + rect.height = pTitleTex->texSize.y; + rect.width = pTitleTex->texSize.x; + rect.x += std::round(((m_fBarWidth * pMonitor->scale) / 2.0) - (pTitleTex->texSize.x / 2.0)); + rect.round(); + + CTexPassElement::SRenderData data; + data.tex = pTitleTex->tex; + data.box = rect; g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); } } - if (*PRENDERTITLES) { - CTitleTex* pTitleTex = textureFromTitle(m_dwGroupMembers[WINDOWINDEX]->m_szTitle); - - if (!pTitleTex) - pTitleTex = - m_sTitleTexs.titleTexs - .emplace_back(makeUnique(m_dwGroupMembers[WINDOWINDEX].lock(), - Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2L * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) - .get(); - rect.y += std::ceil((rect.height - pTitleTex->texSize.y) / 2.0); - rect.height = pTitleTex->texSize.y; - rect.width = pTitleTex->texSize.x; - rect.x += std::round((m_fBarWidth * pMonitor->scale) / 2.0 - (pTitleTex->texSize.x / 2.0)); - rect.round(); - - CTexPassElement::SRenderData data; - data.tex = pTitleTex->tex; - data.box = rect; - g_pHyprRenderer->m_sRenderPass.add(makeShared(data)); - } - if (*PSTACKED) yoff += ONEBARHEIGHT; else From e1179b665b307e46a57367493a85ac80f34f2ce4 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 10 Feb 2025 20:11:35 +0200 Subject: [PATCH 0064/1257] flake.lock: update --- flake.lock | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/flake.lock b/flake.lock index 7637a2c7..38f48983 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1738456976, - "narHash": "sha256-cufyHbOMnSt9V4w4OVSzNcpJ+8DwzRZRJaca2Q89KVI=", + "lastModified": 1739103745, + "narHash": "sha256-c53dcRaw0F4Os9WD05HwIRs9kTDZw4Mxe1XK4edEALo=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "257b2050790ab3b1eb389e0f8bdc400eb9510139", + "rev": "a3dda0d10ce9aa1d1dfb7a6c139ea8c2872c74bd", "type": "github" }, "original": { @@ -79,11 +79,11 @@ ] }, "locked": { - "lastModified": 1738178255, - "narHash": "sha256-+D6Nu2ewXbMTFzx/Q4jDOo+LAOUPr0cxQJg5k33daIE=", + "lastModified": 1738664950, + "narHash": "sha256-xIeGNM+iivwVHkv9tHwOqoUP5dDrtees34bbFKKMZYs=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "dcadd3398abe146d60c67e0d9ee6e27b301cae82", + "rev": "7c6d165e1eb9045a996551eb9f121b6d1b30adc3", "type": "github" }, "original": { @@ -105,11 +105,11 @@ ] }, "locked": { - "lastModified": 1738437059, - "narHash": "sha256-J+8ecqaP3zD9GHeN8Y4hUapoELSoggp0IZI8laTFt/0=", + "lastModified": 1739049071, + "narHash": "sha256-3+7TpXMrbsUXSwgr5VAKAnmkzMb6JO+Rvc9XRb5NMg4=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "5ac80e3686a4dfa55d2bd15c81a266b89594a295", + "rev": "175c6b29b6ff82100539e7c4363a35a02c74dd73", "type": "github" }, "original": { @@ -189,11 +189,11 @@ ] }, "locked": { - "lastModified": 1737981711, - "narHash": "sha256-lh6cL5D8nPplB3WovCQjLUZ7k7MViiBrMlpkfm4R7/c=", + "lastModified": 1739048983, + "narHash": "sha256-REhTcXq4qs3B3cCDtLlYDz0GZvmsBSh947Ub6pQWGTQ=", "owner": "hyprwm", "repo": "hyprland-qtutils", - "rev": "96bf0677fa9cd13508294e3d4559dfbbc8beff73", + "rev": "3504a293c8f8db4127cb0f7cfc1a318ffb4316f8", "type": "github" }, "original": { @@ -215,11 +215,11 @@ ] }, "locked": { - "lastModified": 1737634606, - "narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=", + "lastModified": 1739048914, + "narHash": "sha256-vd5rJBTmp2w7SDgfv23Zcd84ktI5eDA7e5UBzx+pKrU=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "f41271d35cc0f370d300413d756c2677f386af9d", + "rev": "a7334904d591f38757c46fbe2ab68651877d9099", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1737978343, - "narHash": "sha256-TfFS0HCEJh63Kahrkp1h9hVDMdLU8a37Zz+IFucxyfA=", + "lastModified": 1739048933, + "narHash": "sha256-ck6MaoYvISBQKqZR+HcxXnx0wOhyCauxfVMaV5zhJxQ=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "6a8bc9d2a4451df12f5179dc0b1d2d46518a90ab", + "rev": "e4e018a2ca6f5a9c33511973454199e1c7c85499", "type": "github" }, "original": { @@ -261,11 +261,11 @@ ] }, "locked": { - "lastModified": 1735493474, - "narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=", + "lastModified": 1739049028, + "narHash": "sha256-RleJp7LYbr6s+M1xgbmhtBs+fYa3ZdIiF7+QalJ4D1g=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b", + "rev": "04146df74a8d5ec0b579657307be01f1e241125f", "type": "github" }, "original": { @@ -276,11 +276,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1738410390, - "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", + "lastModified": 1739020877, + "narHash": "sha256-mIvECo/NNdJJ/bXjNqIh8yeoSjVLAuDuTUzAo7dzs8Y=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "3a228057f5b619feb3186e986dbe76278d707b6e", + "rev": "a79cfe0ebd24952b580b1cf08cd906354996d547", "type": "github" }, "original": { From f2d43e5f2180adb81b3b7b51a7d0f39dace70b05 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Mon, 10 Feb 2025 20:17:29 +0200 Subject: [PATCH 0065/1257] nix/overlays: add wayland-protocols overlay --- nix/overlays.nix | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/nix/overlays.nix b/nix/overlays.nix index b632d0b4..c5dd1bee 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -28,6 +28,7 @@ in { inputs.hyprlang.overlays.default inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default + self.overlays.wayland-protocols-bump self.overlays.udis86 # Hyprland packages themselves @@ -89,4 +90,17 @@ in { patches = []; }); }; + + # Temporary bump until https://nixpk.gs/pr-tracker.html?pr=367753 is merged. + # Expect to build the universe. + wayland-protocols-bump = final: prev: { + wayland-protocols = prev.wayland-protocols.overrideAttrs (self: super: { + version = "1.40"; + + src = prev.fetchurl { + url = "https://gitlab.freedesktop.org/wayland/${super.pname}/-/releases/${self.version}/downloads/${super.pname}-${self.version}.tar.xz"; + hash = "sha256-shcReTJHwsQnY5FDkt+p/LnjcoyktKoRCtuNkV/ABok="; + }; + }); + }; } From f83fe9986b34c53c67b113a015d54fe8c084e9bd Mon Sep 17 00:00:00 2001 From: "J. J. Ramsey" Date: Tue, 11 Feb 2025 09:58:43 -0500 Subject: [PATCH 0066/1257] protocols: add version 2 of ext-idle-notify-v1 protocol (#8959) Signed-off-by: James Ramsey Co-authored-by: James Ramsey --- protocols/meson.build | 2 +- src/managers/ProtocolManager.cpp | 2 +- src/protocols/IdleNotify.cpp | 26 ++++++++++++++++++-------- src/protocols/IdleNotify.hpp | 9 ++++++--- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/protocols/meson.build b/protocols/meson.build index 7c57470b..f0a6a7e6 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,6 +1,6 @@ wayland_protos = dependency( 'wayland-protocols', - version: '>=1.32', + version: '>=1.40', fallback: 'wayland-protocols', default_options: ['tests=false'], ) diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 6cd3a608..6474d661 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -147,7 +147,7 @@ CProtocolManager::CProtocolManager() { PROTO::constraints = makeUnique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = makeUnique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::activation = makeUnique(&xdg_activation_v1_interface, 1, "XDGActivation"); - PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 1, "IdleNotify"); + PROTO::idle = makeUnique(&ext_idle_notifier_v1_interface, 2, "IdleNotify"); PROTO::lockNotify = makeUnique(&hyprland_lock_notifier_v1_interface, 1, "IdleNotify"); PROTO::sessionLock = makeUnique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); PROTO::ime = makeUnique(&zwp_input_method_manager_v2_interface, 1, "IMEv2"); diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp index bc5aabb1..14a5f3e1 100644 --- a/src/protocols/IdleNotify.cpp +++ b/src/protocols/IdleNotify.cpp @@ -10,7 +10,8 @@ static int onTimer(SP self, void* data) { return 0; } -CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_) : resource(resource_), timeoutMs(timeoutMs_) { +CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_, bool obeyInhibitors_) : + resource(resource_), timeoutMs(timeoutMs_), obeyInhibitors(obeyInhibitors_) { if UNLIKELY (!resource_->resource()) return; @@ -35,7 +36,7 @@ bool CExtIdleNotification::good() { } void CExtIdleNotification::updateTimer() { - if (PROTO::idle->isInhibited) + if (PROTO::idle->isInhibited && obeyInhibitors) timer->updateTimeout(std::nullopt); else timer->updateTimeout(std::chrono::milliseconds(timeoutMs)); @@ -54,6 +55,10 @@ void CExtIdleNotification::onActivity() { updateTimer(); } +bool CExtIdleNotification::inhibitorsAreObeyed() const { + return obeyInhibitors; +} + CIdleNotifyProtocol::CIdleNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -63,7 +68,10 @@ void CIdleNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ve RESOURCE->setOnDestroy([this](CExtIdleNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); }); RESOURCE->setDestroy([this](CExtIdleNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); - RESOURCE->setGetIdleNotification([this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat); }); + RESOURCE->setGetIdleNotification( + [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, true); }); + RESOURCE->setGetInputIdleNotification( + [this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat, false); }); } void CIdleNotifyProtocol::onManagerResourceDestroy(wl_resource* res) { @@ -74,9 +82,10 @@ void CIdleNotifyProtocol::destroyNotification(CExtIdleNotification* notif) { std::erase_if(m_vNotifications, [&](const auto& other) { return other.get() == notif; }); } -void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { - const auto CLIENT = pMgr->client(); - const auto RESOURCE = m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout)).get(); +void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat, bool obeyInhibitors) { + const auto CLIENT = pMgr->client(); + const auto RESOURCE = + m_vNotifications.emplace_back(makeShared(makeShared(CLIENT, pMgr->version(), id), timeout, obeyInhibitors)).get(); if UNLIKELY (!RESOURCE->good()) { pMgr->noMemory(); @@ -94,6 +103,7 @@ void CIdleNotifyProtocol::onActivity() { void CIdleNotifyProtocol::setInhibit(bool inhibited) { isInhibited = inhibited; for (auto const& n : m_vNotifications) { - n->onActivity(); + if (n->inhibitorsAreObeyed()) + n->onActivity(); } -} \ No newline at end of file +} diff --git a/src/protocols/IdleNotify.hpp b/src/protocols/IdleNotify.hpp index e3dcdc98..efc3accc 100644 --- a/src/protocols/IdleNotify.hpp +++ b/src/protocols/IdleNotify.hpp @@ -9,19 +9,22 @@ class CEventLoopTimer; class CExtIdleNotification { public: - CExtIdleNotification(SP resource_, uint32_t timeoutMs); + CExtIdleNotification(SP resource_, uint32_t timeoutMs, bool obeyInhibitors); ~CExtIdleNotification(); bool good(); void onTimerFired(); void onActivity(); + bool inhibitorsAreObeyed() const; + private: SP resource; uint32_t timeoutMs = 0; SP timer; - bool idled = false; + bool idled = false; + bool obeyInhibitors = false; void updateTimer(); }; @@ -38,7 +41,7 @@ class CIdleNotifyProtocol : public IWaylandProtocol { private: void onManagerResourceDestroy(wl_resource* res); void destroyNotification(CExtIdleNotification* notif); - void onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat); + void onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat, bool obeyInhibitors); bool isInhibited = false; From 68bb3e7f0a1d528a8b2da1f92d2005889587561d Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 12 Feb 2025 08:54:42 -0500 Subject: [PATCH 0067/1257] env: move XDG_SESSION_TYPE to before backend init (#9390) --- src/Compositor.cpp | 1 - src/main.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 88a2530b..6d9e8d7e 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -386,7 +386,6 @@ void CCompositor::initServer(std::string socketName, int socketFd) { } setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1); - setenv("XDG_SESSION_TYPE", "wayland", 1); if (!getenv("XDG_CURRENT_DESKTOP")) { setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1); m_bDesktopEnvSet = true; diff --git a/src/main.cpp b/src/main.cpp index 464ed978..397d7463 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ int main(int argc, char** argv) { setenv("HYPRLAND_CMD", cmd.c_str(), 1); setenv("XDG_BACKEND", "wayland", 1); + setenv("XDG_SESSION_TYPE", "wayland", 1); setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); setenv("MOZ_ENABLE_WAYLAND", "1", 1); From 17894051634716ab80c6502abdbb90ae2bc68f25 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:06:36 +0000 Subject: [PATCH 0068/1257] session-lock: send locked when in unsafe state (#9399) --- src/managers/SessionLockManager.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index 996860a1..40611199 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -89,6 +89,13 @@ void CSessionLockManager::onNewSessionLock(SP pLock) { g_pCompositor->focusSurface(nullptr); g_pSeatManager->setGrab(nullptr); + + // Normally the locked event is sent after each output rendered a lock screen frame. + // When there are no outputs, send it right away. + if (g_pCompositor->m_bUnsafeState) { + m_pSessionLock->lock->sendLocked(); + m_pSessionLock->m_hasSentLocked = true; + } } bool CSessionLockManager::isSessionLocked() { @@ -131,8 +138,7 @@ void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) { if (!m_pSessionLock || m_pSessionLock->m_hasSentLocked) return; m_pSessionLock->m_lockedMonitors.emplace(id); - const auto MONITORS = g_pCompositor->m_vMonitors; - const bool LOCKED = std::all_of(MONITORS.begin(), MONITORS.end(), [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); + const bool LOCKED = std::ranges::all_of(g_pCompositor->m_vMonitors, [this](auto m) { return m_pSessionLock->m_lockedMonitors.contains(m->ID); }); if (LOCKED && m_pSessionLock->lock->good()) { m_pSessionLock->lock->sendLocked(); m_pSessionLock->m_hasSentLocked = true; From 208f94fe12a30474d6805262524da3da492a0990 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:08:03 +0000 Subject: [PATCH 0069/1257] animations: sync inactive/active border angles when using borderangle animations (#9401) --- src/render/decorations/CHyprBorderDecoration.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 5f2fdbda..0df3acde 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -63,6 +63,11 @@ void CHyprBorderDecoration::draw(PHLMONITOR pMonitor, float const& a) { if (m_pWindow->m_fBorderAngleAnimationProgress->enabled()) { grad.m_fAngle += m_pWindow->m_fBorderAngleAnimationProgress->value() * M_PI * 2; grad.m_fAngle = normalizeAngleRad(grad.m_fAngle); + + // When borderangle is animated, it is counterintuitive to fade between inactive/active gradient angles. + // Instead we sync the angles to avoid fading between them and additionally rotating the border angle. + if (ANIMATED) + m_pWindow->m_cRealBorderColorPrevious.m_fAngle = grad.m_fAngle; } int borderSize = m_pWindow->getRealBorderSize(); From 5d2b00829484684b619a8c0de6b1d2b1d18d31a9 Mon Sep 17 00:00:00 2001 From: Anthony Ruhier Date: Thu, 13 Feb 2025 12:09:25 +0100 Subject: [PATCH 0070/1257] renderer: disable explicit if aquamarine output doesn't support it (#9396) (#9398) The explicit settings ignore the aquamarine output.supportsExplicit attribute, which creates glitches on drivers not supporting explicit sync (example: freedreno). If the output has been set as not supporting explicit, disable the explicit settings. --- src/helpers/Monitor.cpp | 2 +- src/render/Renderer.cpp | 14 +++++++++++--- src/render/Renderer.hpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e4843211..fead5db9 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1312,7 +1312,7 @@ bool CMonitor::attemptDirectScanout() { return false; } - auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(); + auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings(output); // wait for the explicit fence if present, and if kms explicit is allowed bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6f0bbe44..531ceb33 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1557,7 +1557,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { } } - auto explicitOptions = getExplicitSyncSettings(); + auto explicitOptions = getExplicitSyncSettings(pMonitor->output); if (!explicitOptions.explicitEnabled) return ok; @@ -2293,7 +2293,7 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - auto explicitOptions = getExplicitSyncSettings(); + auto explicitOptions = getExplicitSyncSettings(PMONITOR->output); if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { auto sync = g_pHyprOpenGL->createEGLSync({}); @@ -2336,7 +2336,7 @@ bool CHyprRenderer::isNvidia() { return m_bNvidia; } -SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { +SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings(SP output) { static auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); static auto PENABLEEXPLICITKMS = CConfigValue("render:explicit_sync_kms"); @@ -2344,6 +2344,14 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { settings.explicitEnabled = *PENABLEEXPLICIT; settings.explicitKMSEnabled = *PENABLEEXPLICITKMS; + if (!output->supportsExplicit) { + Debug::log(LOG, "Renderer: the aquamarine output does not support explicit, explicit settings are disabled."); + settings.explicitEnabled = false; + settings.explicitKMSEnabled = false; + + return settings; + } + if (*PENABLEEXPLICIT == 2 /* auto */) settings.explicitEnabled = true; if (*PENABLEEXPLICITKMS == 2 /* auto */) { diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index e64d41c1..731ed926 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -75,7 +75,7 @@ class CHyprRenderer { bool isNvidia(); void makeEGLCurrent(); void unsetEGL(); - SExplicitSyncSettings getExplicitSyncSettings(); + SExplicitSyncSettings getExplicitSyncSettings(SP output); void addWindowToRenderUnfocused(PHLWINDOW window); void makeWindowSnapshot(PHLWINDOW); void makeRawWindowSnapshot(PHLWINDOW, CFramebuffer*); From 40adb3dfb4b6f8cf0c5093f095954e3ef162a8eb Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Thu, 13 Feb 2025 11:37:59 +0000 Subject: [PATCH 0071/1257] config: actually set initial beziers (#9400) --- src/config/ConfigManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f87a5e6b..43abcb1f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -885,9 +885,9 @@ void CConfigManager::setDefaultAnimationVars() { m_AnimationTree.createNode("specialWorkspaceOut", "specialWorkspace"); // init the root nodes - m_AnimationTree.setConfigForNode("global", 1, 8.f, "", "default"); - m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "", "linear"); - m_AnimationTree.setConfigForNode("borderangle", 0, 0.f, "", "default"); + m_AnimationTree.setConfigForNode("global", 1, 8.f, "default"); + m_AnimationTree.setConfigForNode("__internal_fadeCTM", 1, 5.f, "linear"); + m_AnimationTree.setConfigForNode("borderangle", 0, 1, "default"); } std::optional CConfigManager::resetHLConfig() { From df3fba157279de53c582344b59699a21ac5d62b5 Mon Sep 17 00:00:00 2001 From: Honkazel <169346573+Honkazel@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:31:03 +0500 Subject: [PATCH 0072/1257] internal: remove unused variable (#9402) --- src/helpers/MiscFunctions.cpp | 91 ----------------------------------- 1 file changed, 91 deletions(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index f532617c..9e398fd9 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -49,97 +49,6 @@ using namespace Hyprutils::OS; #endif #endif -static const float transforms[][9] = { - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - 1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - -1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - 1.0f, - 0.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 1.0f, - 0.0f, - 0.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, - { - 0.0f, - -1.0f, - 0.0f, - -1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - 1.0f, - }, -}; - std::string absolutePath(const std::string& rawpath, const std::string& currentPath) { auto value = rawpath; From fb36815b0146d7b494cd648be0dfaa67a14d164a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Feb 2025 22:51:36 +0000 Subject: [PATCH 0073/1257] renderer: remove spammy log --- src/render/Renderer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 531ceb33..b61f1c3e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -2345,7 +2345,6 @@ SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings(SPsupportsExplicit) { - Debug::log(LOG, "Renderer: the aquamarine output does not support explicit, explicit settings are disabled."); settings.explicitEnabled = false; settings.explicitKMSEnabled = false; From 1309b59f2cb5179a4c59c111c35c7feede535eb6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Feb 2025 00:18:43 +0000 Subject: [PATCH 0074/1257] monitor: report a scheduled frame when tearing on cursor move --- src/helpers/Monitor.cpp | 18 ++++++++++++++++++ src/helpers/Monitor.hpp | 1 + src/managers/PointerManager.cpp | 10 +++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index fead5db9..24db3ea4 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -1441,6 +1441,24 @@ void CMonitor::onMonitorFrame() { g_pHyprRenderer->renderMonitor(self.lock()); } +void CMonitor::onCursorMovedOnMonitor() { + if (!tearingState.activelyTearing || !solitaryClient || !g_pHyprRenderer->shouldRenderCursor()) + return; + + // submit a frame immediately. This will only update the cursor pos. + // output->state->setBuffer(output->state->state().buffer); + // output->state->addDamage(CRegion{}); + // output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE); + // if (!output->commit()) + // Debug::log(ERR, "onCursorMovedOnMonitor: tearing and wanted to update cursor, failed."); + + // FIXME: try to do the above. We currently can't just render because drm is a fucking bitch + // and throws a "nO pRoP cAn Be ChAnGeD dUrInG AsYnC fLiP" on crtc_x + // this will throw too but fix it if we use sw cursors + + tearingState.frameScheduledWhileBusy = true; +} + CMonitorState::CMonitorState(CMonitor* owner) : m_pOwner(owner) { ; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index c67bccc5..690b8c4a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -186,6 +186,7 @@ class CMonitor { void scheduleDone(); bool attemptDirectScanout(); void setCTM(const Mat3x3& ctm); + void onCursorMovedOnMonitor(); void debugLastPresentation(const std::string& message); void onMonitorFrame(); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 1c8e9976..24f2b35d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -17,6 +17,9 @@ #include #include #include +#include + +using namespace Hyprutils::Utils; CPointerManager::CPointerManager() { hooks.monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any data) { @@ -310,7 +313,12 @@ void CPointerManager::onCursorMoved() { recalc = true; } - if (state->hardwareFailed || !state->entered) + if (!state->entered) + continue; + + CScopeGuard x([m] { m->onCursorMovedOnMonitor(); }); + + if (state->hardwareFailed) continue; const auto CURSORPOS = getCursorPosForMonitor(m); From 2f967037aa00c4aecce62222e5e21c1790148eb0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Feb 2025 00:21:50 +0000 Subject: [PATCH 0075/1257] config: set no_hw_cursors to auto by default and disable on tearing when tearing, updates to the overlay plane may be ignored by the kernel. To avoid the cursor being a slideshow, disable hw cursors --- src/config/ConfigDescriptions.hpp | 2 +- src/config/ConfigManager.cpp | 5 +++-- src/config/ConfigManager.hpp | 2 +- src/managers/PointerManager.cpp | 5 +++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 8d1b73c4..23635760 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1356,7 +1356,7 @@ inline static const std::vector CONFIG_OPTIONS = { }, SConfigOptionDescription{ .value = "cursor:no_hardware_cursors", - .description = "disables hardware cursors", + .description = "disables hardware cursors. Auto = disable when tearing", .type = CONFIG_OPTION_CHOICE, .data = SConfigOptionDescription::SChoiceData{0, "Disabled,Enabled,Auto"}, }, diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 43abcb1f..00dba200 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -621,7 +621,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); - m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{0}); @@ -2798,12 +2798,13 @@ const std::vector& CConfigManager::getAllDescriptions( return CONFIG_OPTIONS; } -bool CConfigManager::shouldUseSoftwareCursors() { +bool CConfigManager::shouldUseSoftwareCursors(PHLMONITOR pMonitor) { static auto PNOHW = CConfigValue("cursor:no_hardware_cursors"); switch (*PNOHW) { case 0: return false; case 1: return true; + case 2: return pMonitor->tearingState.activelyTearing; default: break; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index f0696882..b914a3a3 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -189,7 +189,7 @@ class CConfigManager { void ensureMonitorStatus(); void ensureVRR(PHLMONITOR pMonitor = nullptr); - bool shouldUseSoftwareCursors(); + bool shouldUseSoftwareCursors(PHLMONITOR pMonitor); void updateWatcher(); std::string parseKeyword(const std::string&, const std::string&); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 24f2b35d..048719b8 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -274,7 +274,7 @@ void CPointerManager::updateCursorBackend() { continue; } - if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors() || !attemptHardwareCursor(state)) { + if (state->softwareLocks > 0 || g_pConfigManager->shouldUseSoftwareCursors(m) || !attemptHardwareCursor(state)) { Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName); state->box = getCursorBoxLogicalForMonitor(state->monitor.lock()); state->hardwareFailed = true; @@ -737,7 +737,8 @@ void CPointerManager::damageIfSoftware() { if (mw->monitor.expired() || !mw->monitor->output) continue; - if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors()) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { + if ((mw->softwareLocks > 0 || mw->hardwareFailed || g_pConfigManager->shouldUseSoftwareCursors(mw->monitor.lock())) && + b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { g_pHyprRenderer->damageBox(b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } From 3eb6cb1875bd2f0850d19b1ad1b554c61b06bcec Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Sat, 15 Feb 2025 14:48:52 +0100 Subject: [PATCH 0076/1257] syncobj: ensure we only add waiters on succesful checks (#9412) timeline check only returns nullopt on ETIME_ERR , meaning the if check later on returns true if drmSyncobjTimelineWait returns anything else like EINVAL/EPERM/EACCESS etc, so actually check the returned .value() of the std::optional. also move the fd to rvalue references. --- src/protocols/DRMSyncobj.cpp | 4 ++-- src/protocols/DRMSyncobj.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp index 23dafbca..38aab305 100644 --- a/src/protocols/DRMSyncobj.cpp +++ b/src/protocols/DRMSyncobj.cpp @@ -75,7 +75,7 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SPlockPendingState(); @@ -104,7 +104,7 @@ bool CDRMSyncobjSurfaceResource::good() { return resource->resource(); } -CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor fd_) : fd(std::move(fd_)), resource(resource_) { +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, CFileDescriptor&& fd_) : fd(std::move(fd_)), resource(resource_) { if UNLIKELY (!good()) return; diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp index 8677576f..9895dff1 100644 --- a/src/protocols/DRMSyncobj.hpp +++ b/src/protocols/DRMSyncobj.hpp @@ -33,7 +33,7 @@ class CDRMSyncobjSurfaceResource { class CDRMSyncobjTimelineResource { public: - CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor fd_); + CDRMSyncobjTimelineResource(SP resource_, Hyprutils::OS::CFileDescriptor&& fd_); ~CDRMSyncobjTimelineResource() = default; static SP fromResource(wl_resource*); From 7a6fde8414ae200759ac41569f189ac5e1ba0fbb Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 15 Feb 2025 08:51:17 -0500 Subject: [PATCH 0077/1257] internal: redirect exec'd app output to /dev/null (#9411) --- src/managers/KeybindManager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 8daa6838..4bfd1454 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -967,6 +967,14 @@ uint64_t CKeybindManager::spawnRawProc(std::string args, PHLWORKSPACE pInitialWo setenv(e.first.c_str(), e.second.c_str(), 1); } setenv("WAYLAND_DISPLAY", g_pCompositor->m_szWLDisplaySocket.c_str(), 1); + + int devnull = open("/dev/null", O_WRONLY | O_CLOEXEC); + if (devnull != -1) { + dup2(devnull, STDOUT_FILENO); + dup2(devnull, STDERR_FILENO); + close(devnull); + } + execl("/bin/sh", "/bin/sh", "-c", args.c_str(), nullptr); // exit grandchild _exit(0); From 410da2e46fc44d93196cd902a070391a416cff01 Mon Sep 17 00:00:00 2001 From: Roberto Previdi Date: Sat, 15 Feb 2025 15:01:52 +0100 Subject: [PATCH 0078/1257] workspaces: update persistence on workspace rename (#9368) --- src/Compositor.cpp | 51 ++++++++++++++++++++++++++------------- src/Compositor.hpp | 2 +- src/debug/HyprCtl.cpp | 14 ++++++----- src/desktop/Workspace.cpp | 6 +++++ 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6d9e8d7e..5389844f 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -3043,34 +3043,53 @@ bool CCompositor::shouldChangePreferredImageDescription() { return false; } -void CCompositor::ensurePersistentWorkspacesPresent(const std::vector& rules) { +void CCompositor::ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace) { + for (const auto& rule : rules) { if (!rule.isPersistent) continue; + PHLWORKSPACE PWORKSPACE = nullptr; + if (pWorkspace) { + if (pWorkspace->matchesStaticSelector(rule.workspaceString)) + PWORKSPACE = pWorkspace; + else + continue; + } + const auto PMONITOR = getMonitorFromString(rule.monitor); + if (!PWORKSPACE) { + WORKSPACEID id = rule.workspaceId; + std::string wsname = rule.workspaceName; + + if (id == WORKSPACE_INVALID) { + const auto R = getWorkspaceIDNameFromString(rule.workspaceString); + id = R.id; + wsname = R.name; + } + + if (id == WORKSPACE_INVALID) { + Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); + continue; + } + PWORKSPACE = getWorkspaceByID(id); + if (!PWORKSPACE) + createNewWorkspace(id, PMONITOR ? PMONITOR : m_pLastMonitor.lock(), wsname, false); + } + + if (PWORKSPACE) + PWORKSPACE->m_bPersistent = true; + if (!PMONITOR) { Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve monitor for {}, skipping", rule.monitor); continue; } - WORKSPACEID id = rule.workspaceId; - std::string wsname = rule.workspaceName; - if (id == WORKSPACE_INVALID) { - const auto R = getWorkspaceIDNameFromString(rule.workspaceString); - id = R.id; - wsname = R.name; - } - - if (id == WORKSPACE_INVALID) { - Debug::log(ERR, "ensurePersistentWorkspacesPresent: couldn't resolve id for workspace {}", rule.workspaceString); - continue; - } - - if (const auto PWORKSPACE = getWorkspaceByID(id); PWORKSPACE) { + if (PWORKSPACE) { if (PWORKSPACE->m_pMonitor == PMONITOR) { Debug::log(LOG, "ensurePersistentWorkspacesPresent: workspace persistent {} already on {}", rule.workspaceString, PMONITOR->szName); + continue; } @@ -3078,8 +3097,6 @@ void CCompositor::ensurePersistentWorkspacesPresent(const std::vector pSurface, wl_output_transform transform); void updateSuspendedStates(); void onNewMonitor(SP output); - void ensurePersistentWorkspacesPresent(const std::vector& rules); + void ensurePersistentWorkspacesPresent(const std::vector& rules, PHLWORKSPACE pWorkspace = nullptr); SImageDescription getPreferredImageDescription(); bool shouldChangePreferredImageDescription(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index cd6451e2..a155474d 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -319,15 +319,17 @@ std::string CHyprCtl::getWorkspaceData(PHLWORKSPACE w, eHyprCtlOutputFormat form "windows": {}, "hasfullscreen": {}, "lastwindow": "0x{:x}", - "lastwindowtitle": "{}" + "lastwindowtitle": "{}", + "ispersistent": {} }})#", w->m_iID, escapeJSONStrings(w->m_szName), escapeJSONStrings(PMONITOR ? PMONITOR->szName : "?"), - escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), ((int)w->m_bHasFullscreenWindow == 1 ? "true" : "false"), - (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : ""); + escapeJSONStrings(PMONITOR ? std::to_string(PMONITOR->ID) : "null"), w->getWindows(), w->m_bHasFullscreenWindow ? "true" : "false", + (uintptr_t)PLASTW.get(), PLASTW ? escapeJSONStrings(PLASTW->m_szTitle) : "", w->m_bPersistent ? "true" : "false"); } else { - return std::format("workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\n", w->m_iID, - w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, - (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : ""); + return std::format( + "workspace ID {} ({}) on monitor {}:\n\tmonitorID: {}\n\twindows: {}\n\thasfullscreen: {}\n\tlastwindow: 0x{:x}\n\tlastwindowtitle: {}\n\tispersistent: {}\n\n", + w->m_iID, w->m_szName, PMONITOR ? PMONITOR->szName : "?", PMONITOR ? std::to_string(PMONITOR->ID) : "null", w->getWindows(), (int)w->m_bHasFullscreenWindow, + (uintptr_t)PLASTW.get(), PLASTW ? PLASTW->m_szTitle : "", (int)w->m_bPersistent); } } diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index f2c22195..322c4e33 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -648,6 +648,12 @@ void CWorkspace::rename(const std::string& name) { Debug::log(LOG, "CWorkspace::rename: Renaming workspace {} to '{}'", m_iID, name); m_szName = name; + const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(m_pSelf.lock()); + m_bPersistent = WORKSPACERULE.isPersistent; + + if (WORKSPACERULE.isPersistent) + g_pCompositor->ensurePersistentWorkspacesPresent(std::vector{WORKSPACERULE}, m_pSelf.lock()); + g_pEventManager->postEvent({"renameworkspace", std::to_string(m_iID) + "," + m_szName}); } From 9228116c9aa682477aae1a52d2d7d023bb075352 Mon Sep 17 00:00:00 2001 From: nyx Date: Sat, 15 Feb 2025 14:03:37 -0500 Subject: [PATCH 0079/1257] xwayland: fix a possible clipboard race condition (#9394) --- src/xwayland/XDataSource.cpp | 15 ++++--- src/xwayland/XWM.cpp | 85 ++++++++++++++++++++++++++++-------- src/xwayland/XWM.hpp | 2 +- 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/xwayland/XDataSource.cpp b/src/xwayland/XDataSource.cpp index 9384db69..003f6c9f 100644 --- a/src/xwayland/XDataSource.cpp +++ b/src/xwayland/XDataSource.cpp @@ -71,19 +71,20 @@ void CXDataSource::send(const std::string& mime, CFileDescriptor fd) { Debug::log(LOG, "[XDataSource] send with mime {} to fd {}", mime, fd.get()); - selection.transfer = makeUnique(selection); - selection.transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); - const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; - xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, selection.transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, - XCB_WINDOW_CLASS_INPUT_OUTPUT, g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK); + auto transfer = makeUnique(selection); + transfer->incomingWindow = xcb_generate_id(g_pXWayland->pWM->connection); + const uint32_t MASK = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_create_window(g_pXWayland->pWM->connection, XCB_COPY_FROM_PARENT, transfer->incomingWindow, g_pXWayland->pWM->screen->root, 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, + g_pXWayland->pWM->screen->root_visual, XCB_CW_EVENT_MASK, &MASK); - xcb_convert_selection(g_pXWayland->pWM->connection, selection.transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME); + xcb_convert_selection(g_pXWayland->pWM->connection, transfer->incomingWindow, HYPRATOMS["CLIPBOARD"], mimeAtom, HYPRATOMS["_WL_SELECTION"], XCB_TIME_CURRENT_TIME); xcb_flush(g_pXWayland->pWM->connection); //TODO: make CFileDescriptor setflags take SETFL aswell fcntl(fd.get(), F_SETFL, O_WRONLY | O_NONBLOCK); - selection.transfer->wlFD = std::move(fd); + transfer->wlFD = std::move(fd); + selection.transfers.emplace_back(std::move(transfer)); } void CXDataSource::accepted(const std::string& mime) { diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 68552dd6..f2a9b794 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -571,9 +571,10 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { SXSelection* sel = getSelection(e->selection); if (e->property == XCB_ATOM_NONE) { - if (sel->transfer) { + auto it = std::ranges::find_if(sel->transfers, [](const auto& t) { return !t->propertyReply; }); + if (it != sel->transfers.end()) { Debug::log(TRACE, "[xwm] converting selection failed"); - sel->transfer.reset(); + sel->transfers.erase(it); } } else if (e->target == HYPRATOMS["TARGETS"] && sel == &clipboard) { if (!focusedSurface) { @@ -582,7 +583,7 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { } setClipboardToWayland(*sel); - } else if (sel->transfer) + } else if (!sel->transfers.empty()) getTransferData(*sel); } @@ -1177,17 +1178,50 @@ static int writeDataSource(int fd, uint32_t mask, void* data) { void CXWM::getTransferData(SXSelection& sel) { Debug::log(LOG, "[xwm] getTransferData"); - sel.transfer->getIncomingSelectionProp(true); - - if (sel.transfer->propertyReply->type == HYPRATOMS["INCR"]) { - Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - sel.transfer.reset(); + auto it = std::ranges::find_if(sel.transfers, [](const auto& t) { return !t->propertyReply; }); + if (it == sel.transfers.end()) { + Debug::log(ERR, "[xwm] No pending transfer found"); return; - } else { - sel.onWrite(); - if (sel.transfer) - sel.transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, sel.transfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } + + auto& transfer = *it; + if (!transfer || !transfer->incomingWindow) { + Debug::log(ERR, "[xwm] Invalid transfer state"); + sel.transfers.erase(it); + return; + } + + if (!transfer->getIncomingSelectionProp(true)) { + Debug::log(ERR, "[xwm] Failed to get property data"); + sel.transfers.erase(it); + return; + } + + if (!transfer->propertyReply) { + Debug::log(ERR, "[xwm] No property reply"); + sel.transfers.erase(it); + return; + } + + if (transfer->propertyReply->type == HYPRATOMS["INCR"]) { + Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); + sel.transfers.erase(it); + return; + } + + const size_t pos = std::distance(sel.transfers.begin(), it); + sel.onWrite(); + + if (pos >= sel.transfers.size()) + return; + + auto newIt = sel.transfers.begin() + pos; + if (newIt == sel.transfers.end() || !(*newIt)) + return; + + auto& updatedTransfer = *newIt; + if (updatedTransfer->eventSource && updatedTransfer->wlFD.get() != -1) + updatedTransfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, updatedTransfer->wlFD.get(), WL_EVENT_WRITABLE, ::writeDataSource, &sel); } void CXWM::setCursor(unsigned char* pixData, uint32_t stride, const Vector2D& size, const Vector2D& hotspot) { @@ -1290,16 +1324,21 @@ void SXSelection::onKeyboardFocus() { } int SXSelection::onRead(int fd, uint32_t mask) { - // TODO: support INCR + auto it = std::ranges::find_if(transfers, [fd](const auto& t) { return t->wlFD.get() == fd; }); + if (it == transfers.end()) { + Debug::log(ERR, "[xwm] No transfer found for fd {}", fd); + return 0; + } - size_t pre = transfer->data.size(); + auto& transfer = *it; + size_t pre = transfer->data.size(); transfer->data.resize(INCR_CHUNK_SIZE + pre); auto len = read(fd, transfer->data.data() + pre, INCR_CHUNK_SIZE - 1); if (len < 0) { Debug::log(ERR, "[xwm] readDataSource died"); g_pXWayland->pWM->selectionSendNotify(&transfer->request, false); - transfer.reset(); + transfers.erase(it); return 0; } @@ -1311,7 +1350,7 @@ int SXSelection::onRead(int fd, uint32_t mask) { transfer->data.size(), transfer->data.data()); xcb_flush(g_pXWayland->pWM->connection); g_pXWayland->pWM->selectionSendNotify(&transfer->request, true); - transfer.reset(); + transfers.erase(it); } else Debug::log(LOG, "[xwm] Received {} bytes, waiting...", len); @@ -1346,7 +1385,7 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { mime = *MIMES.begin(); } - transfer = makeUnique(*this); + auto transfer = makeUnique(*this); transfer->request = *e; int p[2]; @@ -1368,18 +1407,26 @@ bool SXSelection::sendData(xcb_selection_request_event_t* e, std::string mime) { selection->send(mime, CFileDescriptor{p[1]}); transfer->eventSource = wl_event_loop_add_fd(g_pCompositor->m_sWLEventLoop, transfer->wlFD.get(), WL_EVENT_READABLE, ::readDataSource, this); + transfers.emplace_back(std::move(transfer)); return true; } int SXSelection::onWrite() { + auto it = std::ranges::find_if(transfers, [](const auto& t) { return t->propertyReply; }); + if (it == transfers.end()) { + Debug::log(ERR, "[xwm] No transfer with property data found"); + return 0; + } + + auto& transfer = *it; char* property = (char*)xcb_get_property_value(transfer->propertyReply); int remainder = xcb_get_property_value_length(transfer->propertyReply) - transfer->propertyStart; ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { Debug::log(ERR, "[xwm] write died in transfer get"); - transfer.reset(); + transfers.erase(it); return 0; } @@ -1388,7 +1435,7 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - transfer.reset(); + transfers.erase(it); } return 1; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 73a02a86..f6dcee54 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -58,7 +58,7 @@ struct SXSelection { CHyprSignalListener keyboardFocusChange; } listeners; - UP transfer; + std::vector> transfers; }; class CXCBConnection { From 94a30889a78fa7c7f87fe8134c18357855824c35 Mon Sep 17 00:00:00 2001 From: andrewandreii <63286820+andrewandreii@users.noreply.github.com> Date: Sat, 15 Feb 2025 21:04:02 +0200 Subject: [PATCH 0080/1257] keybinds: fix some errors not returning a failure (#9416) --- src/managers/KeybindManager.cpp | 65 ++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 4bfd1454..4e63e6dc 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1723,7 +1723,7 @@ SDispatchResult CKeybindManager::changeGroupActive(std::string args) { // index starts from '1'; '0' means last window const int INDEX = std::stoi(args); if (INDEX > PWINDOW->getGroupSize()) - return {}; + return {.success = false, .error = "Index too big, there aren't that many windows in this group"}; if (INDEX == 0) PWINDOW->setGroupCurrent(PWINDOW->getGroupTail()); else @@ -1986,7 +1986,7 @@ SDispatchResult CKeybindManager::moveCurrentWorkspaceToMonitor(std::string args) SDispatchResult CKeybindManager::moveWorkspaceToMonitor(std::string args) { if (!args.contains(' ')) - return {}; + return {.success = false, .error = "Invalid arguments, expected: workspace monitor"}; std::string workspace = args.substr(0, args.find_first_of(' ')); std::string monitor = args.substr(args.find_first_of(' ') + 1); @@ -2129,13 +2129,16 @@ SDispatchResult CKeybindManager::forceRendererReload(std::string args) { SDispatchResult CKeybindManager::resizeActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Window is fullscreen"}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) - return {}; + return {.success = false, .error = "Invalid size provided"}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PLASTWINDOW->m_vRealSize->goal()); @@ -2148,8 +2151,11 @@ SDispatchResult CKeybindManager::resizeActive(std::string args) { SDispatchResult CKeybindManager::moveActive(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || PLASTWINDOW->isFullscreen()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (PLASTWINDOW->isFullscreen()) + return {.success = false, .error = "Window is fullscreen"}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(args, PLASTWINDOW->m_vRealPosition->goal()); @@ -2171,7 +2177,7 @@ SDispatchResult CKeybindManager::moveWindow(std::string args) { } if (PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window is fullscreen"}; const auto POS = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealPosition->goal()); @@ -2193,12 +2199,12 @@ SDispatchResult CKeybindManager::resizeWindow(std::string args) { } if (PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window is fullscreen"}; const auto SIZ = g_pCompositor->parseWindowVectorArgsRelative(MOVECMD, PWINDOW->m_vRealSize->goal()); if (SIZ.x < 1 || SIZ.y < 1) - return {}; + return {.success = false, .error = "Invalid size provided"}; g_pLayoutManager->getCurrentLayout()->resizeActiveWindow(SIZ - PWINDOW->m_vRealSize->goal(), CORNER_NONE, PWINDOW); @@ -2244,7 +2250,7 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { const auto PWINDOW = g_pCompositor->getWindowByRegex(regexp); if (!PWINDOW) - return {}; + return {.success = false, .error = "No such window found"}; Debug::log(LOG, "Focusing to window name: {}", PWINDOW->m_szTitle); @@ -2304,7 +2310,7 @@ SDispatchResult CKeybindManager::tagWindow(std::string args) { else if (vars.size() == 2) PWINDOW = g_pCompositor->getWindowByRegex(vars[1]); else - return {}; + return {.success = false, .error = "Invalid number of arguments, expected 1 or 2 arguments"}; if (PWINDOW && PWINDOW->m_tags.applyTag(vars[0])) { PWINDOW->updateDynamicRules(); @@ -2674,7 +2680,10 @@ SDispatchResult CKeybindManager::swapActiveWorkspaces(std::string args) { const auto PMON1 = g_pCompositor->getMonitorFromString(MON1); const auto PMON2 = g_pCompositor->getMonitorFromString(MON2); - if (!PMON1 || !PMON2 || PMON1 == PMON2) + if (!PMON1 || !PMON2) + return {.success = false, .error = "No such monitor found"}; + + if (PMON1 == PMON2) return {}; g_pCompositor->swapActiveWorkspaces(PMON1, PMON2); @@ -2697,7 +2706,7 @@ SDispatchResult CKeybindManager::pinActive(std::string args) { } if (!PWINDOW->m_bIsFloating || PWINDOW->isFullscreen()) - return {}; + return {.success = false, .error = "Window does not qualify to be pinned"}; PWINDOW->m_bPinned = !PWINDOW->m_bPinned; @@ -2825,8 +2834,11 @@ SDispatchResult CKeybindManager::lockGroups(std::string args) { SDispatchResult CKeybindManager::lockActiveGroup(std::string args) { const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Not a group"}; const auto PHEAD = PWINDOW->getGroupHead(); @@ -2947,7 +2959,7 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { static auto PIGNOREGROUPLOCK = CConfigValue("binds:ignore_group_lock"); if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) - return {}; + return {.success = false, .error = "Groups locked"}; PHLWINDOW PWINDOW = nullptr; @@ -2956,8 +2968,11 @@ SDispatchResult CKeybindManager::moveOutOfGroup(std::string args) { else PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || !PWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Window not in a group"}; moveWindowOutOfGroup(PWINDOW); @@ -2975,7 +2990,10 @@ SDispatchResult CKeybindManager::moveWindowOrGroup(std::string args) { } const auto PWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PWINDOW || PWINDOW->isFullscreen()) + if (!PWINDOW) + return {.success = false, .error = "No window found"}; + + if (PWINDOW->isFullscreen()) return {}; if (!*PIGNOREGROUPLOCK && g_pKeybindManager->m_bGroupsLocked) { @@ -3064,8 +3082,11 @@ SDispatchResult CKeybindManager::moveGroupWindow(std::string args) { const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - if (!PLASTWINDOW || !PLASTWINDOW->m_sGroupData.pNextWindow.lock()) - return {}; + if (!PLASTWINDOW) + return {.success = false, .error = "No window found"}; + + if (!PLASTWINDOW->m_sGroupData.pNextWindow.lock()) + return {.success = false, .error = "Window not in a group"}; if ((!BACK && PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head) || (BACK && PLASTWINDOW->m_sGroupData.head)) { std::swap(PLASTWINDOW->m_sGroupData.head, PLASTWINDOW->m_sGroupData.pNextWindow->m_sGroupData.head); From 897ee276dc0a8a6b11a8102b225a9e969faac0bf Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Sun, 16 Feb 2025 00:20:42 +0000 Subject: [PATCH 0081/1257] xwayland: configure on a configure request and cleanup geometry conversion (#9375) * xwayland: configure the window on a configure request * xwayland: move coordinate conversion handling to their own functions * xwayland: rename configure to configureRequest --- src/desktop/Window.cpp | 120 ++++++++++++++++++++++++-------------- src/desktop/Window.hpp | 9 ++- src/xwayland/XSurface.hpp | 4 +- src/xwayland/XWM.cpp | 9 +-- src/xwayland/XWM.hpp | 2 +- 5 files changed, 91 insertions(+), 53 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7c0cb741..7b7f954d 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -95,15 +95,15 @@ CWindow::CWindow(SP resource) : m_pXDGSurface(resource) { CWindow::CWindow(SP surface) : m_pXWaylandSurface(surface) { m_pWLSurface = CWLSurface::create(); - listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); - listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); - listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); - listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); - listeners.configure = m_pXWaylandSurface->events.configure.registerListener([this](std::any d) { onX11Configure(std::any_cast(d)); }); - listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); - listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); - listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); - listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); }); + listeners.map = m_pXWaylandSurface->events.map.registerListener([this](std::any d) { Events::listener_mapWindow(this, nullptr); }); + listeners.unmap = m_pXWaylandSurface->events.unmap.registerListener([this](std::any d) { Events::listener_unmapWindow(this, nullptr); }); + listeners.destroy = m_pXWaylandSurface->events.destroy.registerListener([this](std::any d) { Events::listener_destroyWindow(this, nullptr); }); + listeners.commit = m_pXWaylandSurface->events.commit.registerListener([this](std::any d) { Events::listener_commitWindow(this, nullptr); }); + listeners.configureRequest = m_pXWaylandSurface->events.configureRequest.registerListener([this](std::any d) { onX11ConfigureRequest(std::any_cast(d)); }); + listeners.updateState = m_pXWaylandSurface->events.stateChanged.registerListener([this](std::any d) { onUpdateState(); }); + listeners.updateMetadata = m_pXWaylandSurface->events.metadataChanged.registerListener([this](std::any d) { onUpdateMeta(); }); + listeners.resourceChange = m_pXWaylandSurface->events.resourceChange.registerListener([this](std::any d) { onResourceChangeX11(); }); + listeners.activate = m_pXWaylandSurface->events.activate.registerListener([this](std::any d) { Events::listener_activateX11(this, nullptr); }); if (m_pXWaylandSurface->overrideRedirect) listeners.setGeometry = m_pXWaylandSurface->events.setGeometry.registerListener([this](std::any d) { Events::listener_unmanagedSetGeometry(this, nullptr); }); @@ -1530,14 +1530,14 @@ void CWindow::onResourceChangeX11() { Debug::log(LOG, "xwayland window {:x} -> association to {:x}", (uintptr_t)m_pXWaylandSurface.get(), (uintptr_t)m_pWLSurface->resource().get()); } -void CWindow::onX11Configure(CBox box) { +void CWindow::onX11ConfigureRequest(CBox box) { if (!m_pXWaylandSurface->surface || !m_pXWaylandSurface->mapped || !m_bIsMapped) { m_pXWaylandSurface->configure(box); m_vPendingReportedSize = box.size(); m_vReportedSize = box.size(); - if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) - m_fX11SurfaceScaledBy = PMONITOR->scale; + m_vReportedPosition = box.pos(); + updateX11SurfaceScale(); return; } @@ -1555,25 +1555,20 @@ void CWindow::onX11Configure(CBox box) { else setHidden(true); - const auto LOGICALPOS = g_pXWaylandManager->xwaylandToWaylandCoords(box.pos()); - - m_vRealPosition->setValueAndWarp(LOGICALPOS); - m_vRealSize->setValueAndWarp(box.size()); - - static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - if (*PXWLFORCESCALEZERO) { - if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) { - m_vRealSize->setValueAndWarp(m_vRealSize->goal() / PMONITOR->scale); - m_fX11SurfaceScaledBy = PMONITOR->scale; - } - } + m_vRealPosition->setValueAndWarp(xwaylandPositionToReal(box.pos())); + m_vRealSize->setValueAndWarp(xwaylandSizeToReal(box.size())); m_vPosition = m_vRealPosition->goal(); m_vSize = m_vRealSize->goal(); - m_vPendingReportedSize = box.size(); - m_vReportedSize = box.size(); + if (m_vPendingReportedSize != box.size() || m_vReportedPosition != box.pos()) { + m_pXWaylandSurface->configure(box); + m_vReportedSize = box.size(); + m_vPendingReportedSize = box.size(); + m_vReportedPosition = box.pos(); + } + updateX11SurfaceScale(); updateWindowDecos(); if (!m_pWorkspace || !m_pWorkspace->isVisible()) @@ -1700,37 +1695,74 @@ Vector2D CWindow::requestedMaxSize() { return maxSize; } -void CWindow::sendWindowSize(bool force) { +Vector2D CWindow::realToReportSize() { + if (!m_bIsX11) + return m_vRealSize->goal().clamp(Vector2D{0, 0}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - const auto PMONITOR = m_pMonitor.lock(); + + const auto REPORTSIZE = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto PMONITOR = m_pMonitor.lock(); + + if (*PXWLFORCESCALEZERO && PMONITOR) + return REPORTSIZE * PMONITOR->scale; + + return REPORTSIZE; +} + +Vector2D CWindow::realToReportPosition() { + if (!m_bIsX11) + return m_vRealPosition->goal(); + + return g_pXWaylandManager->waylandToXWaylandCoords(m_vRealPosition->goal()); +} + +Vector2D CWindow::xwaylandSizeToReal(Vector2D size) { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + const auto PMONITOR = m_pMonitor.lock(); + const auto SIZE = size.clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto SCALE = *PXWLFORCESCALEZERO ? PMONITOR->scale : 1.0f; + + return SIZE / SCALE; +} + +Vector2D CWindow::xwaylandPositionToReal(Vector2D pos) { + return g_pXWaylandManager->xwaylandToWaylandCoords(pos); +} + +void CWindow::updateX11SurfaceScale() { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + m_fX11SurfaceScaledBy = 1.0f; + if (m_bIsX11 && *PXWLFORCESCALEZERO) { + if (const auto PMONITOR = m_pMonitor.lock(); PMONITOR) + m_fX11SurfaceScaledBy = PMONITOR->scale; + } +} + +void CWindow::sendWindowSize(bool force) { + const auto PMONITOR = m_pMonitor.lock(); Debug::log(TRACE, "sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {})", (uintptr_t)this, this->m_szTitle, m_vRealPosition->goal(), m_vRealSize->goal(), force); // TODO: this should be decoupled from setWindowSize IMO - Vector2D windowPos = m_vRealPosition->goal(); - Vector2D size = m_vRealSize->goal().clamp(Vector2D{1, 1}, Vector2D{std::numeric_limits::infinity(), std::numeric_limits::infinity()}); + const auto REPORTPOS = realToReportPosition(); - if (m_bIsX11 && PMONITOR) { - windowPos = g_pXWaylandManager->waylandToXWaylandCoords(windowPos); - if (*PXWLFORCESCALEZERO) - size *= PMONITOR->scale; - } + const auto REPORTSIZE = realToReportSize(); - if (!force && m_vPendingReportedSize == size && (windowPos == m_vReportedPosition || !m_bIsX11)) + if (!force && m_vPendingReportedSize == REPORTSIZE && (m_vReportedPosition == REPORTPOS || !m_bIsX11)) return; - m_vReportedPosition = windowPos; - m_vPendingReportedSize = size; - m_fX11SurfaceScaledBy = 1.0f; - - if (*PXWLFORCESCALEZERO && m_bIsX11 && PMONITOR) - m_fX11SurfaceScaledBy = PMONITOR->scale; + m_vReportedPosition = REPORTPOS; + m_vPendingReportedSize = REPORTSIZE; + updateX11SurfaceScale(); if (m_bIsX11 && m_pXWaylandSurface) - m_pXWaylandSurface->configure({windowPos, size}); + m_pXWaylandSurface->configure({REPORTPOS, REPORTSIZE}); else if (m_pXDGSurface && m_pXDGSurface->toplevel) - m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(size), size.floor()); + m_vPendingSizeAcks.emplace_back(m_pXDGSurface->toplevel->setSize(REPORTSIZE), REPORTPOS.floor()); } NContentType::eContentType CWindow::getContentType() { diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 171a15f4..bc32bab4 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -460,7 +460,7 @@ class CWindow { void onFocusAnimUpdate(); void onUpdateState(); void onUpdateMeta(); - void onX11Configure(CBox box); + void onX11ConfigureRequest(CBox box); void onResourceChangeX11(); std::string fetchTitle(); std::string fetchClass(); @@ -471,6 +471,11 @@ class CWindow { bool isModal(); Vector2D requestedMinSize(); Vector2D requestedMaxSize(); + Vector2D realToReportSize(); + Vector2D realToReportPosition(); + Vector2D xwaylandSizeToReal(Vector2D size); + Vector2D xwaylandPositionToReal(Vector2D size); + void updateX11SurfaceScale(); void sendWindowSize(bool force = false); NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); @@ -497,7 +502,7 @@ class CWindow { CHyprSignalListener commit; CHyprSignalListener destroy; CHyprSignalListener activate; - CHyprSignalListener configure; + CHyprSignalListener configureRequest; CHyprSignalListener setGeometry; CHyprSignalListener updateState; CHyprSignalListener updateMetadata; diff --git a/src/xwayland/XSurface.hpp b/src/xwayland/XSurface.hpp index 7584354e..55e96078 100644 --- a/src/xwayland/XSurface.hpp +++ b/src/xwayland/XSurface.hpp @@ -50,7 +50,7 @@ class CXWaylandSurface { CSignal resourceChange; // associated / dissociated CSignal setGeometry; - CSignal configure; // CBox + CSignal configureRequest; // CBox CSignal map; CSignal unmap; @@ -116,4 +116,4 @@ class CXWaylandSurface { } listeners; friend class CXWM; -}; \ No newline at end of file +}; diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index f2a9b794..a4e3289b 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -59,7 +59,7 @@ void CXWM::handleDestroy(xcb_destroy_notify_event_t* e) { std::erase_if(surfaces, [XSURF](const auto& other) { return XSURF == other; }); } -void CXWM::handleConfigure(xcb_configure_request_event_t* e) { +void CXWM::handleConfigureRequest(xcb_configure_request_event_t* e) { const auto XSURF = windowForXID(e->window); if (!XSURF) @@ -70,8 +70,9 @@ void CXWM::handleConfigure(xcb_configure_request_event_t* e) { if (!(MASK & GEOMETRY)) return; - XSURF->events.configure.emit(CBox{MASK & XCB_CONFIG_WINDOW_X ? e->x : XSURF->geometry.x, MASK & XCB_CONFIG_WINDOW_Y ? e->y : XSURF->geometry.y, - MASK & XCB_CONFIG_WINDOW_WIDTH ? e->width : XSURF->geometry.width, MASK & XCB_CONFIG_WINDOW_HEIGHT ? e->height : XSURF->geometry.height}); + XSURF->events.configureRequest.emit(CBox{MASK & XCB_CONFIG_WINDOW_X ? e->x : XSURF->geometry.x, MASK & XCB_CONFIG_WINDOW_Y ? e->y : XSURF->geometry.y, + MASK & XCB_CONFIG_WINDOW_WIDTH ? e->width : XSURF->geometry.width, + MASK & XCB_CONFIG_WINDOW_HEIGHT ? e->height : XSURF->geometry.height}); } void CXWM::handleConfigureNotify(xcb_configure_notify_event_t* e) { @@ -758,7 +759,7 @@ int CXWM::onEvent(int fd, uint32_t mask) { switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) { case XCB_CREATE_NOTIFY: handleCreate((xcb_create_notify_event_t*)event); break; case XCB_DESTROY_NOTIFY: handleDestroy((xcb_destroy_notify_event_t*)event); break; - case XCB_CONFIGURE_REQUEST: handleConfigure((xcb_configure_request_event_t*)event); break; + case XCB_CONFIGURE_REQUEST: handleConfigureRequest((xcb_configure_request_event_t*)event); break; case XCB_CONFIGURE_NOTIFY: handleConfigureNotify((xcb_configure_notify_event_t*)event); break; case XCB_MAP_REQUEST: handleMapRequest((xcb_map_request_event_t*)event); break; case XCB_MAP_NOTIFY: handleMapNotify((xcb_map_notify_event_t*)event); break; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index f6dcee54..4326c77b 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -148,7 +148,7 @@ class CXWM { // event handlers void handleCreate(xcb_create_notify_event_t* e); void handleDestroy(xcb_destroy_notify_event_t* e); - void handleConfigure(xcb_configure_request_event_t* e); + void handleConfigureRequest(xcb_configure_request_event_t* e); void handleConfigureNotify(xcb_configure_notify_event_t* e); void handleMapRequest(xcb_map_request_event_t* e); void handleMapNotify(xcb_map_notify_event_t* e); From e2a9271150f9f1a2cba825f6f21bb130effc6b11 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Feb 2025 20:53:49 +0000 Subject: [PATCH 0082/1257] animations: add the gnomed animation style for windows --- src/managers/AnimationManager.cpp | 23 +++++++++++++++++++++-- src/managers/AnimationManager.hpp | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index 29f669dc..18dae2a4 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -357,6 +357,21 @@ void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, *pWindow->m_vRealPosition = posOffset; } +void CHyprAnimationManager::animationGnomed(PHLWINDOW pWindow, bool close) { + const auto GOALPOS = pWindow->m_vRealPosition->goal(); + const auto GOALSIZE = pWindow->m_vRealSize->goal(); + + if (close) { + *pWindow->m_vRealPosition = GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}; + *pWindow->m_vRealSize = Vector2D{GOALSIZE.x, 0.F}; + } else { + pWindow->m_vRealPosition->setValueAndWarp(GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}); + pWindow->m_vRealSize->setValueAndWarp(Vector2D{GOALSIZE.x, 0.F}); + *pWindow->m_vRealPosition = GOALPOS; + *pWindow->m_vRealSize = GOALSIZE; + } +} + void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (!close) { pWindow->m_vRealPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); @@ -387,7 +402,9 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos if (STYLE.starts_with("slide")) { CVarList animList2(STYLE, 0, 's'); animationSlide(pWindow, animList2[1], close); - } else { + } else if (STYLE == "gnomed" || STYLE == "gnome") + animationGnomed(pWindow, close); + else { // anim popin, fallback float minPerc = 0.f; @@ -405,6 +422,8 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos } else { if (animList[0] == "slide") animationSlide(pWindow, animList[1], close); + else if (animList[0] == "gnomed" || animList[0] == "gnome") + animationGnomed(pWindow, close); else { // anim popin, fallback @@ -425,7 +444,7 @@ void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool clos std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { - if (style.starts_with("slide")) + if (style.starts_with("slide") || style == "gnome" || style == "gnomed") return ""; else if (style.starts_with("popin")) { // try parsing diff --git a/src/managers/AnimationManager.hpp b/src/managers/AnimationManager.hpp index 067fa676..833087d7 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/AnimationManager.hpp @@ -59,6 +59,7 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { // Anim stuff void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); void animationSlide(PHLWINDOW, std::string force = "", bool close = false); + void animationGnomed(PHLWINDOW, bool close = false); }; inline UP g_pAnimationManager; From 59c615c321c45302491de3b1c003844c86aefca7 Mon Sep 17 00:00:00 2001 From: andrewandreii <63286820+andrewandreii@users.noreply.github.com> Date: Mon, 17 Feb 2025 04:03:27 +0200 Subject: [PATCH 0083/1257] input: add follow_mouse_threshold (#9392) --- src/config/ConfigDescriptions.hpp | 6 ++++++ src/config/ConfigManager.cpp | 1 + src/managers/input/InputManager.cpp | 29 ++++++++++++++++++----------- src/managers/input/InputManager.hpp | 1 + 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 23635760..1283050d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -501,6 +501,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1, 0, 3}, }, + SConfigOptionDescription{ + .value = "input:follow_mouse_threshold", + .description = "The smallest distance in logical pixels the mouse needs to travel for the window under it to get focused. Works only with follow_mouse = 1.", + .type = CONFIG_OPTION_FLOAT, + .data = SConfigOptionDescription::SFloatData{}, + }, SConfigOptionDescription{ .value = "input:focus_on_close", .description = "Controls the window focus behavior when a window is closed. When set to 0, focus will shift to the next window candidate. When set to 1, focus will shift " diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 00dba200..dc56d73f 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -539,6 +539,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("animations:first_launch_animation", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:follow_mouse", Hyprlang::INT{1}); + m_pConfig->addConfigValue("input:follow_mouse_threshold", Hyprlang::FLOAT{0}); m_pConfig->addConfigValue("input:focus_on_close", Hyprlang::INT{0}); m_pConfig->addConfigValue("input:mouse_refocus", Hyprlang::INT{1}); m_pConfig->addConfigValue("input:special_fallthrough", Hyprlang::INT{0}); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3d8c6de8..1d16f915 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -161,17 +161,23 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { if (MOUSECOORDSFLOORED == m_vLastCursorPosFloored && !refocus) return; - static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); - static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); - static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); - static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); - static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); - static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); - static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); - static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); + static auto PFOLLOWMOUSE = CConfigValue("input:follow_mouse"); + static auto PFOLLOWMOUSETHRESHOLD = CConfigValue("input:follow_mouse_threshold"); + static auto PMOUSEREFOCUS = CConfigValue("input:mouse_refocus"); + static auto PFOLLOWONDND = CConfigValue("misc:always_follow_on_dnd"); + static auto PFLOATBEHAVIOR = CConfigValue("input:float_switch_override_focus"); + static auto PMOUSEFOCUSMON = CConfigValue("misc:mouse_move_focuses_monitor"); + static auto PRESIZEONBORDER = CConfigValue("general:resize_on_border"); + static auto PRESIZECURSORICON = CConfigValue("general:hover_icon_on_border"); + static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); const auto FOLLOWMOUSE = *PFOLLOWONDND && PROTO::data->dndActive() ? 1 : *PFOLLOWMOUSE; + if (FOLLOWMOUSE == 1 && m_tmrLastCursorMovement.getSeconds() < 0.5) + m_fMousePosDelta += MOUSECOORDSFLOORED.distance(m_vLastCursorPosFloored); + else + m_fMousePosDelta = 0; + m_pFoundSurfaceToFocus.reset(); m_pFoundLSToFocus.reset(); m_pFoundWindowToFocus.reset(); @@ -513,9 +519,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) { // TODO: this looks wrong. When over a popup, it constantly is switching. // Temp fix until that's figured out. Otherwise spams windowrule lookups and other shit. - if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow) - g_pCompositor->focusWindow(pFoundWindow, foundSurface); - else + if (m_pLastMouseFocus.lock() != pFoundWindow || g_pCompositor->m_pLastWindow.lock() != pFoundWindow) { + if (m_fMousePosDelta > *PFOLLOWMOUSETHRESHOLD || refocus) + g_pCompositor->focusWindow(pFoundWindow, foundSurface); + } else g_pCompositor->focusSurface(foundSurface, pFoundWindow); } } diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 3afb1b88..7774a6db 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -255,6 +255,7 @@ class CInputManager { // used for warping back after non-mouse input Vector2D m_vLastMousePos = {}; + double m_fMousePosDelta = 0; bool m_bLastInputMouse = true; // for holding focus on buttons held From d01f9943e1d401b09fc53be3c161279ab4f2c5ba Mon Sep 17 00:00:00 2001 From: nyx Date: Mon, 17 Feb 2025 13:02:32 -0500 Subject: [PATCH 0084/1257] subsurfaces: dont try to access popup surfaces when handling subsurface updates (#9421) --- src/desktop/Popup.cpp | 7 +++++++ src/desktop/Popup.hpp | 1 + src/desktop/Subsurface.cpp | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/desktop/Popup.cpp b/src/desktop/Popup.cpp index 82767ead..912069e7 100644 --- a/src/desktop/Popup.cpp +++ b/src/desktop/Popup.cpp @@ -282,6 +282,9 @@ void CPopup::recheckTree() { } void CPopup::recheckChildrenRecursive() { + if (m_bInert || !m_pWLSurface) + return; + std::vector> cpy; std::ranges::for_each(m_vChildren, [&cpy](const auto& el) { cpy.emplace_back(el); }); for (auto const& c : cpy) { @@ -367,3 +370,7 @@ WP CPopup::at(const Vector2D& globalCoords, bool allowsInput) { return {}; } + +bool CPopup::inert() const { + return m_bInert; +} diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 0bca436c..f6ca65da 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -34,6 +34,7 @@ class CPopup { void recheckTree(); bool visible(); + bool inert() const; // will also loop over this node void breadthfirst(std::function, void*)> fn, void* data); diff --git a/src/desktop/Subsurface.cpp b/src/desktop/Subsurface.cpp index db106a09..9846764c 100644 --- a/src/desktop/Subsurface.cpp +++ b/src/desktop/Subsurface.cpp @@ -107,7 +107,7 @@ void CSubsurface::onCommit() { g_pHyprRenderer->damageSurface(m_pWLSurface->resource(), COORDS.x, COORDS.y); - if (m_pPopupParent) + if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) m_pPopupParent->recheckTree(); if (!m_pWindowParent.expired()) // I hate you firefox why are you doing this m_pWindowParent->m_pPopupHead->recheckTree(); @@ -124,7 +124,7 @@ void CSubsurface::onCommit() { // g_pHyprRenderer->damageBox(box); CBox box; - if (m_pPopupParent) + if (m_pPopupParent && !m_pPopupParent->inert() && m_pPopupParent->m_pWLSurface) box = m_pPopupParent->m_pWLSurface->getSurfaceBoxGlobal().value_or(CBox{}); else if (m_pWindowParent) box = m_pWindowParent->getWindowMainSurfaceBox(); From e59623d1d564089543cddb496fbed30fbd6ab247 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 00:33:27 +0000 Subject: [PATCH 0085/1257] hyprctl: don't return empty str if there are no global shortcuts fixes #6043 --- src/debug/HyprCtl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a155474d..174eb932 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -811,8 +811,11 @@ static std::string globalShortcutsRequest(eHyprCtlOutputFormat format, std::stri std::string ret = ""; const auto SHORTCUTS = PROTO::globalShortcuts->getAllShortcuts(); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { - for (auto const& sh : SHORTCUTS) + for (auto const& sh : SHORTCUTS) { ret += std::format("{}:{} -> {}\n", sh.appid, sh.id, sh.description); + } + if (ret.empty()) + ret = "none"; } else { ret += "["; for (auto const& sh : SHORTCUTS) { From 3352317ca827dfb2dfd222274dfaf5941c78c086 Mon Sep 17 00:00:00 2001 From: nyx Date: Tue, 18 Feb 2025 09:18:22 -0500 Subject: [PATCH 0086/1257] scripts/generateVersion.sh: convert to posix (#9433) --- scripts/generateVersion.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generateVersion.sh b/scripts/generateVersion.sh index e88cef3f..9313815d 100755 --- a/scripts/generateVersion.sh +++ b/scripts/generateVersion.sh @@ -2,8 +2,8 @@ # if the git directory doesn't exist, don't gather data to avoid overwriting, unless # the version file is missing altogether (otherwise compiling will fail) -if [[ ! -d ./.git ]]; then - if [[ -f ./src/version.h ]]; then +if [ ! -d ./.git ]; then + if [ -f ./src/version.h ]; then exit 0 fi fi From fb8eaba83f2d114fb346730e789a559ccc366887 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:10:40 +0000 Subject: [PATCH 0087/1257] core: add an ANR dialog for xdg-shell, we can ping the wm_base, and thus render an ANR dialog if an app dies for XWayland, there probably is a similar method, but I don't know about it and don't care. --- CMakeLists.txt | 2 +- src/Compositor.cpp | 5 + src/config/ConfigManager.cpp | 1 + src/desktop/Window.cpp | 10 ++ src/desktop/Window.hpp | 4 + src/managers/ANRManager.cpp | 173 +++++++++++++++++++++++++++++++++++ src/managers/ANRManager.hpp | 46 ++++++++++ src/protocols/XDGShell.cpp | 10 ++ src/protocols/XDGShell.hpp | 5 + src/render/OpenGL.cpp | 16 +++- src/render/Renderer.cpp | 6 ++ 11 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 src/managers/ANRManager.cpp create mode 100644 src/managers/ANRManager.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a98f697d..22bc7498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,7 +104,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION}) pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.5) pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.0) +pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.5.1) pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=0.1.1) string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION}) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5389844f..a35e4216 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -13,6 +13,7 @@ #include "managers/SeatManager.hpp" #include "managers/VersionKeeperManager.hpp" #include "managers/DonationNagManager.hpp" +#include "managers/ANRManager.hpp" #include "managers/eventLoop/EventLoopManager.hpp" #include #include @@ -592,6 +593,7 @@ void CCompositor::cleanup() { g_pEventLoopManager.reset(); g_pVersionKeeperMgr.reset(); g_pDonationNagManager.reset(); + g_pANRManager.reset(); g_pConfigWatcher.reset(); if (m_pAqBackend) @@ -694,6 +696,9 @@ void CCompositor::initManagers(eManagersInitStage stage) { Debug::log(LOG, "Creating the DonationNag!"); g_pDonationNagManager = makeUnique(); + Debug::log(LOG, "Creating the ANRManager!"); + g_pANRManager = makeUnique(); + Debug::log(LOG, "Starting XWayland"); g_pXWayland = makeUnique(g_pCompositor->m_bWantsXwayland); } break; diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index dc56d73f..9b547ffb 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -430,6 +430,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("misc:disable_xdg_env_checks", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:disable_hyprland_qtutils_check", Hyprlang::INT{0}); m_pConfig->addConfigValue("misc:lockdead_screen_delay", Hyprlang::INT{1000}); + m_pConfig->addConfigValue("misc:enable_anr_dialog", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:insert_after_current", Hyprlang::INT{1}); m_pConfig->addConfigValue("group:focus_removed_window", Hyprlang::INT{1}); diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 7b7f954d..7c0693bf 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -13,6 +13,7 @@ #include "../config/ConfigValue.hpp" #include "../managers/TokenManager.hpp" #include "../managers/AnimationManager.hpp" +#include "../managers/ANRManager.hpp" #include "../protocols/XDGShell.hpp" #include "../protocols/core/Compositor.hpp" #include "../protocols/ContentType.hpp" @@ -48,6 +49,7 @@ PHLWINDOW CWindow::create(SP surface) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(makeUnique(pWindow)); pWindow->addWindowDeco(makeUnique(pWindow)); @@ -71,6 +73,7 @@ PHLWINDOW CWindow::create(SP resource) { g_pAnimationManager->createAnimation(0.f, pWindow->m_fDimPercent, g_pConfigManager->getAnimationPropertyConfig("fadeDim"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingToWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeOut"), pWindow, AVARDAMAGE_ENTIRE); g_pAnimationManager->createAnimation(0.f, pWindow->m_fMovingFromWorkspaceAlpha, g_pConfigManager->getAnimationPropertyConfig("fadeIn"), pWindow, AVARDAMAGE_ENTIRE); + g_pAnimationManager->createAnimation(0.f, pWindow->m_notRespondingTint, g_pConfigManager->getAnimationPropertyConfig("fade"), pWindow, AVARDAMAGE_ENTIRE); pWindow->addWindowDeco(makeUnique(pWindow)); pWindow->addWindowDeco(makeUnique(pWindow)); @@ -1796,3 +1799,10 @@ void CWindow::deactivateGroupMembers() { break; } } + +bool CWindow::isNotResponding() { + if (!m_pXDGSurface) + return false; + + return g_pANRManager->isNotResponding(m_pXDGSurface->owner.lock()); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index bc32bab4..50b61050 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -388,6 +388,9 @@ class CWindow { // window tags CTagKeeper m_tags; + // ANR + PHLANIMVAR m_notRespondingTint; + // For the list lookup bool operator==(const CWindow& rhs) const { return m_pXDGSurface == rhs.m_pXDGSurface && m_pXWaylandSurface == rhs.m_pXWaylandSurface && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && @@ -480,6 +483,7 @@ class CWindow { NContentType::eContentType getContentType(); void setContentType(NContentType::eContentType contentType); void deactivateGroupMembers(); + bool isNotResponding(); CBox getWindowMainSurfaceBox() const { return {m_vRealPosition->value().x, m_vRealPosition->value().y, m_vRealSize->value().x, m_vRealSize->value().y}; diff --git a/src/managers/ANRManager.cpp b/src/managers/ANRManager.cpp new file mode 100644 index 00000000..e2b276ee --- /dev/null +++ b/src/managers/ANRManager.cpp @@ -0,0 +1,173 @@ +#include "ANRManager.hpp" +#include "../helpers/fs/FsUtils.hpp" +#include "../debug/Log.hpp" +#include "../macros.hpp" +#include "HookSystemManager.hpp" +#include "../Compositor.hpp" +#include "../protocols/XDGShell.hpp" +#include "./eventLoop/EventLoopManager.hpp" +#include "../config/ConfigValue.hpp" + +using namespace Hyprutils::OS; + +static constexpr auto TIMER_TIMEOUT = std::chrono::milliseconds(1500); + +CANRManager::CANRManager() { + if (!NFsUtils::executableExistsInPath("hyprland-dialog")) { + Debug::log(ERR, "hyprland-dialog missing from PATH, cannot start ANRManager"); + return; + } + + m_timer = makeShared(TIMER_TIMEOUT, [this](SP self, void* data) { onTick(); }, this); + g_pEventLoopManager->addTimer(m_timer); + + m_active = true; + + static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { + auto window = std::any_cast(data); + + if (window->m_bIsX11) + return; + + for (const auto& w : g_pCompositor->m_vWindows) { + if (w->m_bIsX11 || w == window || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner == window->m_pXDGSurface->owner) + return; + } + + m_data[window->m_pXDGSurface->owner] = makeShared(); + }); + + m_timer->updateTimeout(TIMER_TIMEOUT); +} + +void CANRManager::onTick() { + std::erase_if(m_data, [](const auto& e) { return e.first.expired(); }); + + static auto PENABLEANR = CConfigValue("misc:enable_anr_dialog"); + + if (!*PENABLEANR) { + m_timer->updateTimeout(TIMER_TIMEOUT * 10); + return; + } + + for (auto& [wmBase, data] : m_data) { + PHLWINDOW firstWindow; + int count = 0; + for (const auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner != wmBase) + continue; + + count++; + if (!firstWindow) + firstWindow = w; + } + + if (count == 0) + continue; + + if (data->missedResponses > 0) { + if (!data->isThreadRunning() && !data->dialogThreadSaidWait) { + pid_t pid = 0; + wl_client_get_credentials(wmBase->client(), &pid, nullptr, nullptr); + data->runDialog("Application Not Responding", firstWindow->m_szTitle, firstWindow->m_szClass, pid); + + for (const auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bIsX11 || !w->m_pXDGSurface) + continue; + + if (w->m_pXDGSurface->owner != wmBase) + continue; + + *w->m_notRespondingTint = 0.2F; + } + } + } else if (data->isThreadRunning()) + data->killDialog(); + + if (data->missedResponses == 0) + data->dialogThreadSaidWait = false; + + data->missedResponses++; + + wmBase->ping(); + } + + m_timer->updateTimeout(TIMER_TIMEOUT); +} + +void CANRManager::onResponse(SP wmBase) { + if (!m_data.contains(wmBase)) + return; + + auto& data = m_data.at(wmBase); + data->missedResponses = 0; + if (data->isThreadRunning()) + data->killDialog(); +} + +void CANRManager::SANRData::runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID) { + if (!dialogThreadExited) + killDialog(); + + // dangerous: might lock if the above failed!! + if (dialogThread.joinable()) + dialogThread.join(); + + dialogThreadExited = false; + dialogThreadSaidWait = false; + dialogThread = std::thread([title, appName, appClass, dialogWmPID, this]() { + SP proc = + makeShared("hyprland-dialog", + std::vector{"--title", title, "--text", + std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName, appClass), + "--buttons", "terminate;wait"}); + + dialogProc = proc; + proc->runSync(); + + dialogThreadExited = true; + + if (proc->stdOut().empty()) + return; + + if (proc->stdOut().starts_with("terminate")) + kill(dialogWmPID, SIGKILL); + if (proc->stdOut().starts_with("wait")) + dialogThreadSaidWait = true; + }); +} + +bool CANRManager::SANRData::isThreadRunning() { + if (dialogThread.native_handle() == 0) + return false; + if (dialogThreadExited) + return false; + return pthread_kill(dialogThread.native_handle(), 0) != ESRCH; +} + +void CANRManager::SANRData::killDialog() const { + if (!dialogProc) + return; + + kill(dialogProc->pid(), SIGKILL); +} + +CANRManager::SANRData::~SANRData() { + if (dialogThread.joinable()) { + killDialog(); + // dangerous: might lock if the above failed!! + dialogThread.join(); + } +} + +bool CANRManager::isNotResponding(SP wmBase) { + if (!m_data.contains(wmBase)) + return false; + return m_data[wmBase]->missedResponses > 1; +} diff --git a/src/managers/ANRManager.hpp b/src/managers/ANRManager.hpp new file mode 100644 index 00000000..7d67e872 --- /dev/null +++ b/src/managers/ANRManager.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "../helpers/memory/Memory.hpp" +#include "../desktop/DesktopTypes.hpp" +#include +#include +#include +#include +#include "./eventLoop/EventLoopTimer.hpp" +#include "../helpers/signal/Signal.hpp" +#include +#include + +class CXDGWMBase; + +class CANRManager { + public: + CANRManager(); + + void onResponse(SP wmBase); + bool isNotResponding(SP wmBase); + + private: + bool m_active = false; + SP m_timer; + + void onTick(); + + struct SANRData { + ~SANRData(); + + int missedResponses = 0; + std::thread dialogThread; + SP dialogProc; + std::atomic dialogThreadExited = false; + std::atomic dialogThreadSaidWait = false; + + void runDialog(const std::string& title, const std::string& appName, const std::string appClass, pid_t dialogWmPID); + bool isThreadRunning(); + void killDialog() const; + }; + + std::map, SP> m_data; +}; + +inline UP g_pANRManager; \ No newline at end of file diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index f5d1a8fa..9424a9d6 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -3,6 +3,7 @@ #include #include "../Compositor.hpp" #include "../managers/SeatManager.hpp" +#include "../managers/ANRManager.hpp" #include "../helpers/Monitor.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" @@ -740,6 +741,11 @@ CXDGWMBase::CXDGWMBase(SP resource_) : resource(resource_) { LOGM(LOG, "New xdg_surface at {:x}", (uintptr_t)RESOURCE.get()); }); + + resource->setPong([this](CXdgWmBase* r, uint32_t serial) { + g_pANRManager->onResponse(self.lock()); + events.pong.emit(); + }); } bool CXDGWMBase::good() { @@ -750,6 +756,10 @@ wl_client* CXDGWMBase::client() { return pClient; } +void CXDGWMBase::ping() { + resource->sendPing(1337); +} + CXDGShellProtocol::CXDGShellProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { grab = makeShared(); grab->keyboard = true; diff --git a/src/protocols/XDGShell.hpp b/src/protocols/XDGShell.hpp index 4c2b8100..b46e0236 100644 --- a/src/protocols/XDGShell.hpp +++ b/src/protocols/XDGShell.hpp @@ -241,12 +241,17 @@ class CXDGWMBase { bool good(); wl_client* client(); + void ping(); std::vector> positioners; std::vector> surfaces; WP self; + struct { + CSignal pong; + } events; + private: SP resource; wl_client* pClient = nullptr; diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 3b641c36..1a296b65 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -1396,12 +1396,18 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(SP tex, const CB glUniform1f(shader->roundingPower, roundingPower); if (allowDim && m_RenderData.currentWindow) { - glUniform1i(shader->applyTint, 1); - const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); - glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); - } else { + if (m_RenderData.currentWindow->m_notRespondingTint->value() > 0) { + const auto DIM = m_RenderData.currentWindow->m_notRespondingTint->value(); + glUniform1i(shader->applyTint, 1); + glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); + } else if (m_RenderData.currentWindow->m_fDimPercent->value() > 0) { + glUniform1i(shader->applyTint, 1); + const auto DIM = m_RenderData.currentWindow->m_fDimPercent->value(); + glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM); + } else + glUniform1i(shader->applyTint, 0); + } else glUniform1i(shader->applyTint, 0); - } } const float verts[] = { diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b61f1c3e..f01a0d12 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -473,6 +473,12 @@ void CHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, timespe if (ignorePosition) { renderdata.pos.x = pMonitor->vecPosition.x; renderdata.pos.y = pMonitor->vecPosition.y; + } else { + const bool ANR = pWindow->isNotResponding(); + if (ANR && pWindow->m_notRespondingTint->goal() != 0.2F) + *pWindow->m_notRespondingTint = 0.2F; + else if (!ANR && pWindow->m_notRespondingTint->goal() != 0.F) + *pWindow->m_notRespondingTint = 0.F; } if (standalone) From 3c1a2e9fcae6575e1f17627047c93d6e9fcc8634 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:18:34 +0000 Subject: [PATCH 0088/1257] config/descriptions: add enable_anr_dialog --- src/config/ConfigDescriptions.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 1283050d..4e591fa8 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1187,6 +1187,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_INT, .data = SConfigOptionDescription::SRangeData{1000, 0, 5000}, }, + SConfigOptionDescription{ + .value = "misc:enable_anr_dialog", + .description = "whether to enable the ANR (app not responding) dialog when your apps hang", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{true}, + }, /* * binds: From 0137a5f6cdd24d5a10f813572791f1e641221a5b Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 18 Feb 2025 15:20:00 +0000 Subject: [PATCH 0089/1257] anr: capitalize options --- src/managers/ANRManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/managers/ANRManager.cpp b/src/managers/ANRManager.cpp index e2b276ee..af1cb93a 100644 --- a/src/managers/ANRManager.cpp +++ b/src/managers/ANRManager.cpp @@ -126,7 +126,7 @@ void CANRManager::SANRData::runDialog(const std::string& title, const std::strin makeShared("hyprland-dialog", std::vector{"--title", title, "--text", std::format("Application {} with class of {} is not responding.\nWhat do you want to do with it?", appName, appClass), - "--buttons", "terminate;wait"}); + "--buttons", "Terminate;Wait"}); dialogProc = proc; proc->runSync(); @@ -136,9 +136,9 @@ void CANRManager::SANRData::runDialog(const std::string& title, const std::strin if (proc->stdOut().empty()) return; - if (proc->stdOut().starts_with("terminate")) + if (proc->stdOut().starts_with("Terminate")) kill(dialogWmPID, SIGKILL); - if (proc->stdOut().starts_with("wait")) + if (proc->stdOut().starts_with("Wait")) dialogThreadSaidWait = true; }); } From 6d25ef09cd6a33bcd589bd0f1e88e86fcff2dc67 Mon Sep 17 00:00:00 2001 From: nyx Date: Wed, 19 Feb 2025 10:29:39 -0500 Subject: [PATCH 0090/1257] xwayland: add INCR support for clipboard transfers (#9434) add INCR protocol support for large transfers fix write handling for partial transfers fix an issue where wayland windows could die from a paste from an xwayland window --- src/xwayland/XWM.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index a4e3289b..0899261a 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -589,9 +589,18 @@ void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { } bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { - // Debug::log(LOG, "[xwm] Selection property notify for {} target {}", e->atom, e->window); + if (e->state != XCB_PROPERTY_DELETE) + return false; - // Debug::log(ERR, "[xwm] FIXME: CXWM::handleSelectionPropertyNotify stub"); + auto it = std::ranges::find_if(clipboard.transfers, [e](const auto& t) { return t->incomingWindow == e->window; }); + if (it != clipboard.transfers.end()) { + if (!(*it)->getIncomingSelectionProp(true)) { + clipboard.transfers.erase(it); + return false; + } + getTransferData(clipboard); + return true; + } return false; } @@ -1205,8 +1214,10 @@ void CXWM::getTransferData(SXSelection& sel) { } if (transfer->propertyReply->type == HYPRATOMS["INCR"]) { - Debug::log(ERR, "[xwm] Transfer is INCR, which we don't support :("); - sel.transfers.erase(it); + transfer->incremental = true; + transfer->propertyStart = 0; + free(transfer->propertyReply); + transfer->propertyReply = nullptr; return; } @@ -1426,6 +1437,8 @@ int SXSelection::onWrite() { ssize_t len = write(transfer->wlFD.get(), property + transfer->propertyStart, remainder); if (len == -1) { + if (errno == EAGAIN) + return 1; Debug::log(ERR, "[xwm] write died in transfer get"); transfers.erase(it); return 0; @@ -1436,7 +1449,13 @@ int SXSelection::onWrite() { Debug::log(LOG, "[xwm] wl client read partially: len {}", len); } else { Debug::log(LOG, "[xwm] cb transfer to wl client complete, read {} bytes", len); - transfers.erase(it); + if (!transfer->incremental) { + transfers.erase(it); + } else { + free(transfer->propertyReply); + transfer->propertyReply = nullptr; + transfer->propertyStart = 0; + } } return 1; From fa246cb6ed5f486aad27c11dd46b3a26768a15d1 Mon Sep 17 00:00:00 2001 From: Mihai Fufezan Date: Thu, 20 Feb 2025 14:56:17 +0200 Subject: [PATCH 0091/1257] flake.lock: update hyprutils and aquamarine --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 38f48983..76eee761 100644 --- a/flake.lock +++ b/flake.lock @@ -16,11 +16,11 @@ ] }, "locked": { - "lastModified": 1739103745, - "narHash": "sha256-c53dcRaw0F4Os9WD05HwIRs9kTDZw4Mxe1XK4edEALo=", + "lastModified": 1739298463, + "narHash": "sha256-oAFv9jKwwA7d7384d2LeywDSgwhvb3ZnrwbfoWPhXsI=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "a3dda0d10ce9aa1d1dfb7a6c139ea8c2872c74bd", + "rev": "f239e5aadd6d23c48e085c2de3397e2058e54d16", "type": "github" }, "original": { @@ -238,11 +238,11 @@ ] }, "locked": { - "lastModified": 1739048933, - "narHash": "sha256-ck6MaoYvISBQKqZR+HcxXnx0wOhyCauxfVMaV5zhJxQ=", + "lastModified": 1739891528, + "narHash": "sha256-h8HOCZ/rw2Buzku+GKF77VXxrGjCSOQkLhptiEKMYg0=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "e4e018a2ca6f5a9c33511973454199e1c7c85499", + "rev": "61a5382f4b1ab578064d470b1b3d3f0df396b8ba", "type": "github" }, "original": { From 2cfa5d2408cd3e213aa0c87076ce9ada0dc08e20 Mon Sep 17 00:00:00 2001 From: Aaron Tulino <13600347+aaronjamt@users.noreply.github.com> Date: Fri, 21 Feb 2025 07:20:11 -0700 Subject: [PATCH 0092/1257] hyprctl: Add IPC support for Hyprsunset (#9315) * Add IPC support for Hyprsunset * clang-format * Add documentation --- hyprctl/Strings.hpp | 11 +++++++++++ hyprctl/main.cpp | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index f77626a5..c70ca737 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -22,6 +22,7 @@ commands: getoption