From b17381eb819d784146ec40d81d30a2b33a8a4e64 Mon Sep 17 00:00:00 2001 From: zakk4223 Date: Tue, 11 Jun 2024 11:00:50 -0400 Subject: [PATCH 01/51] groupbar: Don't apply monitor scale twice to groupbar text (#6411) --- src/render/decorations/CHyprGroupBarDecoration.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 731fce04..a87dba31 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -172,10 +172,10 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { .emplace_back(std::make_unique(m_dwGroupMembers[WINDOWINDEX].lock(), Vector2D{m_fBarWidth * pMonitor->scale, (*PTITLEFONTSIZE + 2 * BAR_TEXT_PAD) * pMonitor->scale}, pMonitor->scale)) .get(); - rect.y += ((rect.height - pTitleTex->textHeight) / 2.0) * pMonitor->scale; - rect.height = (pTitleTex->textHeight) * pMonitor->scale; - rect.width = pTitleTex->textWidth * pMonitor->scale; - rect.x += m_fBarWidth / 2.0 - (pTitleTex->textWidth / 2.0) * pMonitor->scale; + rect.y += (rect.height - pTitleTex->textHeight) / 2.0; + rect.height = pTitleTex->textHeight; + rect.width = pTitleTex->textWidth; + rect.x += (m_fBarWidth * pMonitor->scale) / 2.0 - (pTitleTex->textWidth / 2.0); rect.round(); g_pHyprOpenGL->renderTexture(pTitleTex->tex, &rect, 1.f); From 90d00977169e8478b5f4c27ec0a364a7ec11b0aa Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 08:01:25 -0700 Subject: [PATCH 02/51] input: fix input regions being ignored on ls-es (#6413) --- src/Compositor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5c0b8eaa..5cb7c7be 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1056,7 +1056,7 @@ SP CCompositor::vectorToLayerSurface(const Vector2D& pos, st if (ls->fadingOut || !ls->layerSurface || (ls->layerSurface && !ls->layerSurface->surface->mapped) || ls->alpha.value() == 0.f) continue; - auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos()); + auto [surf, local] = ls->layerSurface->surface->at(pos - ls->geometry.pos(), true); if (surf) { if (surf->current.input.empty()) From 809820921d9844e1bc09b843392fd7d277b83f73 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 08:11:15 -0700 Subject: [PATCH 03/51] sessionLock: fix focus not being tied to mouse (#6414) --- src/managers/input/InputManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index ff10f303..5ce53472 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -155,6 +155,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { Vector2D surfacePos = Vector2D(-1337, -1337); PHLWINDOW pFoundWindow; PHLLS pFoundLayerSurface; + SSessionLockSurface* pSessionLock = nullptr; if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState) return; @@ -261,12 +262,12 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { g_pCompositor->setActiveMonitor(PMONITOR); if (g_pSessionLockManager->isSessionLocked()) { - const auto PSLS = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; + pSessionLock = PMONITOR ? g_pSessionLockManager->getSessionLockSurfaceForMonitor(PMONITOR->ID) : nullptr; - if (!PSLS) + if (!pSessionLock) return; - foundSurface = PSLS->surface->surface(); + foundSurface = pSessionLock->surface->surface(); surfacePos = PMONITOR->vecPosition; } @@ -455,7 +456,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { restoreCursorIconToApp(); } - if (pFoundWindow) { + if (pSessionLock != nullptr) + g_pCompositor->focusSurface(foundSurface); + else if (pFoundWindow) { // change cursor icon if hovering over border if (*PRESIZEONBORDER && *PRESIZECURSORICON) { if (!pFoundWindow->m_bIsFullscreen && !pFoundWindow->hasPopupAt(mouseCoords)) { From 1f46296ea05f9a8e6020ab694b531c91a1abdfa6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Tue, 11 Jun 2024 17:12:24 +0200 Subject: [PATCH 04/51] deps: update wlroots --- subprojects/wlroots-hyprland | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/wlroots-hyprland b/subprojects/wlroots-hyprland index 91de8da4..422207db 160000 --- a/subprojects/wlroots-hyprland +++ b/subprojects/wlroots-hyprland @@ -1 +1 @@ -Subproject commit 91de8da4b6b9b3c5630123d2446cd6de4e80071a +Subproject commit 422207dbcf0949e28042403edab539159282885e From 8c64a4bad710fb18e9b84812bd680a89d1e93661 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:17:45 +0200 Subject: [PATCH 05/51] core: move to hyprutils for utils (#6385) * core: move to hyprutils for utils Nix: add hyprutils dep * Meson: add hyprutils dep * flake.lock: update --------- Co-authored-by: Mihai Fufezan --- .github/actions/setup_base/action.yml | 5 + CMakeLists.txt | 2 +- flake.lock | 45 +++- flake.nix | 7 + hyprctl/CMakeLists.txt | 4 + hyprctl/main.cpp | 8 +- hyprctl/meson.build | 3 + hyprpm/CMakeLists.txt | 4 +- hyprpm/src/core/PluginManager.cpp | 24 +- hyprpm/src/meson.build | 1 + nix/default.nix | 2 + nix/overlays.nix | 1 + src/Compositor.cpp | 5 +- src/config/ConfigDataValues.hpp | 2 +- src/config/ConfigManager.cpp | 22 +- src/config/ConfigManager.hpp | 2 +- src/debug/HyprCtl.cpp | 9 +- src/desktop/Popup.hpp | 2 +- src/desktop/Window.cpp | 5 +- src/desktop/Workspace.cpp | 5 +- src/devices/IKeyboard.cpp | 2 +- src/events/Windows.cpp | 7 +- src/helpers/MiscFunctions.cpp | 61 +---- src/helpers/MiscFunctions.hpp | 3 - src/helpers/Monitor.cpp | 5 +- src/helpers/VarList.cpp | 37 --- src/helpers/VarList.hpp | 64 ----- src/helpers/WLClasses.hpp | 2 +- src/helpers/memory/Memory.hpp | 9 + src/helpers/memory/SharedPtr.hpp | 302 ---------------------- src/helpers/memory/WeakPtr.hpp | 190 -------------- src/helpers/signal/Listener.cpp | 21 -- src/helpers/signal/Listener.hpp | 41 --- src/helpers/signal/Signal.cpp | 51 ---- src/helpers/signal/Signal.hpp | 23 +- src/helpers/varlist/VarList.hpp | 5 + src/macros.hpp | 4 +- src/managers/EventManager.hpp | 2 +- src/managers/KeybindManager.cpp | 7 +- src/managers/ProtocolManager.hpp | 4 +- src/managers/SessionLockManager.hpp | 2 +- src/managers/TokenManager.hpp | 2 +- src/managers/eventLoop/EventLoopTimer.hpp | 2 +- src/managers/input/InputManager.hpp | 2 +- src/managers/input/InputMethodPopup.hpp | 2 +- src/managers/input/InputMethodRelay.hpp | 2 +- src/managers/input/TextInput.hpp | 2 +- src/meson.build | 1 + src/plugins/HookSystem.cpp | 2 +- src/protocols/AlphaModifier.hpp | 2 +- src/protocols/FocusGrab.hpp | 2 +- src/protocols/GammaControl.hpp | 2 +- src/protocols/OutputManagement.hpp | 2 +- src/protocols/OutputPower.hpp | 2 +- src/protocols/PointerConstraints.hpp | 2 +- src/protocols/core/Output.hpp | 2 +- src/xwayland/XWM.hpp | 2 +- 57 files changed, 158 insertions(+), 873 deletions(-) delete mode 100644 src/helpers/VarList.cpp delete mode 100644 src/helpers/VarList.hpp create mode 100644 src/helpers/memory/Memory.hpp delete mode 100644 src/helpers/memory/SharedPtr.hpp delete mode 100644 src/helpers/memory/WeakPtr.hpp delete mode 100644 src/helpers/signal/Listener.cpp delete mode 100644 src/helpers/signal/Listener.hpp delete mode 100644 src/helpers/signal/Signal.cpp create mode 100644 src/helpers/varlist/VarList.hpp diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index ea3eecd3..a7b9994c 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -68,6 +68,11 @@ runs: cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --install build + - name: Get hyprutils-git + shell: bash + run: | + git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build + - name: Get Xorg pacman pkgs shell: bash if: inputs.INSTALL_XORG_PKGS == 'true' diff --git a/CMakeLists.txt b/CMakeLists.txt index 43cbb50c..7aa2bf5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET wayland-server wayland-client wayland-cursor wayland-protocols cairo pango pangocairo pixman-1 libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm - hyprlang>=0.3.2 hyprcursor>=0.1.7 + hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.1 ) find_package(hyprwayland-scanner 0.3.10 REQUIRED) diff --git a/flake.lock b/flake.lock index ab886a15..477db69b 100644 --- a/flake.lock +++ b/flake.lock @@ -53,6 +53,9 @@ }, "hyprlang": { "inputs": { + "hyprutils": [ + "hyprutils" + ], "nixpkgs": [ "nixpkgs" ], @@ -61,11 +64,11 @@ ] }, "locked": { - "lastModified": 1716473782, - "narHash": "sha256-+qLn4lsHU6iL3+HTo1gTQ1tWzet8K9h+IfVemzEQZj8=", + "lastModified": 1717881852, + "narHash": "sha256-XeeVoKHQgfKuXoP6q90sUqKyl7EYy3ol2dVZGM+Jj94=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "87d5d984109c839482b88b4795db073eb9ed446f", + "rev": "ec6938c66253429192274d612912649a0cfe4d28", "type": "github" }, "original": { @@ -74,6 +77,29 @@ "type": "github" } }, + "hyprutils": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1717881334, + "narHash": "sha256-a0inRgJhPL6v9v7RPM/rx1kbXdfe3xJA1c9z0ZkYnh4=", + "owner": "hyprwm", + "repo": "hyprutils", + "rev": "0693f9398ab693d89c9a0aa3b3d062dd61b7a60e", + "type": "github" + }, + "original": { + "owner": "hyprwm", + "repo": "hyprutils", + "type": "github" + } + }, "hyprwayland-scanner": { "inputs": { "nixpkgs": [ @@ -99,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717602782, - "narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", + "lastModified": 1717974879, + "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", + "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3", "type": "github" }, "original": { @@ -117,6 +143,7 @@ "inputs": { "hyprcursor": "hyprcursor", "hyprlang": "hyprlang", + "hyprutils": "hyprutils", "hyprwayland-scanner": "hyprwayland-scanner", "nixpkgs": "nixpkgs", "systems": "systems", @@ -152,11 +179,11 @@ ] }, "locked": { - "lastModified": 1716290197, - "narHash": "sha256-1u9Exrc7yx9qtES2brDh7/DDZ8w8ap1nboIOAtCgeuM=", + "lastModified": 1717918856, + "narHash": "sha256-I38bmPLqamvOfVSArd1hhZtkVRAYBK38fOHZCU1P9Qg=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "91e48d6acd8a5a611d26f925e51559ab743bc438", + "rev": "72907822c19afc0983c69d59d299204381623725", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 82e3e4bb..c1be8720 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,13 @@ url = "github:hyprwm/hyprlang"; inputs.nixpkgs.follows = "nixpkgs"; inputs.systems.follows = "systems"; + inputs.hyprutils.follows = "hyprutils"; + }; + + hyprutils = { + url = "github:hyprwm/hyprutils"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.systems.follows = "systems"; }; hyprwayland-scanner = { diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt index 6f70ace8..64b983e6 100644 --- a/hyprctl/CMakeLists.txt +++ b/hyprctl/CMakeLists.txt @@ -5,8 +5,12 @@ project( DESCRIPTION "Control utility for Hyprland" ) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1) + add_executable(hyprctl "main.cpp") +target_link_libraries(hyprctl PUBLIC PkgConfig::deps) + # binary install(TARGETS hyprctl) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 34abe46f..8fb9194c 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +using namespace Hyprutils::String; #include "Strings.hpp" @@ -270,12 +272,6 @@ std::deque splitArgs(int argc, char** argv) { return result; } -bool isNumber(const std::string& str, bool allowfloat) { - if (str.empty()) - return false; - return std::ranges::all_of(str.begin(), str.end(), [&](char c) { return isdigit(c) != 0 || c == '-' || (allowfloat && c == '.'); }); -} - int main(int argc, char** argv) { bool parseArgs = true; diff --git a/hyprctl/meson.build b/hyprctl/meson.build index 94e98b4b..5488845f 100644 --- a/hyprctl/meson.build +++ b/hyprctl/meson.build @@ -1,4 +1,7 @@ executable('hyprctl', 'main.cpp', + dependencies: [ + dependency('hyprutils', version: '>= 0.1.1'), + ], install: true ) diff --git a/hyprpm/CMakeLists.txt b/hyprpm/CMakeLists.txt index 8b6a8320..692e8da1 100644 --- a/hyprpm/CMakeLists.txt +++ b/hyprpm/CMakeLists.txt @@ -9,11 +9,11 @@ file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp") set(CMAKE_CXX_STANDARD 23) -pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus) +pkg_check_modules(deps REQUIRED IMPORTED_TARGET tomlplusplus hyprutils>=0.1.1) add_executable(hyprpm ${SRCFILES}) -target_link_libraries(hyprpm PUBLIC PkgConfig::tomlplusplus) +target_link_libraries(hyprpm PUBLIC PkgConfig::deps) # binary install(TARGETS hyprpm) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index fb338d25..446d6af3 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -19,24 +19,8 @@ #include -static std::string removeBeginEndSpacesTabs(std::string str) { - if (str.empty()) - return str; - - int countBefore = 0; - while (str[countBefore] == ' ' || str[countBefore] == '\t') { - countBefore++; - } - - int countAfter = 0; - while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) { - countAfter++; - } - - str = str.substr(countBefore, str.length() - countBefore - countAfter); - - return str; -} +#include +using namespace Hyprutils::String; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; @@ -374,7 +358,7 @@ eHeadersErrors CPluginManager::headersValid() { if (PATH.ends_with("protocols") || PATH.ends_with("wlroots-hyprland")) continue; - verHeader = removeBeginEndSpacesTabs(PATH.substr(2)) + "/hyprland/src/version.h"; + verHeader = trim(PATH.substr(2)) + "/hyprland/src/version.h"; break; } @@ -447,7 +431,7 @@ bool CPluginManager::updateHeaders(bool force) { // let us give a bit of leg-room for shallowing // due to timezones, etc. const std::string SHALLOW_DATE = - removeBeginEndSpacesTabs(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); + trim(HLVER.date).empty() ? "" : execAndGet("LC_TIME=\"en_US.UTF-8\" date --date='" + HLVER.date + " - 1 weeks' '+\%a \%b \%d \%H:\%M:\%S \%Y'"); if (m_bVerbose && bShallow) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "will shallow since: " + SHALLOW_DATE); diff --git a/hyprpm/src/meson.build b/hyprpm/src/meson.build index a8644169..e2c512a5 100644 --- a/hyprpm/src/meson.build +++ b/hyprpm/src/meson.build @@ -3,6 +3,7 @@ src = globber.stdout().strip().split('\n') executable('hyprpm', src, dependencies: [ + dependency('hyprutils', version: '>= 0.1.1'), dependency('threads'), dependency('tomlplusplus') ], diff --git a/nix/default.nix b/nix/default.nix index 5da00d72..0493abc1 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,6 +13,7 @@ git, hyprcursor, hyprlang, + hyprutils, hyprwayland-scanner, jq, libGL, @@ -110,6 +111,7 @@ assert lib.assertMsg (!hidpiXWayland) "The option `hidpiXWayland` has been remov git hyprcursor.dev hyprlang + hyprutils libGL libdrm libdatrie diff --git a/nix/overlays.nix b/nix/overlays.nix index fbd7e9fc..cc66e1b5 100644 --- a/nix/overlays.nix +++ b/nix/overlays.nix @@ -23,6 +23,7 @@ in { # Dependencies inputs.hyprcursor.overlays.default inputs.hyprlang.overlays.default + inputs.hyprutils.overlays.default inputs.hyprwayland-scanner.overlays.default self.overlays.xwayland diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 5cb7c7be..8b19f010 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -14,7 +14,7 @@ #include // for SdNotify #endif #include -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include "protocols/FractionalScale.hpp" #include "protocols/PointerConstraints.hpp" #include "protocols/LayerShell.hpp" @@ -24,6 +24,9 @@ #include "desktop/LayerSurface.hpp" #include "xwayland/XWayland.hpp" +#include +using namespace Hyprutils::String; + #include #include diff --git a/src/config/ConfigDataValues.hpp b/src/config/ConfigDataValues.hpp index c162bb40..322bd14a 100644 --- a/src/config/ConfigDataValues.hpp +++ b/src/config/ConfigDataValues.hpp @@ -1,6 +1,6 @@ #pragma once #include "../defines.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include enum eConfigValueDataTypes { diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e10522d9..6bb24e46 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -3,7 +3,7 @@ #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "config/ConfigDataValues.hpp" -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" #include @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,7 +21,8 @@ #include #include #include -#include +#include +using namespace Hyprutils::String; extern "C" char** environ; @@ -2087,8 +2089,8 @@ bool layerRuleValid(const std::string& RULE) { } std::optional CConfigManager::handleWindowRule(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); - const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); + const auto VALUE = trim(value.substr(value.find_first_of(',') + 1)); // check rule and value if (RULE.empty() || VALUE.empty()) @@ -2114,8 +2116,8 @@ std::optional CConfigManager::handleWindowRule(const std::string& c } std::optional CConfigManager::handleLayerRule(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); - const auto VALUE = removeBeginEndSpacesTabs(value.substr(value.find_first_of(',') + 1)); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); + const auto VALUE = trim(value.substr(value.find_first_of(',') + 1)); // check rule and value if (RULE.empty() || VALUE.empty()) @@ -2142,7 +2144,7 @@ std::optional CConfigManager::handleLayerRule(const std::string& co } std::optional CConfigManager::handleWindowRuleV2(const std::string& command, const std::string& value) { - const auto RULE = removeBeginEndSpacesTabs(value.substr(0, value.find_first_of(','))); + const auto RULE = trim(value.substr(0, value.find_first_of(','))); const auto VALUE = value.substr(value.find_first_of(',') + 1); if (!windowRuleValid(RULE) && RULE != "unset") { @@ -2219,7 +2221,7 @@ std::optional CConfigManager::handleWindowRuleV2(const std::string& result = result.substr(0, min - pos); - result = removeBeginEndSpacesTabs(result); + result = trim(result); if (!result.empty() && result.back() == ',') result.pop_back(); @@ -2341,7 +2343,7 @@ void CConfigManager::updateBlurredLS(const std::string& name, const bool forceBl std::optional CConfigManager::handleBlurLS(const std::string& command, const std::string& value) { if (value.starts_with("remove,")) { - const auto TOREMOVE = removeBeginEndSpacesTabs(value.substr(7)); + const auto TOREMOVE = trim(value.substr(7)); if (std::erase_if(m_dBlurLSNamespaces, [&](const auto& other) { return other == TOREMOVE; })) updateBlurredLS(TOREMOVE, false); return {}; @@ -2358,7 +2360,7 @@ std::optional CConfigManager::handleWorkspaceRules(const std::strin const auto FIRST_DELIM = value.find_first_of(','); std::string name = ""; - auto first_ident = removeBeginEndSpacesTabs(value.substr(0, FIRST_DELIM)); + auto first_ident = trim(value.substr(0, FIRST_DELIM)); int id = getWorkspaceIDFromString(first_ident, name); auto rules = value.substr(FIRST_DELIM + 1); diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index ca22904d..c43cb020 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -15,7 +15,7 @@ #include #include "../helpers/WLClasses.hpp" #include "../helpers/Monitor.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index bdb12e58..6f4d74b7 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -16,6 +16,9 @@ #include #include +#include +using namespace Hyprutils::String; + #include "../config/ConfigDataValues.hpp" #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" @@ -826,7 +829,7 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { std::string versionRequest(eHyprCtlOutputFormat format, std::string request) { - auto commitMsg = removeBeginEndSpacesTabs(GIT_COMMIT_MESSAGE); + auto commitMsg = trim(GIT_COMMIT_MESSAGE); std::replace(commitMsg.begin(), commitMsg.end(), '#', ' '); if (format == eHyprCtlOutputFormat::FORMAT_NORMAL) { @@ -1051,7 +1054,7 @@ std::string dispatchBatch(eHyprCtlOutputFormat format, std::string request) { request = ""; } - curitem = removeBeginEndSpacesTabs(curitem); + curitem = trim(curitem); }; nextItem(); @@ -1305,7 +1308,7 @@ std::string dispatchGetOption(eHyprCtlOutputFormat format, std::string request) request = ""; } - curitem = removeBeginEndSpacesTabs(curitem); + curitem = trim(curitem); }; nextItem(); diff --git a/src/desktop/Popup.hpp b/src/desktop/Popup.hpp index 91e569e7..47e180a8 100644 --- a/src/desktop/Popup.hpp +++ b/src/desktop/Popup.hpp @@ -3,7 +3,7 @@ #include #include #include "Subsurface.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CXDGPopupResource; diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index 5d6e32e9..b02a53e0 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -12,6 +12,9 @@ #include "../protocols/core/Compositor.hpp" #include "../xwayland/XWayland.hpp" +#include +using namespace Hyprutils::String; + PHLWINDOW CWindow::create(SP surface) { PHLWINDOW pWindow = SP(new CWindow(surface)); @@ -687,7 +690,7 @@ void CWindow::applyDynamicRule(const SWindowRule& r) { CGradientValueData activeBorderGradient = {}; CGradientValueData inactiveBorderGradient = {}; bool active = true; - CVarList colorsAndAngles = CVarList(removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true); + CVarList colorsAndAngles = CVarList(trim(r.szRule.substr(r.szRule.find_first_of(' ') + 1)), 0, 's', true); // Basic form has only two colors, everything else can be parsed as a gradient if (colorsAndAngles.size() == 2 && !colorsAndAngles[1].contains("deg")) { diff --git a/src/desktop/Workspace.cpp b/src/desktop/Workspace.cpp index 7a836b3b..ed09fbc0 100644 --- a/src/desktop/Workspace.cpp +++ b/src/desktop/Workspace.cpp @@ -2,6 +2,9 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include +using namespace Hyprutils::String; + PHLWORKSPACE CWorkspace::create(int id, int monitorID, std::string name, bool special, bool isEmtpy) { PHLWORKSPACE workspace = makeShared(id, monitorID, name, special, isEmtpy); workspace->init(workspace); @@ -219,7 +222,7 @@ std::string CWorkspace::getConfigName() { } bool CWorkspace::matchesStaticSelector(const std::string& selector_) { - auto selector = removeBeginEndSpacesTabs(selector_); + auto selector = trim(selector_); if (selector.empty()) return true; diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp index 7e4dd912..cb294d1a 100644 --- a/src/devices/IKeyboard.cpp +++ b/src/devices/IKeyboard.cpp @@ -1,6 +1,6 @@ #include "IKeyboard.hpp" #include "../defines.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../managers/input/InputManager.hpp" uint32_t IKeyboard::getCapabilities() { diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 88b28c87..899318ce 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -12,6 +12,9 @@ #include "../protocols/core/Compositor.hpp" #include "../xwayland/XSurface.hpp" +#include +using namespace Hyprutils::String; + // ------------------------------------------------------------ // // __ _______ _ _ _____ ______ _______ // // \ \ / /_ _| \ | | __ \ / __ \ \ / / ____| // @@ -140,7 +143,7 @@ void Events::listener_mapWindow(void* owner, void* data) { for (auto& r : PWINDOW->m_vMatchedRules) { if (r.szRule.starts_with("monitor")) { try { - const auto MONITORSTR = removeBeginEndSpacesTabs(r.szRule.substr(r.szRule.find(' '))); + const auto MONITORSTR = trim(r.szRule.substr(r.szRule.find(' '))); if (MONITORSTR == "unset") { PWINDOW->m_iMonitorID = PMONITOR->ID; @@ -235,7 +238,7 @@ void Events::listener_mapWindow(void* owner, void* data) { continue; // `group` is a shorthand of `group set` - if (removeBeginEndSpacesTabs(r.szRule) == "group") { + if (trim(r.szRule) == "group") { PWINDOW->m_eGroupRules |= GROUP_SET; continue; } diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 32cd9868..b1d734c8 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -13,6 +13,8 @@ #ifdef HAS_EXECINFO #include #endif +#include +using namespace Hyprutils::String; #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include @@ -195,25 +197,6 @@ std::string escapeJSONStrings(const std::string& str) { return oss.str(); } -std::string removeBeginEndSpacesTabs(std::string str) { - if (str.empty()) - return str; - - int countBefore = 0; - while (str[countBefore] == ' ' || str[countBefore] == '\t') { - countBefore++; - } - - int countAfter = 0; - while ((int)str.length() - countAfter - 1 >= 0 && (str[str.length() - countAfter - 1] == ' ' || str[str.length() - 1 - countAfter] == '\t')) { - countAfter++; - } - - str = str.substr(countBefore, str.length() - countBefore - countAfter); - - return str; -} - std::optional getPlusMinusKeywordResult(std::string source, float relative) { try { return relative + stof(source); @@ -223,31 +206,6 @@ std::optional getPlusMinusKeywordResult(std::string source, float relativ } } -bool isNumber(const std::string& str, bool allowfloat) { - - std::string copy = str; - if (*copy.begin() == '-') - copy = copy.substr(1); - - if (copy.empty()) - return false; - - bool point = !allowfloat; - for (auto& c : copy) { - if (c == '.') { - if (point) - return false; - point = true; - continue; - } - - if (!std::isdigit(c)) - return false; - } - - return true; -} - bool isDirection(const std::string& arg) { return arg == "l" || arg == "r" || arg == "u" || arg == "d" || arg == "t" || arg == "b"; } @@ -579,7 +537,7 @@ int getWorkspaceIDFromString(const std::string& in, std::string& outName) { std::optional cleanCmdForWorkspace(const std::string& inWorkspaceName, std::string dirtyCmd) { - std::string cmd = removeBeginEndSpacesTabs(dirtyCmd); + std::string cmd = trim(dirtyCmd); if (!cmd.empty()) { std::string rules; @@ -748,7 +706,7 @@ int64_t configStringToInt(const std::string& VALUE) { } else if (VALUE.starts_with("rgba(") && VALUE.ends_with(')')) { const auto VALUEWITHOUTFUNC = VALUE.substr(5, VALUE.length() - 6); - if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 8) { + if (trim(VALUEWITHOUTFUNC).length() != 8) { Debug::log(WARN, "invalid length {} for rgba", VALUEWITHOUTFUNC.length()); throw std::invalid_argument("rgba() expects length of 8 characters (4 bytes)"); } @@ -760,7 +718,7 @@ int64_t configStringToInt(const std::string& VALUE) { } else if (VALUE.starts_with("rgb(") && VALUE.ends_with(')')) { const auto VALUEWITHOUTFUNC = VALUE.substr(4, VALUE.length() - 5); - if (removeBeginEndSpacesTabs(VALUEWITHOUTFUNC).length() != 6) { + if (trim(VALUEWITHOUTFUNC).length() != 6) { Debug::log(WARN, "invalid length {} for rgb", VALUEWITHOUTFUNC.length()); throw std::invalid_argument("rgb() expects length of 6 characters (3 bytes)"); } @@ -822,15 +780,6 @@ double normalizeAngleRad(double ang) { return ang; } -std::string replaceInString(std::string subject, const std::string& search, const std::string& replace) { - size_t pos = 0; - while ((pos = subject.find(search, pos)) != std::string::npos) { - subject.replace(pos, search.length(), replace); - pos += replace.length(); - } - return subject; -} - std::vector getBacktrace() { std::vector callstack; diff --git a/src/helpers/MiscFunctions.hpp b/src/helpers/MiscFunctions.hpp index 9d34174c..feb0380b 100644 --- a/src/helpers/MiscFunctions.hpp +++ b/src/helpers/MiscFunctions.hpp @@ -17,8 +17,6 @@ std::string absolutePath(const std::string&, const std::str void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString); void removeWLSignal(wl_listener*); std::string escapeJSONStrings(const std::string& str); -std::string removeBeginEndSpacesTabs(std::string); -bool isNumber(const std::string&, bool allowfloat = false); bool isDirection(const std::string&); bool isDirection(const char&); int getWorkspaceIDFromString(const std::string&, std::string&); @@ -32,7 +30,6 @@ Vector2D configStringToVector2D(const std::string&); std::optional getPlusMinusKeywordResult(std::string in, float relative); void matrixProjection(float mat[9], int w, int h, wl_output_transform tr); double normalizeAngleRad(double ang); -std::string replaceInString(std::string subject, const std::string& search, const std::string& replace); std::vector getBacktrace(); void throwError(const std::string& err); bool envEnabled(const std::string& env); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index a30f1057..027b47bd 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -6,6 +6,8 @@ #include "../devices/ITouch.hpp" #include "../protocols/LayerShell.hpp" #include "../protocols/PresentationTime.hpp" +#include +using namespace Hyprutils::String; int ratHandler(void* data) { g_pHyprRenderer->renderMonitor((CMonitor*)data); @@ -71,8 +73,7 @@ void CMonitor::onConnect(bool noRule) { std::erase(szDescription, ','); // field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix - szShortDescription = - removeBeginEndSpacesTabs(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); + szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : "")); std::erase(szShortDescription, ','); if (!wlr_backend_is_drm(output->backend)) diff --git a/src/helpers/VarList.cpp b/src/helpers/VarList.cpp deleted file mode 100644 index 780ea9a0..00000000 --- a/src/helpers/VarList.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "MiscFunctions.hpp" -#include "VarList.hpp" -#include -#include - -CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) { - if (in.empty()) - m_vArgs.emplace_back(""); - - std::string args{in}; - size_t idx = 0; - size_t pos = 0; - std::ranges::replace_if( - args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0); - - for (const auto& s : args | std::views::split(0)) { - if (removeEmpty && s.empty()) - continue; - if (++idx == lastArgNo) { - m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos))); - break; - } - pos += s.size() + 1; - m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data())); - } -} - -std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const { - size_t last = to == 0 ? size() : to; - - std::string rolling; - for (size_t i = from; i < last; ++i) { - rolling += m_vArgs[i] + (i + 1 < last ? joiner : ""); - } - - return rolling; -} \ No newline at end of file diff --git a/src/helpers/VarList.hpp b/src/helpers/VarList.hpp deleted file mode 100644 index d70f2c3f..00000000 --- a/src/helpers/VarList.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#include -#include "../macros.hpp" - -class CVarList { - public: - /** Split string into arg list - @param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args - @param delim if delimiter is 's', use std::isspace - @param removeEmpty remove empty args from argv - */ - CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false); - - ~CVarList() = default; - - size_t size() const { - return m_vArgs.size(); - } - - std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const; - - void map(std::function func) { - for (auto& s : m_vArgs) - func(s); - } - - void append(const std::string arg) { - m_vArgs.emplace_back(arg); - } - - std::string operator[](const size_t& idx) const { - if (idx >= m_vArgs.size()) - return ""; - return m_vArgs[idx]; - } - - // for range-based loops - std::vector::iterator begin() { - return m_vArgs.begin(); - } - std::vector::const_iterator begin() const { - return m_vArgs.begin(); - } - std::vector::iterator end() { - return m_vArgs.end(); - } - std::vector::const_iterator end() const { - return m_vArgs.end(); - } - - bool contains(const std::string& el) { - for (auto& a : m_vArgs) { - if (a == el) - return true; - } - - return false; - } - - private: - std::vector m_vArgs; -}; \ No newline at end of file diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp index d5be9f40..247aa8f0 100644 --- a/src/helpers/WLClasses.hpp +++ b/src/helpers/WLClasses.hpp @@ -7,7 +7,7 @@ #include "../desktop/Popup.hpp" #include "AnimatedVariable.hpp" #include "../desktop/WLSurface.hpp" -#include "signal/Listener.hpp" +#include "signal/Signal.hpp" #include "Region.hpp" class CMonitor; diff --git a/src/helpers/memory/Memory.hpp b/src/helpers/memory/Memory.hpp new file mode 100644 index 00000000..135a84af --- /dev/null +++ b/src/helpers/memory/Memory.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +using namespace Hyprutils::Memory; + +#define SP Hyprutils::Memory::CSharedPointer +#define WP Hyprutils::Memory::CWeakPointer +#define UP std::unique_ptr diff --git a/src/helpers/memory/SharedPtr.hpp b/src/helpers/memory/SharedPtr.hpp deleted file mode 100644 index 02900911..00000000 --- a/src/helpers/memory/SharedPtr.hpp +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#define SP CSharedPointer - -/* - This is a custom impl of std::shared_ptr. - It is not thread-safe like the STL one, - but Hyprland is single-threaded anyways. - - It differs a bit from how the STL one works, - namely in the fact that it keeps the T* inside the - control block, and that you can still make a CWeakPtr - or deref an existing one inside the destructor. -*/ -namespace CSharedPointer_ { - - class impl_base { - public: - virtual ~impl_base(){}; - - virtual void inc() noexcept = 0; - virtual void dec() noexcept = 0; - virtual void incWeak() noexcept = 0; - virtual void decWeak() noexcept = 0; - virtual unsigned int ref() noexcept = 0; - virtual unsigned int wref() noexcept = 0; - virtual void destroy() noexcept = 0; - virtual bool destroying() noexcept = 0; - virtual bool dataNonNull() noexcept = 0; - }; - - template - class impl : public impl_base { - public: - impl(T* data) noexcept : _data(data) { - ; - } - - /* strong refcount */ - unsigned int _ref = 0; - /* weak refcount */ - unsigned int _weak = 0; - - T* _data = nullptr; - - friend void swap(impl*& a, impl*& b) { - impl* tmp = a; - a = b; - b = tmp; - } - - /* if the destructor was called, - creating shared_ptrs is no longer valid */ - bool _destroying = false; - - void _destroy() { - if (!_data || _destroying) - return; - - // first, we destroy the data, but keep the pointer. - // this way, weak pointers will still be able to - // reference and use, but no longer create shared ones. - _destroying = true; - __deleter(_data); - // now, we can reset the data and call it a day. - _data = nullptr; - _destroying = false; - } - - std::default_delete __deleter{}; - - // - virtual void inc() noexcept { - _ref++; - } - - virtual void dec() noexcept { - _ref--; - } - - virtual void incWeak() noexcept { - _weak++; - } - - virtual void decWeak() noexcept { - _weak--; - } - - virtual unsigned int ref() noexcept { - return _ref; - } - - virtual unsigned int wref() noexcept { - return _weak; - } - - virtual void destroy() noexcept { - _destroy(); - } - - virtual bool destroying() noexcept { - return _destroying; - } - - virtual bool dataNonNull() noexcept { - return _data; - } - - virtual ~impl() { - destroy(); - } - }; -}; - -template -class CSharedPointer { - public: - template - using validHierarchy = typename std::enable_if&, X>::value, CSharedPointer&>::type; - template - using isConstructible = typename std::enable_if::value>::type; - - /* creates a new shared pointer managing a resource - avoid calling. Could duplicate ownership. Prefer makeShared */ - explicit CSharedPointer(T* object) noexcept { - impl_ = new CSharedPointer_::impl(object); - increment(); - } - - /* creates a shared pointer from a reference */ - template > - CSharedPointer(const CSharedPointer& ref) noexcept { - impl_ = ref.impl_; - increment(); - } - - CSharedPointer(const CSharedPointer& ref) noexcept { - impl_ = ref.impl_; - increment(); - } - - template > - CSharedPointer(CSharedPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - CSharedPointer(CSharedPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - /* allows weakPointer to create from an impl */ - CSharedPointer(CSharedPointer_::impl_base* implementation) noexcept { - impl_ = implementation; - increment(); - } - - /* creates an empty shared pointer with no implementation */ - CSharedPointer() noexcept { - ; // empty - } - - /* creates an empty shared pointer with no implementation */ - CSharedPointer(std::nullptr_t) noexcept { - ; // empty - } - - ~CSharedPointer() { - // we do not decrement here, - // because we want to preserve the pointer - // in case this is the last owner. - if (impl_ && impl_->ref() == 1) - destroyImpl(); - else - decrement(); - } - - template - validHierarchy&> operator=(const CSharedPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrement(); - impl_ = rhs.impl_; - increment(); - return *this; - } - - CSharedPointer& operator=(const CSharedPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrement(); - impl_ = rhs.impl_; - increment(); - return *this; - } - - template - validHierarchy&> operator=(CSharedPointer&& rhs) { - std::swap(impl_, rhs.impl_); - return *this; - } - - CSharedPointer& operator=(CSharedPointer&& rhs) { - std::swap(impl_, rhs.impl_); - return *this; - } - - operator bool() const { - return impl_ && impl_->dataNonNull(); - } - - bool operator==(const CSharedPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const { - return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; - } - - bool operator<(const CSharedPointer& rhs) const { - return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; - } - - T* operator->() const { - return get(); - } - - T& operator*() const { - return *get(); - } - - void reset() { - decrement(); - impl_ = nullptr; - } - - T* get() const { - return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); - } - - unsigned int strongRef() const { - return impl_ ? impl_->ref() : 0; - } - - CSharedPointer_::impl_base* impl_ = nullptr; - - private: - /* - no-op if there is no impl_ - may delete the stored object if ref == 0 - may delete and reset impl_ if ref == 0 and weak == 0 - */ - void decrement() { - if (!impl_) - return; - - impl_->dec(); - - // if ref == 0, we can destroy impl - if (impl_->ref() == 0) - destroyImpl(); - } - /* no-op if there is no impl_ */ - void increment() { - if (!impl_) - return; - - impl_->inc(); - } - - /* destroy the pointed-to object - if able, will also destroy impl */ - void destroyImpl() { - // destroy the impl contents - impl_->destroy(); - - // check for weak refs, if zero, we can also delete impl_ - if (impl_->wref() == 0) { - delete impl_; - impl_ = nullptr; - } - } -}; - -template -static CSharedPointer makeShared(Args&&... args) { - return CSharedPointer(new U(std::forward(args)...)); -} - -template -struct std::hash> { - std::size_t operator()(const CSharedPointer& p) const noexcept { - return std::hash{}(p.impl_); - } -}; diff --git a/src/helpers/memory/WeakPtr.hpp b/src/helpers/memory/WeakPtr.hpp deleted file mode 100644 index 872f8e55..00000000 --- a/src/helpers/memory/WeakPtr.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#pragma once - -#include "SharedPtr.hpp" - -#define WP CWeakPointer - -/* - This is a Hyprland implementation of std::weak_ptr. - - See SharedPtr.hpp for more info on how it's different. -*/ - -template -class CWeakPointer { - public: - template - using validHierarchy = typename std::enable_if&, X>::value, CWeakPointer&>::type; - template - using isConstructible = typename std::enable_if::value>::type; - - /* create a weak ptr from a reference */ - template > - CWeakPointer(const CSharedPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - /* create a weak ptr from another weak ptr */ - template > - CWeakPointer(const CWeakPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - CWeakPointer(const CWeakPointer& ref) noexcept { - if (!ref.impl_) - return; - - impl_ = ref.impl_; - incrementWeak(); - } - - template > - CWeakPointer(CWeakPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - CWeakPointer(CWeakPointer&& ref) noexcept { - std::swap(impl_, ref.impl_); - } - - /* create a weak ptr from another weak ptr with assignment */ - template - validHierarchy&> operator=(const CWeakPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - CWeakPointer& operator=(const CWeakPointer& rhs) { - if (impl_ == rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - /* create a weak ptr from a shared ptr with assignment */ - template - validHierarchy&> operator=(const CSharedPointer& rhs) { - if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) - return *this; - - decrementWeak(); - impl_ = rhs.impl_; - incrementWeak(); - return *this; - } - - /* create an empty weak ptr */ - CWeakPointer() { - ; - } - - ~CWeakPointer() { - decrementWeak(); - } - - /* expired MAY return true even if the pointer is still stored. - the situation would be e.g. self-weak pointer in a destructor. - for pointer validity, use valid() */ - bool expired() const { - return !impl_ || !impl_->dataNonNull() || impl_->destroying(); - } - - /* this means the pointed-to object is not yet deleted and can still be - referenced, but it might be in the process of being deleted. - check !expired() if you want to check whether it's valid and - assignable to a SP. */ - bool valid() const { - return impl_ && impl_->dataNonNull(); - } - - void reset() { - decrementWeak(); - impl_ = nullptr; - } - - CSharedPointer lock() const { - if (!impl_ || !impl_->dataNonNull() || impl_->destroying()) - return {}; - - return CSharedPointer(impl_); - } - - /* this returns valid() */ - operator bool() const { - return valid(); - } - - bool operator==(const CWeakPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator==(const CSharedPointer& rhs) const { - return impl_ == rhs.impl_; - } - - bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const { - return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; - } - - bool operator<(const CWeakPointer& rhs) const { - return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; - } - - T* get() const { - return (T*)(impl_ ? static_cast*>(impl_)->_data : nullptr); - } - - T* operator->() const { - return get(); - } - - CSharedPointer_::impl_base* impl_ = nullptr; - - private: - /* no-op if there is no impl_ */ - void decrementWeak() { - if (!impl_) - return; - - impl_->decWeak(); - - // we need to check for ->destroying, - // because otherwise we could destroy here - // and have a shared_ptr destroy the same thing - // later (in situations where we have a weak_ptr to self) - if (impl_->wref() == 0 && impl_->ref() == 0 && !impl_->destroying()) { - delete impl_; - impl_ = nullptr; - } - } - /* no-op if there is no impl_ */ - void incrementWeak() { - if (!impl_) - return; - - impl_->incWeak(); - } -}; - -template -struct std::hash> { - std::size_t operator()(const CWeakPointer& p) const noexcept { - return std::hash{}(p.impl_); - } -}; diff --git a/src/helpers/signal/Listener.cpp b/src/helpers/signal/Listener.cpp deleted file mode 100644 index 4023477f..00000000 --- a/src/helpers/signal/Listener.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "Listener.hpp" -#include "Signal.hpp" - -CSignalListener::CSignalListener(std::function handler) : m_fHandler(handler) { - ; -} - -void CSignalListener::emit(std::any data) { - if (!m_fHandler) - return; - - m_fHandler(data); -} - -CStaticSignalListener::CStaticSignalListener(std::function handler, void* owner) : m_pOwner(owner), m_fHandler(handler) { - ; -} - -void CStaticSignalListener::emit(std::any data) { - m_fHandler(m_pOwner, data); -} diff --git a/src/helpers/signal/Listener.hpp b/src/helpers/signal/Listener.hpp deleted file mode 100644 index e6aa8d73..00000000 --- a/src/helpers/signal/Listener.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../../macros.hpp" - -class CSignal; - -class CSignalListener { - public: - CSignalListener(std::function handler); - - CSignalListener(CSignalListener&&) = delete; - CSignalListener(CSignalListener&) = delete; - CSignalListener(const CSignalListener&) = delete; - CSignalListener(const CSignalListener&&) = delete; - - void emit(std::any data); - - private: - std::function m_fHandler; -}; - -typedef SP CHyprSignalListener; - -class CStaticSignalListener { - public: - CStaticSignalListener(std::function handler, void* owner); - - CStaticSignalListener(CStaticSignalListener&&) = delete; - CStaticSignalListener(CStaticSignalListener&) = delete; - CStaticSignalListener(const CStaticSignalListener&) = delete; - CStaticSignalListener(const CStaticSignalListener&&) = delete; - - void emit(std::any data); - - private: - void* m_pOwner = nullptr; - std::function m_fHandler; -}; \ No newline at end of file diff --git a/src/helpers/signal/Signal.cpp b/src/helpers/signal/Signal.cpp deleted file mode 100644 index fd2d11c8..00000000 --- a/src/helpers/signal/Signal.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "Signal.hpp" -#include - -void CSignal::emit(std::any data) { - bool dirty = false; - - std::vector> listeners; - for (auto& l : m_vListeners) { - if (l.expired()) { - dirty = true; - continue; - } - - listeners.emplace_back(l.lock()); - } - - std::vector statics; - for (auto& l : m_vStaticListeners) { - statics.emplace_back(l.get()); - } - - for (auto& l : listeners) { - // if there is only one lock, it means the event is only held by the listeners - // vector and was removed during our iteration - if (l.strongRef() == 1) { - dirty = true; - continue; - } - l->emit(data); - } - - for (auto& l : statics) { - l->emit(data); - } - - // release SPs - listeners.clear(); - - if (dirty) - std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); -} - -CHyprSignalListener CSignal::registerListener(std::function handler) { - CHyprSignalListener listener = makeShared(handler); - m_vListeners.emplace_back(WP(listener)); - return listener; -} - -void CSignal::registerStaticListener(std::function handler, void* owner) { - m_vStaticListeners.emplace_back(std::make_unique(handler, owner)); -} \ No newline at end of file diff --git a/src/helpers/signal/Signal.hpp b/src/helpers/signal/Signal.hpp index 3d04f7de..9eea3671 100644 --- a/src/helpers/signal/Signal.hpp +++ b/src/helpers/signal/Signal.hpp @@ -1,24 +1,5 @@ #pragma once -#include -#include -#include -#include +#include -#include "Listener.hpp" - -class CSignal { - public: - void emit(std::any data = {}); - - // - [[nodiscard("Listener is unregistered when the ptr is lost")]] CHyprSignalListener registerListener(std::function handler); - - // this is for static listeners. They die with this signal. - // TODO: can we somehow rid of the void* data and make it a custom this? - void registerStaticListener(std::function handler, void* owner); - - private: - std::vector> m_vListeners; - std::vector> m_vStaticListeners; -}; +using namespace Hyprutils::Signal; diff --git a/src/helpers/varlist/VarList.hpp b/src/helpers/varlist/VarList.hpp new file mode 100644 index 00000000..34629e4c --- /dev/null +++ b/src/helpers/varlist/VarList.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +using namespace Hyprutils::String; diff --git a/src/macros.hpp b/src/macros.hpp index 4c6d621c..cca088d8 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -4,9 +4,7 @@ #include #include -#include "helpers/memory/WeakPtr.hpp" - -#define UP std::unique_ptr +#include "helpers/memory/Memory.hpp" #ifndef NDEBUG #ifdef HYPRLAND_DEBUG diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp index 94dbab59..383d3246 100644 --- a/src/managers/EventManager.hpp +++ b/src/managers/EventManager.hpp @@ -3,7 +3,7 @@ #include #include "../defines.hpp" -#include "../helpers/memory/SharedPtr.hpp" +#include "../helpers/memory/Memory.hpp" struct SHyprIPCEvent { std::string event; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 5811f4a1..49ea39a3 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -6,13 +6,16 @@ #include "KeybindManager.hpp" #include "TokenManager.hpp" #include "debug/Log.hpp" -#include "helpers/VarList.hpp" +#include "helpers/varlist/VarList.hpp" #include #include #include #include +#include +using namespace Hyprutils::String; + #include #include #include @@ -836,7 +839,7 @@ bool CKeybindManager::handleInternalKeybinds(xkb_keysym_t keysym) { void CKeybindManager::spawn(std::string args) { - args = removeBeginEndSpacesTabs(args); + args = trim(args); std::string RULES = ""; diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 52a54253..91fb82a0 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -5,8 +5,8 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" -#include "../helpers/memory/WeakPtr.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/memory/Memory.hpp" +#include "../helpers/signal/Signal.hpp" #include class CProtocolManager { diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index ea1b2029..fe4a4434 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -2,7 +2,7 @@ #include "../defines.hpp" #include "../helpers/Timer.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" #include #include diff --git a/src/managers/TokenManager.hpp b/src/managers/TokenManager.hpp index afe8c55b..4587f556 100644 --- a/src/managers/TokenManager.hpp +++ b/src/managers/TokenManager.hpp @@ -5,7 +5,7 @@ #include #include -#include "../helpers/memory/SharedPtr.hpp" +#include "../helpers/memory/Memory.hpp" class CUUIDToken { public: diff --git a/src/managers/eventLoop/EventLoopTimer.hpp b/src/managers/eventLoop/EventLoopTimer.hpp index fc0b2522..73f5dc73 100644 --- a/src/managers/eventLoop/EventLoopTimer.hpp +++ b/src/managers/eventLoop/EventLoopTimer.hpp @@ -4,7 +4,7 @@ #include #include -#include "../../helpers/memory/SharedPtr.hpp" +#include "../../helpers/memory/Memory.hpp" class CEventLoopTimer { public: diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 9fdf061c..930f3025 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -6,7 +6,7 @@ #include "../../helpers/WLClasses.hpp" #include "../../helpers/Timer.hpp" #include "InputMethodRelay.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include "../../devices/IPointer.hpp" #include "../../devices/ITouch.hpp" #include "../../devices/Tablet.hpp" diff --git a/src/managers/input/InputMethodPopup.hpp b/src/managers/input/InputMethodPopup.hpp index 9c5491bf..3151aedb 100644 --- a/src/managers/input/InputMethodPopup.hpp +++ b/src/managers/input/InputMethodPopup.hpp @@ -4,7 +4,7 @@ #include "../../desktop/WLSurface.hpp" #include "../../macros.hpp" #include "../../helpers/Box.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" class CInputMethodPopupV2; diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index e942add8..e13a1f1c 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -3,7 +3,7 @@ #include #include "../../defines.hpp" #include "../../helpers/WLClasses.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include "TextInput.hpp" #include "InputMethodPopup.hpp" #include diff --git a/src/managers/input/TextInput.hpp b/src/managers/input/TextInput.hpp index 30fbb4cc..61a664b9 100644 --- a/src/managers/input/TextInput.hpp +++ b/src/managers/input/TextInput.hpp @@ -3,7 +3,7 @@ #include "../../helpers/WLListener.hpp" #include "../../macros.hpp" #include "../../helpers/Box.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" #include struct wl_client; diff --git a/src/meson.build b/src/meson.build index ef00d4e0..ccb1922a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -13,6 +13,7 @@ executable('Hyprland', src, dependency('cairo'), dependency('hyprcursor'), dependency('hyprlang', version: '>= 0.3.2'), + dependency('hyprutils', version: '>= 0.1.1'), dependency('libdrm'), dependency('egl'), dependency('xkbcommon'), diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index 84faec4e..9118456b 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -1,6 +1,6 @@ #include "HookSystem.hpp" #include "../debug/Log.hpp" -#include "../helpers/VarList.hpp" +#include "../helpers/varlist/VarList.hpp" #include "../managers/TokenManager.hpp" #include "../Compositor.hpp" diff --git a/src/protocols/AlphaModifier.hpp b/src/protocols/AlphaModifier.hpp index d49d1e4e..1bb9cf23 100644 --- a/src/protocols/AlphaModifier.hpp +++ b/src/protocols/AlphaModifier.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "alpha-modifier-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CWLSurfaceResource; diff --git a/src/protocols/FocusGrab.hpp b/src/protocols/FocusGrab.hpp index 80166f9f..a2d545c5 100644 --- a/src/protocols/FocusGrab.hpp +++ b/src/protocols/FocusGrab.hpp @@ -6,7 +6,7 @@ #include #include #include -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CFocusGrab; class CSeatGrab; diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 074a51f0..93465b81 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-gamma-control-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 12e324b7..81ae9a71 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/OutputPower.hpp b/src/protocols/OutputPower.hpp index 44788a8f..410742ca 100644 --- a/src/protocols/OutputPower.hpp +++ b/src/protocols/OutputPower.hpp @@ -5,7 +5,7 @@ #include #include "WaylandProtocol.hpp" #include "wlr-output-power-management-unstable-v1.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/protocols/PointerConstraints.hpp b/src/protocols/PointerConstraints.hpp index 06bebb02..8a78de99 100644 --- a/src/protocols/PointerConstraints.hpp +++ b/src/protocols/PointerConstraints.hpp @@ -9,7 +9,7 @@ #include "pointer-constraints-unstable-v1.hpp" #include "../helpers/Vector2D.hpp" #include "../helpers/Region.hpp" -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" class CWLSurface; class CWLSurfaceResource; diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index b17a8272..46981635 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -5,7 +5,7 @@ #include #include "../WaylandProtocol.hpp" #include "wayland.hpp" -#include "../../helpers/signal/Listener.hpp" +#include "../../helpers/signal/Signal.hpp" class CMonitor; diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index bdf4fac2..7f68454c 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../helpers/signal/Listener.hpp" +#include "../helpers/signal/Signal.hpp" #include "../helpers/WLListener.hpp" #include "../macros.hpp" From 1c388e52fb71b116d728830f31883f0ef0e6cf17 Mon Sep 17 00:00:00 2001 From: Maximilian Seidler <78690852+PaideiaDilemma@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:18:51 +0200 Subject: [PATCH 06/51] session-lock: fix refocus after unlocking (#6423) --- src/protocols/SessionLock.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp index ae45b0f1..e7abc7cb 100644 --- a/src/protocols/SessionLock.cpp +++ b/src/protocols/SessionLock.cpp @@ -114,9 +114,11 @@ CSessionLock::CSessionLock(SP resource_) : resource(resource_ return; } - events.unlockAndDestroy.emit(); - inert = true; PROTO::sessionLock->locked = false; + + events.unlockAndDestroy.emit(); + + inert = true; PROTO::sessionLock->destroyResource(this); }); } From 21b9e31bf432e3d58f408b83e7dd15b653b49494 Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Tue, 11 Jun 2024 10:35:30 -0700 Subject: [PATCH 07/51] layershell: Fix keyboard focus grabs (#4968) (#6394) --- src/desktop/LayerSurface.cpp | 85 +++++++++++++---------------- src/desktop/LayerSurface.hpp | 53 +++++++++--------- src/managers/input/InputManager.cpp | 37 ++++++++++++- src/managers/input/InputManager.hpp | 1 + 4 files changed, 103 insertions(+), 73 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 62cae8f6..0b2e23a3 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -116,8 +116,8 @@ void CLayerSurface::onDestroy() { void CLayerSurface::onMap() { Debug::log(LOG, "LayerSurface {:x} mapped", (uintptr_t)layerSurface); - mapped = true; - keyboardExclusive = layerSurface->current.interactivity; + mapped = true; + interactivity = layerSurface->current.interactivity; // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -133,12 +133,15 @@ void CLayerSurface::onMap() { surface->resource()->enter(PMONITOR->self.lock()); - if (layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + + if (ISEXCLUSIVE) g_pInputManager->m_dExclusiveLSes.push_back(self); - const bool GRABSFOCUS = layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && - // don't focus if constrained - (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()); + const bool GRABSFOCUS = ISEXCLUSIVE || + (layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + // don't focus if constrained + (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())); if (GRABSFOCUS) { // TODO: use the new superb really very cool grab @@ -177,9 +180,6 @@ void CLayerSurface::onUnmap() { std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); - if (!g_pInputManager->m_dExclusiveLSes.empty()) - g_pCompositor->focusSurface(g_pInputManager->m_dExclusiveLSes[0]->surface->resource()); - if (!g_pCompositor->getMonitorFromID(monitorID) || g_pCompositor->m_bUnsafeState) { Debug::log(WARN, "Layersurface unmapping on invalid monitor (removed?) ignoring."); @@ -210,33 +210,8 @@ void CLayerSurface::onUnmap() { return; // refocus if needed - if (WASLASTFOCUS) { - g_pInputManager->releaseAllMouseButtons(); - - Vector2D surfaceCoords; - PHLLS pFoundLayerSurface; - SP foundSurface = nullptr; - - g_pCompositor->m_pLastFocus.reset(); - - // find LS-es to focus - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface) - foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &surfaceCoords, &pFoundLayerSurface); - - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { - // if there isn't any, focus the last window - const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); - g_pCompositor->focusWindow(nullptr); - g_pCompositor->focusWindow(PLASTWINDOW); - } else { - // otherwise, full refocus - g_pInputManager->refocus(); - } - } + if (WASLASTFOCUS) + g_pInputManager->refocusLastWindow(PMONITOR); CBox geomFixed = {geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y, geometry.width, geometry.height}; g_pHyprRenderer->damageBox(&geomFixed); @@ -311,18 +286,36 @@ void CLayerSurface::onCommit() { realSize.setValueAndWarp(geometry.size()); } - if (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) // don't focus if constrained - && !keyboardExclusive && mapped) { - g_pCompositor->focusSurface(surface->resource()); + if (mapped) { + const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); + const bool WASEXCLUSIVE = interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; + const bool ISEXCLUSIVE = layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE; - const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); - g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); - g_pInputManager->m_bEmptyFocusCursorSet = false; - } else if (!layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained()) && keyboardExclusive) { - g_pInputManager->refocus(); + if (!WASEXCLUSIVE && ISEXCLUSIVE) + g_pInputManager->m_dExclusiveLSes.push_back(self); + else if (WASEXCLUSIVE && !ISEXCLUSIVE) + std::erase_if(g_pInputManager->m_dExclusiveLSes, [this](const auto& other) { return !other.lock() || other.lock() == self.lock(); }); + + // if the surface was focused and interactive but now isn't, refocus + if (WASLASTFOCUS && !layerSurface->current.interactivity) { + // moveMouseUnified won't focus non interactive layers but it won't unfocus them either, + // so unfocus the surface here. + g_pCompositor->focusSurface(nullptr); + g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); + } else if (!WASEXCLUSIVE && !WASLASTFOCUS && + (ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) { + // if not focused last and exclusive or accepting input + unconstrained + g_pSeatManager->setGrab(nullptr); + g_pInputManager->releaseAllMouseButtons(); + g_pCompositor->focusSurface(surface->resource()); + + const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(geometry.x + PMONITOR->vecPosition.x, geometry.y + PMONITOR->vecPosition.y); + g_pSeatManager->setPointerFocus(surface->resource(), LOCAL); + g_pInputManager->m_bEmptyFocusCursorSet = false; + } } - keyboardExclusive = layerSurface->current.interactivity; + interactivity = layerSurface->current.interactivity; g_pHyprRenderer->damageSurface(surface->resource(), position.x, position.y); @@ -512,4 +505,4 @@ int CLayerSurface::popupsCount() { int no = -1; // we have one dummy popupHead->breadthfirst([](CPopup* p, void* data) { *(int*)data += 1; }, &no); return no; -} \ No newline at end of file +} diff --git a/src/desktop/LayerSurface.hpp b/src/desktop/LayerSurface.hpp index 9fa96d2d..056f66a8 100644 --- a/src/desktop/LayerSurface.hpp +++ b/src/desktop/LayerSurface.hpp @@ -34,40 +34,41 @@ class CLayerSurface { WP layerSurface; wl_list link; - bool keyboardExclusive = false; + // the header providing the enum type cannot be imported here + int interactivity = 0; - SP surface; + SP surface; - bool mapped = false; - uint32_t layer = 0; + bool mapped = false; + uint32_t layer = 0; - int monitorID = -1; + int monitorID = -1; - bool fadingOut = false; - bool readyToDelete = false; - bool noProcess = false; - bool noAnimations = false; + bool fadingOut = false; + bool readyToDelete = false; + bool noProcess = false; + bool noAnimations = false; - bool forceBlur = false; - bool forceBlurPopups = false; - int xray = -1; - bool ignoreAlpha = false; - float ignoreAlphaValue = 0.f; - bool dimAround = false; + bool forceBlur = false; + bool forceBlurPopups = false; + int xray = -1; + bool ignoreAlpha = false; + float ignoreAlphaValue = 0.f; + bool dimAround = false; - std::optional animationStyle; + std::optional animationStyle; - PHLLSREF self; + PHLLSREF self; - CBox geometry = {0, 0, 0, 0}; - Vector2D position; - std::string szNamespace = ""; - std::unique_ptr popupHead; + CBox geometry = {0, 0, 0, 0}; + Vector2D position; + std::string szNamespace = ""; + std::unique_ptr popupHead; - void onDestroy(); - void onMap(); - void onUnmap(); - void onCommit(); + void onDestroy(); + void onMap(); + void onUnmap(); + void onCommit(); private: struct { @@ -83,4 +84,4 @@ class CLayerSurface { bool operator==(const CLayerSurface& rhs) const { return layerSurface == rhs.layerSurface && monitorID == rhs.monitorID; } -}; \ No newline at end of file +}; diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 5ce53472..3e412b27 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -512,7 +512,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { } if (pFoundLayerSurface && (pFoundLayerSurface->layerSurface->current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) && FOLLOWMOUSE != 3 && - allowKeyboardRefocus) { + (allowKeyboardRefocus || pFoundLayerSurface->layerSurface->current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)) { g_pCompositor->focusSurface(foundSurface); } @@ -1384,6 +1384,41 @@ void CInputManager::refocus() { mouseMoveUnified(0, true); } +void CInputManager::refocusLastWindow(CMonitor* pMonitor) { + if (!pMonitor) { + refocus(); + return; + } + + Vector2D surfaceCoords; + PHLLS pFoundLayerSurface; + SP foundSurface = nullptr; + + g_pInputManager->releaseAllMouseButtons(); + + // first try for an exclusive layer + if (!m_dExclusiveLSes.empty()) + foundSurface = m_dExclusiveLSes[m_dExclusiveLSes.size() - 1]->surface->resource(); + + // then any surfaces above windows on the same monitor + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface) + foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &surfaceCoords, &pFoundLayerSurface); + + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + // then the last focused window if we're on the same workspace as it + const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); + g_pCompositor->focusWindow(PLASTWINDOW); + } else { + // otherwise fall back to a normal refocus. + refocus(); + } +} + void CInputManager::unconstrainMouse() { if (g_pSeatManager->mouse.expired()) return; diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 930f3025..8050defe 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -104,6 +104,7 @@ class CInputManager { Vector2D getMouseCoordsInternal(); void refocus(); + void refocusLastWindow(CMonitor* pMonitor); void simulateMouseMovement(); void sendMotionEventsToFocused(); From e1b05f8eafd8cd3e7e9197fa1db92391174b9206 Mon Sep 17 00:00:00 2001 From: Moritz G <100203892+Moerliy@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:49:54 +0200 Subject: [PATCH 08/51] binds: Add description to key binds (#6358) --------- Co-authored-by: Yusuf Duran --- src/config/ConfigManager.cpp | 39 +++++++++++++++++++-------------- src/debug/HyprCtl.cpp | 14 ++++++++---- src/managers/KeybindManager.hpp | 36 ++++++++++++++++-------------- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 6bb24e46..80af063b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -6,6 +6,7 @@ #include "helpers/varlist/VarList.hpp" #include "../protocols/LayerShell.hpp" +#include #include #include #include @@ -1957,15 +1958,16 @@ std::optional CConfigManager::handleBind(const std::string& command // bind[fl]=SUPER,G,exec,dmenu_run // flags - bool locked = false; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; - bool multiKey = false; - const auto BINDARGS = command.substr(4); + bool locked = false; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; + bool hasDescription = false; + const auto BINDARGS = command.substr(4); for (auto& arg : BINDARGS) { if (arg == 'l') { @@ -1984,6 +1986,8 @@ std::optional CConfigManager::handleBind(const std::string& command ignoreMods = true; } else if (arg == 's') { multiKey = true; + } else if (arg == 'd') { + hasDescription = true; } else { return "bind: invalid flag"; } @@ -1995,11 +1999,13 @@ std::optional CConfigManager::handleBind(const std::string& command if (mouse && (repeat || release || locked)) return "flag m is exclusive"; - const auto ARGS = CVarList(value, 4); + const int numbArgs = hasDescription ? 5 : 4; + const auto ARGS = CVarList(value, numbArgs); + const int DESCR_OFFSET = hasDescription ? 1 : 0; if ((ARGS.size() < 3 && !mouse) || (ARGS.size() < 3 && mouse)) return "bind: too few args"; - else if ((ARGS.size() > 4 && !mouse) || (ARGS.size() > 3 && mouse)) + else if ((ARGS.size() > (size_t)4 + DESCR_OFFSET && !mouse) || (ARGS.size() > (size_t)3 + DESCR_OFFSET && mouse)) return "bind: too many args"; std::set KEYSYMS; @@ -2018,12 +2024,11 @@ std::optional CConfigManager::handleBind(const std::string& command const auto KEY = multiKey ? "" : ARGS[1]; - auto HANDLER = ARGS[2]; + const auto DESCRIPTION = hasDescription ? ARGS[2] : ""; - const auto COMMAND = mouse ? HANDLER : ARGS[3]; + auto HANDLER = ARGS[2 + DESCR_OFFSET]; - if (mouse) - HANDLER = "mouse"; + const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET]; // to lower std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower); @@ -2048,8 +2053,8 @@ std::optional CConfigManager::handleBind(const std::string& command return "Invalid catchall, catchall keybinds are only allowed in submaps."; } - g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, - repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey}); + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, KEYSYMS, parsedKey.keycode, parsedKey.catchAll, MOD, MODS, HANDLER, COMMAND, locked, m_szCurrentSubmap, DESCRIPTION, + release, repeat, mouse, nonConsuming, transparent, ignoreMods, multiKey, hasDescription}); } return {}; diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 6f4d74b7..a7e714bd 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -1,5 +1,6 @@ #include "HyprCtl.hpp" +#include #include #include #include @@ -28,6 +29,7 @@ using namespace Hyprutils::String; #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" #include "config/ConfigManager.hpp" +#include "helpers/MiscFunctions.hpp" static void trimTrailingComma(std::string& str) { if (!str.empty() && str.back() == ',') @@ -792,9 +794,11 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { ret += "e"; if (kb.nonConsuming) ret += "n"; + if (kb.hasDescription) + ret += "d"; - ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, - kb.keycode, kb.catchAll, kb.handler, kb.arg); + ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdescription: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, + kb.key, kb.keycode, kb.catchAll, kb.description, kb.handler, kb.arg); } } else { // json @@ -808,17 +812,19 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "release": {}, "repeat": {}, "non_consuming": {}, + "has_description": {}, "modmask": {}, "submap": "{}", "key": "{}", "keycode": {}, "catch_all": {}, + "description": "{}", "dispatcher": "{}", "arg": "{}" }},)#", kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", - kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler), - escapeJSONStrings(kb.arg)); + kb.hasDescription ? "true" : "false", kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", + escapeJSONStrings(kb.description), escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 305e563f..ecab6ee1 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -14,23 +14,25 @@ class CPluginSystem; class IKeyboard; struct SKeybind { - std::string key = ""; - std::set sMkKeys = {}; - uint32_t keycode = 0; - bool catchAll = false; - uint32_t modmask = 0; - std::set sMkMods = {}; - std::string handler = ""; - std::string arg = ""; - bool locked = false; - std::string submap = ""; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; - bool multiKey = false; + std::string key = ""; + std::set sMkKeys = {}; + uint32_t keycode = 0; + bool catchAll = false; + uint32_t modmask = 0; + std::set sMkMods = {}; + std::string handler = ""; + std::string arg = ""; + bool locked = false; + std::string submap = ""; + std::string description = ""; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; + bool hasDescription = false; // DO NOT INITIALIZE bool shadowed = false; From b6bf4afb4861c7a7b41c6bf53daadf57a708e352 Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:56:35 +0000 Subject: [PATCH 09/51] layer: don't close special ws when restoring focus (#6424) modified: src/Compositor.cpp modified: src/Compositor.hpp modified: src/managers/input/InputManager.cpp --- src/Compositor.cpp | 11 +++++++++++ src/Compositor.hpp | 1 + src/managers/input/InputManager.cpp | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8b19f010..7d33889e 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1111,6 +1111,17 @@ bool CCompositor::isWorkspaceVisible(PHLWORKSPACE w) { return valid(w) && w->m_bVisible; } +bool CCompositor::isWorkspaceVisibleNotCovered(PHLWORKSPACE w) { + if (!valid(w)) + return false; + + const auto PMONITOR = getMonitorFromID(w->m_iMonitorID); + if (PMONITOR->activeSpecialWorkspace) + return PMONITOR->activeSpecialWorkspace->m_iID == w->m_iID; + + return PMONITOR->activeWorkspace->m_iID == w->m_iID; +} + PHLWORKSPACE CCompositor::getWorkspaceByID(const int& id) { for (auto& w : m_vWorkspaces) { if (w->m_iID == id && !w->inert()) diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 793899ee..458e37a7 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -118,6 +118,7 @@ class CCompositor { PHLWINDOW getWindowFromSurface(SP); PHLWINDOW getWindowFromHandle(uint32_t); bool isWorkspaceVisible(PHLWORKSPACE); + bool isWorkspaceVisibleNotCovered(PHLWORKSPACE); PHLWORKSPACE getWorkspaceByID(const int&); PHLWORKSPACE getWorkspaceByName(const std::string&); PHLWORKSPACE getWorkspaceByString(const std::string&); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3e412b27..033f4d6d 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1409,7 +1409,7 @@ void CInputManager::refocusLastWindow(CMonitor* pMonitor) { foundSurface = g_pCompositor->vectorToLayerSurface(g_pInputManager->getMouseCoordsInternal(), &pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &surfaceCoords, &pFoundLayerSurface); - if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisible(g_pCompositor->m_pLastWindow->m_pWorkspace)) { + if (!foundSurface && g_pCompositor->m_pLastWindow.lock() && g_pCompositor->isWorkspaceVisibleNotCovered(g_pCompositor->m_pLastWindow->m_pWorkspace)) { // then the last focused window if we're on the same workspace as it const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock(); g_pCompositor->focusWindow(PLASTWINDOW); From 8412ffcc42012888757cd00a004871e8bc353cf2 Mon Sep 17 00:00:00 2001 From: Moritz G <100203892+Moerliy@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:02:29 +0200 Subject: [PATCH 10/51] keybinds: fix bindm (#6429) * fixed mouse dispatcher * no brakets * move command up --- src/config/ConfigManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 80af063b..e0de33cf 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -2030,6 +2030,9 @@ std::optional CConfigManager::handleBind(const std::string& command const auto COMMAND = mouse ? HANDLER : ARGS[3 + DESCR_OFFSET]; + if (mouse) + HANDLER = "mouse"; + // to lower std::transform(HANDLER.begin(), HANDLER.end(), HANDLER.begin(), ::tolower); From 32283ed706291255d8e8b5d1249bbc2394bf532f Mon Sep 17 00:00:00 2001 From: MightyPlaza <123664421+MightyPlaza@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:56:35 +0000 Subject: [PATCH 11/51] groupbar: fix groupbar position rounding (#6433) modified: src/render/decorations/CHyprGroupBarDecoration.cpp --- src/render/decorations/CHyprGroupBarDecoration.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index a87dba31..e461ba08 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -119,15 +119,15 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { g_pDecorationPositioner->repositionDeco(this); } - int xoff = 0; - int yoff = 0; + float xoff = 0; + float yoff = 0; for (int i = 0; i < barsToDraw; ++i) { const auto WINDOWINDEX = *PSTACKED ? m_dwGroupMembers.size() - i - 1 : i; - CBox rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, - BAR_INDICATOR_HEIGHT}; + CBox rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - BAR_INDICATOR_HEIGHT - BAR_PADDING_OUTER_VERT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, + m_fBarWidth, BAR_INDICATOR_HEIGHT}; if (rect.width <= 0 || rect.height <= 0) break; @@ -151,8 +151,8 @@ void CHyprGroupBarDecoration::draw(CMonitor* pMonitor, float a) { color.a *= a; g_pHyprOpenGL->renderRect(&rect, color); - rect = {ASSIGNEDBOX.x + xoff - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, - ASSIGNEDBOX.y + ASSIGNEDBOX.h - yoff - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, + rect = {ASSIGNEDBOX.x + floor(xoff) - pMonitor->vecPosition.x + m_pWindow->m_vFloatingOffset.x, + ASSIGNEDBOX.y + ASSIGNEDBOX.h - floor(yoff) - ONEBARHEIGHT - pMonitor->vecPosition.y + m_pWindow->m_vFloatingOffset.y, m_fBarWidth, (*PGRADIENTS || *PRENDERTITLES ? *PHEIGHT : 0)}; rect.scale(pMonitor->scale); From f687105eff61aebff34669852e7153584286a357 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 16:02:19 +0200 Subject: [PATCH 12/51] compositor: update suspended states on moveworkspacetomonitor fixes #6417 --- src/Compositor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 7d33889e..20bc82e7 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2098,9 +2098,11 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon if (POLDMON) { g_pLayoutManager->getCurrentLayout()->recalculateMonitor(POLDMON->ID); updateFullscreenFadeOnWorkspace(POLDMON->activeWorkspace); + updateSuspendedStates(); } updateFullscreenFadeOnWorkspace(pWorkspace); + updateSuspendedStates(); // event g_pEventManager->postEvent(SHyprIPCEvent{"moveworkspace", pWorkspace->m_szName + "," + pMonitor->szName}); From 1bae19ce85ae9a25f2dddb6cee8bbd6ed3872ade Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 16:16:27 +0200 Subject: [PATCH 13/51] datadevice: only send actions for ver >= 3 fixes #6444 --- src/protocols/core/DataDevice.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index ca044e93..c1de8f83 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -85,8 +85,10 @@ void CWLDataOfferResource::sendData() { if (!source) return; - resource->sendSourceActions(7); - resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + if (resource->version() >= 3) { + resource->sendSourceActions(7); + resource->sendAction(WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE); + } for (auto& m : source->mimes()) { LOGM(LOG, " | offer {:x} supports mime {}", (uintptr_t)this, m); From c7e85e26f761fb58db6692649e259589cdf55cf0 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Wed, 12 Jun 2024 16:49:26 +0200 Subject: [PATCH 14/51] seat: fixup touch event handling fixes #6353 --- src/managers/SeatManager.cpp | 50 ++++++++++++++++++------------------ src/managers/SeatManager.hpp | 1 + src/protocols/core/Seat.cpp | 21 +++++++-------- src/protocols/core/Seat.hpp | 2 ++ 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index 862bd2b5..c1b13ccb 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -337,34 +337,11 @@ void CSeatManager::sendPointerAxis(uint32_t timeMs, wl_pointer_axis axis, double } void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, int32_t id, const Vector2D& local) { - if (state.touchFocus == surf) - return; - listeners.touchSurfaceDestroy.reset(); - if (state.touchFocusResource) { - auto client = state.touchFocusResource->client(); - for (auto& s : seatResources) { - if (s->resource->client() != client) - continue; - - for (auto& t : s->resource->touches) { - if (!t) - continue; - - t->sendUp(timeMs, id); - } - } - } - state.touchFocusResource.reset(); state.touchFocus = surf; - if (!surf) { - events.touchFocusChange.emit(); - return; - } - auto client = surf->client(); for (auto& r : seatResources | std::views::reverse) { if (r->resource->client() != client) @@ -381,11 +358,34 @@ void CSeatManager::sendTouchDown(SP surf, uint32_t timeMs, i listeners.touchSurfaceDestroy = surf->events.destroy.registerListener([this, timeMs, id](std::any d) { sendTouchUp(timeMs + 10, id); }); - events.touchFocusChange.emit(); + touchLocks++; + + if (touchLocks <= 1) + events.touchFocusChange.emit(); } void CSeatManager::sendTouchUp(uint32_t timeMs, int32_t id) { - sendTouchDown(nullptr, timeMs, id, {}); + if (!state.touchFocusResource || touchLocks <= 0) + return; + + auto client = state.touchFocusResource->client(); + for (auto& r : seatResources | std::views::reverse) { + if (r->resource->client() != client) + continue; + + state.touchFocusResource = r->resource; + for (auto& t : r->resource->touches) { + if (!t) + continue; + + t->sendUp(timeMs, id); + } + } + + touchLocks--; + + if (touchLocks <= 0) + events.touchFocusChange.emit(); } void CSeatManager::sendTouchMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { diff --git a/src/managers/SeatManager.hpp b/src/managers/SeatManager.hpp index e74d9ace..1a1df1d5 100644 --- a/src/managers/SeatManager.hpp +++ b/src/managers/SeatManager.hpp @@ -155,6 +155,7 @@ class CSeatManager { } listeners; Vector2D lastLocalCoords; + int touchLocks = 0; // we assume there aint like 20 touch devices at once... friend struct SSeatResourceContainer; friend class CSeatGrab; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 8bf03909..331eb15e 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -25,37 +25,38 @@ void CWLTouchResource::sendDown(SP surface, uint32_t timeMs, if (!owner) return; - if (currentSurface) { - LOGM(WARN, "requested CWLTouchResource::sendDown without sendUp first."); - sendUp(timeMs, id); - } - ASSERT(surface->client() == owner->client()); currentSurface = surface; listeners.destroySurface = surface->events.destroy.registerListener([this, timeMs, id](std::any d) { sendUp(timeMs + 10 /* hack */, id); }); resource->sendDown(g_pSeatManager->nextSerial(owner.lock()), timeMs, surface->getResource().get(), id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); + + fingers++; } void CWLTouchResource::sendUp(uint32_t timeMs, int32_t id) { - if (!owner || !currentSurface) + if (!owner) return; resource->sendUp(g_pSeatManager->nextSerial(owner.lock()), timeMs, id); - currentSurface.reset(); - listeners.destroySurface.reset(); + fingers--; + if (fingers <= 0) { + currentSurface.reset(); + listeners.destroySurface.reset(); + fingers = 0; + } } void CWLTouchResource::sendMotion(uint32_t timeMs, int32_t id, const Vector2D& local) { - if (!owner || !currentSurface) + if (!owner) return; resource->sendMotion(timeMs, id, wl_fixed_from_double(local.x), wl_fixed_from_double(local.y)); } void CWLTouchResource::sendFrame() { - if (!owner || !currentSurface) + if (!owner) return; resource->sendFrame(); diff --git a/src/protocols/core/Seat.hpp b/src/protocols/core/Seat.hpp index 524783f9..625d3a98 100644 --- a/src/protocols/core/Seat.hpp +++ b/src/protocols/core/Seat.hpp @@ -46,6 +46,8 @@ class CWLTouchResource { SP resource; WP currentSurface; + int fingers = 0; + struct { CHyprSignalListener destroySurface; } listeners; From 9d7d5ec3c8ea3550ca3053a7a26e97231ad6fde9 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 17:03:04 +0200 Subject: [PATCH 15/51] seatmgr: fix missing nullcheck in updateActiveKeyboardData sometimes we may set a keyboard that's about-to-be-deleted, we might as well check for that additionally avoid setting null keyboards altogether --- src/managers/SeatManager.cpp | 2 +- src/managers/input/InputManager.cpp | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index c1b13ccb..a58bca72 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -94,7 +94,7 @@ void CSeatManager::setKeyboard(SP KEEB) { } void CSeatManager::updateActiveKeyboardData() { - if (keyboard) + if (keyboard && keyboard->wlr()) PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay); PROTO::seat->updateKeymap(); } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 033f4d6d..ed8e834c 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -1226,12 +1226,20 @@ void CInputManager::destroyKeyboard(SP pKeyboard) { std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; }); if (m_vKeyboards.size() > 0) { - const auto PNEWKEYBOARD = m_vKeyboards.back(); - g_pSeatManager->setKeyboard(PNEWKEYBOARD); - PNEWKEYBOARD->active = true; - } else { + bool found = false; + for (auto& k : m_vKeyboards | std::views::reverse) { + if (!k->wlr()) + continue; + + g_pSeatManager->setKeyboard(k); + found = true; + break; + } + + if (!found) + g_pSeatManager->setKeyboard(nullptr); + } else g_pSeatManager->setKeyboard(nullptr); - } removeFromHIDs(pKeyboard); } From a99f314106cd2ae45e12e7c4012ab68026cf5522 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 18:39:52 +0200 Subject: [PATCH 16/51] input: fallback to main surface if not found on window fixes #6421 --- src/managers/input/InputManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index ed8e834c..3aa8d2ae 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -351,6 +351,10 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (pFoundWindow) { if (!pFoundWindow->m_bIsX11) { foundSurface = g_pCompositor->vectorWindowToSurface(mouseCoords, pFoundWindow, surfaceCoords); + if (!foundSurface) { + foundSurface = pFoundWindow->m_pWLSurface->resource(); + surfacePos = pFoundWindow->m_vRealPosition.value(); + } } else { foundSurface = pFoundWindow->m_pWLSurface->resource(); surfacePos = pFoundWindow->m_vRealPosition.value(); From 38132ffaf53c843a3ed03be5b305702fde8f5a49 Mon Sep 17 00:00:00 2001 From: Ikalco <73481042+ikalco@users.noreply.github.com> Date: Wed, 12 Jun 2024 12:28:52 -0500 Subject: [PATCH 17/51] renderer: properly software lock cursors with zoom_factor (#6434) --- src/managers/PointerManager.cpp | 14 ++++++++++++++ src/managers/PointerManager.hpp | 2 ++ src/render/Renderer.cpp | 16 +++++++++------- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index 80a7ee76..bf7b5d0a 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -150,6 +150,20 @@ CPointerManager::CPointerManager() { }); } +void CPointerManager::lockSoftwareAll() { + for (auto& state : monitorStates) + state->softwareLocks++; + + updateCursorBackend(); +} + +void CPointerManager::unlockSoftwareAll() { + for (auto& state : monitorStates) + state->softwareLocks--; + + updateCursorBackend(); +} + void CPointerManager::lockSoftwareForMonitor(SP mon) { auto state = stateFor(mon); state->softwareLocks++; diff --git a/src/managers/PointerManager.hpp b/src/managers/PointerManager.hpp index b71a79c3..1e386797 100644 --- a/src/managers/PointerManager.hpp +++ b/src/managers/PointerManager.hpp @@ -43,6 +43,8 @@ class CPointerManager { void lockSoftwareForMonitor(SP pMonitor); void unlockSoftwareForMonitor(SP pMonitor); + void lockSoftwareAll(); + void unlockSoftwareAll(); void renderSoftwareCursorsFor(SP pMonitor, timespec* now, CRegion& damage /* logical */, std::optional overridePos = {} /* monitor-local */); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 8fac5869..48fa92a0 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1253,6 +1253,15 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { TRACY_GPU_ZONE("Render"); + static bool zoomLock = false; + if (zoomLock && *PZOOMFACTOR == 1.f) { + g_pPointerManager->unlockSoftwareAll(); + zoomLock = false; + } else if (!zoomLock && *PZOOMFACTOR != 1.f) { + g_pPointerManager->lockSoftwareAll(); + zoomLock = true; + } + if (pMonitor == g_pCompositor->getMonitorFromCursor()) g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY); else @@ -1265,10 +1274,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->forceFullFrames = 10; } - bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f; - if (lockSoftware) - g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock()); - CRegion damage, finalDamage; if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) { Debug::log(ERR, "renderer: couldn't beginRender()!"); @@ -1370,9 +1375,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { endRender(); - if (lockSoftware) - g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock()); - TRACY_GPU_COLLECT; if (!pMonitor->mirrors.empty()) { From 18ee9ece9cec51daa75fbf765d9fa6b72ef898e5 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 22:57:06 +0200 Subject: [PATCH 18/51] layershell: minor fixes to re-mapping of layers ref #2012 --- src/Compositor.cpp | 4 ++++ src/Compositor.hpp | 1 + src/desktop/LayerSurface.cpp | 19 +++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 20bc82e7..8f36b4ae 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1361,6 +1361,10 @@ void CCompositor::addToFadingOutSafe(PHLLS pLS) { m_vSurfacesFadingOut.emplace_back(pLS); } +void CCompositor::removeFromFadingOutSafe(PHLLS ls) { + std::erase(m_vSurfacesFadingOut, ls); +} + void CCompositor::addToFadingOutSafe(PHLWINDOW pWindow) { const auto FOUND = std::find_if(m_vWindowsFadingOut.begin(), m_vWindowsFadingOut.end(), [&](PHLWINDOWREF& other) { return other.lock() == pWindow; }); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 458e37a7..242c3b13 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -156,6 +156,7 @@ class CCompositor { PHLWINDOW getX11Parent(PHLWINDOW); void scheduleFrameForMonitor(CMonitor*); void addToFadingOutSafe(PHLLS); + void removeFromFadingOutSafe(PHLLS); void addToFadingOutSafe(PHLWINDOW); PHLWINDOW getWindowByRegex(const std::string&); void warpCursorTo(const Vector2D&, bool force = false); diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 0b2e23a3..2eb66440 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -119,6 +119,10 @@ void CLayerSurface::onMap() { mapped = true; interactivity = layerSurface->current.interactivity; + // this layer might be re-mapped. + fadingOut = false; + g_pCompositor->removeFromFadingOutSafe(self.lock()); + // fix if it changed its mon const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); @@ -204,8 +208,6 @@ void CLayerSurface::onUnmap() { const bool WASLASTFOCUS = g_pCompositor->m_pLastFocus == surface->resource(); - surface.reset(); - if (!PMONITOR) return; @@ -221,12 +223,25 @@ void CLayerSurface::onUnmap() { g_pHyprRenderer->damageBox(&geomFixed); g_pInputManager->sendMotionEventsToFocused(); + + g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->ID); } void CLayerSurface::onCommit() { if (!layerSurface) return; + if (!mapped) { + // we're re-mapping if this is the case + if (layerSurface->surface && !layerSurface->surface->current.buffer) { + fadingOut = false; + geometry = {}; + g_pHyprRenderer->arrangeLayersForMonitor(monitorID); + } + + return; + } + const auto PMONITOR = g_pCompositor->getMonitorFromID(monitorID); if (!PMONITOR) From 0e18da8467136806d191f84c88aa7536453869e0 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 23:28:52 +0200 Subject: [PATCH 19/51] foreign-toplevel: fixup output resource finding fixes #6457 --- src/protocols/ForeignToplevelWlr.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp index 8224f495..14800393 100644 --- a/src/protocols/ForeignToplevelWlr.cpp +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -122,25 +122,19 @@ void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { if (lastMonitorID == (int64_t)pMonitor->ID) return; - const auto CLIENT = resource->client(); - - struct wl_resource* outputResource; + const auto CLIENT = resource->client(); if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR) { - wl_resource_for_each(outputResource, &PLASTMONITOR->output->resources) { - if (wl_resource_get_client(outputResource) != CLIENT) - continue; + const auto OLDRESOURCE = PROTO::outputs.at(PLASTMONITOR->szName)->outputResourceFrom(CLIENT); - resource->sendOutputLeave(outputResource); - } + if (OLDRESOURCE) + resource->sendOutputLeave(OLDRESOURCE->getResource()->resource()); } - wl_resource_for_each(outputResource, &pMonitor->output->resources) { - if (wl_resource_get_client(outputResource) != CLIENT) - continue; + const auto NEWRESOURCE = PROTO::outputs.at(pMonitor->szName)->outputResourceFrom(CLIENT); - resource->sendOutputEnter(outputResource); - } + if (NEWRESOURCE) + resource->sendOutputEnter(NEWRESOURCE->getResource()->resource()); lastMonitorID = pMonitor->ID; } From a9d7befc36f2890f080d02b8c04b678778ded080 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Wed, 12 Jun 2024 23:29:24 +0200 Subject: [PATCH 20/51] formats: fixup for legacy_renderer builds --- src/helpers/Format.cpp | 94 ++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 343440b4..9c94f68b 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -93,70 +93,100 @@ inline const std::vector GLES3_FORMATS = { .bytesPerBlock = 2, }, { - .drmFormat = DRM_FORMAT_XBGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_XBGR2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XBGR2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_ABGR2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_ABGR2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XBGR2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XRGB2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_XRGB2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XRGB2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_ARGB2101010, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_INT_2_10_10_10_REV, + .drmFormat = DRM_FORMAT_ARGB2101010, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_UNSIGNED_INT_2_10_10_10_REV, +#else + .glType = GL_UNSIGNED_INT_2_10_10_10_REV_EXT, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XRGB2101010, .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XBGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT, + .drmFormat = DRM_FORMAT_XBGR16161616F, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_HALF_FLOAT, +#else + .glType = GL_HALF_FLOAT_OES, +#endif .withAlpha = false, .alphaStripped = DRM_FORMAT_XBGR16161616F, .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_ABGR16161616F, - .glFormat = GL_RGBA, - .glType = GL_HALF_FLOAT, + .drmFormat = DRM_FORMAT_ABGR16161616F, + .glFormat = GL_RGBA, +#ifndef GLES2 + .glType = GL_HALF_FLOAT, +#else + .glType = GL_HALF_FLOAT_OES, +#endif .withAlpha = true, .alphaStripped = DRM_FORMAT_XBGR16161616F, .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_XBGR16161616, - .glInternalFormat = GL_RGBA16UI, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = false, - .alphaStripped = DRM_FORMAT_XBGR16161616, - .bytesPerBlock = 8, + .drmFormat = DRM_FORMAT_XBGR16161616, +#ifndef GLES2 + .glFormat = GL_RGBA16UI, +#else + .glFormat = GL_RGBA16_EXT, +#endif + .glType = GL_UNSIGNED_SHORT, + .withAlpha = false, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, }, { - .drmFormat = DRM_FORMAT_ABGR16161616, - .glInternalFormat = GL_RGBA16UI, - .glFormat = GL_RGBA, - .glType = GL_UNSIGNED_SHORT, - .withAlpha = true, - .alphaStripped = DRM_FORMAT_XBGR16161616, - .bytesPerBlock = 8, + .drmFormat = DRM_FORMAT_ABGR16161616, +#ifndef GLES2 + .glFormat = GL_RGBA16UI, +#else + .glFormat = GL_RGBA16_EXT, +#endif + .glType = GL_UNSIGNED_SHORT, + .withAlpha = true, + .alphaStripped = DRM_FORMAT_XBGR16161616, + .bytesPerBlock = 8, }, { .drmFormat = DRM_FORMAT_YVYU, From d677ac6f87acf97103327e321f7a05a0ce5774d6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 11:33:20 +0200 Subject: [PATCH 21/51] hyprpm: print all types of cmake errors during configure --- hyprpm/src/core/PluginManager.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index 446d6af3..f9e9664a 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -479,13 +479,16 @@ bool CPluginManager::updateHeaders(bool force) { if (m_bVerbose) progress.printMessageAbove(std::string{Colors::BLUE} + "[v] " + Colors::RESET + "cmake returned: " + ret); - if (ret.contains("required packages were not found")) { + if (ret.contains("CMake Error at")) { // missing deps, let the user know. - std::string missing = ret.substr(ret.find("The following required packages were not found:")); - missing = missing.substr(0, missing.find("Call Stack")); + std::string missing = ret.substr(ret.find("CMake Error at")); + missing = ret.substr(ret.find_first_of('\n') + 1); + missing = missing.substr(0, missing.find("-- Configuring incomplete")); missing = missing.substr(0, missing.find_last_of('\n')); - std::cerr << "\n" << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" << missing << "\n"; + std::cerr << "\n" + << Colors::RED << "✖" << Colors::RESET << " Could not configure the hyprland source, cmake complained:\n" + << missing << "\n\nThis likely means that you are missing the above dependencies or they are out of date.\n"; return false; } From a54f98c20301a71efe5e73a8fc5e1bcd66f2bd34 Mon Sep 17 00:00:00 2001 From: "Yang, Ying-chao" Date: Thu, 13 Jun 2024 17:33:47 +0800 Subject: [PATCH 22/51] virtualkeyboard: check if VirtualKeyboard is valid before accessing client. (#6460) This fixes crash when restarting fcitx (#6378) --- src/protocols/InputMethodV2.cpp | 4 ++-- src/protocols/VirtualKeyboard.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 5d0bd417..24f7ad54 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -81,7 +81,7 @@ SP CInputMethodKeyboardGrabV2::getOwner() { } wl_client* CInputMethodKeyboardGrabV2::client() { - return resource->client(); + return resource->resource() ? resource->client() : nullptr; } CInputMethodPopupV2::CInputMethodPopupV2(SP resource_, SP owner_, SP surface) : resource(resource_), owner(owner_) { @@ -373,4 +373,4 @@ void CInputMethodV2Protocol::onGetIME(CZwpInputMethodManagerV2* mgr, wl_resource LOGM(LOG, "New IME with resource id {}", id); events.newIME.emit(RESOURCE); -} \ No newline at end of file +} diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 89b14c32..009c277c 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -100,7 +100,7 @@ wlr_keyboard* CVirtualKeyboardV1Resource::wlr() { } wl_client* CVirtualKeyboardV1Resource::client() { - return resource->client(); + return resource->resource() ? resource->client() : nullptr; } void CVirtualKeyboardV1Resource::releasePressed() { @@ -151,4 +151,4 @@ void CVirtualKeyboardProtocol::onCreateKeeb(CZwpVirtualKeyboardManagerV1* pMgr, LOGM(LOG, "New VKeyboard at id {}", id); events.newKeyboard.emit(RESOURCE); -} \ No newline at end of file +} From 9e781040d9067c2711ec2e9f5b47b76ef70762b3 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 11:54:01 +0200 Subject: [PATCH 23/51] props: bump version to 0.41.1 --- props.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/props.json b/props.json index d9bd7cea..4af3eb2a 100644 --- a/props.json +++ b/props.json @@ -1,3 +1,3 @@ { - "version": "0.41.0" + "version": "0.41.1" } \ No newline at end of file From e6d10539af1fdca33b10bc3c1dfac16f1cdfe1c8 Mon Sep 17 00:00:00 2001 From: Tom Englund Date: Thu, 13 Jun 2024 12:08:02 +0200 Subject: [PATCH 24/51] core: fix a few small memory leaks on exit (#6470) * renderer: add destructor and destroy event source add destructor and destroy the event source. one less leak on exit of compositor reported by asan. * compositor: cleanup eventloop on exit destruct hyprctl to release the event sources, and properly cleanup the event loop on exit of compositor. less leaks on exit reported by asan * threadmgr: destroy event source on destruction destroy the event source on destruction. * eventloopmgr: reset eventloopmgr on exit aswell reset the eventloopmanager on exit of compositor and free the leaking last idle frame on monitor destroy. --- src/Compositor.cpp | 3 +++ src/events/Monitors.cpp | 3 +++ src/managers/ThreadManager.cpp | 3 ++- src/render/Renderer.cpp | 5 +++++ src/render/Renderer.hpp | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 8f36b4ae..2f972335 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -351,6 +351,8 @@ void CCompositor::cleanup() { g_pXWaylandManager.reset(); g_pPointerManager.reset(); g_pSeatManager.reset(); + g_pHyprCtl.reset(); + g_pEventLoopManager.reset(); if (m_sWLRRenderer) wlr_renderer_destroy(m_sWLRRenderer); @@ -364,6 +366,7 @@ void CCompositor::cleanup() { if (m_critSigSource) wl_event_source_remove(m_critSigSource); + wl_event_loop_destroy(m_sWLEventLoop); wl_display_terminate(m_sWLDisplay); m_sWLDisplay = nullptr; diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp index e3f8f03a..17b8ef65 100644 --- a/src/events/Monitors.cpp +++ b/src/events/Monitors.cpp @@ -188,6 +188,9 @@ void Events::listener_monitorDestroy(void* owner, void* data) { Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name); + if (pMonitor->output->idle_frame) + wl_event_source_remove(pMonitor->output->idle_frame); + pMonitor->onDisconnect(true); pMonitor->output = nullptr; diff --git a/src/managers/ThreadManager.cpp b/src/managers/ThreadManager.cpp index cd892503..6f8e0c9a 100644 --- a/src/managers/ThreadManager.cpp +++ b/src/managers/ThreadManager.cpp @@ -25,5 +25,6 @@ CThreadManager::CThreadManager() { } CThreadManager::~CThreadManager() { - // + if (m_esConfigTimer) + wl_event_source_remove(m_esConfigTimer); } \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 48fa92a0..4fe35c7e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -90,6 +90,11 @@ CHyprRenderer::CHyprRenderer() { wl_event_source_timer_update(m_pCursorTicker, 500); } +CHyprRenderer::~CHyprRenderer() { + if (m_pCursorTicker) + wl_event_source_remove(m_pCursorTicker); +} + static void renderSurface(SP surface, int x, int y, void* data) { if (!surface->current.buffer || !surface->current.buffer->texture) return; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index f88bfebf..60101e87 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -42,6 +42,7 @@ struct SSessionLockSurface; class CHyprRenderer { public: CHyprRenderer(); + ~CHyprRenderer(); void renderMonitor(CMonitor* pMonitor); void arrangeLayersForMonitor(const int&); From 4842eb83b444418ad3fe1901d645dd02224989e5 Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Thu, 13 Jun 2024 12:20:14 +0000 Subject: [PATCH 25/51] helpers: make shm_open() portable after 8bcccf9f0f0f (#6471) https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html https://man.freebsd.org/shm_open/2 https://www.man7.org/linux/man-pages/man3/shm_open.3.html --- src/helpers/MiscFunctions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index b1d734c8..346a3ffa 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -814,7 +814,8 @@ bool envEnabled(const std::string& env) { } std::pair openExclusiveShm() { - std::string name = g_pTokenManager->getRandomUUID(); + // Only absolute paths can be shared across different shm_open() calls + std::string name = "/" + g_pTokenManager->getRandomUUID(); for (size_t i = 0; i < 69; ++i) { int fd = shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); From 5de273a14427cb4a4cad9ac57a22b418bcd4248d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Thu, 13 Jun 2024 17:32:32 +0200 Subject: [PATCH 26/51] xwayland: drop some spammy logs to trace fixes #6478 --- src/xwayland/XWM.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 7af1d506..247af4b7 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -248,11 +248,11 @@ void CXWM::readProp(SP XSURF, uint32_t atom, xcb_get_property_ } } } else { - Debug::log(LOG, "[xwm] Unhandled prop {} -> {}", atom, propName); + Debug::log(TRACE, "[xwm] Unhandled prop {} -> {}", atom, propName); return; } - Debug::log(LOG, "[xwm] Handled prop {} -> {}", atom, propName); + Debug::log(TRACE, "[xwm] Handled prop {} -> {}", atom, propName); } void CXWM::handlePropertyNotify(xcb_property_notify_event_t* e) { @@ -354,11 +354,11 @@ void CXWM::handleClientMessage(xcb_client_message_event_t* e) { } else if (e->type == HYPRATOMS["_NET_ACTIVE_WINDOW"]) { XSURF->events.activate.emit(); } else { - Debug::log(LOG, "[xwm] Unhandled message prop {} -> {}", e->type, propName); + Debug::log(TRACE, "[xwm] Unhandled message prop {} -> {}", e->type, propName); return; } - Debug::log(LOG, "[xwm] Handled message prop {} -> {}", e->type, propName); + Debug::log(TRACE, "[xwm] Handled message prop {} -> {}", e->type, propName); } void CXWM::handleFocusIn(xcb_focus_in_event_t* e) { @@ -490,18 +490,18 @@ std::string CXWM::mimeFromAtom(xcb_atom_t atom) { } void CXWM::handleSelectionNotify(xcb_selection_notify_event_t* e) { - Debug::log(LOG, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target); + Debug::log(TRACE, "[xwm] Selection notify for {} prop {} target {}", e->selection, e->property, e->target); SXSelection& sel = clipboard; if (e->property == XCB_ATOM_NONE) { if (sel.transfer) { - Debug::log(ERR, "[xwm] converting selection failed"); + Debug::log(TRACE, "[xwm] converting selection failed"); sel.transfer.reset(); } } else if (e->target == HYPRATOMS["TARGETS"]) { if (!focusedSurface) { - Debug::log(LOG, "[xwm] denying access to write to clipboard because no X client is in focus"); + Debug::log(TRACE, "[xwm] denying access to write to clipboard because no X client is in focus"); return; } @@ -519,7 +519,7 @@ bool CXWM::handleSelectionPropertyNotify(xcb_property_notify_event_t* e) { } void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { - Debug::log(LOG, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor, + Debug::log(TRACE, "[xwm] Selection request for {} prop {} target {} time {} requestor {} selection {}", e->selection, e->property, e->target, e->time, e->requestor, e->selection); SXSelection& sel = clipboard; @@ -542,7 +542,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { } if (!g_pSeatManager->state.keyboardFocusResource || g_pSeatManager->state.keyboardFocusResource->client() != g_pXWayland->pServer->xwaylandClient) { - Debug::log(LOG, "[xwm] Ignoring clipboard access: xwayland not in focus"); + Debug::log(TRACE, "[xwm] Ignoring clipboard access: xwayland not in focus"); selectionSendNotify(e, false); return; } @@ -585,7 +585,7 @@ void CXWM::handleSelectionRequest(xcb_selection_request_event_t* e) { } bool CXWM::handleSelectionXFixesNotify(xcb_xfixes_selection_notify_event_t* e) { - Debug::log(LOG, "[xwm] Selection xfixes notify for {}", e->selection); + Debug::log(TRACE, "[xwm] Selection xfixes notify for {}", e->selection); // IMPORTANT: mind the g_pSeatManager below SXSelection& sel = clipboard; From 8055b1c00a102f5419e40f5eddfb6ee8be693f33 Mon Sep 17 00:00:00 2001 From: phonetic112 <73647246+phonetic112@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:23:23 -0400 Subject: [PATCH 27/51] misc: Fix build warnings (#6486) --- hyprpm/src/core/PluginManager.cpp | 7 ++++--- src/helpers/MiscFunctions.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index f9e9664a..e8c6e251 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -24,9 +24,10 @@ using namespace Hyprutils::String; static std::string execAndGet(std::string cmd) { cmd += " 2>&1"; - std::array buffer; - std::string result; - const std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); + std::array buffer; + std::string result; + using PcloseType = int (*)(FILE*); + const std::unique_ptr pipe(popen(cmd.c_str(), "r"), static_cast(pclose)); if (!pipe) return ""; diff --git a/src/helpers/MiscFunctions.cpp b/src/helpers/MiscFunctions.cpp index 346a3ffa..821f3231 100644 --- a/src/helpers/MiscFunctions.cpp +++ b/src/helpers/MiscFunctions.cpp @@ -580,9 +580,10 @@ float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Ve // Execute a shell command and get the output std::string execAndGet(const char* cmd) { - std::array buffer; - std::string result; - const std::unique_ptr pipe(popen(cmd, "r"), pclose); + std::array buffer; + std::string result; + using PcloseType = int (*)(FILE*); + const std::unique_ptr pipe(popen(cmd, "r"), static_cast(pclose)); if (!pipe) { Debug::log(ERR, "execAndGet: failed in pipe"); return ""; From 9cd5b3587cb1e3d42b647fa230024cd0153ea9cb Mon Sep 17 00:00:00 2001 From: outfoxxed Date: Fri, 14 Jun 2024 02:52:37 -0700 Subject: [PATCH 28/51] layerSurface: fix layer being refocused every commit with on_demand (#6487) * layerSurface: fix layer being refocused every commit with on_demand Fixes #6477 The surface will now only receive focus when its keyboard interactivity is more than the previous keyboard interactivity in the order none -> on_demand -> exclusive. * layerSurface: only kb focus if becoming exclusive --- src/desktop/LayerSurface.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/desktop/LayerSurface.cpp b/src/desktop/LayerSurface.cpp index 2eb66440..64eeead1 100644 --- a/src/desktop/LayerSurface.cpp +++ b/src/desktop/LayerSurface.cpp @@ -317,9 +317,8 @@ void CLayerSurface::onCommit() { // so unfocus the surface here. g_pCompositor->focusSurface(nullptr); g_pInputManager->refocusLastWindow(g_pCompositor->getMonitorFromID(monitorID)); - } else if (!WASEXCLUSIVE && !WASLASTFOCUS && - (ISEXCLUSIVE || (layerSurface->current.interactivity && (g_pSeatManager->mouse.expired() || !g_pInputManager->isConstrained())))) { - // if not focused last and exclusive or accepting input + unconstrained + } else if (!WASEXCLUSIVE && ISEXCLUSIVE) { + // if now exclusive and not previously g_pSeatManager->setGrab(nullptr); g_pInputManager->releaseAllMouseButtons(); g_pCompositor->focusSurface(surface->resource()); From b2590b58c51094424a9651d8df37dfab838b5bbb Mon Sep 17 00:00:00 2001 From: Alexander <51529891+Truenya@users.noreply.github.com> Date: Fri, 14 Jun 2024 13:11:40 +0300 Subject: [PATCH 29/51] hyprctl: added --follow option to rolliglog (#6325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Крылов Александр --- Makefile | 2 +- hyprctl/Strings.hpp | 5 ++- hyprctl/main.cpp | 71 ++++++++++++++++++++++++++++++---- src/debug/HyprCtl.cpp | 51 +++++++++++++++++++++++- src/debug/Log.cpp | 4 ++ src/debug/RollingLogFollow.hpp | 65 +++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 src/debug/RollingLogFollow.hpp diff --git a/Makefile b/Makefile index a33f4cb7..493a6784 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ uninstall: pluginenv: @echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n" @exit 1 - + installheaders: @if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi diff --git a/hyprctl/Strings.hpp b/hyprctl/Strings.hpp index 76e87ecb..17725e77 100644 --- a/hyprctl/Strings.hpp +++ b/hyprctl/Strings.hpp @@ -38,7 +38,8 @@ commands: plugin ... → Issue a plugin request reload [config-only] → Issue a reload to force reload the config. Pass 'config-only' to disable monitor reload - rollinglog → Prints tail of the log + rollinglog → Prints tail of the log. Also supports -f/--follow + option setcursor → Sets the cursor theme and reloads the cursor manager seterror → Sets the hyprctl error string. Color has @@ -112,7 +113,7 @@ create : remove : Removes virtual output. Pass the output's name, as found in 'hyprctl monitors' - + flags: See 'hyprctl --help')#"; diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 8fb9194c..f5de041b 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -1,9 +1,9 @@ -#include +#include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include @@ -22,8 +22,9 @@ #include #include #include -#include +#include #include +#include #include using namespace Hyprutils::String; @@ -100,13 +101,53 @@ std::vector instances() { return result; } -int request(std::string arg, int minArgs = 0) { +static volatile bool sigintReceived = false; +void intHandler(int sig) { + sigintReceived = true; + std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl; +} + +int rollingRead(const int socket) { + sigintReceived = false; + signal(SIGINT, intHandler); + + constexpr size_t BUFFER_SIZE = 8192; + std::array buffer = {0}; + int sizeWritten = 0; + std::cout << "[hyprctl] reading from socket following up log:" << std::endl; + while (!sigintReceived) { + sizeWritten = read(socket, buffer.data(), BUFFER_SIZE); + if (sizeWritten < 0 && errno != EAGAIN) { + if (errno != EINTR) + std::cout << "Couldn't read (5) " << strerror(errno) << ":" << errno << std::endl; + close(socket); + return 5; + } + + if (sizeWritten == 0) + break; + + if (sizeWritten > 0) { + std::cout << std::string(buffer.data(), sizeWritten); + buffer.fill('\0'); + } + + usleep(100000); + } + close(socket); + return 0; +} + +int request(std::string arg, int minArgs = 0, bool needRoll = false) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + auto t = timeval{.tv_sec = 0, .tv_usec = 100000}; + setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval)); + const auto ARGS = std::count(arg.begin(), arg.end(), ' '); if (ARGS < minArgs) { - log("Not enough arguments, expected at least " + minArgs); + log(std::format("Not enough arguments in '{}', expected at least {}", arg, minArgs)); return -1; } @@ -141,6 +182,9 @@ int request(std::string arg, int minArgs = 0) { return 4; } + if (needRoll) + return rollingRead(SERVERSOCKET); + std::string reply = ""; char buffer[8192] = {0}; @@ -284,6 +328,7 @@ int main(int argc, char** argv) { std::string fullArgs = ""; const auto ARGS = splitArgs(argc, argv); bool json = false; + bool needRoll = false; std::string overrideInstance = ""; for (std::size_t i = 0; i < ARGS.size(); ++i) { @@ -303,6 +348,9 @@ int main(int argc, char** argv) { fullArgs += "a"; } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) { fullArgs += "c"; + } else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) { + fullArgs += "f"; + needRoll = true; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") { @@ -362,6 +410,11 @@ int main(int argc, char** argv) { return 0; } + if (needRoll && !fullRequest.contains("/rollinglog")) { + log("only 'rollinglog' command supports '--follow' option"); + return 1; + } + if (overrideInstance.contains("_")) instanceSignature = overrideInstance; else if (!overrideInstance.empty()) { @@ -421,6 +474,8 @@ int main(int argc, char** argv) { exitStatus = request(fullRequest, 1); else if (fullRequest.contains("/--help")) std::cout << USAGE << std::endl; + else if (fullRequest.contains("/rollinglog") && needRoll) + exitStatus = request(fullRequest, 0, true); else { exitStatus = request(fullRequest); } diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index a7e714bd..70b886f2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -28,6 +28,7 @@ using namespace Hyprutils::String; #include "../devices/IKeyboard.hpp" #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" +#include "debug/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" @@ -1732,6 +1733,46 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) { return getReply(input); } +bool successWrite(int fd, const std::string& data, bool needLog = true) { + if (write(fd, data.c_str(), data.length()) > 0) + return true; + + if (errno == EAGAIN) + return true; + + if (needLog) + Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); + + return false; +} + +void runWritingDebugLogThread(const int conn) { + using namespace std::chrono_literals; + Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn); + //will be finished, when reading side close connection + std::thread([conn]() { + while (Debug::RollingLogFollow::Get().IsRunning()) { + if (Debug::RollingLogFollow::Get().isEmpty(conn)) { + std::this_thread::sleep_for(1000ms); + continue; + } + + auto line = Debug::RollingLogFollow::Get().GetLog(conn); + if (!successWrite(conn, line)) + // We cannot write, when connection is closed. So thread will successfully exit by itself + break; + + std::this_thread::sleep_for(100ms); + } + close(conn); + Debug::RollingLogFollow::Get().StopFor(conn); + }).detach(); +} + +bool isFollowUpRollingLogRequest(const std::string& request) { + return request.contains("rollinglog") && request.contains("f"); +} + int hyprCtlFDTick(int fd, uint32_t mask, void* data) { if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP) return 0; @@ -1775,9 +1816,15 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) { reply = "Err: " + std::string(e.what()); } - write(ACCEPTEDCONNECTION, reply.c_str(), reply.length()); + successWrite(ACCEPTEDCONNECTION, reply); - close(ACCEPTEDCONNECTION); + if (isFollowUpRollingLogRequest(request)) { + Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket."); + Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION); + runWritingDebugLogThread(ACCEPTEDCONNECTION); + Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo()); + } else + close(ACCEPTEDCONNECTION); if (g_pConfigManager->m_bWantsMonitorReload) g_pConfigManager->ensureMonitorStatus(); diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 8b82c852..7547204a 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -1,6 +1,7 @@ #include "Log.hpp" #include "../defines.hpp" #include "../Compositor.hpp" +#include "RollingLogFollow.hpp" #include #include @@ -73,6 +74,9 @@ void Debug::log(LogLevel level, std::string str) { if (rollingLog.size() > ROLLING_LOG_SIZE) rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE); + if (RollingLogFollow::Get().IsRunning()) + RollingLogFollow::Get().AddLog(str); + if (!disableLogs || !**disableLogs) { // log to a file std::ofstream ofs; diff --git a/src/debug/RollingLogFollow.hpp b/src/debug/RollingLogFollow.hpp new file mode 100644 index 00000000..5ff018af --- /dev/null +++ b/src/debug/RollingLogFollow.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +namespace Debug { + struct RollingLogFollow { + std::unordered_map socketToRollingLogFollowQueue; + std::shared_mutex m; + bool running = false; + static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; + + // Returns true if the queue is empty for the given socket + bool isEmpty(int socket) { + std::shared_lock r(m); + return socketToRollingLogFollowQueue[socket].empty(); + } + + std::string DebugInfo() { + std::shared_lock r(m); + return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size()); + } + + std::string GetLog(int socket) { + std::unique_lock w(m); + + const std::string ret = socketToRollingLogFollowQueue[socket]; + socketToRollingLogFollowQueue[socket] = ""; + + return ret; + }; + + void AddLog(std::string log) { + std::unique_lock w(m); + running = true; + std::vector to_erase; + for (const auto& p : socketToRollingLogFollowQueue) + socketToRollingLogFollowQueue[p.first] += log + "\n"; + } + + bool IsRunning() { + std::shared_lock r(m); + return running; + } + + void StopFor(int socket) { + std::unique_lock w(m); + socketToRollingLogFollowQueue.erase(socket); + if (socketToRollingLogFollowQueue.empty()) + running = false; + } + + void StartFor(int socket) { + std::unique_lock w(m); + socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); + running = true; + } + + static RollingLogFollow& Get() { + static RollingLogFollow instance; + static std::mutex gm; + std::lock_guard lock(gm); + return instance; + }; + }; +} From a9d53a2252f7ec084e2487d18777e2df01c8c351 Mon Sep 17 00:00:00 2001 From: UjinT34 <41110182+UjinT34@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:45:32 +0300 Subject: [PATCH 30/51] vrr: add option to fix mouse breaking vrr (#6483) * option to fix mouse breaking vrr * skip damage on mouse move * remove this-> & cleanup * add cursor:min_refresh_rate to avoid cursor freezing * run clang-format --------- Co-authored-by: UjinT34 --- src/config/ConfigManager.cpp | 2 ++ src/helpers/Monitor.cpp | 18 ++++++++++++++++++ src/helpers/Monitor.hpp | 1 + src/managers/PointerManager.cpp | 2 +- src/managers/input/InputManager.cpp | 6 ++++-- src/render/Renderer.cpp | 5 +++-- src/render/Renderer.hpp | 2 +- 7 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index e0de33cf..f63ff552 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -522,6 +522,8 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2}); m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:no_break_fs_vrr", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:min_refresh_rate", Hyprlang::INT{24}); m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1}); m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 027b47bd..58687e09 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -362,6 +362,24 @@ void CMonitor::addDamage(const CBox* box) { g_pCompositor->scheduleFrameForMonitor(this); } +bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { + static auto PNOBREAK = CConfigValue("cursor:no_break_fs_vrr"); + static auto PMINRR = CConfigValue("cursor:min_refresh_rate"); + + // skip scheduling extra frames for fullsreen apps with vrr + bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && + activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL; + + // keep requested minimum refresh rate + if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { + // damage whole screen because some previous cursor box damages were skipped + wlr_damage_ring_add_whole(&damage); + return false; + } + + return shouldSkip; +} + bool CMonitor::isMirror() { return pMirrorOf != nullptr; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 4bfbf53c..c59e00ac 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -158,6 +158,7 @@ class CMonitor { void addDamage(const pixman_region32_t* rg); void addDamage(const CRegion* rg); void addDamage(const CBox* box); + bool shouldSkipScheduleFrameOnMouseEvent(); void setMirror(const std::string&); bool isMirror(); bool matchesStaticSelector(const std::string& selector) const; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index bf7b5d0a..3a28ea8d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -675,7 +675,7 @@ void CPointerManager::damageIfSoftware() { continue; if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) { - g_pHyprRenderer->damageBox(&b); + g_pHyprRenderer->damageBox(&b, mw->monitor->shouldSkipScheduleFrameOnMouseEvent()); break; } } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 3aa8d2ae..81a46f97 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -187,7 +187,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (*PZOOMFACTOR != 1.f) g_pHyprRenderer->damageMonitor(PMONITOR); - if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0) + bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent(); + + if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(PMONITOR); PHLWINDOW forcedFocus = m_pForcedFocus.lock(); @@ -370,7 +372,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { foundSurface = g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface); - if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0) + if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule) g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get()); // grabs diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4fe35c7e..19b646a4 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1763,7 +1763,7 @@ void CHyprRenderer::damageMonitor(CMonitor* pMonitor) { Debug::log(LOG, "Damage: Monitor {}", pMonitor->szName); } -void CHyprRenderer::damageBox(CBox* pBox) { +void CHyprRenderer::damageBox(CBox* pBox, bool skipFrameSchedule) { if (g_pCompositor->m_bUnsafeState) return; @@ -1773,7 +1773,8 @@ void CHyprRenderer::damageBox(CBox* pBox) { CBox damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; damageBox.scale(m->scale); - m->addDamage(&damageBox); + if (!skipFrameSchedule) + m->addDamage(&damageBox); } static auto PLOGDAMAGE = CConfigValue("debug:log_damage"); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 60101e87..6adca72a 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -48,7 +48,7 @@ class CHyprRenderer { void arrangeLayersForMonitor(const int&); void damageSurface(SP, double, double, double scale = 1.0); void damageWindow(PHLWINDOW, bool forceFull = false); - void damageBox(CBox*); + void damageBox(CBox*, bool skipFrameSchedule = false); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageRegion(const CRegion&); void damageMonitor(CMonitor*); From a357fa3e0a60b4f96a1924e0d9753d23001ab00e Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 16:45:41 +0200 Subject: [PATCH 31/51] window: use effective damage for tearing re-schedules fixes #6377 --- src/events/Windows.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index 899318ce..becff152 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -803,7 +803,7 @@ void Events::listener_commitWindow(void* owner, void* data) { // tearing: if solitary, redraw it. This still might be a single surface window const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID); if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.buffer) { - CRegion damageBox{PWINDOW->m_pWLSurface->resource()->current.bufferDamage}; + CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()}; if (!damageBox.empty()) { if (PMONITOR->tearingState.busy) { From 12ce06f39b2194685ddeadf656ebf2d334836992 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 19:10:12 +0200 Subject: [PATCH 32/51] format: fix flipped r/b channels on legacy_renderer We don't wanna use an extension, but for gles2 there is no other option. fixes #6465 --- src/helpers/Format.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 9c94f68b..65828519 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -11,9 +11,13 @@ */ inline const std::vector GLES3_FORMATS = { { - .drmFormat = DRM_FORMAT_ARGB8888, - .flipRB = true, - .glFormat = GL_RGBA, + .drmFormat = DRM_FORMAT_ARGB8888, + .flipRB = true, +#ifndef GLES2 + .glFormat = GL_RGBA, +#else + .glFormat = GL_BGRA_EXT, +#endif .glType = GL_UNSIGNED_BYTE, .withAlpha = true, .alphaStripped = DRM_FORMAT_XRGB8888, @@ -22,7 +26,11 @@ inline const std::vector GLES3_FORMATS = { { .drmFormat = DRM_FORMAT_XRGB8888, .flipRB = true, - .glFormat = GL_RGBA, +#ifndef GLES2 + .glFormat = GL_RGBA, +#else + .glFormat = GL_BGRA_EXT, +#endif .glType = GL_UNSIGNED_BYTE, .withAlpha = false, .alphaStripped = DRM_FORMAT_XRGB8888, From 2f278dc883f3e4e84fb1d18154132f8f4efe42cf Mon Sep 17 00:00:00 2001 From: Vaxry Date: Fri, 14 Jun 2024 21:59:21 +0200 Subject: [PATCH 33/51] egl: fixup format modifier lookups with implicit modifiers ref #6485 --- src/helpers/Format.cpp | 4 ++-- src/render/OpenGL.cpp | 32 ++++++++++++++++++++++---------- src/render/OpenGL.hpp | 4 +++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/helpers/Format.cpp b/src/helpers/Format.cpp index 65828519..08c3ca63 100644 --- a/src/helpers/Format.cpp +++ b/src/helpers/Format.cpp @@ -24,8 +24,8 @@ inline const std::vector GLES3_FORMATS = { .bytesPerBlock = 4, }, { - .drmFormat = DRM_FORMAT_XRGB8888, - .flipRB = true, + .drmFormat = DRM_FORMAT_XRGB8888, + .flipRB = true, #ifndef GLES2 .glFormat = GL_RGBA, #else diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 406ffdd0..5d8d6b83 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -79,20 +79,20 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_tGlobalTimer.reset(); } -std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { +std::optional> CHyprOpenGLImpl::getModsForFormat(EGLint format) { // TODO: return std::expected when clang supports it if (!m_sExts.EXT_image_dma_buf_import_modifiers) - return {}; + return std::nullopt; EGLint len = 0; if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) { Debug::log(ERR, "EGL: Failed to query mods"); - return {}; + return std::nullopt; } if (len <= 0) - return {DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID}; // assume the driver can do linear and implicit. + return std::vector{}; std::vector mods; std::vector external; @@ -103,13 +103,21 @@ std::vector CHyprOpenGLImpl::getModsForFormat(EGLint format) { m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len); std::vector result; + bool linearIsExternal = false; for (size_t i = 0; i < mods.size(); ++i) { - if (external.at(i)) + if (external.at(i)) { + if (mods.at(i) == DRM_FORMAT_MOD_LINEAR) + linearIsExternal = true; continue; + } result.push_back(mods.at(i)); } + // if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia) + if (!linearIsExternal && std::find(mods.begin(), mods.end(), DRM_FORMAT_MOD_LINEAR) == mods.end() && mods.size() == 0) + mods.push_back(DRM_FORMAT_MOD_LINEAR); + return result; } @@ -147,15 +155,19 @@ void CHyprOpenGLImpl::initDRMFormats() { for (auto& fmt : formats) { std::vector mods; - if (!DISABLE_MODS) - mods = getModsForFormat(fmt); - else + if (!DISABLE_MODS) { + auto ret = getModsForFormat(fmt); + if (!ret.has_value()) + continue; + + mods = *ret; + } else mods = {DRM_FORMAT_MOD_LINEAR}; m_bHasModifiers = m_bHasModifiers || mods.size() > 0; - if (mods.size() == 0) - continue; + // EGL can always do implicit modifiers. + mods.push_back(DRM_FORMAT_MOD_INVALID); dmaFormats.push_back(SDRMFormat{ .format = fmt, diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index db0f8ea1..c6e173e5 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -238,7 +238,9 @@ class CHyprOpenGLImpl { void createBGTextureForMonitor(CMonitor*); void initShaders(); void initDRMFormats(); - std::vector getModsForFormat(EGLint format); + + // + std::optional> getModsForFormat(EGLint format); // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, CRegion* damage); From cb63398f079b4b4324c04e2e41ba17983d66487c Mon Sep 17 00:00:00 2001 From: vaxerski Date: Fri, 14 Jun 2024 20:00:53 +0000 Subject: [PATCH 34/51] [gha] Nix: update inputs --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 477db69b..94fc9d90 100644 --- a/flake.lock +++ b/flake.lock @@ -13,11 +13,11 @@ ] }, "locked": { - "lastModified": 1717181720, - "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=", + "lastModified": 1718368322, + "narHash": "sha256-VfMg3RsnRLQzbq0hFIh1dCM09b5C/F/qPFUOgU/CRi0=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c", + "rev": "dd3a853c8239d1c3f3f37de7d2b8ae4b4f3840df", "type": "github" }, "original": { @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1717881334, - "narHash": "sha256-a0inRgJhPL6v9v7RPM/rx1kbXdfe3xJA1c9z0ZkYnh4=", + "lastModified": 1718271409, + "narHash": "sha256-8KvVqtApNt4FWTdn1TqVvw00rpqyG9UuUPA2ilPVD1U=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "0693f9398ab693d89c9a0aa3b3d062dd61b7a60e", + "rev": "8e10e0626fb26a14b859b3811b6ed7932400c86e", "type": "github" }, "original": { @@ -110,11 +110,11 @@ ] }, "locked": { - "lastModified": 1717784906, - "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=", + "lastModified": 1718119275, + "narHash": "sha256-nqDYXATNkyGXVmNMkT19fT4sjtSPBDS1LLOxa3Fueo4=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d", + "rev": "1419520d5f7f38d35e05504da5c1b38212a38525", "type": "github" }, "original": { @@ -125,11 +125,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1717974879, - "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=", + "lastModified": 1718318537, + "narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3", + "rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420", "type": "github" }, "original": { @@ -179,11 +179,11 @@ ] }, "locked": { - "lastModified": 1717918856, - "narHash": "sha256-I38bmPLqamvOfVSArd1hhZtkVRAYBK38fOHZCU1P9Qg=", + "lastModified": 1718272114, + "narHash": "sha256-KsX7sAwkEFpXiwyjt0HGTnnrUU58wW1jlzj5IA/LRz8=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "72907822c19afc0983c69d59d299204381623725", + "rev": "24be4a26f0706e456fca1b61b8c79f7486a9e86d", "type": "github" }, "original": { From df0c014ba0c9c665df51fe7750ab9d7288b57478 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:06:02 +0200 Subject: [PATCH 35/51] xwayland: use safeRemove for removing files fixes #6514 --- src/xwayland/Server.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 26010cfb..e2dab412 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -155,6 +155,14 @@ static int xwaylandReady(int fd, uint32_t mask, void* data) { return g_pXWayland->pServer->ready(fd, mask); } +static bool safeRemove(const std::string& path) { + try { + return std::filesystem::remove(path); + } catch (std::exception& e) { Debug::log(ERR, "[XWayland] failed to remove {}", path); } + + return false; +} + bool CXWaylandServer::tryOpenSockets() { for (size_t i = 0; i <= 32; ++i) { auto LOCK = std::format("/tmp/.X{}-lock", i); @@ -162,7 +170,7 @@ bool CXWaylandServer::tryOpenSockets() { if (int fd = open(LOCK.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0444); fd >= 0) { // we managed to open the lock if (!openSockets(xFDs, i)) { - std::filesystem::remove(LOCK); + safeRemove(LOCK); close(fd); continue; } @@ -170,7 +178,7 @@ bool CXWaylandServer::tryOpenSockets() { const auto PIDSTR = std::format("{}", getpid()); if (write(fd, PIDSTR.c_str(), PIDSTR.length()) != (long)PIDSTR.length()) { - std::filesystem::remove(LOCK); + safeRemove(LOCK); close(fd); continue; } @@ -197,7 +205,7 @@ bool CXWaylandServer::tryOpenSockets() { } catch (...) { continue; } if (kill(pid, 0) != 0 && errno == ESRCH) { - if (!std::filesystem::remove(LOCK)) + if (!safeRemove(LOCK)) continue; i--; @@ -228,7 +236,7 @@ CXWaylandServer::~CXWaylandServer() { close(xFDs[1]); auto LOCK = std::format("/tmp/.X{}-lock", display); - std::filesystem::remove(LOCK); + safeRemove(LOCK); std::string path; #ifdef __linux__ @@ -236,7 +244,7 @@ CXWaylandServer::~CXWaylandServer() { #else path = std::format("/tmp/.X11-unix/X{}_", display); #endif - std::filesystem::remove(path); + safeRemove(path); } void CXWaylandServer::die() { From 32aca887522063cf728357af247ca6f20d93eb97 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:20:00 +0200 Subject: [PATCH 36/51] keybinds: add custom event dispatcher fixes #3439 --- src/managers/KeybindManager.cpp | 5 +++++ src/managers/KeybindManager.hpp | 1 + 2 files changed, 6 insertions(+) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 49ea39a3..eb07850c 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -114,6 +114,7 @@ CKeybindManager::CKeybindManager() { m_mDispatchers["movewindoworgroup"] = moveWindowOrGroup; m_mDispatchers["setignoregrouplock"] = setIgnoreGroupLock; m_mDispatchers["denywindowfromgroup"] = denyWindowFromGroup; + m_mDispatchers["event"] = event; m_mDispatchers["global"] = global; m_tScrollTimer.reset(); @@ -2680,3 +2681,7 @@ void CKeybindManager::moveGroupWindow(std::string args) { PLASTWINDOW->updateWindowDecos(); } + +void CKeybindManager::event(std::string args) { + g_pEventManager->postEvent(SHyprIPCEvent{"custom", args}); +} diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index ecab6ee1..2a256760 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -205,6 +205,7 @@ class CKeybindManager { static void setIgnoreGroupLock(std::string); static void denyWindowFromGroup(std::string); static void global(std::string); + static void event(std::string); friend class CCompositor; friend class CInputManager; From fb82f6bcd7d829a3ab2d2cb7d9a27f3837abfb80 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 16:31:35 +0200 Subject: [PATCH 37/51] animations: fix overriding direction for slide fixes #6512 --- src/managers/AnimationManager.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/managers/AnimationManager.cpp b/src/managers/AnimationManager.cpp index f8cb0184..74fe4117 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/AnimationManager.cpp @@ -6,6 +6,7 @@ #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" #include "eventLoop/EventLoopManager.hpp" +#include "../helpers/varlist/VarList.hpp" int wlTick(SP self, void* data) { if (g_pAnimationManager) @@ -396,6 +397,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { auto ANIMSTYLE = pWindow->m_vRealPosition.m_pConfig->pValues->internalStyle; transform(ANIMSTYLE.begin(), ANIMSTYLE.end(), ANIMSTYLE.begin(), ::tolower); + CVarList animList(ANIMSTYLE, 0, 's'); + // if the window is not being animated, that means the layout set a fixed size for it, don't animate. if (!pWindow->m_vRealPosition.isBeingAnimated() && !pWindow->m_vRealSize.isBeingAnimated()) return; @@ -407,12 +410,8 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { if (pWindow->m_sAdditionalConfigData.animationStyle != "") { // the window has config'd special anim if (pWindow->m_sAdditionalConfigData.animationStyle.starts_with("slide")) { - if (pWindow->m_sAdditionalConfigData.animationStyle.contains(' ')) { - // has a direction - animationSlide(pWindow, pWindow->m_sAdditionalConfigData.animationStyle.substr(pWindow->m_sAdditionalConfigData.animationStyle.find(' ') + 1), close); - } else { - animationSlide(pWindow, "", close); - } + CVarList animList2(pWindow->m_sAdditionalConfigData.animationStyle, 0, 's'); + animationSlide(pWindow, animList2[1], close); } else { // anim popin, fallback @@ -429,9 +428,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { animationPopin(pWindow, close, minPerc / 100.f); } } else { - if (ANIMSTYLE == "slide") { - animationSlide(pWindow, "", close); - } else { + if (animList[0] == "slide") + animationSlide(pWindow, animList[1], close); + else { // anim popin, fallback float minPerc = 0.f; @@ -451,9 +450,9 @@ void CAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { std::string CAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { - if (style == "slide") { + if (style.starts_with("slide")) return ""; - } else if (style.starts_with("popin")) { + else if (style.starts_with("popin")) { // try parsing float minPerc = 0.f; if (style.find("%") != std::string::npos) { From 46ef6653be90f1a3e2a8cecc1fd9112dc3c6f464 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:33:21 +0200 Subject: [PATCH 38/51] data-device: abort drag on unaccepted offers fixes #6509 --- src/protocols/core/DataDevice.cpp | 28 ++++++++++++++++++++++++++-- src/protocols/core/DataDevice.hpp | 1 + 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index c1de8f83..86b372bf 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -13,13 +13,17 @@ CWLDataOfferResource::CWLDataOfferResource(SP resource_, SPsetDestroy([this](CWlDataOffer* r) { - if (!dead) + if (!dead && (recvd || accepted)) PROTO::data->completeDrag(); + else + PROTO::data->abortDrag(); PROTO::data->destroyResource(this); }); resource->setOnDestroy([this](CWlDataOffer* r) { - if (!dead) + if (!dead && (recvd || accepted)) PROTO::data->completeDrag(); + else + PROTO::data->abortDrag(); PROTO::data->destroyResource(this); }); @@ -592,6 +596,11 @@ void CWLDataDeviceProtocol::dropDrag() { return; } + if (!wasDragSuccessful()) { + abortDrag(); + return; + } + dnd.currentSource->sendDndDropPerformed(); dnd.focusedDevice->sendDrop(); dnd.focusedDevice->sendLeave(); @@ -603,6 +612,21 @@ void CWLDataDeviceProtocol::dropDrag() { dnd.overriddenCursor = false; } +bool CWLDataDeviceProtocol::wasDragSuccessful() { + if (!dnd.focusedDevice || !dnd.currentSource) + return false; + + for (auto& o : m_vOffers) { + if (o->dead || !o->source || !o->source->hasDnd()) + continue; + + if (o->recvd || o->accepted) + return true; + } + + return false; +} + void CWLDataDeviceProtocol::completeDrag() { resetDndState(); diff --git a/src/protocols/core/DataDevice.hpp b/src/protocols/core/DataDevice.hpp index f31725ee..5b31559f 100644 --- a/src/protocols/core/DataDevice.hpp +++ b/src/protocols/core/DataDevice.hpp @@ -175,6 +175,7 @@ class CWLDataDeviceProtocol : public IWaylandProtocol { void dropDrag(); void completeDrag(); void resetDndState(); + bool wasDragSuccessful(); // SP dataDeviceForClient(wl_client*); From 6c24dc0bb147d60cc5c7e44cc3e257a737ead828 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:43:39 +0200 Subject: [PATCH 39/51] xdg-shell: fixup xdg-positioner's pointForAnchor with non-corner points fixes #6157 --- src/protocols/XDGShell.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index dcbc6162..49b7b417 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -507,12 +507,12 @@ CXDGPositionerRules::CXDGPositionerRules(SP positioner) state = positioner->state; } -static Vector2D pointForAnchor(const CBox& box, xdgPositionerAnchor anchor) { +static Vector2D pointForAnchor(const CBox& box, const Vector2D& predictionSize, xdgPositionerAnchor anchor) { switch (anchor) { - case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F, 0}; - case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F, box.size().y}; - case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F}; - case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F}; + case XDG_POSITIONER_ANCHOR_TOP: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, 0}; + case XDG_POSITIONER_ANCHOR_BOTTOM: return box.pos() + Vector2D{box.size().x / 2.F - predictionSize.x / 2.F, box.size().y}; + case XDG_POSITIONER_ANCHOR_LEFT: return box.pos() + Vector2D{0, box.size().y / 2.F - predictionSize.y / 2.F}; + case XDG_POSITIONER_ANCHOR_RIGHT: return box.pos() + Vector2D{box.size().x, box.size().y / 2.F - predictionSize.y / 2.F}; case XDG_POSITIONER_ANCHOR_TOP_LEFT: return box.pos(); case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT: return box.pos() + Vector2D{0, box.size().y}; case XDG_POSITIONER_ANCHOR_TOP_RIGHT: return box.pos() + Vector2D{box.size().x, 0}; @@ -527,7 +527,7 @@ CBox CXDGPositionerRules::getPosition(const CBox& constraint, const Vector2D& pa Debug::log(LOG, "GetPosition with constraint {} {} and parent {}", constraint.pos(), constraint.size(), parentCoord); - CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.anchor) + state.offset, state.requestedSize}; + CBox predictedBox = {parentCoord + constraint.pos() + pointForAnchor(state.anchorRect, state.requestedSize, state.anchor) + state.offset, state.requestedSize}; bool success = predictedBox.inside(constraint); From 77f44bfcab6c3e553d26a776c011613efbfe6cfd Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 17:56:44 +0200 Subject: [PATCH 40/51] output: avoid crashes when binding a defunct wl_output global ref #6508 --- src/protocols/core/Output.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 90358fa5..10daa15e 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -9,6 +9,9 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni pClient = resource->client(); + if (!monitor) + return; + resource->setOnDestroy([this](CWlOutput* r) { if (monitor && PROTO::outputs.contains(monitor->szName)) PROTO::outputs.at(monitor->szName)->destroyResource(this); @@ -69,6 +72,9 @@ CWLOutputProtocol::CWLOutputProtocol(const wl_interface* iface, const int& ver, } void CWLOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + if (defunct) + Debug::log(WARN, "[wl_output] Binding a wl_output that's inert?? Possible client bug."); + const auto RESOURCE = m_vOutputs.emplace_back(makeShared(makeShared(client, ver, id), monitor.lock())); if (!RESOURCE->good()) { From 91fe58f8f278d126852877eadc87c50ca7b9b78d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 18:20:09 +0200 Subject: [PATCH 41/51] window: improve swallowing functionality cleanups, fixes, etc. ref #6095 --- src/desktop/Window.cpp | 55 +++++++++++++++++++++++++++++++++ src/desktop/Window.hpp | 1 + src/events/Windows.cpp | 69 +++++------------------------------------- 3 files changed, 63 insertions(+), 62 deletions(-) diff --git a/src/desktop/Window.cpp b/src/desktop/Window.cpp index b02a53e0..d153b344 100644 --- a/src/desktop/Window.cpp +++ b/src/desktop/Window.cpp @@ -1540,3 +1540,58 @@ void CWindow::warpCursor() { else g_pCompositor->warpCursorTo(middle()); } + +PHLWINDOW CWindow::getSwallower() { + static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); + static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); + static auto PSWALLOW = CConfigValue("misc:enable_swallow"); + + if (!*PSWALLOW || (*PSWALLOWREGEX).empty()) + return nullptr; + + // check parent + std::vector candidates; + pid_t currentPid = getPID(); + // walk up the tree until we find someone, 25 iterations max. + for (size_t i = 0; i < 25; ++i) { + currentPid = getPPIDof(currentPid); + + if (!currentPid) + break; + + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->isHidden()) + continue; + + if (w->getPID() == currentPid) + candidates.push_back(w); + } + } + + if (!(*PSWALLOWREGEX).empty()) + std::erase_if(candidates, [&](const auto& other) { return !std::regex_match(other->m_szClass, std::regex(*PSWALLOWREGEX)); }); + + if (candidates.size() <= 0) + return nullptr; + + if (!(*PSWALLOWEXREGEX).empty()) + std::erase_if(candidates, [&](const auto& other) { return std::regex_match(other->m_szTitle, std::regex(*PSWALLOWEXREGEX)); }); + + if (candidates.size() <= 0) + return nullptr; + + if (candidates.size() == 1) + return candidates.at(0); + + // walk up the focus history and find the last focused + for (auto& w : g_pCompositor->m_vWindowFocusHistory) { + if (!w) + continue; + + if (std::find(candidates.begin(), candidates.end(), w.lock()) != candidates.end()) + return w.lock(); + } + + // if none are found (??) then just return the first one + return candidates.at(0); +} diff --git a/src/desktop/Window.hpp b/src/desktop/Window.hpp index 85c74622..16bf297c 100644 --- a/src/desktop/Window.hpp +++ b/src/desktop/Window.hpp @@ -450,6 +450,7 @@ class CWindow { std::string fetchTitle(); std::string fetchClass(); void warpCursor(); + PHLWINDOW getSwallower(); // listeners void onAck(uint32_t serial); diff --git a/src/events/Windows.cpp b/src/events/Windows.cpp index becff152..d37ba12b 100644 --- a/src/events/Windows.cpp +++ b/src/events/Windows.cpp @@ -44,7 +44,6 @@ void Events::listener_mapWindow(void* owner, void* data) { static auto PDIMSTRENGTH = CConfigValue("decoration:dim_strength"); static auto PSWALLOW = CConfigValue("misc:enable_swallow"); static auto PSWALLOWREGEX = CConfigValue("misc:swallow_regex"); - static auto PSWALLOWEXREGEX = CConfigValue("misc:swallow_exception_regex"); static auto PNEWTAKESOVERFS = CConfigValue("misc:new_window_takes_over_fullscreen"); static auto PINITIALWSTRACKING = CConfigValue("misc:initial_workspace_tracking"); @@ -527,71 +526,17 @@ void Events::listener_mapWindow(void* owner, void* data) { // verify swallowing if (*PSWALLOW && std::string{*PSWALLOWREGEX} != STRVAL_EMPTY) { - // don't swallow ourselves - std::regex rgx(*PSWALLOWREGEX); - if (!std::regex_match(PWINDOW->m_szClass, rgx)) { - // check parent - int ppid = getPPIDof(PWINDOW->getPID()); + const auto SWALLOWER = PWINDOW->getSwallower(); - int curppid = 0; + if (SWALLOWER) { + // swallow + PWINDOW->m_pSwallowed = SWALLOWER; - for (int i = 0; i < 5; ++i) { - curppid = getPPIDof(ppid); + g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER); - if (curppid < 10) { - break; - } + SWALLOWER->setHidden(true); - ppid = curppid; - } - - if (ppid) { - // get window by pid - std::vector found; - PHLWINDOW finalFound; - for (auto& w : g_pCompositor->m_vWindows) { - if (!w->m_bIsMapped || w->isHidden()) - continue; - - if (w->getPID() == ppid) { - found.push_back(w); - } - } - - if (found.size() > 1) { - for (auto& w : found) { - // try get the focus, otherwise we'll ignore to avoid swallowing incorrect windows - if (w == PFOCUSEDWINDOWPREV) { - finalFound = w; - break; - } - } - } else if (found.size() == 1) { - finalFound = found[0]; - } - - if (finalFound) { - bool valid = std::regex_match(PWINDOW->m_szClass, rgx); - - if (std::string{*PSWALLOWEXREGEX} != STRVAL_EMPTY) { - std::regex exc(*PSWALLOWEXREGEX); - - valid = valid && !std::regex_match(PWINDOW->m_szTitle, exc); - } - - // check if it's the window we want & not exempt from getting swallowed - if (valid) { - // swallow - PWINDOW->m_pSwallowed = finalFound; - - g_pLayoutManager->getCurrentLayout()->onWindowRemoved(finalFound); - - finalFound->setHidden(true); - - g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); - } - } - } + g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PWINDOW->m_iMonitorID); } } From 89f795da98cc53faf7e3a683d8c189aa24986267 Mon Sep 17 00:00:00 2001 From: memchr Date: Sat, 15 Jun 2024 19:17:38 +0000 Subject: [PATCH 42/51] master: refine master layout new window handling (#6479) * ## Open window relative to active window `new_on_active`: - `none` (default): - `before`: above of the focused window - `after`: below the focused window If the focused window is the solo master window, or the new window replaces master, this option has no effect and new_on_top are respected. ## Refine new window status control **BREAKING CHANGE**: new_is_master removed in favour of new variable `new_status`: - `slave` (default): new window open as slave - `master`: new window open as master - `inherit`: new window inherit status from active window, i.e. when the focused window is master, new window will become new master, otherwise new window are added to slaves * refactor: rename a few variables --- src/config/ConfigManager.cpp | 3 +- src/layout/MasterLayout.cpp | 54 +++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index f63ff552..1b069f5d 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -431,8 +431,9 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("master:special_scale_factor", {1.f}); m_pConfig->addConfigValue("master:mfact", {0.55f}); - m_pConfig->addConfigValue("master:new_is_master", Hyprlang::INT{1}); + m_pConfig->addConfigValue("master:new_status", {"slave"}); m_pConfig->addConfigValue("master:always_center_master", Hyprlang::INT{0}); + m_pConfig->addConfigValue("master:new_on_active", {"none"}); m_pConfig->addConfigValue("master:new_on_top", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:no_gaps_when_only", Hyprlang::INT{0}); m_pConfig->addConfigValue("master:orientation", {"left"}); diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index af0182e1..c5784c74 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -76,17 +76,31 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire if (pWindow->m_bIsFloating) return; - static auto PNEWTOP = CConfigValue("master:new_on_top"); + static auto PNEWONACTIVE = CConfigValue("master:new_on_active"); + static auto PNEWONTOP = CConfigValue("master:new_on_top"); + static auto PNEWSTATUS = CConfigValue("master:new_status"); const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const auto PNODE = *PNEWTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); + const bool BNEWBEFOREACTIVE = *PNEWONACTIVE == "before"; + const bool BNEWISMASTER = *PNEWSTATUS == "master"; + + const auto PNODE = [&]() { + if (*PNEWONACTIVE != "none" && !BNEWISMASTER) { + const auto pLastNode = getNodeFromWindow(g_pCompositor->m_pLastWindow.lock()); + if (pLastNode && !(pLastNode->isMaster && (getMastersOnWorkspace(pWindow->workspaceID()) == 1 || *PNEWSTATUS == "slave"))) { + auto it = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *pLastNode); + if (!BNEWBEFOREACTIVE) + ++it; + return &(*m_lMasterNodesData.emplace(it)); + } + } + return *PNEWONTOP ? &m_lMasterNodesData.emplace_front() : &m_lMasterNodesData.emplace_back(); + }(); PNODE->workspaceID = pWindow->workspaceID(); PNODE->pWindow = pWindow; - static auto PNEWISMASTER = CConfigValue("master:new_is_master"); - const auto WINDOWSONWORKSPACE = getNodesOnWorkspace(PNODE->workspaceID); static auto PMFACT = CConfigValue("master:mfact"); float lastSplitPercent = *PMFACT; @@ -186,13 +200,27 @@ void CHyprMasterLayout::onWindowCreatedTiling(PHLWINDOW pWindow, eDirection dire } } - if ((*PNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) || WINDOWSONWORKSPACE == 1 || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) || - forceDropAsMaster) { - for (auto& nd : m_lMasterNodesData) { - if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { - nd.isMaster = false; - lastSplitPercent = nd.percMaster; - break; + if ((BNEWISMASTER && g_pInputManager->dragMode != MBIND_MOVE) // + || WINDOWSONWORKSPACE == 1 // + || (WINDOWSONWORKSPACE > 2 && !pWindow->m_bFirstMap && OPENINGON->isMaster) // + || forceDropAsMaster // + || (*PNEWSTATUS == "inherit" && OPENINGON && OPENINGON->isMaster && g_pInputManager->dragMode != MBIND_MOVE)) { + + if (BNEWBEFOREACTIVE) { + for (auto& nd : m_lMasterNodesData | std::views::reverse) { + if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { + nd.isMaster = false; + lastSplitPercent = nd.percMaster; + break; + } + } + } else { + for (auto& nd : m_lMasterNodesData) { + if (nd.isMaster && nd.workspaceID == PNODE->workspaceID) { + nd.isMaster = false; + lastSplitPercent = nd.percMaster; + break; + } } } @@ -1440,7 +1468,7 @@ void CHyprMasterLayout::replaceWindowDataWith(PHLWINDOW from, PHLWINDOW to) { } Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { - static auto PNEWISMASTER = CConfigValue("master:new_is_master"); + static auto PNEWSTATUS = CConfigValue("master:new_status"); if (!g_pCompositor->m_pLastMonitor) return {}; @@ -1454,7 +1482,7 @@ Vector2D CHyprMasterLayout::predictSizeForNewWindowTiled() { if (!MASTER) // wtf return {}; - if (*PNEWISMASTER) { + if (*PNEWSTATUS == "master") { return MASTER->size; } else { const auto SLAVES = NODES - getMastersOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspace->m_iID); From 908bec1564e4fe448a2a8a7371bbb0621c62b11a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 21:24:26 +0200 Subject: [PATCH 43/51] wl_seat: send repeat data from current keyboard on bind ref #6515 --- src/protocols/core/Seat.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 331eb15e..8f9174f5 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -200,10 +200,13 @@ CWLKeyboardResource::CWLKeyboardResource(SP resource_, SPsetRelease([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); resource->setOnDestroy([this](CWlKeyboard* r) { PROTO::seat->destroyResource(this); }); - static auto REPEAT = CConfigValue("input:repeat_rate"); - static auto DELAY = CConfigValue("input:repeat_delay"); + if (!g_pSeatManager->keyboard) { + LOGM(ERR, "No keyboard on bound wl_keyboard??"); + return; + } + sendKeymap(g_pSeatManager->keyboard.lock()); - repeatInfo(*REPEAT, *DELAY); + repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay); } bool CWLKeyboardResource::good() { From 1f5fd7e64a1c0e8d1815bdd6d168193bf9c28d6d Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sat, 15 Jun 2024 21:46:36 +0200 Subject: [PATCH 44/51] hyprpm: add --no-shallow --- hyprpm/src/core/PluginManager.cpp | 2 +- hyprpm/src/core/PluginManager.hpp | 3 ++- hyprpm/src/main.cpp | 10 +++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hyprpm/src/core/PluginManager.cpp b/hyprpm/src/core/PluginManager.cpp index e8c6e251..848b9cab 100644 --- a/hyprpm/src/core/PluginManager.cpp +++ b/hyprpm/src/core/PluginManager.cpp @@ -427,7 +427,7 @@ bool CPluginManager::updateHeaders(bool force) { progress.printMessageAbove(std::string{Colors::YELLOW} + "!" + Colors::RESET + " Cloning https://github.com/hyprwm/hyprland, this might take a moment."); - const bool bShallow = HLVER.branch == "main" || HLVER.branch == ""; + const bool bShallow = (HLVER.branch == "main" || HLVER.branch == "") && !m_bNoShallow; // let us give a bit of leg-room for shallowing // due to timezones, etc. diff --git a/hyprpm/src/core/PluginManager.hpp b/hyprpm/src/core/PluginManager.hpp index a87240e3..13ea5b12 100644 --- a/hyprpm/src/core/PluginManager.hpp +++ b/hyprpm/src/core/PluginManager.hpp @@ -58,7 +58,8 @@ class CPluginManager { bool hasDeps(); - bool m_bVerbose = false; + bool m_bVerbose = false; + bool m_bNoShallow = false; // will delete recursively if exists!! bool createSafeDirectory(const std::string& path); diff --git a/hyprpm/src/main.cpp b/hyprpm/src/main.cpp index 38b32c83..4f00f708 100644 --- a/hyprpm/src/main.cpp +++ b/hyprpm/src/main.cpp @@ -26,6 +26,7 @@ const std::string HELP = R"#(┏ hyprpm, a Hyprland Plugin Manager ┣ --help | -h → Show this menu ┣ --verbose | -v → Enable too much logging ┣ --force | -f → Force an operation ignoring checks (e.g. update -f) +┣ --no-shallow | -s → Disable shallow cloning of Hyprland sources ┗ )#"; @@ -41,7 +42,7 @@ int main(int argc, char** argv, char** envp) { } std::vector command; - bool notify = false, verbose = false, force = false; + bool notify = false, verbose = false, force = false, noShallow = false; for (int i = 1; i < argc; ++i) { if (ARGS[i].starts_with("-")) { @@ -52,6 +53,8 @@ int main(int argc, char** argv, char** envp) { notify = true; } else if (ARGS[i] == "--verbose" || ARGS[i] == "-v") { verbose = true; + } else if (ARGS[i] == "--no-shallow" || ARGS[i] == "-s") { + noShallow = true; } else if (ARGS[i] == "--force" || ARGS[i] == "-f") { force = true; std::cout << Colors::RED << "!" << Colors::RESET << " Using --force, I hope you know what you are doing.\n"; @@ -69,8 +72,9 @@ int main(int argc, char** argv, char** envp) { return 0; } - g_pPluginManager = std::make_unique(); - g_pPluginManager->m_bVerbose = verbose; + g_pPluginManager = std::make_unique(); + g_pPluginManager->m_bVerbose = verbose; + g_pPluginManager->m_bNoShallow = noShallow; if (command[0] == "add") { if (command.size() < 2) { From 2566d818848b58b114071f199ffe944609376270 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 12:38:09 +0200 Subject: [PATCH 45/51] xwayland: fixup unfocus atom conditions ref #6468 --- src/xwayland/XSurface.cpp | 2 +- src/xwayland/XWM.cpp | 25 +++++++++++++++++-------- src/xwayland/XWM.hpp | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/xwayland/XSurface.cpp b/src/xwayland/XSurface.cpp index 07cac832..5d25e0e8 100644 --- a/src/xwayland/XSurface.cpp +++ b/src/xwayland/XSurface.cpp @@ -179,7 +179,7 @@ void CXWaylandSurface::configure(const CBox& box) { void CXWaylandSurface::activate(bool activate) { if (overrideRedirect && !activate) return; - g_pXWayland->pWM->activateSurface(self.lock()); + g_pXWayland->pWM->activateSurface(self.lock(), activate); } void CXWaylandSurface::setFullscreen(bool fs) { diff --git a/src/xwayland/XWM.cpp b/src/xwayland/XWM.cpp index 247af4b7..719adcb9 100644 --- a/src/xwayland/XWM.cpp +++ b/src/xwayland/XWM.cpp @@ -394,11 +394,16 @@ void CXWM::focusWindow(SP surf) { if (surf == focusedSurface) return; - auto oldSurf = focusedSurface.lock(); focusedSurface = surf; - if (oldSurf) - sendState(oldSurf); + // send state to all surfaces, sometimes we might lose some + // that could still stick with the focused atom + for (auto& s : mappedSurfaces) { + if (!s) + continue; + + sendState(s.lock()); + } if (!surf) { xcb_set_input_focus_checked(connection, XCB_INPUT_FOCUS_POINTER_ROOT, XCB_NONE, XCB_CURRENT_TIME); @@ -868,13 +873,17 @@ void CXWM::createWMWindow() { xcb_set_selection_owner(connection, wmWindow, HYPRATOMS["_NET_WM_CM_S0"], XCB_CURRENT_TIME); } -void CXWM::activateSurface(SP surf) { - if (surf == focusedSurface || (surf && surf->overrideRedirect)) +void CXWM::activateSurface(SP surf, bool activate) { + if ((surf == focusedSurface && activate) || (surf && surf->overrideRedirect)) return; - setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE); - - focusWindow(surf); + if (!activate || !surf) { + setActiveWindow((uint32_t)XCB_WINDOW_NONE); + focusWindow(nullptr); + } else { + setActiveWindow(surf ? surf->xID : (uint32_t)XCB_WINDOW_NONE); + focusWindow(surf); + } xcb_flush(connection); } diff --git a/src/xwayland/XWM.hpp b/src/xwayland/XWM.hpp index 7f68454c..6456c71b 100644 --- a/src/xwayland/XWM.hpp +++ b/src/xwayland/XWM.hpp @@ -79,7 +79,7 @@ class CXWM { void setActiveWindow(xcb_window_t window); void sendState(SP surf); void focusWindow(SP surf); - void activateSurface(SP surf); + void activateSurface(SP surf, bool activate); bool isWMWindow(xcb_window_t w); void sendWMMessage(SP surf, xcb_client_message_data_t* data, uint32_t mask); From 3eaf35f1e2d984bea89ab1d8a5abbef66243aa5d Mon Sep 17 00:00:00 2001 From: memchr Date: Sun, 16 Jun 2024 13:44:13 +0000 Subject: [PATCH 46/51] hyprland.conf: update master section (#6537) --- example/hyprland.conf | 2 +- src/config/defaultConfig.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/hyprland.conf b/example/hyprland.conf index f0ee8b25..f69309c2 100644 --- a/example/hyprland.conf +++ b/example/hyprland.conf @@ -125,7 +125,7 @@ dwindle { # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more master { - new_is_master = true + new_status = master } # https://wiki.hyprland.org/Configuring/Variables/#misc diff --git a/src/config/defaultConfig.hpp b/src/config/defaultConfig.hpp index dd7df126..98b617d0 100644 --- a/src/config/defaultConfig.hpp +++ b/src/config/defaultConfig.hpp @@ -138,7 +138,7 @@ dwindle { # See https://wiki.hyprland.org/Configuring/Master-Layout/ for more master { - new_is_master = true + new_status = master } # https://wiki.hyprland.org/Configuring/Variables/#misc From 1b5444494d26624804de8f479da3cffb5d480dc6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 16:23:35 +0200 Subject: [PATCH 47/51] seat/dnd: unfocus pointer from surfaces on dnd start GTK is speshyal and requires this for functioning properly. Ugh. It's technically not required by spec, f you gtk. Ref #6509 --- src/managers/SeatManager.cpp | 5 +++++ src/protocols/core/DataDevice.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/managers/SeatManager.cpp b/src/managers/SeatManager.cpp index a58bca72..fc14f0fc 100644 --- a/src/managers/SeatManager.cpp +++ b/src/managers/SeatManager.cpp @@ -191,6 +191,11 @@ void CSeatManager::setPointerFocus(SP surf, const Vector2D& if (state.pointerFocus == surf) return; + if (PROTO::data->dndActive() && surf) { + Debug::log(LOG, "[seatmgr] Refusing pointer focus during an active dnd"); + return; + } + if (!mouse || !mouse->wlr()) { Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set"); return; diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 86b372bf..03c51852 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -542,6 +542,11 @@ void CWLDataDeviceProtocol::initiateDrag(WP currentSource } }); + // unfocus the pointer from the surface, this is part of """standard""" wayland procedure and gtk will freak out if this isn't happening. + // BTW, the spec does NOT require this explicitly... + // Fuck you gtk. + g_pSeatManager->setPointerFocus(nullptr, {}); + // make a new offer, etc updateDrag(); } @@ -638,7 +643,7 @@ void CWLDataDeviceProtocol::completeDrag() { dnd.focusedDevice.reset(); dnd.currentSource.reset(); - g_pSeatManager->resendEnterEvents(); + g_pInputManager->simulateMouseMovement(); } void CWLDataDeviceProtocol::abortDrag() { @@ -657,7 +662,7 @@ void CWLDataDeviceProtocol::abortDrag() { dnd.focusedDevice.reset(); dnd.currentSource.reset(); - g_pSeatManager->resendEnterEvents(); + g_pInputManager->simulateMouseMovement(); } void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { From 43c75f17eb9ce89f90ef443a3ae740a1bdd55d31 Mon Sep 17 00:00:00 2001 From: memchr Date: Sun, 16 Jun 2024 14:42:32 +0000 Subject: [PATCH 48/51] input: add cursor:warp_on_changeworkspace (#6480) * input: add cursor:warp_on_changeworkspace If enabled, warp the cursor to the last focused window on the workspace in the `changeworkspace' dispatcher, except if the cursor is currently on the WLR top layer. Respect persistent warps. * warp_on_change_workspace: check if focused layer is a window. --- src/config/ConfigManager.cpp | 1 + src/managers/KeybindManager.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 1b069f5d..56fdae25 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -529,6 +529,7 @@ CConfigManager::CConfigManager() { m_pConfig->addConfigValue("cursor:inactive_timeout", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:no_warps", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:persistent_warps", Hyprlang::INT{0}); + m_pConfig->addConfigValue("cursor:warp_on_change_workspace", Hyprlang::INT{0}); m_pConfig->addConfigValue("cursor:default_monitor", {STRVAL_EMPTY}); m_pConfig->addConfigValue("cursor:zoom_factor", {1.f}); m_pConfig->addConfigValue("cursor:zoom_rigid", Hyprlang::INT{0}); diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index eb07850c..14fadf02 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1,6 +1,7 @@ #include "../config/ConfigValue.hpp" #include "../devices/IKeyboard.hpp" #include "../managers/SeatManager.hpp" +#include "../protocols/LayerShell.hpp" #include "../protocols/ShortcutsInhibit.hpp" #include "../render/decorations/CHyprGroupBarDecoration.hpp" #include "KeybindManager.hpp" @@ -1087,6 +1088,8 @@ void CKeybindManager::changeworkspace(std::string args) { if (!PMONITORWORKSPACEOWNER) return; + updateRelativeCursorCoords(); + g_pCompositor->setActiveMonitor(PMONITORWORKSPACEOWNER); if (BISWORKSPACECURRENT) { @@ -1115,6 +1118,16 @@ void CKeybindManager::changeworkspace(std::string args) { else g_pInputManager->simulateMouseMovement(); } + + const static auto PWARPONWORKSPACECHANGE = CConfigValue("cursor:warp_on_change_workspace"); + + if (*PWARPONWORKSPACECHANGE) { + auto PLAST = pWorkspaceToChangeTo->getLastFocusedWindow(); + auto HLSurface = CWLSurface::fromResource(g_pSeatManager->state.pointerFocus.lock()); + + if (PLAST && (!HLSurface || HLSurface->getWindow())) + PLAST->warpCursor(); + } } void CKeybindManager::fullscreenActive(std::string args) { From 648ac8a00b0d68a9e3a86e928b30a490870dbed6 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 16:46:15 +0200 Subject: [PATCH 49/51] xdg-shell: properly check for resource version for TILED and SUSPENDED states fixes #6535 --- src/protocols/XDGShell.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 49b7b417..dddc3bca 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -136,10 +136,12 @@ CXDGToplevelResource::CXDGToplevelResource(SP resource_, SPversion() >= 2) { + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_LEFT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_RIGHT); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_TOP); + pendingApply.states.push_back(XDG_TOPLEVEL_STATE_TILED_BOTTOM); + } resource->setSetTitle([this](CXdgToplevel* r, const char* t) { state.title = t; @@ -261,6 +263,9 @@ uint32_t CXDGToplevelResource::setActive(bool active) { } uint32_t CXDGToplevelResource::setSuspeneded(bool sus) { + if (resource->version() < 6) + return owner->scheduleConfigure(); // SUSPENDED is since 6 + bool set = std::find(pendingApply.states.begin(), pendingApply.states.end(), XDG_TOPLEVEL_STATE_SUSPENDED) != pendingApply.states.end(); if (sus == set) From d0a6fa7aa6c3a9d94611130a9213de19a8754d67 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 17:04:10 +0200 Subject: [PATCH 50/51] wl_seat: accomodate for apps late-binding seat resources Sends enter events when an app binds wl_keyboard or wl_pointer later than it should. Fixes some buggy apps. Fixes #6131 --- src/protocols/core/Seat.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 8f9174f5..be05955c 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -98,6 +98,9 @@ CWLPointerResource::CWLPointerResource(SP resource_, SPonSetCursor(owner.lock(), serial, surf ? CWLSurfaceResource::fromResource(surf) : nullptr, {hotX, hotY}); }); + + if (g_pSeatManager->state.pointerFocus && g_pSeatManager->state.pointerFocus->client() == resource->client()) + sendEnter(g_pSeatManager->state.pointerFocus.lock(), {-1, -1} /* Coords don't really matter that much, they will be updated next move */); } bool CWLPointerResource::good() { @@ -207,6 +210,9 @@ CWLKeyboardResource::CWLKeyboardResource(SP resource_, SPkeyboard.lock()); repeatInfo(g_pSeatManager->keyboard->repeatRate, g_pSeatManager->keyboard->repeatDelay); + + if (g_pSeatManager->state.keyboardFocus && g_pSeatManager->state.keyboardFocus->client() == resource->client()) + sendEnter(g_pSeatManager->state.keyboardFocus.lock()); } bool CWLKeyboardResource::good() { From 2031af82fa029aa098357339d502b53c371919d4 Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 16 Jun 2024 17:41:16 +0200 Subject: [PATCH 51/51] wl_data_device: send drop_performed in completeDrag ref #6509 --- src/protocols/core/DataDevice.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/protocols/core/DataDevice.cpp b/src/protocols/core/DataDevice.cpp index 03c51852..e54d3633 100644 --- a/src/protocols/core/DataDevice.cpp +++ b/src/protocols/core/DataDevice.cpp @@ -606,15 +606,15 @@ void CWLDataDeviceProtocol::dropDrag() { return; } - dnd.currentSource->sendDndDropPerformed(); dnd.focusedDevice->sendDrop(); - dnd.focusedDevice->sendLeave(); resetDndState(); if (dnd.overriddenCursor) g_pInputManager->unsetCursorImage(); dnd.overriddenCursor = false; + + g_pInputManager->simulateMouseMovement(); } bool CWLDataDeviceProtocol::wasDragSuccessful() { @@ -638,6 +638,7 @@ void CWLDataDeviceProtocol::completeDrag() { if (!dnd.focusedDevice || !dnd.currentSource) return; + dnd.currentSource->sendDndDropPerformed(); dnd.currentSource->sendDndFinished(); dnd.focusedDevice.reset(); @@ -681,5 +682,5 @@ void CWLDataDeviceProtocol::renderDND(CMonitor* pMonitor, timespec* when) { } bool CWLDataDeviceProtocol::dndActive() { - return dnd.currentSource; + return dnd.currentSource && dnd.mouseButton /* test a member of the state to ensure it's also present */; }