From b6e080577daf6575b95e6733dd2e2aef714bcf10 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Mon, 4 May 2026 16:35:52 -0700 Subject: [PATCH] all: lua update compatibility (#649) --- borders-plus-plus/BorderppPassElement.cpp | 8 +- borders-plus-plus/BorderppPassElement.hpp | 14 ++- borders-plus-plus/borderDeco.cpp | 1 + csgo-vulkan-fix/README.md | 20 +++- flake.lock | 94 ++++++++-------- flake.nix | 1 - hyprbars/README.md | 30 +++++ hyprexpo/OverviewPassElement.cpp | 3 +- hyprexpo/OverviewPassElement.hpp | 17 +-- hyprexpo/README.md | 22 +++- hyprexpo/main.cpp | 95 ++++++++++++++-- hyprexpo/overview.cpp | 131 ++++++++++++++-------- hyprexpo/overview.hpp | 35 +++--- hyprtrails/TrailPassElement.cpp | 8 +- hyprtrails/TrailPassElement.hpp | 14 ++- hyprtrails/globals.hpp | 10 +- hyprtrails/main.cpp | 89 ++++----------- hyprtrails/trail.cpp | 53 ++++++--- hyprtrails/trail.hpp | 4 +- hyprwinwrap/main.cpp | 50 +++++++-- xtra-dispatchers/main.cpp | 6 +- 21 files changed, 452 insertions(+), 253 deletions(-) diff --git a/borders-plus-plus/BorderppPassElement.cpp b/borders-plus-plus/BorderppPassElement.cpp index 295e88d..53772a4 100644 --- a/borders-plus-plus/BorderppPassElement.cpp +++ b/borders-plus-plus/BorderppPassElement.cpp @@ -1,13 +1,15 @@ #include "BorderppPassElement.hpp" #include +#include #include "borderDeco.hpp" CBorderPPPassElement::CBorderPPPassElement(const CBorderPPPassElement::SBorderPPData& data_) : data(data_) { ; } -void CBorderPPPassElement::draw(const CRegion& damage) { - data.deco->drawPass(g_pHyprOpenGL->m_renderData.pMonitor.lock(), data.a); +std::vector> CBorderPPPassElement::draw() { + data.deco->drawPass(g_pHyprRenderer->m_renderData.pMonitor.lock(), data.a); + return {}; } bool CBorderPPPassElement::needsLiveBlur() { @@ -16,4 +18,4 @@ bool CBorderPPPassElement::needsLiveBlur() { bool CBorderPPPassElement::needsPrecomputeBlur() { return false; -} \ No newline at end of file +} diff --git a/borders-plus-plus/BorderppPassElement.hpp b/borders-plus-plus/BorderppPassElement.hpp index 12b858a..6d8abe5 100644 --- a/borders-plus-plus/BorderppPassElement.hpp +++ b/borders-plus-plus/BorderppPassElement.hpp @@ -13,14 +13,18 @@ class CBorderPPPassElement : public IPassElement { CBorderPPPassElement(const SBorderPPData& data_); virtual ~CBorderPPPassElement() = default; - virtual void draw(const CRegion& damage); - virtual bool needsLiveBlur(); - virtual bool needsPrecomputeBlur(); + virtual std::vector> draw() override; + virtual bool needsLiveBlur() override; + virtual bool needsPrecomputeBlur() override; - virtual const char* passName() { + virtual const char* passName() override { return "CBorderPPPassElement"; } + virtual ePassElementType type() override { + return EK_CUSTOM; + } + private: SBorderPPData data; -}; \ No newline at end of file +}; diff --git a/borders-plus-plus/borderDeco.cpp b/borders-plus-plus/borderDeco.cpp index 9a2abfa..dbb1855 100644 --- a/borders-plus-plus/borderDeco.cpp +++ b/borders-plus-plus/borderDeco.cpp @@ -5,6 +5,7 @@ #include #include using namespace Hyprutils::Memory; +using namespace Render::GL; #include "BorderppPassElement.hpp" #include "globals.hpp" diff --git a/csgo-vulkan-fix/README.md b/csgo-vulkan-fix/README.md index 0727576..6615838 100644 --- a/csgo-vulkan-fix/README.md +++ b/csgo-vulkan-fix/README.md @@ -18,9 +18,9 @@ CS2 launch options: ``` example plugin config: -``` +```ini plugin { - csgo-vulkan-fix { + csgo_vulkan_fix { # Whether to fix the mouse position. A select few apps might be wonky with this. fix_mouse = true @@ -31,4 +31,18 @@ plugin { } ``` -fullscreen the game manually and enjoy. \ No newline at end of file +Lua config: +```lua +hl.config({ + plugin = { + csgo_vulkan_fix = { + fix_mouse = true, + }, + }, +}) + +hl.plugin.csgo_vulkan_fix.vkfix_app({ app = "cs2", w = 1650, h = 1050 }) +hl.plugin.csgo_vulkan_fix.vkfix_app({ app = "myapp", w = 1920, h = 1080 }) +``` + +fullscreen the game manually and enjoy. diff --git a/flake.lock b/flake.lock index c291026..1dcaed1 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ ] }, "locked": { - "lastModified": 1765900596, - "narHash": "sha256-+hn8v9jkkLP9m+o0Nm5SiEq10W0iWDSotH2XfjU45fA=", + "lastModified": 1776876344, + "narHash": "sha256-Ubqb/agkuMJK+k19gjQgHux/eOYRc1sRGoOZOho8+VY=", "owner": "hyprwm", "repo": "aquamarine", - "rev": "d83c97f8f5c0aae553c1489c7d9eff3eadcadace", + "rev": "648a13d0ee1e03a843b3e145b8ece15393058701", "type": "github" }, "original": { @@ -36,15 +36,15 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1761588595, - "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", - "owner": "edolstra", + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", "repo": "flake-compat", - "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", "type": "github" }, "original": { - "owner": "edolstra", + "owner": "NixOS", "repo": "flake-compat", "type": "github" } @@ -87,11 +87,11 @@ ] }, "locked": { - "lastModified": 1753964049, - "narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=", + "lastModified": 1776511930, + "narHash": "sha256-fCpwFiTW0rT7oKJqr3cqHMnkwypSwQKpbtUEtxdkgrM=", "owner": "hyprwm", "repo": "hyprcursor", - "rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5", + "rev": "39435900785d0c560c6ae8777d29f28617d031ef", "type": "github" }, "original": { @@ -116,11 +116,11 @@ ] }, "locked": { - "lastModified": 1763733840, - "narHash": "sha256-JnET78yl5RvpGuDQy3rCycOCkiKoLr5DN1fPhRNNMco=", + "lastModified": 1776426399, + "narHash": "sha256-RUESLKNikIeEq9ymGJ6nmcDXiSFQpUW1IhJ245nL3xM=", "owner": "hyprwm", "repo": "hyprgraphics", - "rev": "8f1bec691b2d198c60cccabca7a94add2df4ed1a", + "rev": "68d064434787cf1ed4a2fe257c03c5f52f33cf84", "type": "github" }, "original": { @@ -146,11 +146,11 @@ "xdph": "xdph" }, "locked": { - "lastModified": 1767201430, - "narHash": "sha256-2FF66EaIbsc7CL1jKHbRFslSePDq40fzlTTbUlm5v3k=", + "lastModified": 1777469508, + "narHash": "sha256-2j6wX8051O5KcLw03t9x/RsFUOIGmQ2BPMMEO//iF1o=", "owner": "hyprwm", "repo": "Hyprland", - "rev": "48a024e0322bbd7c4c88126498ec478444ec4cb2", + "rev": "202cf48ecf627839c0a7433cbeb018c744214390", "type": "github" }, "original": { @@ -192,11 +192,11 @@ ] }, "locked": { - "lastModified": 1765643131, - "narHash": "sha256-CCGohW5EBIRy4B7vTyBMqPgsNcaNenVad/wszfddET0=", + "lastModified": 1776426575, + "narHash": "sha256-KI6nIfVihn/DPaeB5Et46Xg3dkNHrrEtUd5LBBVomB0=", "owner": "hyprwm", "repo": "hyprland-guiutils", - "rev": "e50ae912813bdfa8372d62daf454f48d6df02297", + "rev": "a968d211048e3ed538e47b84cb3649299578f19d", "type": "github" }, "original": { @@ -217,11 +217,11 @@ ] }, "locked": { - "lastModified": 1765214753, - "narHash": "sha256-P9zdGXOzToJJgu5sVjv7oeOGPIIwrd9hAUAP3PsmBBs=", + "lastModified": 1772460177, + "narHash": "sha256-/6G/MsPvtn7bc4Y32pserBT/Z4SUUdBd4XYJpOEKVR4=", "owner": "hyprwm", "repo": "hyprland-protocols", - "rev": "3f3860b869014c00e8b9e0528c7b4ddc335c21ab", + "rev": "1cb6db5fd6bb8aee419f4457402fa18293ace917", "type": "github" }, "original": { @@ -246,11 +246,11 @@ ] }, "locked": { - "lastModified": 1764612430, - "narHash": "sha256-54ltTSbI6W+qYGMchAgCR6QnC1kOdKXN6X6pJhOWxFg=", + "lastModified": 1776426736, + "narHash": "sha256-rl7i4aY+9p8LysJp7o8uRWahCkpFznCgGHXszlTw7b0=", "owner": "hyprwm", "repo": "hyprlang", - "rev": "0d00dc118981531aa731150b6ea551ef037acddd", + "rev": "7833ff33b2e82d3406337b5dcf0d1cec595d83e9", "type": "github" }, "original": { @@ -298,11 +298,11 @@ ] }, "locked": { - "lastModified": 1764592794, - "narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=", + "lastModified": 1772462885, + "narHash": "sha256-5pHXrQK9zasMnIo6yME6EOXmWGFMSnCITcfKshhKJ9I=", "owner": "hyprwm", "repo": "hyprtoolkit", - "rev": "5cfe0743f0e608e1462972303778d8a0859ee63e", + "rev": "9af245a69fa6b286b88ddfc340afd288e00a6998", "type": "github" }, "original": { @@ -323,11 +323,11 @@ ] }, "locked": { - "lastModified": 1766160771, - "narHash": "sha256-roINUGikWRqqgKrD4iotKbGj3ZKJl3hjMz5l/SyKrHw=", + "lastModified": 1777148223, + "narHash": "sha256-PTf7kRFFzCW6rIYxLH2fWfVJmj86FSYe3k6L8B+IM9o=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "5ac060bfcf2f12b3a6381156ebbc13826a05b09f", + "rev": "fa3992be2dfebe4ab06d753c6ca59bea298e798f", "type": "github" }, "original": { @@ -348,11 +348,11 @@ ] }, "locked": { - "lastModified": 1763640274, - "narHash": "sha256-Uan1Nl9i4TF/kyFoHnTq1bd/rsWh4GAK/9/jDqLbY5A=", + "lastModified": 1777148232, + "narHash": "sha256-Uv0WZLhu89SafuSOmYDA7akrPt4wBRmsa1ucasO5aXg=", "owner": "hyprwm", "repo": "hyprwayland-scanner", - "rev": "f6cf414ca0e16a4d30198fd670ec86df3c89f671", + "rev": "fec9cf1abcc1011e46f0a0986f46bf93c6bf8b92", "type": "github" }, "original": { @@ -377,11 +377,11 @@ ] }, "locked": { - "lastModified": 1766253200, - "narHash": "sha256-26qPwrd3od+xoYVywSB7hC2cz9ivN46VPLlrsXyGxvE=", + "lastModified": 1776728575, + "narHash": "sha256-z9eGphrArEBpl1O/GCH0wlY6z4K9vA6yWh2gAS6qytU=", "owner": "hyprwm", "repo": "hyprwire", - "rev": "1079777525b30a947c8d657fac158e00ae85de9d", + "rev": "f3a80888783702a39691b684d099e16b83ed4702", "type": "github" }, "original": { @@ -392,11 +392,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1766070988, - "narHash": "sha256-G/WVghka6c4bAzMhTwT2vjLccg/awmHkdKSd2JrycLc=", + "lastModified": 1776877367, + "narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "c6245e83d836d0433170a16eb185cefe0572f8b8", + "rev": "0726a0ecb6d4e08f6adced58726b95db924cef57", "type": "github" }, "original": { @@ -416,11 +416,11 @@ ] }, "locked": { - "lastModified": 1765911976, - "narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=", + "lastModified": 1776796298, + "narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", + "rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad", "type": "github" }, "original": { @@ -485,11 +485,11 @@ ] }, "locked": { - "lastModified": 1761431178, - "narHash": "sha256-xzjC1CV3+wpUQKNF+GnadnkeGUCJX+vgaWIZsnz9tzI=", + "lastModified": 1777035886, + "narHash": "sha256-m1TNuBoSXUBSKhD9UVMkU90M0wFTPTfvIOOltO8IM8A=", "owner": "hyprwm", "repo": "xdg-desktop-portal-hyprland", - "rev": "4b8801228ff958d028f588f0c2b911dbf32297f9", + "rev": "ecfcdcc781f48821d83e1e2a0e30d7beca0eeb5e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 1ff5a3e..0f598d7 100644 --- a/flake.nix +++ b/flake.nix @@ -34,7 +34,6 @@ hyprbars hyprexpo hyprfocus - hyprscrolling hyprtrails hyprwinwrap xtra-dispatchers diff --git a/hyprbars/README.md b/hyprbars/README.md index bded3bb..7224107 100644 --- a/hyprbars/README.md +++ b/hyprbars/README.md @@ -55,6 +55,36 @@ hyprbars-button = bgcolor, size, icon, on-click, fgcolor Please note it _has_ to be inside `plugin { hyprbars { } }`. +For Lua config, use `hl.config` for plugin options and +`hl.plugin.hyprbars.add_button` for buttons: + +```lua +hl.config({ + plugin = { + hyprbars = { + bar_height = 20, + on_double_click = "hyprctl dispatch fullscreen 1", + }, + }, +}) + +hl.plugin.hyprbars.add_button({ + bg_color = "rgb(ff4040)", + fg_color = "rgb(ffffff)", + size = 10, + icon = "X", + action = "hyprctl dispatch killactive", +}) + +hl.plugin.hyprbars.add_button({ + bg_color = "rgb(eeee11)", + fg_color = "rgb(000000)", + size = 10, + icon = "_", + action = "hyprctl dispatch fullscreen 1", +}) +``` + ## Window rules Hyprbars supports the following _dynamic_ [window rules](https://wiki.hypr.land/Configuring/Window-Rules/): diff --git a/hyprexpo/OverviewPassElement.cpp b/hyprexpo/OverviewPassElement.cpp index 1fc88e7..ef40486 100644 --- a/hyprexpo/OverviewPassElement.cpp +++ b/hyprexpo/OverviewPassElement.cpp @@ -6,8 +6,9 @@ COverviewPassElement::COverviewPassElement() { ; } -void COverviewPassElement::draw(const CRegion& damage) { +std::vector> COverviewPassElement::draw() { g_pOverview->fullRender(); + return {}; } bool COverviewPassElement::needsLiveBlur() { diff --git a/hyprexpo/OverviewPassElement.hpp b/hyprexpo/OverviewPassElement.hpp index f9d5a37..3a364ec 100644 --- a/hyprexpo/OverviewPassElement.hpp +++ b/hyprexpo/OverviewPassElement.hpp @@ -8,13 +8,16 @@ class COverviewPassElement : public IPassElement { COverviewPassElement(); virtual ~COverviewPassElement() = default; - virtual void draw(const CRegion& damage); - virtual bool needsLiveBlur(); - virtual bool needsPrecomputeBlur(); - virtual std::optional boundingBox(); - virtual CRegion opaqueRegion(); + virtual std::vector> draw() override; + virtual bool needsLiveBlur() override; + virtual bool needsPrecomputeBlur() override; + virtual std::optional boundingBox() override; + virtual CRegion opaqueRegion() override; + virtual ePassElementType type() override { + return EK_CUSTOM; + } - virtual const char* passName() { + virtual const char* passName() override { return "COverviewPassElement"; } -}; \ No newline at end of file +}; diff --git a/hyprexpo/README.md b/hyprexpo/README.md index 97bd1d4..cbc9d07 100644 --- a/hyprexpo/README.md +++ b/hyprexpo/README.md @@ -48,13 +48,33 @@ Example: bind = SUPER, g, hyprexpo:expo, toggle ``` +Lua config: +```lua +hl.config({ + plugin = { + hyprexpo = { + columns = 3, + gap_size = 5, + bg_col = "rgb(111111)", + workspace_method = "center current", + skip_empty = false, + gesture_distance = 300, + }, + }, +}) + +hl.bind("SUPER + g", function() + hl.plugin.hyprexpo.expo("toggle") +end) +``` + Here are a list of options you can use: | option | description | | --- | --- | toggle | displays if hidden, hide if displayed select | selects the hovered desktop +bring | brings a window from the hovered desktop to the current desktop off | hides the overview disable | same as `off` on | displays the overview enable | same as `on` - diff --git a/hyprexpo/main.cpp b/hyprexpo/main.cpp index 1f74f38..65521f4 100644 --- a/hyprexpo/main.cpp +++ b/hyprexpo/main.cpp @@ -6,12 +6,18 @@ #include #include #include +#include +#include +#include +#include #include +#include #include #include #include #include +#include #include using namespace Hyprutils::String; @@ -23,7 +29,7 @@ using namespace Hyprutils::String; inline CFunctionHook* g_pRenderWorkspaceHook = nullptr; inline CFunctionHook* g_pAddDamageHookA = nullptr; inline CFunctionHook* g_pAddDamageHookB = nullptr; -typedef void (*origRenderWorkspace)(void*, PHLMONITOR, PHLWORKSPACE, timespec*, const CBox&); +typedef void (*origRenderWorkspace)(void*, PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&, const CBox&); typedef void (*origAddDamageA)(void*, const CBox&); typedef void (*origAddDamageB)(void*, const pixman_region32_t*); @@ -39,7 +45,7 @@ static bool renderingOverview = false; const std::string KEYWORD_EXPO_GESTURE = "hyprexpo-gesture"; // -static void hkRenderWorkspace(void* thisptr, PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, timespec* now, const CBox& geometry) { +static void hkRenderWorkspace(void* thisptr, PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry) { if (!g_pOverview || renderingOverview || g_pOverview->blockOverviewRendering || g_pOverview->pMonitor != pMonitor) ((origRenderWorkspace)(g_pRenderWorkspaceHook->m_original))(thisptr, pMonitor, pWorkspace, now, geometry); else @@ -68,6 +74,47 @@ static void hkAddDamageB(void* thisptr, const pixman_region32_t* rg) { g_pOverview->onDamageReported(); } +static PHLWINDOW windowToBringFromWorkspace(const PHLWORKSPACE& workspace) { + if (!workspace) + return nullptr; + + for (auto it = g_pCompositor->m_windows.rbegin(); it != g_pCompositor->m_windows.rend(); ++it) { + const auto& w = *it; + if (!w || w->m_workspace != workspace || !w->m_isMapped || w->isHidden()) + continue; + + return w; + } + + return nullptr; +} + +static SDispatchResult bringWindowFromWorkspace(int64_t sourceWorkspaceID) { + if (sourceWorkspaceID == WORKSPACE_INVALID) + return {.success = false, .error = "selected workspace is empty"}; + + const auto FOCUSSTATE = Desktop::focusState(); + const auto MONITOR = FOCUSSTATE->monitor(); + if (!MONITOR || !MONITOR->m_activeWorkspace) + return {.success = false, .error = "no active monitor/workspace"}; + + if (sourceWorkspaceID == MONITOR->activeWorkspaceID()) + return {}; + + const auto SOURCEWORKSPACE = g_pCompositor->getWorkspaceByID(sourceWorkspaceID); + if (!SOURCEWORKSPACE) + return {.success = false, .error = "selected workspace is not open"}; + + const auto WINDOW = windowToBringFromWorkspace(SOURCEWORKSPACE); + if (!WINDOW) + return {.success = false, .error = "selected workspace has no mapped windows"}; + + g_pCompositor->moveWindowToWorkspaceSafe(WINDOW, MONITOR->m_activeWorkspace); + FOCUSSTATE->fullWindowFocus(WINDOW, Desktop::FOCUS_REASON_KEYBIND); + g_pCompositor->warpCursorTo(WINDOW->middle()); + return {}; +} + static SDispatchResult onExpoDispatcher(std::string arg) { if (g_pOverview && g_pOverview->m_isSwiping) @@ -80,6 +127,15 @@ static SDispatchResult onExpoDispatcher(std::string arg) { } return {}; } + if (arg == "bring") { + if (g_pOverview) { + g_pOverview->selectHoveredWorkspace(); + const auto BRINGRESULT = bringWindowFromWorkspace(g_pOverview->selectedWorkspaceID()); + g_pOverview->close(false); + return BRINGRESULT; + } + return {}; + } if (arg == "toggle") { if (g_pOverview) g_pOverview->close(); @@ -106,10 +162,27 @@ static SDispatchResult onExpoDispatcher(std::string arg) { return {}; } +static int luaExpo(lua_State* L) { + const auto RESULT = onExpoDispatcher(luaL_optstring(L, 1, "toggle")); + if (!RESULT.success) + return luaL_error(L, "%s", RESULT.error.c_str()); + return 0; +} + static void failNotif(const std::string& reason) { HyprlandAPI::addNotification(PHANDLE, "[hyprexpo] Failure in initialization: " + reason, CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000); } +static bool addConfigValue(SP value) { + const auto RET = Config::mgr()->registerPluginValue(PHANDLE, value); + if (!RET) { + Log::logger->log(Log::ERR, "[hyprexpo] failed to register plugin value \"{}\": {}", value->name(), RET.error()); + return false; + } + + return true; +} + static Hyprlang::CParseResult expoGestureKeyword(const char* LHS, const char* RHS) { Hyprlang::CParseResult result; @@ -242,18 +315,16 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { }); HyprlandAPI::addDispatcherV2(PHANDLE, "hyprexpo:expo", ::onExpoDispatcher); + HyprlandAPI::addLuaFunction(PHANDLE, "hyprexpo", "expo", ::luaExpo); HyprlandAPI::addConfigKeyword(PHANDLE, KEYWORD_EXPO_GESTURE, ::expoGestureKeyword, {true}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:columns", Hyprlang::INT{3}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gap_size", Hyprlang::INT{5}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:bg_col", Hyprlang::INT{0xFF111111}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:workspace_method", Hyprlang::STRING{"center current"}); - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:skip_empty", Hyprlang::INT{0}); - - HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance", Hyprlang::INT{200}); - - HyprlandAPI::reloadConfig(); + addConfigValue(makeShared("plugin:hyprexpo:columns", "columns", 3)); + addConfigValue(makeShared("plugin:hyprexpo:gap_size", "gap size", 5)); + addConfigValue(makeShared("plugin:hyprexpo:bg_col", "background color", 0xFF111111)); + addConfigValue(makeShared("plugin:hyprexpo:workspace_method", "workspace method", "center current")); + addConfigValue(makeShared("plugin:hyprexpo:skip_empty", "skip empty workspaces", 0)); + addConfigValue(makeShared("plugin:hyprexpo:gesture_distance", "gesture distance", 200)); return {"hyprexpo", "A plugin for an overview", "Vaxry", "1.0"}; } @@ -263,5 +334,5 @@ APICALL EXPORT void PLUGIN_EXIT() { g_unloading = true; - g_pConfigManager->reload(); // we need to reload now to clear all the gestures + Config::mgr()->reload(); // we need to reload now to clear all the gestures } diff --git a/hyprexpo/overview.cpp b/hyprexpo/overview.cpp index 00bb8c9..097280c 100644 --- a/hyprexpo/overview.cpp +++ b/hyprexpo/overview.cpp @@ -1,44 +1,76 @@ #include "overview.hpp" +#include #include -#define private public +#include +#define private public +#define protected public #include #include #include #include #include +#include +#include +#include #include #include #include #include #include #include +#include +#include #undef private +#undef protected #include "OverviewPassElement.hpp" +using namespace Hyprutils::String; + +static uint32_t framebufferFormatWithAlpha(uint32_t drmFormat) { + const auto alphaFormat = NFormatUtils::alphaFormat(drmFormat); + return alphaFormat == 0 ? DRM_FORMAT_ABGR8888 : alphaFormat; +} + +static void clearWithColor(const CHyprColor& color) { + glClearColor(color.r, color.g, color.b, color.a); + glClear(GL_COLOR_BUFFER_BIT); +} + +static void ensureFramebuffer(COverview::SWorkspaceImage& image, const CBox& monbox, uint32_t drmFormat) { + if (!image.fb) + image.fb = g_pHyprRenderer->createFB("hyprexpo"); + + if (image.fb->m_size != monbox.size()) { + image.fb->release(); + image.fb->alloc(monbox.w, monbox.h, drmFormat); + } +} + static void damageMonitor(WP thisptr) { g_pOverview->damage(); } COverview::~COverview() { - g_pHyprRenderer->makeEGLCurrent(); + Render::GL::g_pHyprOpenGL->makeEGLCurrent(); images.clear(); // otherwise we get a vram leak Cursor::overrideController->unsetOverride(Cursor::CURSOR_OVERRIDE_UNKNOWN); - g_pHyprOpenGL->markBlurDirtyForMonitor(pMonitor.lock()); + if (pMonitor) + pMonitor->m_blurFBDirty = true; } COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn_), swipe(swipe_) { const auto PMONITOR = Desktop::focusState()->monitor(); pMonitor = PMONITOR; - static auto* const* PCOLUMNS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:columns")->getDataStaticPtr(); - static auto* const* PGAPS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gap_size")->getDataStaticPtr(); - static auto* const* PCOL = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:bg_col")->getDataStaticPtr(); - static auto* const* PSKIP = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:skip_empty")->getDataStaticPtr(); - static auto const* PMETHOD = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:workspace_method")->getDataStaticPtr(); + static const CConfigValue PCOLUMNS("plugin:hyprexpo:columns"); + static const CConfigValue PGAPS("plugin:hyprexpo:gap_size"); + static const CConfigValue PCOL("plugin:hyprexpo:bg_col"); + static const CConfigValue PSKIP("plugin:hyprexpo:skip_empty"); + static const CConfigValue PMETHOD("plugin:hyprexpo:workspace_method"); - SIDE_LENGTH = **PCOLUMNS; - GAP_WIDTH = **PGAPS; - BG_COLOR = **PCOL; + SIDE_LENGTH = *PCOLUMNS; + GAP_WIDTH = *PGAPS; + BG_COLOR = CHyprColor(*PCOL); // process the method bool methodCenter = true; @@ -56,7 +88,7 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn images.resize(SIDE_LENGTH * SIDE_LENGTH); // r includes empty workspaces; m skips over them - std::string selector = **PSKIP ? "m" : "r"; + std::string selector = *PSKIP ? "m" : "r"; if (methodCenter) { int currentID = methodStartID; @@ -120,7 +152,7 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn pMonitor->m_activeWorkspace = startedOn; } - g_pHyprRenderer->makeEGLCurrent(); + Render::GL::g_pHyprOpenGL->makeEGLCurrent(); Vector2D tileSize = pMonitor->m_size / SIDE_LENGTH; Vector2D tileRenderSize = (pMonitor->m_size - Vector2D{GAP_WIDTH * pMonitor->m_scale, GAP_WIDTH * pMonitor->m_scale} * (SIDE_LENGTH - 1)) / SIDE_LENGTH; @@ -141,12 +173,12 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn for (size_t i = 0; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) { COverview::SWorkspaceImage& image = images[i]; - image.fb.alloc(monbox.w, monbox.h, PMONITOR->m_output->state->state().drmFormat); + ensureFramebuffer(image, monbox, framebufferFormatWithAlpha(PMONITOR->m_output->state->state().drmFormat)); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &image.fb); + g_pHyprRenderer->beginRender(PMONITOR, fakeDamage, Render::RENDER_MODE_FULL_FAKE, nullptr, image.fb); - g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 1.0}); + clearWithColor(CHyprColor{0, 0, 0, 1.0}); const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(image.workspaceID); @@ -175,7 +207,7 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn image.box = {(i % SIDE_LENGTH) * tileRenderSize.x + (i % SIDE_LENGTH) * GAP_WIDTH, (i / SIDE_LENGTH) * tileRenderSize.y + (i / SIDE_LENGTH) * GAP_WIDTH, tileRenderSize.x, tileRenderSize.y}; - g_pHyprOpenGL->m_renderData.blockScreenShader = true; + g_pHyprRenderer->m_renderData.blockScreenShader = true; g_pHyprRenderer->endRender(); } @@ -189,10 +221,10 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn // zoom on the current workspace. // const auto& TILE = images[std::clamp(currentid, 0, SIDE_LENGTH * SIDE_LENGTH)]; - g_pAnimationManager->createAnimation(pMonitor->m_size * pMonitor->m_size / tileSize, size, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); + g_pAnimationManager->createAnimation(pMonitor->m_size * pMonitor->m_size / tileSize, size, Config::animationTree()->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); g_pAnimationManager->createAnimation((-((pMonitor->m_size / (double)SIDE_LENGTH) * Vector2D{currentid % SIDE_LENGTH, currentid / SIDE_LENGTH}) * pMonitor->m_scale) * (pMonitor->m_size / tileSize), - pos, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); + pos, Config::animationTree()->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE); size->setUpdateCallback(damageMonitor); pos->setUpdateCallback(damageMonitor); @@ -241,9 +273,9 @@ void COverview::selectHoveredWorkspace() { return; // get tile x,y - int x = lastMousePosLocal.x / pMonitor->m_size.x * SIDE_LENGTH; - int y = lastMousePosLocal.y / pMonitor->m_size.y * SIDE_LENGTH; - closeOnID = x + y * SIDE_LENGTH; + int x = std::clamp((int)(lastMousePosLocal.x / pMonitor->m_size.x * SIDE_LENGTH), 0, SIDE_LENGTH - 1); + int y = std::clamp((int)(lastMousePosLocal.y / pMonitor->m_size.y * SIDE_LENGTH), 0, SIDE_LENGTH - 1); + closeOnID = std::clamp(x + y * SIDE_LENGTH, 0, SIDE_LENGTH * SIDE_LENGTH - 1); } void COverview::redrawID(int id, bool forcelowres) { @@ -257,9 +289,9 @@ void COverview::redrawID(int id, bool forcelowres) { blockOverviewRendering = true; - g_pHyprRenderer->makeEGLCurrent(); + Render::GL::g_pHyprOpenGL->makeEGLCurrent(); - id = std::clamp(id, 0, SIDE_LENGTH * SIDE_LENGTH); + id = std::clamp(id, 0, SIDE_LENGTH * SIDE_LENGTH - 1); Vector2D tileSize = pMonitor->m_size / SIDE_LENGTH; Vector2D tileRenderSize = (pMonitor->m_size - Vector2D{GAP_WIDTH, GAP_WIDTH} * (SIDE_LENGTH - 1)) / SIDE_LENGTH; @@ -273,15 +305,12 @@ void COverview::redrawID(int id, bool forcelowres) { auto& image = images[id]; - if (image.fb.m_size != monbox.size()) { - image.fb.release(); - image.fb.alloc(monbox.w, monbox.h, pMonitor->m_output->state->state().drmFormat); - } + ensureFramebuffer(image, monbox, framebufferFormatWithAlpha(pMonitor->m_output->state->state().drmFormat)); CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX}; - g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &image.fb); + g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, Render::RENDER_MODE_FULL_FAKE, nullptr, image.fb); - g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 1.0}); + clearWithColor(CHyprColor{0, 0, 0, 1.0}); const auto PWORKSPACE = image.pWorkspace; @@ -309,7 +338,7 @@ void COverview::redrawID(int id, bool forcelowres) { } else g_pHyprRenderer->renderWorkspace(pMonitor.lock(), PWORKSPACE, Time::steadyNow(), monbox); - g_pHyprOpenGL->m_renderData.blockScreenShader = true; + g_pHyprRenderer->m_renderData.blockScreenShader = true; g_pHyprRenderer->endRender(); pMonitor->m_activeSpecialWorkspace = openSpecial; @@ -354,13 +383,22 @@ void COverview::onDamageReported() { g_pCompositor->scheduleFrameForMonitor(pMonitor.lock()); } -void COverview::close() { +int64_t COverview::selectedWorkspaceID() const { + const int ID = closeOnID == -1 ? openedID : closeOnID; + if (ID < 0 || ID >= (int)images.size()) + return WORKSPACE_INVALID; + + return images[ID].workspaceID; +} + +void COverview::close(bool switchToSelection) { if (closing) return; - const int ID = closeOnID == -1 ? openedID : closeOnID; + const int ID = closeOnID == -1 ? openedID : closeOnID; + const int SAFEID = std::clamp(ID, 0, SIDE_LENGTH * SIDE_LENGTH - 1); - const auto& TILE = images[std::clamp(ID, 0, SIDE_LENGTH * SIDE_LENGTH)]; + const auto& TILE = images[SAFEID]; Vector2D tileSize = (pMonitor->m_size / SIDE_LENGTH); @@ -368,13 +406,13 @@ void COverview::close() { pos->warp(); *size = pMonitor->m_size * pMonitor->m_size / tileSize; - *pos = (-((pMonitor->m_size / (double)SIDE_LENGTH) * Vector2D{ID % SIDE_LENGTH, ID / SIDE_LENGTH}) * pMonitor->m_scale) * (pMonitor->m_size / tileSize); + *pos = (-((pMonitor->m_size / (double)SIDE_LENGTH) * Vector2D{SAFEID % SIDE_LENGTH, SAFEID / SIDE_LENGTH}) * pMonitor->m_scale) * (pMonitor->m_size / tileSize); closing = true; redrawAll(); - if (TILE.workspaceID != pMonitor->activeWorkspaceID()) { + if (switchToSelection && TILE.workspaceID != pMonitor->activeWorkspaceID()) { pMonitor->setSpecialWorkspace(0); // If this tile's workspace was WORKSPACE_INVALID, move to the next @@ -387,9 +425,9 @@ void COverview::close() { const auto OLDWS = pMonitor->m_activeWorkspace; if (!NEWIDWS) - g_pKeybindManager->changeworkspace(std::to_string(NEWID)); + Config::Actions::changeWorkspace(std::to_string(NEWID)); else - g_pKeybindManager->changeworkspace(NEWIDWS->getConfigName()); + Config::Actions::changeWorkspace(NEWIDWS->getConfigName()); g_pDesktopAnimationManager->startAnimation(pMonitor->m_activeWorkspace, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true); g_pDesktopAnimationManager->startAnimation(OLDWS, CDesktopAnimationManager::ANIMATION_TYPE_OUT, false, true); @@ -443,7 +481,7 @@ void COverview::fullRender() { Vector2D tileSize = (SIZE / SIDE_LENGTH); Vector2D tileRenderSize = (SIZE - Vector2D{GAPSIZE, GAPSIZE} * (SIDE_LENGTH - 1)) / SIDE_LENGTH; - g_pHyprOpenGL->clear(BG_COLOR.stripA()); + clearWithColor(BG_COLOR.stripA()); for (size_t y = 0; y < (size_t)SIDE_LENGTH; ++y) { for (size_t x = 0; x < (size_t)SIDE_LENGTH; ++x) { @@ -451,7 +489,8 @@ void COverview::fullRender() { texbox.scale(pMonitor->m_scale).translate(pos->value()); texbox.round(); CRegion damage{0, 0, INT16_MAX, INT16_MAX}; - g_pHyprOpenGL->renderTextureInternal(images[x + y * SIDE_LENGTH].fb.getTexture(), texbox, {.damage = &damage, .a = 1.0}); + auto& image = images[x + y * SIDE_LENGTH]; + Render::GL::g_pHyprOpenGL->renderTextureInternal(image.fb->getTexture(), texbox, {.damage = &damage, .a = 1.0}); } } } @@ -475,15 +514,15 @@ void COverview::resetSwipe() { void COverview::onSwipeUpdate(double delta) { m_isSwiping = true; - static auto* const* PDISTANCE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance")->getDataStaticPtr(); + static const CConfigValue PDISTANCE("plugin:hyprexpo:gesture_distance"); - const float PERC = closing ? std::clamp(delta / (double)**PDISTANCE, 0.0, 1.0) : 1.0 - std::clamp(delta / (double)**PDISTANCE, 0.0, 1.0); - const auto WORKSPACE_FOCUS_ID = closing && closeOnID != -1 ? closeOnID : openedID; + const float PERC = closing ? std::clamp(delta / (double)*PDISTANCE, 0.0, 1.0) : 1.0 - std::clamp(delta / (double)*PDISTANCE, 0.0, 1.0); + const auto WORKSPACE_FOCUS_ID = closing && closeOnID != -1 ? closeOnID : openedID; - Vector2D tileSize = (pMonitor->m_size / SIDE_LENGTH); + Vector2D tileSize = (pMonitor->m_size / SIDE_LENGTH); - const auto SIZEMAX = pMonitor->m_size * pMonitor->m_size / tileSize; - const auto POSMAX = (-((pMonitor->m_size / (double)SIDE_LENGTH) * Vector2D{WORKSPACE_FOCUS_ID % SIDE_LENGTH, WORKSPACE_FOCUS_ID / SIDE_LENGTH}) * pMonitor->m_scale) * + const auto SIZEMAX = pMonitor->m_size * pMonitor->m_size / tileSize; + const auto POSMAX = (-((pMonitor->m_size / (double)SIDE_LENGTH) * Vector2D{WORKSPACE_FOCUS_ID % SIDE_LENGTH, WORKSPACE_FOCUS_ID / SIDE_LENGTH}) * pMonitor->m_scale) * (pMonitor->m_size / tileSize); const auto SIZEMIN = pMonitor->m_size; diff --git a/hyprexpo/overview.hpp b/hyprexpo/overview.hpp index 144add9..1cbf2df 100644 --- a/hyprexpo/overview.hpp +++ b/hyprexpo/overview.hpp @@ -32,8 +32,9 @@ class COverview { void onSwipeEnd(); // close without a selection - void close(); + void close(bool switchToSelection = true); void selectHoveredWorkspace(); + int64_t selectedWorkspaceID() const; bool blockOverviewRendering = false; bool blockDamageReporting = false; @@ -41,25 +42,25 @@ class COverview { PHLMONITORREF pMonitor; bool m_isSwiping = false; - private: - void redrawID(int id, bool forcelowres = false); - void redrawAll(bool forcelowres = false); - void onWorkspaceChange(); - void fullRender(); - - int SIDE_LENGTH = 3; - int GAP_WIDTH = 5; - CHyprColor BG_COLOR = CHyprColor{0.1, 0.1, 0.1, 1.0}; - - bool damageDirty = false; - struct SWorkspaceImage { - CFramebuffer fb; - int64_t workspaceID = -1; - PHLWORKSPACE pWorkspace; - CBox box; + SP fb; + int64_t workspaceID = -1; + PHLWORKSPACE pWorkspace; + CBox box; }; + private: + void redrawID(int id, bool forcelowres = false); + void redrawAll(bool forcelowres = false); + void onWorkspaceChange(); + void fullRender(); + + int SIDE_LENGTH = 3; + int GAP_WIDTH = 5; + CHyprColor BG_COLOR = CHyprColor{0.1, 0.1, 0.1, 1.0}; + + bool damageDirty = false; + Vector2D lastMousePosLocal = Vector2D{}; int openedID = -1; diff --git a/hyprtrails/TrailPassElement.cpp b/hyprtrails/TrailPassElement.cpp index a2734f6..c5bf781 100644 --- a/hyprtrails/TrailPassElement.cpp +++ b/hyprtrails/TrailPassElement.cpp @@ -1,13 +1,15 @@ #include "TrailPassElement.hpp" #include +#include #include "trail.hpp" CTrailPassElement::CTrailPassElement(const CTrailPassElement::STrailData& data_) : data(data_) { ; } -void CTrailPassElement::draw(const CRegion& damage) { - data.deco->renderPass(g_pHyprOpenGL->m_renderData.pMonitor.lock(), data.a); +std::vector> CTrailPassElement::draw() { + data.deco->renderPass(g_pHyprRenderer->m_renderData.pMonitor.lock(), data.a); + return {}; } bool CTrailPassElement::needsLiveBlur() { @@ -16,4 +18,4 @@ bool CTrailPassElement::needsLiveBlur() { bool CTrailPassElement::needsPrecomputeBlur() { return false; -} \ No newline at end of file +} diff --git a/hyprtrails/TrailPassElement.hpp b/hyprtrails/TrailPassElement.hpp index b9e998d..ff33ff1 100644 --- a/hyprtrails/TrailPassElement.hpp +++ b/hyprtrails/TrailPassElement.hpp @@ -13,14 +13,18 @@ class CTrailPassElement : public IPassElement { CTrailPassElement(const STrailData& data_); virtual ~CTrailPassElement() = default; - virtual void draw(const CRegion& damage); - virtual bool needsLiveBlur(); - virtual bool needsPrecomputeBlur(); + virtual std::vector> draw() override; + virtual bool needsLiveBlur() override; + virtual bool needsPrecomputeBlur() override; - virtual const char* passName() { + virtual const char* passName() override { return "CTrailPassElement"; } + virtual ePassElementType type() override { + return EK_CUSTOM; + } + private: STrailData data; -}; \ No newline at end of file +}; diff --git a/hyprtrails/globals.hpp b/hyprtrails/globals.hpp index 5abe391..87bc18f 100644 --- a/hyprtrails/globals.hpp +++ b/hyprtrails/globals.hpp @@ -1,12 +1,18 @@ #pragma once #include +#include +#include + +class CEventLoopTimer; +class CTrail; inline HANDLE PHANDLE = nullptr; struct SGlobalState { - SShader trailShader; - wl_event_source* tick = nullptr; + CShader trailShader; + SP tick; + std::vector trails; }; inline UP g_pGlobalState; diff --git a/hyprtrails/main.cpp b/hyprtrails/main.cpp index 76201a8..cec5f09 100644 --- a/hyprtrails/main.cpp +++ b/hyprtrails/main.cpp @@ -8,7 +8,9 @@ #include #include #include -#include +#include +#include +#include #include "globals.hpp" #include "shaders.hpp" @@ -19,82 +21,25 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() { return HYPRLAND_API_VERSION; } -void onNewWindow(void* self, std::any data) { - // data is guaranteed - const auto PWINDOW = std::any_cast(data); - +void onNewWindow(PHLWINDOW PWINDOW) { HyprlandAPI::addWindowDecoration(PHANDLE, PWINDOW, makeUnique(PWINDOW)); } -GLuint CompileShader(const GLuint& type, std::string src) { - auto shader = glCreateShader(type); +static void onTick(SP self, void* data) { + tickTrails(); - auto shaderSource = src.c_str(); - - glShaderSource(shader, 1, (const GLchar**)&shaderSource, nullptr); - glCompileShader(shader); - - GLint ok; - glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); - - if (ok == GL_FALSE) - throw std::runtime_error("compileShader() failed!"); - - return shader; -} - -GLuint CreateProgram(const std::string& vert, const std::string& frag) { - auto vertCompiled = CompileShader(GL_VERTEX_SHADER, vert); - - if (!vertCompiled) - throw std::runtime_error("Compiling vshader failed."); - - auto fragCompiled = CompileShader(GL_FRAGMENT_SHADER, frag); - - if (!fragCompiled) - throw std::runtime_error("Compiling fshader failed."); - - auto prog = glCreateProgram(); - glAttachShader(prog, vertCompiled); - glAttachShader(prog, fragCompiled); - glLinkProgram(prog); - - glDetachShader(prog, vertCompiled); - glDetachShader(prog, fragCompiled); - glDeleteShader(vertCompiled); - glDeleteShader(fragCompiled); - - GLint ok; - glGetProgramiv(prog, GL_LINK_STATUS, &ok); - - if (ok == GL_FALSE) - throw std::runtime_error("createProgram() failed! GL_LINK_STATUS not OK!"); - - return prog; -} - -int onTick(void* data) { - EMIT_HOOK_EVENT("trailTick", nullptr); - - const int TIMEOUT = g_pHyprRenderer->m_mostHzMonitor ? 1000.0 / g_pHyprRenderer->m_mostHzMonitor->m_refreshRate : 16; - wl_event_source_timer_update(g_pGlobalState->tick, TIMEOUT); - - return 0; + const int timeoutMs = g_pHyprRenderer->m_mostHzMonitor ? 1000.0 / g_pHyprRenderer->m_mostHzMonitor->m_refreshRate : 16; + self->updateTimeout(std::chrono::milliseconds(timeoutMs)); } void initGlobal() { - g_pHyprRenderer->makeEGLCurrent(); + Render::GL::g_pHyprOpenGL->makeEGLCurrent(); - GLuint prog = CreateProgram(QUADTRAIL, FRAGTRAIL); - g_pGlobalState->trailShader.program = prog; - g_pGlobalState->trailShader.uniformLocations[SHADER_PROJ] = glGetUniformLocation(prog, "proj"); - g_pGlobalState->trailShader.uniformLocations[SHADER_TEX] = glGetUniformLocation(prog, "tex"); - g_pGlobalState->trailShader.uniformLocations[SHADER_COLOR] = glGetUniformLocation(prog, "color"); - g_pGlobalState->trailShader.uniformLocations[SHADER_POS_ATTRIB] = glGetAttribLocation(prog, "pos"); - g_pGlobalState->trailShader.uniformLocations[SHADER_GRADIENT] = glGetUniformLocation(prog, "snapshots"); + if (!g_pGlobalState->trailShader.createProgram(QUADTRAIL, FRAGTRAIL, true, false)) + throw std::runtime_error("[ht] Failed to create trail shader"); - g_pGlobalState->tick = wl_event_loop_add_timer(g_pCompositor->m_wlEventLoop, &onTick, nullptr); - wl_event_source_timer_update(g_pGlobalState->tick, 1); + g_pGlobalState->tick = makeShared(std::chrono::milliseconds(1), onTick, nullptr); + g_pEventLoopManager->addTimer(g_pGlobalState->tick); } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { @@ -115,7 +60,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:history_step", Hyprlang::INT{2}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprtrails:color", Hyprlang::INT{*configStringToInt("rgba(ffaa00ff)")}); - static auto P = HyprlandAPI::registerCallbackDynamic(PHANDLE, "openWindow", [&](void* self, SCallbackInfo& info, std::any data) { onNewWindow(self, data); }); + static auto P = Event::bus()->m_events.window.open.listen([&](PHLWINDOW w) { onNewWindow(w); }); g_pGlobalState = makeUnique(); initGlobal(); @@ -136,6 +81,10 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { } APICALL EXPORT void PLUGIN_EXIT() { - wl_event_source_remove(g_pGlobalState->tick); + if (g_pGlobalState && g_pGlobalState->tick) { + g_pGlobalState->tick->cancel(); + g_pEventLoopManager->removeTimer(g_pGlobalState->tick); + } + g_pHyprRenderer->m_renderPass.removeAllOfType("CTrailPassElement"); } diff --git a/hyprtrails/trail.cpp b/hyprtrails/trail.cpp index 8598449..ebf1553 100644 --- a/hyprtrails/trail.cpp +++ b/hyprtrails/trail.cpp @@ -1,10 +1,12 @@ #include "trail.hpp" +#include #include #include #include #include using namespace Hyprutils::Memory; +using namespace Render::GL; #include "globals.hpp" #include "TrailPassElement.hpp" @@ -12,6 +14,9 @@ void CTrail::onTick() { static auto* const PHISTORYSTEP = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprtrails:history_step")->getDataStaticPtr(); static auto* const PHISTORYPOINTS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprtrails:history_points")->getDataStaticPtr(); + if (!validMapped(m_pWindow)) + return; + m_iTimer++; const auto PWINDOW = m_pWindow.lock(); @@ -36,12 +41,15 @@ CTrail::CTrail(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_pWindow(pW m_lastWindowPos = pWindow->m_realPosition->value(); m_lastWindowSize = pWindow->m_realSize->value(); - pTickCb = HyprlandAPI::registerCallbackDynamic(PHANDLE, "trailTick", [this](void* self, SCallbackInfo& info, std::any data) { this->onTick(); }); + if (g_pGlobalState) + g_pGlobalState->trails.push_back(this); } CTrail::~CTrail() { damageEntire(); - HyprlandAPI::unregisterCallback(PHANDLE, pTickCb); + + if (g_pGlobalState) + std::erase(g_pGlobalState->trails, this); } SDecorationPositioningInfo CTrail::getPositioningInfo() { @@ -127,14 +135,13 @@ void CTrail::renderPass(PHLMONITOR pMonitor, const float& a) { glStencilFunc(GL_NOTEQUAL, 1, -1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - CBox monbox = {0, 0, g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.x, g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.y}; + CBox monbox = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y}; - Mat3x3 matrix = g_pHyprOpenGL->m_renderData.monitorProjection.projectBox(monbox, Math::wlTransformToHyprutils(Math::invertTransform(WL_OUTPUT_TRANSFORM_NORMAL)), monbox.rot); - Mat3x3 glMatrix = g_pHyprOpenGL->m_renderData.projection.copy().multiply(matrix); + Mat3x3 glMatrix = g_pHyprRenderer->projectBoxToTarget(monbox, Math::wlTransformToHyprutils(Math::invertTransform(WL_OUTPUT_TRANSFORM_NORMAL))); g_pHyprOpenGL->blend(true); - glUseProgram(g_pGlobalState->trailShader.program); + glUseProgram(g_pGlobalState->trailShader.program()); glMatrix.transpose(); g_pGlobalState->trailShader.setUniformMatrix3fv(SHADER_PROJ, 1, GL_FALSE, glMatrix.getMatrix()); @@ -246,21 +253,21 @@ void CTrail::renderPass(PHLMONITOR pMonitor, const float& a) { sc((PWINDOW->m_realPosition->value().y - pMonitor->m_position.y) / pMonitor->m_size.y), sc((PWINDOW->m_realPosition->value().x + PWINDOW->m_realSize->value().x) / pMonitor->m_size.x), sc((PWINDOW->m_realPosition->value().y + PWINDOW->m_realSize->value().y) / pMonitor->m_size.y)}; - glUniform4f(g_pGlobalState->trailShader.uniformLocations[SHADER_GRADIENT], thisboxopengl.x, thisboxopengl.y, thisboxopengl.w, thisboxopengl.h); - glUniform4f(g_pGlobalState->trailShader.uniformLocations[SHADER_COLOR], COLOR.r, COLOR.g, COLOR.b, COLOR.a); + glUniform4f(g_pGlobalState->trailShader.getUniformLocation(SHADER_GRADIENT), thisboxopengl.x, thisboxopengl.y, thisboxopengl.w, thisboxopengl.h); + glUniform4f(g_pGlobalState->trailShader.getUniformLocation(SHADER_COLOR), COLOR.r, COLOR.g, COLOR.b, COLOR.a); CBox transformedBox = monbox; - transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprOpenGL->m_renderData.pMonitor->m_transform)), g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.x, - g_pHyprOpenGL->m_renderData.pMonitor->m_transformedSize.y); + transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(g_pHyprRenderer->m_renderData.pMonitor->m_transform)), g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, + g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y); - glVertexAttribPointer(g_pGlobalState->trailShader.uniformLocations[SHADER_POS_ATTRIB], 2, GL_FLOAT, GL_FALSE, 0, (float*)points.data()); + glVertexAttribPointer(g_pGlobalState->trailShader.getUniformLocation(SHADER_POS_ATTRIB), 2, GL_FLOAT, GL_FALSE, 0, (float*)points.data()); - glEnableVertexAttribArray(g_pGlobalState->trailShader.uniformLocations[SHADER_POS_ATTRIB]); + glEnableVertexAttribArray(g_pGlobalState->trailShader.getUniformLocation(SHADER_POS_ATTRIB)); - if (g_pHyprOpenGL->m_renderData.clipBox.width != 0 && g_pHyprOpenGL->m_renderData.clipBox.height != 0) { - CRegion damageClip{g_pHyprOpenGL->m_renderData.clipBox.x, g_pHyprOpenGL->m_renderData.clipBox.y, g_pHyprOpenGL->m_renderData.clipBox.width, - g_pHyprOpenGL->m_renderData.clipBox.height}; - damageClip.intersect(g_pHyprOpenGL->m_renderData.damage); + if (g_pHyprRenderer->m_renderData.clipBox.width != 0 && g_pHyprRenderer->m_renderData.clipBox.height != 0) { + CRegion damageClip{g_pHyprRenderer->m_renderData.clipBox.x, g_pHyprRenderer->m_renderData.clipBox.y, g_pHyprRenderer->m_renderData.clipBox.width, + g_pHyprRenderer->m_renderData.clipBox.height}; + damageClip.intersect(g_pHyprRenderer->m_renderData.damage); if (!damageClip.empty()) { for (auto& RECT : damageClip.getRects()) { @@ -269,13 +276,13 @@ void CTrail::renderPass(PHLMONITOR pMonitor, const float& a) { } } } else { - for (auto& RECT : g_pHyprOpenGL->m_renderData.damage.getRects()) { + for (auto& RECT : g_pHyprRenderer->m_renderData.damage.getRects()) { g_pHyprOpenGL->scissor(&RECT); glDrawArrays(GL_TRIANGLE_STRIP, 0, points.size()); } } - glDisableVertexAttribArray(g_pGlobalState->trailShader.uniformLocations[SHADER_POS_ATTRIB]); + glDisableVertexAttribArray(g_pGlobalState->trailShader.getUniformLocation(SHADER_POS_ATTRIB)); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -336,3 +343,13 @@ void CTrail::damageEntire() { sc(m_lastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), sc(m_seExtents.topLeft.y)}; g_pHyprRenderer->damageBox(dm); } + +void tickTrails() { + if (!g_pGlobalState) + return; + + for (auto* const trail : g_pGlobalState->trails) { + if (trail) + trail->onTick(); + } +} diff --git a/hyprtrails/trail.hpp b/hyprtrails/trail.hpp index 956775f..e2e259d 100644 --- a/hyprtrails/trail.hpp +++ b/hyprtrails/trail.hpp @@ -46,7 +46,6 @@ class CTrail : public IHyprWindowDecoration { virtual void damageEntire(); private: - SP pTickCb; void onTick(); void renderPass(PHLMONITOR pMonitor, const float& a); @@ -65,4 +64,7 @@ class CTrail : public IHyprWindowDecoration { bool m_bNeedsDamage = false; friend class CTrailPassElement; + friend void tickTrails(); }; + +void tickTrails(); diff --git a/hyprwinwrap/main.cpp b/hyprwinwrap/main.cpp index 5cb2d00..afb475d 100644 --- a/hyprwinwrap/main.cpp +++ b/hyprwinwrap/main.cpp @@ -8,15 +8,22 @@ #include #define private public +#define protected public #include #include #include +#include +#include #include #include #include #include #include #undef private +#undef protected + +using namespace Render; +using namespace Render::GL; #include "globals.hpp" @@ -32,6 +39,23 @@ typedef void (*origCommitSubsurface)(Desktop::View::CSubsurface* thisptr); typedef void (*origCommit)(void* owner, void* data); std::vector bgWindows; +std::vector> bgRules; + +static SP makeWindowRule(const std::string& name, const Desktop::Rule::eRuleProperty prop, const std::string& match) { + auto rule = makeShared(name); + rule->registerMatch(prop, "^(" + match + ")$"); + rule->addEffect(Desktop::Rule::WINDOW_RULE_EFFECT_FLOAT, "1"); + rule->addEffect(Desktop::Rule::WINDOW_RULE_EFFECT_SIZE, "100% 100%"); + return rule; +} + +static void clearWindowRules() { + for (auto& rule : bgRules) { + if (rule) + Desktop::Rule::ruleEngine()->unregisterRule(rule); + } + bgRules.clear(); +} void onNewWindow(PHLWINDOW pWindow) { static auto* const PCLASS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:class")->getDataStaticPtr(); @@ -121,13 +145,13 @@ void onRenderStage(eRenderStage stage) { for (auto& bg : bgWindows) { const auto bgw = bg.lock(); - if (bgw->m_monitor != g_pHyprOpenGL->m_renderData.pMonitor) + if (bgw->m_monitor != g_pHyprRenderer->m_renderData.pMonitor) continue; // cant use setHidden cuz that sends suspended and shit too that would be laggy bgw->m_hidden = false; - g_pHyprRenderer->renderWindow(bgw, g_pHyprOpenGL->m_renderData.pMonitor.lock(), Time::steadyNow(), false, RENDER_PASS_ALL, false, true); + g_pHyprRenderer->renderWindow(bgw, g_pHyprRenderer->m_renderData.pMonitor.lock(), Time::steadyNow(), false, RENDER_PASS_ALL, false, true); bgw->m_hidden = true; } @@ -146,7 +170,7 @@ void onCommitSubsurface(Desktop::View::CSubsurface* thisptr) { ((origCommitSubsurface)subsurfaceHook->m_original)(thisptr); if (const auto MON = PWINDOW->m_monitor.lock(); MON) - g_pHyprOpenGL->markBlurDirtyForMonitor(MON); + g_pHyprRenderer->damageMonitor(MON); PWINDOW->m_hidden = true; } @@ -164,25 +188,31 @@ void onCommit(void* owner, void* data) { ((origCommit)commitHook->m_original)(owner, data); if (const auto MON = PWINDOW->m_monitor.lock(); MON) - g_pHyprOpenGL->markBlurDirtyForMonitor(MON); + g_pHyprRenderer->damageMonitor(MON); PWINDOW->m_hidden = true; } void onConfigReloaded() { + clearWindowRules(); + static auto* const PCLASS = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:class")->getDataStaticPtr(); const std::string classRule(*PCLASS); if (!classRule.empty()) { - g_pConfigManager->parseKeyword("windowrulev2", std::string{"float, class:^("} + classRule + ")$"); - g_pConfigManager->parseKeyword("windowrulev2", std::string{"size 100\% 100\%, class:^("} + classRule + ")$"); + auto rule = makeWindowRule("hyprwinwrap-class", Desktop::Rule::RULE_PROP_CLASS, classRule); + bgRules.emplace_back(rule); + Desktop::Rule::ruleEngine()->registerRule(SP{rule}); } static auto* const PTITLE = (Hyprlang::STRING const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprwinwrap:title")->getDataStaticPtr(); const std::string titleRule(*PTITLE); if (!titleRule.empty()) { - g_pConfigManager->parseKeyword("windowrulev2", std::string{"float, title:^("} + titleRule + ")$"); - g_pConfigManager->parseKeyword("windowrulev2", std::string{"size 100\% 100\%, title:^("} + titleRule + ")$"); + auto rule = makeWindowRule("hyprwinwrap-title", Desktop::Rule::RULE_PROP_TITLE, titleRule); + bgRules.emplace_back(rule); + Desktop::Rule::ruleEngine()->registerRule(SP{rule}); } + + Desktop::Rule::ruleEngine()->updateAllRules(); } APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { @@ -226,11 +256,13 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_x", Hyprlang::STRING{"0"}); HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprwinwrap:pos_y", Hyprlang::STRING{"0"}); + onConfigReloaded(); + HyprlandAPI::addNotification(PHANDLE, "[hyprwinwrap] Initialized successfully!", CHyprColor{0.2, 1.0, 0.2, 1.0}, 5000); return {"hyprwinwrap", "A clone of xwinwrap for Hyprland", "Vaxry", "1.0"}; } APICALL EXPORT void PLUGIN_EXIT() { - ; + clearWindowRules(); } diff --git a/xtra-dispatchers/main.cpp b/xtra-dispatchers/main.cpp index 3509581..9a2fb73 100644 --- a/xtra-dispatchers/main.cpp +++ b/xtra-dispatchers/main.cpp @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #undef private @@ -38,7 +40,7 @@ static SDispatchResult moveOrExec(std::string in) { const auto PWINDOW = g_pCompositor->getWindowByRegex(vars[0]); if (!PWINDOW) - g_pKeybindManager->spawn(vars[1]); + Config::Supplementary::executor()->spawn(vars[1]); else { if (monitor->m_activeWorkspace != PWINDOW->m_workspace) g_pCompositor->moveWindowToWorkspaceSafe(PWINDOW, monitor->m_activeWorkspace); @@ -122,7 +124,7 @@ static SDispatchResult closeUnfocused(std::string in) { if (w->m_workspace != monitor->m_activeWorkspace || w->m_monitor != monitor || !w->m_isMapped || w == window) continue; - g_pCompositor->closeWindow(w); + Config::Actions::closeWindow(w); } return SDispatchResult{};