From c7ba4606870200e049ff1537f6a1a2882d1099a9 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 1 Jan 2024 18:19:22 +0100 Subject: [PATCH 01/15] wlroots: update version patches --- CMakeLists.txt | 2 +- subprojects/packagefiles/wlroots-meson-build.patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bedb7bbf..0dbcea09 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ ExternalProject_Add( wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots - PATCH_COMMAND sed -E -i -e "s/(soversion = 13)([^032]|$$)/soversion = 13032/g" meson.build + PATCH_COMMAND sed -E -i -e "s/(soversion = version_minor.to_int() - 5)([^032]|$$)/soversion = 13032/g" meson.build CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> --reconfigure BUILD_COMMAND ninja -C build BUILD_ALWAYS true diff --git a/subprojects/packagefiles/wlroots-meson-build.patch b/subprojects/packagefiles/wlroots-meson-build.patch index fd6f84db..4e911980 100644 --- a/subprojects/packagefiles/wlroots-meson-build.patch +++ b/subprojects/packagefiles/wlroots-meson-build.patch @@ -38,7 +38,7 @@ index 29b103a..0b6e5a4 100644 # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. --soversion = 13 +-soversion = version_minor.to_int() - 5 +soversion = 13032 little_endian = target_machine.endian() == 'little' From 4e0e8d933e8eec460a31e3a811f6f1a2717a1ec1 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 1 Jan 2024 18:26:48 +0100 Subject: [PATCH 02/15] CI: add stalebot --- .github/workflows/stale.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/stale.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..09f7a992 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time. +# +# You can adjust the behavior by modifying this file. +# For more information, see: +# https://github.com/actions/stale +name: Mark stale issues and pull requests + +on: + schedule: + - cron: '26 0 * * *' + +jobs: + stale: + + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - uses: actions/stale@v5 + with: + repo-token: ${{ secrets.STALEBOT_PAT }} + stale-issue-label: 'stale' + stale-pr-label: 'stale' From 0be36cd02d20617010ac3efff198fe7df0d6d07a Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 1 Jan 2024 18:29:03 +0100 Subject: [PATCH 03/15] cmakelists: fix wlroots patch sed --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dbcea09..88e094a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ ExternalProject_Add( wlroots PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots - PATCH_COMMAND sed -E -i -e "s/(soversion = version_minor.to_int() - 5)([^032]|$$)/soversion = 13032/g" meson.build + PATCH_COMMAND sed -E -i -e "s/(soversion = .*$)/soversion = 13032/g" meson.build CONFIGURE_COMMAND meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> && meson setup build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dexamples=false -Drenderers=gles2 $,-Db_sanitize=address,-Db_sanitize=none> --reconfigure BUILD_COMMAND ninja -C build BUILD_ALWAYS true From 37b76cd1caed209e20e0e353671abf6ba4346b42 Mon Sep 17 00:00:00 2001 From: rszyma Date: Mon, 1 Jan 2024 18:29:51 +0100 Subject: [PATCH 04/15] keybinds: fix keys getting stuck + minor refactor & optimizations to keybind handling (#4304) --- src/config/ConfigManager.cpp | 2 +- src/managers/KeybindManager.cpp | 160 ++++++++++++++++++++++---------- src/managers/KeybindManager.hpp | 53 ++++++----- 3 files changed, 142 insertions(+), 73 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index ee198ded..28959128 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -935,7 +935,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v g_pKeybindManager->addKeybind( SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods}); else - g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods}); + g_pKeybindManager->addKeybind(SKeybind{KEY, 0, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods}); } } diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 899003d8..d379a408 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -7,6 +7,7 @@ #include #include +#include #if defined(__linux__) #include #elif defined(__NetBSD__) || defined(__OpenBSD__) @@ -95,7 +96,7 @@ void CKeybindManager::addKeybind(SKeybind kb) { void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) { for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) { if (isNumber(key) && std::stoi(key) > 9) { - const auto KEYNUM = std::stoi(key); + const uint32_t KEYNUM = std::stoi(key); if (it->modmask == mod && it->keycode == KEYNUM) { it = m_lKeybinds.erase(it); @@ -137,6 +138,22 @@ uint32_t CKeybindManager::stringToModMask(std::string mods) { return modMask; } +uint32_t CKeybindManager::keycodeToModifier(xkb_keycode_t keycode) { + switch (keycode - 8) { + case KEY_LEFTMETA: return WLR_MODIFIER_LOGO; + case KEY_RIGHTMETA: return WLR_MODIFIER_LOGO; + case KEY_LEFTSHIFT: return WLR_MODIFIER_SHIFT; + case KEY_RIGHTSHIFT: return WLR_MODIFIER_SHIFT; + case KEY_LEFTCTRL: return WLR_MODIFIER_CTRL; + case KEY_RIGHTCTRL: return WLR_MODIFIER_CTRL; + case KEY_LEFTALT: return WLR_MODIFIER_ALT; + case KEY_RIGHTALT: return WLR_MODIFIER_ALT; + case KEY_CAPSLOCK: return WLR_MODIFIER_CAPS; + case KEY_NUMLOCK: return WLR_MODIFIER_MOD2; + default: return 0; + } +} + void CKeybindManager::updateXKBTranslationState() { if (m_pXKBTranslationState) { xkb_keymap_unref(xkb_state_get_keymap(m_pXKBTranslationState)); @@ -261,8 +278,7 @@ void CKeybindManager::switchToWindow(CWindow* PWINDOWTOCHANGETO) { bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard) { if (!g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) { - m_dPressedKeycodes.clear(); - m_dPressedKeysyms.clear(); + m_dPressedKeys.clear(); return true; } @@ -291,7 +307,13 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard m_uLastCode = KEYCODE; m_uLastMouseCode = 0; - bool mouseBindWasActive = ensureMouseBindState(); + bool mouseBindWasActive = ensureMouseBindState(); + + const auto KEY = SPressedKeyWithMods{ + .keysym = keysym, + .keycode = KEYCODE, + .modmaskAtPressTime = MODS, + }; bool found = false; if (e->state == WL_KEYBOARD_KEY_STATE_PRESSED) { @@ -302,16 +324,13 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard m_pActiveKeybind = nullptr; } - m_dPressedKeycodes.push_back(KEYCODE); - m_dPressedKeysyms.push_back(keysym); + m_dPressedKeys.push_back(KEY); - found = handleKeybinds(MODS, "", keysym, 0, true, e->time_msec) || found; - - found = handleKeybinds(MODS, "", 0, KEYCODE, true, e->time_msec) || found; + found = handleKeybinds(MODS, KEY, true); if (found) shadowKeybinds(keysym, KEYCODE); - } else if (e->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + } else { // key release // clean repeat if (m_pActiveKeybindEventSource) { wl_event_source_remove(m_pActiveKeybindEventSource); @@ -319,12 +338,23 @@ bool CKeybindManager::onKeyEvent(wlr_keyboard_key_event* e, SKeyboard* pKeyboard m_pActiveKeybind = nullptr; } - m_dPressedKeycodes.erase(std::remove(m_dPressedKeycodes.begin(), m_dPressedKeycodes.end(), KEYCODE), m_dPressedKeycodes.end()); - m_dPressedKeysyms.erase(std::remove(m_dPressedKeysyms.begin(), m_dPressedKeysyms.end(), keysym), m_dPressedKeysyms.end()); - - found = handleKeybinds(MODS, "", keysym, 0, false, e->time_msec) || found; - - found = handleKeybinds(MODS, "", 0, KEYCODE, false, e->time_msec) || found; + bool foundInPressedKeys = false; + for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { + if (it->keycode == KEYCODE) { + if (!foundInPressedKeys) { + found = handleKeybinds(MODS, *it, false); + foundInPressedKeys = true; + } + it = m_dPressedKeys.erase(it); + } else { + ++it; + } + } + if (!foundInPressedKeys) { + Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys"); + // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy + found = handleKeybinds(MODS, KEY, false); + } shadowKeybinds(); } @@ -347,14 +377,14 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) { bool found = false; if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_VERTICAL) { if (e->delta < 0) - found = handleKeybinds(MODS, "mouse_down", 0, 0, true, 0); + found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true); else - found = handleKeybinds(MODS, "mouse_up", 0, 0, true, 0); + found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true); } else if (e->source == WLR_AXIS_SOURCE_WHEEL && e->orientation == WLR_AXIS_ORIENTATION_HORIZONTAL) { if (e->delta < 0) - found = handleKeybinds(MODS, "mouse_left", 0, 0, true, 0); + found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true); else - found = handleKeybinds(MODS, "mouse_right", 0, 0, true, 0); + found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true); } if (found) @@ -372,15 +402,40 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) { m_uLastCode = 0; m_uTimeLastMs = e->time_msec; - bool mouseBindWasActive = ensureMouseBindState(); + bool mouseBindWasActive = ensureMouseBindState(); + + const auto KEY_NAME = "mouse:" + std::to_string(e->button); + + const auto KEY = SPressedKeyWithMods{ + .keyName = KEY_NAME, + .modmaskAtPressTime = MODS, + }; if (e->state == WLR_BUTTON_PRESSED) { - found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, true, 0); + m_dPressedKeys.push_back(KEY); + + found = handleKeybinds(MODS, KEY, true); if (found) shadowKeybinds(); } else { - found = handleKeybinds(MODS, "mouse:" + std::to_string(e->button), 0, 0, false, 0); + bool foundInPressedKeys = false; + for (auto it = m_dPressedKeys.begin(); it != m_dPressedKeys.end();) { + if (it->keyName == KEY_NAME) { + if (!foundInPressedKeys) { + found = handleKeybinds(MODS, *it, false); + foundInPressedKeys = true; + } + it = m_dPressedKeys.erase(it); + } else { + ++it; + } + } + if (!foundInPressedKeys) { + Debug::log(ERR, "BUG THIS: key not found in m_dPressedKeys (2)"); + // fallback with wrong `KEY.modmaskAtPressTime`, this can be buggy + found = handleKeybinds(MODS, KEY, false); + } shadowKeybinds(); } @@ -397,15 +452,15 @@ void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) { } void CKeybindManager::onSwitchEvent(const std::string& switchName) { - handleKeybinds(0, "switch:" + switchName, 0, 0, true, 0); + handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:" + switchName}, true); } void CKeybindManager::onSwitchOnEvent(const std::string& switchName) { - handleKeybinds(0, "switch:on:" + switchName, 0, 0, true, 0); + handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:on:" + switchName}, true); } void CKeybindManager::onSwitchOffEvent(const std::string& switchName) { - handleKeybinds(0, "switch:off:" + switchName, 0, 0, true, 0); + handleKeybinds(0, SPressedKeyWithMods{.keyName = "switch:off:" + switchName}, true); } int repeatKeyHandler(void* data) { @@ -424,7 +479,7 @@ int repeatKeyHandler(void* data) { return 0; } -bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& key, const xkb_keysym_t& keysym, const int& keycode, bool pressed, uint32_t time) { +bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { bool found = false; if (g_pCompositor->m_sSeat.exclusiveClient) @@ -441,22 +496,19 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& ((modmask != k.modmask && !k.ignoreMods) || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) continue; - if (!key.empty()) { - if (key != k.key) + if (!key.keyName.empty()) { + if (key.keyName != k.key) continue; - } else if (k.keycode != -1) { - if (keycode != k.keycode) + } else if (k.keycode != 0) { + if (key.keycode != k.keycode) continue; } else { - if (keysym == 0) - continue; // this is a keycode check run - // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - if (keysym != KBKEY && keysym != KBKEYUPPER) + if (key.keysym != KBKEY && key.keysym != KBKEYUPPER) continue; } @@ -468,12 +520,24 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& continue; } - if (!pressed && !k.release && !SPECIALDISPATCHER) { - if (k.nonConsuming) - continue; + if (!pressed) { + // Require mods to be matching when the key was first pressed. + if (key.modmaskAtPressTime != modmask) { + // Handle properly `bindr` where a key is itself a bind mod for example: + // "bindr = SUPER, SUPER_L, exec, $launcher". + // This needs to be handled separately for the above case, because `key.modmaskAtPressTime` is set + // from currently pressed keys as programs see them, but it doesn't yet include the currently + // pressed mod key, which is still being handled internally. + if (keycodeToModifier(key.keycode) == key.modmaskAtPressTime) + continue; - found = true; // suppress the event - continue; + } else if (!k.release && !SPECIALDISPATCHER) { + if (k.nonConsuming) + continue; + + found = true; // suppress the event + continue; + } } const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler); @@ -488,7 +552,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& Debug::log(ERR, "Invalid handler in a keybind! (handler {} does not exist)", k.handler); } else { // call the dispatcher - Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key, keysym); + Debug::log(LOG, "Keybind triggered, calling dispatcher ({}, {}, {})", modmask, key.keyName, key.keysym); m_iPassPressed = (int)pressed; @@ -521,7 +585,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string& return found; } -void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int& doesntHaveCode) { +void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint32_t doesntHaveCode) { // shadow disables keybinds after one has been triggered for (auto& k : m_lKeybinds) { @@ -534,22 +598,20 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int& const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - for (auto& pk : m_dPressedKeysyms) { - if ((pk == KBKEY || pk == KBKEYUPPER)) { + for (auto& pk : m_dPressedKeys) { + if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { shadow = true; - if (pk == doesntHave && doesntHave != 0) { + if (pk.keysym == doesntHave && doesntHave != 0) { shadow = false; break; } } - } - for (auto& pk : m_dPressedKeycodes) { - if (pk == k.keycode) { + if (pk.keycode != 0 && pk.keycode == k.keycode) { shadow = true; - if (pk == doesntHaveCode && doesntHaveCode != 0 && doesntHaveCode != -1) { + if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { shadow = false; break; } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 73997dd6..631b0147 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -12,7 +12,7 @@ class CPluginSystem; struct SKeybind { std::string key = ""; - int keycode = -1; + uint32_t keycode = 0; uint32_t modmask = 0; std::string handler = ""; std::string arg = ""; @@ -36,6 +36,13 @@ enum eFocusWindowMode { MODE_PID }; +struct SPressedKeyWithMods { + std::string keyName = ""; + xkb_keysym_t keysym = 0; + uint32_t keycode = 0; + uint32_t modmaskAtPressTime = 0; +}; + class CKeybindManager { public: CKeybindManager(); @@ -51,8 +58,9 @@ class CKeybindManager { void addKeybind(SKeybind); void removeKeybind(uint32_t, const std::string&); uint32_t stringToModMask(std::string); + uint32_t keycodeToModifier(xkb_keycode_t); void clearKeybinds(); - void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const int& doesntHaveCode = 0); + void shadowKeybinds(const xkb_keysym_t& doesntHave = 0, const uint32_t doesntHaveCode = 0); std::unordered_map> m_mDispatchers; @@ -63,38 +71,37 @@ class CKeybindManager { std::list m_lKeybinds; private: - std::deque m_dPressedKeysyms; - std::deque m_dPressedKeycodes; + std::deque m_dPressedKeys; - inline static std::string m_szCurrentSelectedSubmap = ""; + inline static std::string m_szCurrentSelectedSubmap = ""; - SKeybind* m_pActiveKeybind = nullptr; + SKeybind* m_pActiveKeybind = nullptr; - uint32_t m_uTimeLastMs = 0; - uint32_t m_uLastCode = 0; - uint32_t m_uLastMouseCode = 0; + uint32_t m_uTimeLastMs = 0; + uint32_t m_uLastCode = 0; + uint32_t m_uLastMouseCode = 0; - bool m_bIsMouseBindActive = false; - std::vector m_vPressedSpecialBinds; + bool m_bIsMouseBindActive = false; + std::vector m_vPressedSpecialBinds; - int m_iPassPressed = -1; // used for pass + int m_iPassPressed = -1; // used for pass - CTimer m_tScrollTimer; + CTimer m_tScrollTimer; - bool handleKeybinds(const uint32_t&, const std::string&, const xkb_keysym_t&, const int&, bool, uint32_t); + bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); - bool handleInternalKeybinds(xkb_keysym_t); - bool handleVT(xkb_keysym_t); + bool handleInternalKeybinds(xkb_keysym_t); + bool handleVT(xkb_keysym_t); - xkb_state* m_pXKBTranslationState = nullptr; + xkb_state* m_pXKBTranslationState = nullptr; - void updateXKBTranslationState(); - bool ensureMouseBindState(); + void updateXKBTranslationState(); + bool ensureMouseBindState(); - static bool tryMoveFocusToMonitor(CMonitor* monitor); - static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = ""); - static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection); - static void switchToWindow(CWindow* PWINDOWTOCHANGETO); + static bool tryMoveFocusToMonitor(CMonitor* monitor); + static void moveWindowOutOfGroup(CWindow* pWindow, const std::string& dir = ""); + static void moveWindowIntoGroup(CWindow* pWindow, CWindow* pWindowInDirection); + static void switchToWindow(CWindow* PWINDOWTOCHANGETO); // -------------- Dispatchers -------------- // static void killActive(std::string); From d4e68ab60216596867d6ee08b1e96ff0eeaec80e Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Mon, 1 Jan 2024 18:34:15 +0100 Subject: [PATCH 05/15] CI: allow manual stale execution --- .github/workflows/stale.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 09f7a992..223186b5 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -8,6 +8,7 @@ name: Mark stale issues and pull requests on: schedule: - cron: '26 0 * * *' + workflow_dispatch: jobs: stale: From 46753b1f22478c64222e5d9f7e0fb4c10b001be6 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Mon, 1 Jan 2024 18:37:49 +0100 Subject: [PATCH 06/15] CI: limit stalebot ops per run --- .github/workflows/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 223186b5..8955517f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ name: Mark stale issues and pull requests on: schedule: - - cron: '26 0 * * *' + - cron: '7 */4 * * *' workflow_dispatch: jobs: @@ -24,3 +24,4 @@ jobs: repo-token: ${{ secrets.STALEBOT_PAT }} stale-issue-label: 'stale' stale-pr-label: 'stale' + operations-per-run: 40 From 42ab06e7c84fed39b3f853f213ef2966f23baaa5 Mon Sep 17 00:00:00 2001 From: bvr-yr <130279855+bvr-yr@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:58:01 +0300 Subject: [PATCH 07/15] meson: fix wlroots patch (#4324) --- subprojects/packagefiles/wlroots-meson-build.patch | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/packagefiles/wlroots-meson-build.patch b/subprojects/packagefiles/wlroots-meson-build.patch index 4e911980..a184eb77 100644 --- a/subprojects/packagefiles/wlroots-meson-build.patch +++ b/subprojects/packagefiles/wlroots-meson-build.patch @@ -35,9 +35,9 @@ index 29b103a..0b6e5a4 100644 --- a/meson.build +++ b/meson.build @@ -15,7 +15,7 @@ project( - # necessary for bugfix releases. Increasing soversion is required because - # wlroots never guarantees ABI stability -- only API stability is guaranteed - # between minor releases. + version_major = version.split('.')[0] + version_minor = version.split('.')[1] + assert(version_major == '0') -soversion = version_minor.to_int() - 5 +soversion = 13032 From 1a4f23eb2fee77b23b2cc6ff1fbfc87f60f10314 Mon Sep 17 00:00:00 2001 From: q234rty Date: Tue, 2 Jan 2024 03:20:27 +0800 Subject: [PATCH 08/15] renderer: Only force nearest neighbor when the sizes are off by one or two (#4325) Fixes rendering issues in arch's extra/telegram-desktop --- src/render/Renderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0416d08f..533215ce 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -118,6 +118,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data) const auto NEARESTNEIGHBORSET = g_pHyprOpenGL->m_RenderData.useNearestNeighbor; if (std::floor(RDATA->pMonitor->scale) != RDATA->pMonitor->scale /* Fractional */ && surface->current.scale == 1 /* fs protocol */ && windowBox.size() != Vector2D{surface->current.buffer_width, surface->current.buffer_height} /* misaligned */ && + DELTALESSTHAN(windowBox.width, surface->current.buffer_width, 3) && DELTALESSTHAN(windowBox.height, surface->current.buffer_height, 3) /* off by one-or-two */ && (!RDATA->pWindow || (!RDATA->pWindow->m_vRealSize.isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */) g_pHyprOpenGL->m_RenderData.useNearestNeighbor = true; From 1607e967041fd3311411de0def8cdc0610274f98 Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Mon, 1 Jan 2024 17:05:26 -0500 Subject: [PATCH 09/15] HookSystem: rename PAGESIZE_VAR from PAGESIZE to avoid conflict (#4321) --- src/plugins/HookSystem.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp index e52fd749..a7625ffe 100644 --- a/src/plugins/HookSystem.cpp +++ b/src/plugins/HookSystem.cpp @@ -190,9 +190,9 @@ bool CFunctionHook::hook() { (uint64_t)((uint8_t*)m_pSource + sizeof(ABSOLUTE_JMP_ADDRESS)); // make jump to hk - const auto PAGESIZE = sysconf(_SC_PAGE_SIZE); - const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE); - const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE) * PAGESIZE; + const auto PAGESIZE_VAR = sysconf(_SC_PAGE_SIZE); + const uint8_t* PROTSTART = (uint8_t*)m_pSource - ((uint64_t)m_pSource % PAGESIZE_VAR); + const size_t PROTLEN = std::ceil((float)(ORIGSIZE + ((uint64_t)m_pSource - (uint64_t)PROTSTART)) / (float)PAGESIZE_VAR) * PAGESIZE_VAR; mprotect((uint8_t*)PROTSTART, PROTLEN, PROT_READ | PROT_WRITE | PROT_EXEC); memcpy((uint8_t*)m_pSource, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS)); From 583b05a8c67772e96e534e37e21b608fb5723546 Mon Sep 17 00:00:00 2001 From: dranull <150595692+dranull@users.noreply.github.com> Date: Tue, 2 Jan 2024 12:37:03 +0000 Subject: [PATCH 10/15] groupbar: Drag single window instead of destroying group (#4327) --- src/render/decorations/CHyprGroupBarDecoration.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 33ecff6a..61409256 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -317,6 +317,9 @@ void refreshGroupBarGradients() { } bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) { + if (m_pWindow == m_pWindow->m_sGroupData.pNextWindow) + return false; + const float BARRELATIVEX = pos.x - assignedBoxGlobal().x; const int WINDOWINDEX = (BARRELATIVEX) / (m_fBarWidth + BAR_HORIZONTAL_PADDING); From 813af393f1b61ecd0105e126681986e58e73ffee Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 2 Jan 2024 14:21:22 +0100 Subject: [PATCH 11/15] layout: update rules before applying fullscreen nodes in layouts --- src/Compositor.cpp | 1 - src/layout/DwindleLayout.cpp | 5 ++++- src/layout/MasterLayout.cpp | 3 +++ src/render/decorations/CHyprBorderDecoration.cpp | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 26bd56c4..af03e025 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -2284,7 +2284,6 @@ void CCompositor::setWindowFullscreen(CWindow* pWindow, bool on, eFullscreenMode g_pXWaylandManager->setWindowFullscreen(pWindow, pWindow->shouldSendFullscreenState()); - pWindow->updateDynamicRules(); updateWindowAnimatedDecorationValues(pWindow); // make all windows on the same workspace under the fullscreen window diff --git a/src/layout/DwindleLayout.cpp b/src/layout/DwindleLayout.cpp index 53ddb86e..76b9aeb4 100644 --- a/src/layout/DwindleLayout.cpp +++ b/src/layout/DwindleLayout.cpp @@ -780,6 +780,9 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree pWindow->m_bIsFullscreen = on; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; + pWindow->updateDynamicRules(); + pWindow->updateWindowDecos(); + g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)}); EMIT_HOOK_EVENT("fullscreen", pWindow); @@ -824,7 +827,7 @@ void CHyprDwindleLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscree pWindow->m_vPosition = fakeNode.box.pos(); pWindow->m_vSize = fakeNode.box.size(); - applyNodeDataToWindow(&fakeNode); + applyNodeDataToWindow(&fakeNode, true); } } diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 65f85691..63389c3a 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -883,6 +883,9 @@ void CHyprMasterLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreen pWindow->m_bIsFullscreen = on; PWORKSPACE->m_bHasFullscreenWindow = !PWORKSPACE->m_bHasFullscreenWindow; + pWindow->updateDynamicRules(); + pWindow->updateWindowDecos(); + g_pEventManager->postEvent(SHyprIPCEvent{"fullscreen", std::to_string((int)on)}); EMIT_HOOK_EVENT("fullscreen", pWindow); diff --git a/src/render/decorations/CHyprBorderDecoration.cpp b/src/render/decorations/CHyprBorderDecoration.cpp index 4e3e824e..77ebdd57 100644 --- a/src/render/decorations/CHyprBorderDecoration.cpp +++ b/src/render/decorations/CHyprBorderDecoration.cpp @@ -104,5 +104,5 @@ std::string CHyprBorderDecoration::getDisplayName() { } bool CHyprBorderDecoration::doesntWantBorders() { - return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders; + return !m_pWindow->m_sSpecialRenderData.border || m_pWindow->m_bX11DoesntWantBorders || m_pWindow->getRealBorderSize() == 0; } From bd3ea8dcb5f7803b0cc05e25f84200102c0fad21 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 2 Jan 2024 14:25:18 +0100 Subject: [PATCH 12/15] examples: remove example plugin closes #4329 --- example/examplePlugin/Makefile | 8 -- example/examplePlugin/customDecoration.cpp | 74 ---------------- example/examplePlugin/customDecoration.hpp | 29 ------- example/examplePlugin/customLayout.cpp | 80 ----------------- example/examplePlugin/customLayout.hpp | 32 ------- example/examplePlugin/globals.hpp | 5 -- example/examplePlugin/main.cpp | 99 ---------------------- 7 files changed, 327 deletions(-) delete mode 100644 example/examplePlugin/Makefile delete mode 100644 example/examplePlugin/customDecoration.cpp delete mode 100644 example/examplePlugin/customDecoration.hpp delete mode 100644 example/examplePlugin/customLayout.cpp delete mode 100644 example/examplePlugin/customLayout.hpp delete mode 100644 example/examplePlugin/globals.hpp delete mode 100644 example/examplePlugin/main.cpp diff --git a/example/examplePlugin/Makefile b/example/examplePlugin/Makefile deleted file mode 100644 index bb79532a..00000000 --- a/example/examplePlugin/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# compile with HYPRLAND_HEADERS= make all -# make sure that the path above is to the root hl repo directory, NOT src/ -# and that you have ran `make protocols` in the hl dir. - -all: - $(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b -clean: - rm ./examplePlugin.so diff --git a/example/examplePlugin/customDecoration.cpp b/example/examplePlugin/customDecoration.cpp deleted file mode 100644 index e2b5d136..00000000 --- a/example/examplePlugin/customDecoration.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "customDecoration.hpp" -#include -#include -#include "globals.hpp" - -CCustomDecoration::CCustomDecoration(CWindow* pWindow) { - m_pWindow = pWindow; - m_vLastWindowPos = pWindow->m_vRealPosition.vec(); - m_vLastWindowSize = pWindow->m_vRealSize.vec(); -} - -CCustomDecoration::~CCustomDecoration() { - damageEntire(); -} - -SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() { - return m_seExtents; -} - -void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) { - if (!g_pCompositor->windowValidMapped(m_pWindow)) - return; - - if (!m_pWindow->m_sSpecialRenderData.decorate) - return; - - static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue; - static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue; - static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue; - - const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ? - 0 : - (m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying()); - - // draw the border - CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE), - (int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)}; - - fullBox.x -= pMonitor->vecPosition.x; - fullBox.y -= pMonitor->vecPosition.y; - - m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2}, - {fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2, - fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}}; - - fullBox.x += offset.x; - fullBox.y += offset.y; - - if (fullBox.width < 1 || fullBox.height < 1) - return; // don't draw invisible shadows - - g_pHyprOpenGL->scissor((CBox*)nullptr); - - fullBox.scale(pMonitor->scale); - g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a); -} - -eDecorationType CCustomDecoration::getDecorationType() { - return DECORATION_CUSTOM; -} - -void CCustomDecoration::updateWindow(CWindow* pWindow) { - - m_vLastWindowPos = pWindow->m_vRealPosition.vec(); - m_vLastWindowSize = pWindow->m_vRealSize.vec(); - - damageEntire(); -} - -void CCustomDecoration::damageEntire() { - CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y), - (int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y}; - g_pHyprRenderer->damageBox(&dm); -} \ No newline at end of file diff --git a/example/examplePlugin/customDecoration.hpp b/example/examplePlugin/customDecoration.hpp deleted file mode 100644 index dbb0c0e2..00000000 --- a/example/examplePlugin/customDecoration.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include - -class CCustomDecoration : public IHyprWindowDecoration { - public: - CCustomDecoration(CWindow*); - virtual ~CCustomDecoration(); - - virtual SWindowDecorationExtents getWindowDecorationExtents(); - - virtual void draw(CMonitor*, float a, const Vector2D& offset); - - virtual eDecorationType getDecorationType(); - - virtual void updateWindow(CWindow*); - - virtual void damageEntire(); - - private: - SWindowDecorationExtents m_seExtents; - - CWindow* m_pWindow = nullptr; - - Vector2D m_vLastWindowPos; - Vector2D m_vLastWindowSize; -}; \ No newline at end of file diff --git a/example/examplePlugin/customLayout.cpp b/example/examplePlugin/customLayout.cpp deleted file mode 100644 index 8001c72d..00000000 --- a/example/examplePlugin/customLayout.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "customLayout.hpp" -#include -#include "globals.hpp" - -void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) { - const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); - const auto SIZE = PMONITOR->vecSize; - - // these are used for focus and move calculations, and are *required* to touch for moving focus to work properly. - pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)}; - pWindow->m_vSize = SIZE / 2.0; - - // this is the actual pos and size of the window (where it's rendered) - pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10}; - pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20}; - - const auto PDATA = &m_vWindowData.emplace_back(); - PDATA->pWindow = pWindow; -} - -void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) { - std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; }); -} - -bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) { - return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end(); -} - -void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) { - ; // empty -} - -void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) { - ; // empty -} - -void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) { - ; // empty -} - -void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) { - ; // empty -} - -std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) { - return ""; -} - -SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) { - return {}; -} - -void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) { - ; // empty -} - -void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) { - ; // empty -} - -std::string CHyprCustomLayout::getLayoutName() { - return "custom"; -} - -void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) { - ; // empty -} - -void CHyprCustomLayout::onEnable() { - for (auto& w : g_pCompositor->m_vWindows) { - if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating) - continue; - - onWindowCreatedTiling(w.get()); - } -} - -void CHyprCustomLayout::onDisable() { - m_vWindowData.clear(); -} \ No newline at end of file diff --git a/example/examplePlugin/customLayout.hpp b/example/examplePlugin/customLayout.hpp deleted file mode 100644 index 44797ccc..00000000 --- a/example/examplePlugin/customLayout.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#define WLR_USE_UNSTABLE - -#include - -struct SWindowData { - CWindow* pWindow = nullptr; -}; - -class CHyprCustomLayout : public IHyprLayout { - public: - virtual void onWindowCreatedTiling(CWindow*); - virtual void onWindowRemovedTiling(CWindow*); - virtual bool isWindowTiled(CWindow*); - virtual void recalculateMonitor(const int&); - virtual void recalculateWindow(CWindow*); - virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr); - virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool); - virtual std::any layoutMessage(SLayoutMessageHeader, std::string); - virtual SWindowRenderLayoutHints requestRenderHints(CWindow*); - virtual void switchWindows(CWindow*, CWindow*); - virtual void alterSplitRatio(CWindow*, float, bool); - virtual std::string getLayoutName(); - virtual void replaceWindowDataWith(CWindow* from, CWindow* to); - - virtual void onEnable(); - virtual void onDisable(); - - private: - std::vector m_vWindowData; -}; \ No newline at end of file diff --git a/example/examplePlugin/globals.hpp b/example/examplePlugin/globals.hpp deleted file mode 100644 index 22574754..00000000 --- a/example/examplePlugin/globals.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -inline HANDLE PHANDLE = nullptr; \ No newline at end of file diff --git a/example/examplePlugin/main.cpp b/example/examplePlugin/main.cpp deleted file mode 100644 index f2cd1075..00000000 --- a/example/examplePlugin/main.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#define WLR_USE_UNSTABLE - -#include "globals.hpp" - -#include -#include -#include "customLayout.hpp" -#include "customDecoration.hpp" - -#include -#include - -// Methods -inline std::unique_ptr g_pCustomLayout; -inline CFunctionHook* g_pFocusHook = nullptr; -inline CFunctionHook* g_pMotionHook = nullptr; -inline CFunctionHook* g_pMouseDownHook = nullptr; -typedef void (*origFocusWindow)(void*, CWindow*, wlr_surface*); -typedef void (*origMotion)(wlr_seat*, uint32_t, double, double); -typedef void (*origMouseDownNormal)(void*, wlr_pointer_button_event*); - -// Do NOT change this function. -APICALL EXPORT std::string PLUGIN_API_VERSION() { - return HYPRLAND_API_VERSION; -} - -static void onActiveWindowChange(void* self, std::any data) { - try { - auto* const PWINDOW = std::any_cast(data); - - HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: " + (PWINDOW ? PWINDOW->m_szTitle : "None"), CColor{0.f, 0.5f, 1.f, 1.f}, 5000); - } catch (std::bad_any_cast& e) { HyprlandAPI::addNotification(PHANDLE, "[ExamplePlugin] Active window: None", CColor{0.f, 0.5f, 1.f, 1.f}, 5000); } -} - -static void onNewWindow(void* self, std::any data) { - auto* const PWINDOW = std::any_cast(data); - - HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, new CCustomDecoration(PWINDOW)); -} - -void hkFocusWindow(void* thisptr, CWindow* pWindow, wlr_surface* pSurface) { - // HyprlandAPI::addNotification(PHANDLE, getFormat("FocusWindow with %lx %lx", pWindow, pSurface), CColor{0.f, 1.f, 1.f, 1.f}, 5000); - (*(origFocusWindow)g_pFocusHook->m_pOriginal)(thisptr, pWindow, pSurface); -} - -void hkNotifyMotion(wlr_seat* wlr_seat, uint32_t time_msec, double sx, double sy) { - // HyprlandAPI::addNotification(PHANDLE, getFormat("NotifyMotion with %lf %lf", sx, sy), CColor{0.f, 1.f, 1.f, 1.f}, 5000); - (*(origMotion)g_pMotionHook->m_pOriginal)(wlr_seat, time_msec, sx, sy); -} - -void hkProcessMouseDownNormal(void* thisptr, wlr_pointer_button_event* e) { - // HyprlandAPI::addNotification(PHANDLE, "Mouse down normal!", CColor{0.8f, 0.2f, 0.5f, 1.0f}, 5000); - (*(origMouseDownNormal)g_pMouseDownHook->m_pOriginal)(thisptr, e); -} - -APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { - PHANDLE = handle; - - HyprlandAPI::addNotification(PHANDLE, "Hello World from an example plugin!", CColor{0.f, 1.f, 1.f, 1.f}, 5000); - - HyprlandAPI::registerCallbackDynamic(PHANDLE, "activeWindow", [&](void* self, SCallbackInfo& info, std::any data) { onActiveWindowChange(self, data); }); - HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); }); - - g_pCustomLayout = std::make_unique(); - - HyprlandAPI::addLayout(PHANDLE, "custom", g_pCustomLayout.get()); - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:example:border_color", SConfigValue{.intValue = configStringToInt("rgb(44ee44)")}); - - HyprlandAPI::addDispatcher(PHANDLE, "example", [](std::string arg) { HyprlandAPI::addNotification(PHANDLE, "Arg passed: " + arg, CColor{0.5f, 0.5f, 0.7f, 1.0f}, 5000); }); - - // Hook a public member - g_pFocusHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&CCompositor::focusWindow, (void*)&hkFocusWindow); - // Hook a public non-member - g_pMotionHook = HyprlandAPI::createFunctionHook(PHANDLE, (void*)&wlr_seat_pointer_notify_motion, (void*)&hkNotifyMotion); - // Hook a private member - static const auto METHODS = HyprlandAPI::findFunctionsByName(PHANDLE, "processMouseDownNormal"); - g_pMouseDownHook = HyprlandAPI::createFunctionHook(PHANDLE, METHODS[0].address, (void*)&hkProcessMouseDownNormal); - - static auto* const PBORDERCOLOR = HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color"); - - // fancy notifications - HyprlandAPI::addNotificationV2( - PHANDLE, - {{"text", "Example hint, color " + std::to_string(PBORDERCOLOR->intValue)}, {"time", (uint64_t)10000}, {"color", CColor{PBORDERCOLOR->intValue}}, {"icon", ICON_HINT}}); - - // Enable our hooks - g_pFocusHook->hook(); - g_pMotionHook->hook(); - g_pMouseDownHook->hook(); - - HyprlandAPI::reloadConfig(); - - return {"ExamplePlugin", "An example plugin", "Vaxry", "1.0"}; -} - -APICALL EXPORT void PLUGIN_EXIT() { - HyprlandAPI::invokeHyprctlCommand("seterror", "disable"); -} \ No newline at end of file From 3c33d4b9dda3c418a6b842c71720040b092f8510 Mon Sep 17 00:00:00 2001 From: dranull <150595692+dranull@users.noreply.github.com> Date: Tue, 2 Jan 2024 13:50:30 +0000 Subject: [PATCH 13/15] keybinds: Refocus only if the silently moved window had the focus (#4328) --- src/managers/KeybindManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index d379a408..21cc1f74 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -1062,10 +1062,12 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, pWorkspace); } - if (const auto PATCOORDS = g_pCompositor->vectorToWindowIdeal(OLDMIDDLE); PATCOORDS && PATCOORDS != PWINDOW) - g_pCompositor->focusWindow(PATCOORDS); - else - g_pInputManager->refocus(); + if (PWINDOW == g_pCompositor->m_pLastWindow) { + if (const auto PATCOORDS = g_pCompositor->vectorToWindowIdeal(OLDMIDDLE, PWINDOW); PATCOORDS) + g_pCompositor->focusWindow(PATCOORDS); + else + g_pInputManager->refocus(); + } } void CKeybindManager::moveFocusTo(std::string args) { From 4f26c4e1ebf868243dc628182c88d7feb52c8472 Mon Sep 17 00:00:00 2001 From: flicko <77581181+flick0@users.noreply.github.com> Date: Tue, 2 Jan 2024 21:08:30 +0530 Subject: [PATCH 14/15] config: variables update their value when set again (#4263) * variables update their value when set again * only sort if new variable is found * clang-format --- src/config/ConfigManager.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 28959128..44b5374b 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -395,10 +395,20 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s if (!COMMAND.starts_with("device:") /* devices parsed later */ && !COMMAND.starts_with("plugin:") /* plugins parsed later */) { if (COMMAND[0] == '$') { // register a dynamic var - Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE); - configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE)); + bool found = false; + for (auto& [var, val] : configDynamicVars) { + if (var == COMMAND.substr(1)) { + Debug::log(LOG, "Registered new value for dynamic var \"{}\" -> {}", COMMAND, VALUE); + val = VALUE; + found = true; + } + } - std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); }); + if (!found) { + Debug::log(LOG, "Registered dynamic var \"{}\" -> {}", COMMAND, VALUE); + configDynamicVars.emplace_back(std::make_pair<>(COMMAND.substr(1), VALUE)); + std::sort(configDynamicVars.begin(), configDynamicVars.end(), [&](const auto& a, const auto& b) { return a.first.length() > b.first.length(); }); + } } else { parseError = "Error setting value <" + VALUE + "> for field <" + COMMAND + ">: No such field."; } From 1512b81126dd115f089fd21244692d92034c78f8 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 2 Jan 2024 22:18:30 +0100 Subject: [PATCH 15/15] master: guard PNODE in roll* fixes #4331 --- src/layout/MasterLayout.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/layout/MasterLayout.cpp b/src/layout/MasterLayout.cpp index 63389c3a..2506bbf2 100644 --- a/src/layout/MasterLayout.cpp +++ b/src/layout/MasterLayout.cpp @@ -1331,6 +1331,9 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto PWINDOW = header.pWindow; const auto PNODE = getNodeFromWindow(PWINDOW); + if (!PNODE) + return 0; + const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID); const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER); @@ -1353,6 +1356,9 @@ std::any CHyprMasterLayout::layoutMessage(SLayoutMessageHeader header, std::stri const auto PWINDOW = header.pWindow; const auto PNODE = getNodeFromWindow(PWINDOW); + if (!PNODE) + return 0; + const auto OLDMASTER = PNODE->isMaster ? PNODE : getMasterNodeOnWorkspace(PNODE->workspaceID); const auto OLDMASTERIT = std::find(m_lMasterNodesData.begin(), m_lMasterNodesData.end(), *OLDMASTER);